Permalink
Browse files

Added notify metaprogramming, more changes

  • Loading branch information...
1 parent 803cd30 commit dfb518c46f741d392cb3d912ca63857d3dbd7488 @tallakt committed Feb 25, 2009
View
@@ -1 +1,2 @@
*.swp
+secret/
View
@@ -4,6 +4,29 @@ PostInstall.txt
README.rdoc
Rakefile
lib/ruby-plc.rb
+lib/ruby-plc/etc/notify.rb
+lib/ruby-plc/io/io_access.rb
+lib/ruby-plc/physical/interlocks.rb
+lib/ruby-plc/physical/motor.rb
+lib/ruby-plc/physical/valve.rb
+lib/ruby-plc/sequences/branch.rb
+lib/ruby-plc/sequences/in_parallel.rb
+lib/ruby-plc/sequences/sequence.rb
+lib/ruby-plc/sequences/stack_sequence.rb
+lib/ruby-plc/sequences/step.rb
+lib/ruby-plc/sequences/step_listeners.rb
+lib/ruby-plc/sequences/wait_step.rb
+lib/ruby-plc/timedomain/and_signal.rb
+lib/ruby-plc/timedomain/binary_op_signal.rb
+lib/ruby-plc/timedomain/discrete_signal.rb
+lib/ruby-plc/timedomain/or_signal.rb
+lib/ruby-plc/timedomain/sequencer.rb
+lib/ruby-plc/timedomain/timer.rb
+lib/ruby-plc/timedomain/val_signal.rb
script/console
script/destroy
script/generate
+spec/ruby-plc_spec.rb
+spec/spec.opts
+spec/spec_helper.rb
+tasks/rspec.rake
View
@@ -0,0 +1,42 @@
+module Notify
+ @debug = nil
+ class<<self
+ # force Notification to show up in stack backtraces of delegated methods
+ attr_accessor :debug
+ end
+
+ def notify(name)
+ n = name.to_s
+ listeners = "@notify_#{n}_listeners"
+ module_eval(<<-EOS, '(__NOTIFICATION__)', 1)
+ #{listeners} = nil
+
+
+ def notify_#{n}
+ exceptions = nil
+ if #{listeners}
+ #{listeners}.each do |l|
+ begin
+ |l| l.call
+ rescue Exception => ex
+ $@.delete_if{|s| /^\\(__NOTIFICATION__\\):/ =~ s} unless Notification::debug
+ exceptions ||= []
+ exceptions << ex
+ end
+ end
+ if exceptions && respond_to? :handle_notify_exception
+ handle_notify_exception(exceptions)
+ end
+ end
+ end
+
+ def on_#{n}(&proc)
+ #{listeners} ||= []
+ #{listeners} << proc
+ end
+
+ private :notify_#{n}
+ EOS
+ end
+end
+
@@ -1,6 +1,6 @@
include 'ruby_plc/sequences/step_listeners'
-mmodule RubyPlc
+module RubyPlc
module Sequences
class Branch
include StepListeners
@@ -17,6 +17,15 @@ def initialize(name = nil, options = {})
@current_step_index = nil # index of current step
@options = options
yield self if block_given?
+ if @options[:auto_start]
+ Sequencer::at_once { start }
+ end
+ if @options[:cyclic]
+ on_exit do
+ Sequencer::at_once { start }
+ end
+ end
+
end
def step(s)
@@ -1,15 +1,17 @@
include 'ruby-plc/timedomain/timer'
include 'ruby-plc/timedomain/and_signal'
include 'ruby-plc/timedomain/or_signal'
+include 'ruby-plc/etc/notify'
module RubyPlc
module Physical
module DiscreteSignal
+ extend Notify
+
attr_accessor :name, :description
+ notify :re, :fe, :change
def initialize
- @re_listeners = []
- @fe_listeners = []
@name, @description = nil
end
@@ -35,22 +37,10 @@ def ||(other)
OrSignal.new(self, other)
end
- def on_re(&block)
- @re_listeners << block
- end
-
- def on_fe(&block)
- @fe_listeners << block
- end
-
- def on_change(&block)
- @fe_listeners << block
- @re_listeners << block
- end
-
def data_change(value)
- @re_listeners.each {|l| l.call } if value
- @fe_listeners.each {|l| l.call } unless value
+ notify_re if value
+ notify_fe unless value
+ notify_change
end
end
end
View
@@ -0,0 +1,86 @@
+require File.dirname(__FILE__) + '/spec_helper.rb'
+require 'ruby-plc/etc/notify.rb'
+
+class NotifyTestEmpty
+ extend Notify
+end
+
+class NotifyTestOne
+ extend Notify
+ notify :one
+end
+
+class NotifyTestOneTwo
+ extend Notify
+ notify :one
+ notify :two
+end
+
+#class NotifyTestTwo
+# extend Notify
+# notify :one, :two
+#end
+
+
+
+describe Notify do
+ before(:each) do
+ @empty = NotifyTestEmpty.new
+ @one = NotifyTestOne.new
+ @one_two = NotifyTestOneTwo.new
+ # @two = NotifyTestTwo.new
+ end
+
+ it "should support the on_one method for adding listeners" do
+ @one.on_one do
+ end
+ end
+
+ it "should support the notify_one methos for informing listeners" do
+ @one.notify_one
+ end
+
+ it "should call the callback method when notify is issued" do
+ tmp = nil
+ @one.on_one do
+ tmp = true
+ end
+ @one.notify_one
+ tmp.should be_true
+ end
+
+ it "should not call the callback in the wrong notification" do
+ @one_two.on_two do
+ violated 'This should not happen'
+ end
+ @one_two.notify_one
+ end
+
+ it "should support more than one listener" do
+ @count = 0
+ 1.up_to 5 do
+ @one.on_one { @count += 1 }
+ end
+ @one.notify_one
+ @count.should equal(5)
+ end
+
+ it "should not misbehave if an exception is thrown by a listener" do
+ test = nil
+ @one.on_one { throw 'Boom!' }
+ @one.on_one { @test = true }
+ lambda { @one.notify_one }.should_not raise_error
+ test.should be_true
+ end
+
+ it "should call handle_notify_exception if available" do
+ test = nil
+ @one.class_eval <<-EOF
+ def handle_notify_exception(ex) do
+ throw 'you heard me!'
+ end
+ EOF
+ @one.on_one { throw 'BOOM' }
+ lambda { @on_one.notify_one }.should raise_exception
+ end
+end
View
@@ -0,0 +1 @@
+--colour
View
@@ -0,0 +1,10 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ gem 'rspec'
+ require 'spec'
+end
+
+$:.unshift(File.dirname(__FILE__) + '/../lib')
+require 'ruby-plc'
View
@@ -0,0 +1,21 @@
+begin
+ require 'spec'
+rescue LoadError
+ require 'rubygems'
+ require 'spec'
+end
+begin
+ require 'spec/rake/spectask'
+rescue LoadError
+ puts <<-EOS
+To use rspec for testing you must install rspec gem:
+ gem install rspec
+EOS
+ exit(0)
+end
+
+desc "Run the specs under spec/models"
+Spec::Rake::SpecTask.new do |t|
+ t.spec_opts = ['--options', "spec/spec.opts"]
+ t.spec_files = FileList['spec/**/*_spec.rb']
+end

0 comments on commit dfb518c

Please sign in to comment.