Permalink
Browse files

I think I'll default now...

  • Loading branch information...
1 parent 9b283e7 commit 61b621175ff371629b802a211a16d5b869a5edad Elias Karakoulakis committed Feb 17, 2012
View
@@ -22,6 +22,8 @@
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
=end
+require 'weakref'
+
module Ansible
module AnsibleCallback
@@ -31,46 +33,100 @@ module AnsibleCallback
#
# callback declaration mechanism.
- # callbacks must be defined by a Symbol (eg :onChange) starting with "on"
- # A special case is :default , this callback gets called at all events.
- # the callback Proc always gets supplied these arguments
- # 1st argument to callback proc is the ValueID instance
- # 2nd argument is the callback symbol (eg :onChange)
- # 3rd and later arguments: event-specific data
- # example:
- # obj.declare_callback(:onChange) { |o| puts "Object #{o} has changed!" }
- # obj.declare_callback(:default) { |o, cb| puts "Object #{o}: callback #{cb}!" }
- def declare_callback(cb, &cb_body)
- raise "declare_callback: 1st argument must be a Symbol" unless cb.is_a?Symbol
- raise "declare_callback: 2nd argument must be a Proc" unless cb_body.is_a?Proc
- @callbacks = {} if @callbacks.nil?
- if (cb.to_s[0..1] == "on") then
- puts "Registering callback (#{cb}) for #{self.inspect}"
- @callbacks[cb] = cb_body
- elsif (cb.to_s == "default") then
- puts "Registering DEFAULT callback for #{self.inspect}"
- @callbacks.default = cb_body
+ # arguments:
+ # 1) event: a Symbol for the event (eg :onChange)
+ # A special case is :default , this callback gets called at all events.
+ # 2) target: a unique hashable target (so as to register a target-specific callback
+ # for an event) - you can pass any value, if it can be hashed.
+ # TODO: use WeakRef,so that the target can be reclaimed by Ruby's GC
+ # when its fixed on Ruby1.9 (http://bugs.ruby-lang.org/issues/4168)
+ # 3) cb_body: a Proc to get called when a callback is fired.
+ # the callback Proc always gets supplied these arguments:
+ # 1st argument to callback proc is the AnsibleValue instance
+ # 2nd argument is the callback symbol (eg :onChange)
+ # 3rd and later arguments: event-specific data
+ # examples:
+ # obj.add_callback(:onChange) { |o| puts "Object #{o} has changed!" }
+ # obj.add_callback(:onChange, 'SPECIAL') { |o| puts "Object #{o} has changed!" }
+ # obj.add_callback(:default) { |o, cb, *args| puts "Object #{o}: callback #{cb}!" }
+ def add_callback(event, target=nil, &cb_body)
+ raise "add_callback: last argument must be a Proc" unless cb_body.is_a?Proc
+ init_callbacks(event)
+ puts "#{self}: Registering #{event} callback" + (target.nil? ? '' : " especially for target #{target}")
+ if target.nil? then
+ @callbacks[event].default = cb_body
+ else
+ @callbacks[event][target] = cb_body
end
end
- # callback firing processor.
- # Checks if a proc is stored as an instance variable, then calls it
+ # remove a callback
+ # arguments:
+ # 1) event: a Symbol for the event (eg :onChange)
+ # A special case is :default , this callback gets called at all events.
+ # 2) target: a unique hashable target - you can pass any value
+ # examples:
+ #
+ def remove_callback(event, target=nil)
+ init_callbacks(event)
+ @callbacks[event].delete(target)
+ end
+
+ # callback firing processor.
+ #
+ # Checks if a proc is stored for a ginen event, then calls it
# with the object instance as its first argument, the callback symbol
# as its second arg, and all other *args appended to the call
+ #
+ # arguments:
+ # 1) event: a Symbol for the event (eg :onChange)
+ # 2) target: the unique id of target (so as to fire target-specific callbacks
+ # for a specific event)
+ # NOTE 1) its prohibited to fire the DEFAULT callback programmatically
+ # (it will get fired anyway at ANY event)
+ # NOTE 2) if a target_id is given, then try to fire target-specific callbacks.
+ # if none is found, fall-back to the generic callback for this event
# example:
- # obj.fire_callback(:onChange, :arg1, :arg2, :arg3)
- def fire_callback(cb, *args)
- raise "fire_callback: 1st argument must be a Symbol" unless cb.is_a?Symbol
- @callbacks = {} unless @callbacks.is_a?Hash
- default = @callbacks.has_key?(cb)
- if (cb_proc = @callbacks[cb]).is_a?Proc then
- puts "firing callback(#{cb}) args: #{args.inspect}" if $DEBUG
- cb_proc.call(self, cb.to_s, *args)
- else
- #puts "WARNING: callback #{cb} not found for #{self}, iv=#{iv} cb_proc=#{cb_proc.inspect}"
+ # obj.fire_callback(:onChange, 'GROUPADDR', :arg1, :arg2, :arg3)
+ def fire_callback(event, target=nil, *args)
+ raise "cannot fire DEFAULT callback programmatically!" if event.to_s == "default"
+ #puts "fire_callback called by #{self}.#{event}, args: #{args.inspect}"
+ init_callbacks(event)
+ # array of callback Procs to get called
+ cb_procs = []
+ # first add callbacks for this specific event
+ if defined?(@callbacks) and @callbacks.is_a?Hash then
+ [@callbacks[event], @callbacks[:default]].each { |hsh|
+ if hsh.is_a?Hash then
+ #puts "#{self}: callbacks for #{event} are: #{hsh.inspect}"
+ if target.nil? then
+ # add all targets to the list of procs to call
+ # including the default
+ cb_procs << [hsh.values, hsh.default].flatten
+ else
+ # only add target-specific procs to the list
+ cb_procs << hsh[target]
+ end
+ end
+ }
end
+ #puts cb_procs.inspect
+ # time to fire callbacks
+ cb_procs.flatten.compact.each { |cb_proc|
+ raise "ooops, found a #{cb_proc.class} stored as a callback!" unless cb_proc.is_a?Proc
+ puts "firing #{event} callback, args: #{args.inspect}"
+ cb_proc.call(self, event.to_s, *args)
+ }
end
+ private
+ # initialize callback hash for a given event
+ def init_callbacks(event)
+ md = caller[1].match(/`(\w*)'/); clr = md and md[1] or caller[1]
+ raise "#{clr}: no event Symbol supplied!" unless event.is_a?Symbol
+ @callbacks = {} unless defined?(@callbacks) and @callbacks.is_a?Hash
+ @callbacks[event] = {} unless @callbacks[event].is_a?Hash
+ end
end
end #module
View
@@ -22,26 +22,82 @@
http://en.wikipedia.org/wiki/GNU_Lesser_General_Public_License
=end
-require 'ansible_value'
-
module Ansible
-
- module AnsibleDevice
- class AbstractDevice
- def initialize()
- @values = []
- end
-
- def add(value)
- @values << value
- end
+ # a CommandChain is a graph describing the sequence
+ # of inputs, outputs and status values for an Ansible Device
+ class CommandChain
+
+ # initialize an empty command chain
+ def initialize()
+ @inputs, @outputs, @statuses = [], [], []
end
#
- # load all known Ansible Device classes
- Dir["devices/*.rb"].each { |f| load f }
+ # add an input value
+ def input(value)
+ raise "add_input: #{value} must be an AnsibleValue!" unless value.is_a? AnsibleValue
+ puts "#{self.class}: adding input value #{value}"
+ @inputs << value unless @inputs.include?(value)
+ return self # so as to chain multiple calls
+ end #def
+
+ #
+ # add an output value
+ def output(value)
+ raise "add_output: #{value} must be an AnsibleValue!" unless value.is_a? AnsibleValue
+ raise "add_output: #{value} is already declared as input!" if @inputs.include?(value)
+ puts "#{self.class}: adding output value #{value}"
+ @outputs << value unless @outputs.include?(value)
+ return self # so as to chain multiple calls
+ end #def
+
+ #
+ # add a status feedback value
+ def status(value)
+ raise "add_status: #{value} must be an AnsibleValue!" unless value.is_a? AnsibleValue
+ raise "add_status: #{value} is already declared as output!" if @outputs.include?(value)
+ puts "#{self.class}: adding status value #{value}"
+ @statuses << value unless @statuses.include?(value)
+ return self # so as to chain multiple calls
+ end
+ def link(source, target)
+ raise "link: both arguments must be AnsibleValues!" if [source,target].find{|v| not v.is_a?AnsibleValue}
+ source.add_callback(:onUpdate, self) { |sender, cb, args|
+ puts "(#{sender.class}) #{sender} input value updated! args=#{args}"
+ #convert value domains
+ cv = sender.as_canonical_value
+ newval = output.to_protocol_value(cv)
+ puts "+++ setting output #{output} +++ cv=#{cv} newval=#{newval}"
+ target.set(newval)
+ }
+ end
+
+ def bind_all
+ puts "#{self}: binding all values"
+ @inputs.each { |input|
+
+ }
+ return self
+ end
end
+
+ class AbstractDevice
+
+ #
+ def initialize(state_value)
+ raise "add_status: #{value} must be an AnsibleValue!" unless value.is_a? AnsibleValue
+ @state_value = state_value
+ end
+
+
+ end
+
+
+ #
+ # load all known Ansible Device classes
+ Dir["devices/*.rb"].each { |f| load f }
+
end
Oops, something went wrong.

0 comments on commit 61b6211

Please sign in to comment.