Class: StateFu::MethodFactory
Overview
This class is responsible for defining methods at runtime.
TODO: all events, simple or complex, should get the same method signature simple events will be called as: event_name! nil, *args complex events will be called as: event_name! :state, *args
Instance Attribute Summary collapse
-
#binding ⇒ Object
readonly
Returns the value of attribute binding.
-
#machine ⇒ Object
readonly
Returns the value of attribute machine.
-
#method_definitions ⇒ Object
Returns the value of attribute method_definitions.
Class Method Summary collapse
- .method_definitions_for(machine, name) ⇒ Object
-
.prepare_class_machine(klass, machine, name, options) ⇒ Object
This should be called once per machine bound to a class.
Instance Method Summary collapse
-
#initialize(_binding) ⇒ MethodFactory
constructor
An instance of MethodFactory is created to define methods on a specific StateFu::Binding, and on the object / class it is bound to.
-
#install! ⇒ Object
Define the same helper methods on the StateFu::Binding and its object.
Constructor Details
#initialize(_binding) ⇒ MethodFactory
An instance of MethodFactory is created to define methods on a specific StateFu::Binding, and on the object / class it is bound to.
15 16 17 18 19 20 |
# File 'lib/method_factory.rb', line 15 def initialize(_binding) @binding = _binding @machine = binding.machine @method_definitions = MethodFactory.method_definitions_for(@machine, @binding.method_name) self end |
Instance Attribute Details
#binding ⇒ Object (readonly)
Returns the value of attribute binding.
10 11 12 |
# File 'lib/method_factory.rb', line 10 def binding @binding end |
#machine ⇒ Object (readonly)
Returns the value of attribute machine.
10 11 12 |
# File 'lib/method_factory.rb', line 10 def machine @machine end |
#method_definitions ⇒ Object
Returns the value of attribute method_definitions.
9 10 11 |
# File 'lib/method_factory.rb', line 9 def method_definitions @method_definitions end |
Class Method Details
.method_definitions_for(machine, name) ⇒ Object
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/method_factory.rb', line 22 def self.method_definitions_for(machine, name) returning Hash.new do |method_definitions| simple_events, complex_events = machine.events.partition &:simple? # simple event methods # all arguments are passed into the transition / transition query simple_events.each do |event| method_definitions["#{event.name}"] = lambda do |*args| state_fu(name).find_transition(event, event.target, *args) end method_definitions["can_#{event.name}?"] = lambda do |*args| state_fu(name).can_transition?(event, event.target, *args) end method_definitions["#{event.name}!"] = lambda do |*args| state_fu(name).fire_transition!(event, event.target, *args) end end # "complex" event methods (for events with more than one possible target) # the first argument is the target state # any remaining arguments are passed into the transition / transition query # object.event_name [:target], *arguments # # returns a new transition. Will raise an IllegalTransition if # it is not given arguments which result in a valid combination # of event and target state being deducted. # # object.event_name [nil] suffices if the event has only one valid # target (ie only one transition which would not raise a # RequirementError if fired) # object.event_name! [:target], *arguments # # as per the method above, except that it also fires the event # object.can_<event_name>? [:target], *arguments # # tests that calling event_name or event_name! would not raise an error # ie, the transition is legal and is valid with the arguments supplied complex_events.each do |event| method_definitions["#{event.name}"] = lambda do |target, *args| state_fu(name).find_transition(event, target, *args) end method_definitions["can_#{event.name}?"] = lambda do |target, *args| begin t = state_fu(name).find_transition(event, target, *args) t.valid? rescue IllegalTransition false end end method_definitions["#{event.name}!"] = lambda do |target, *args| state_fu(name).fire_transition!(event, target, *args) end end # methods for a "complex" event with a specific target # eg progress_to_deleted!(*args) # is equivalent to progress!(:deleted, *args) (simple_events + complex_events).each do |event| event.targets.each do |target| method_definitions["#{event.name}_to_#{target.name}"] = lambda do |*args| state_fu(name).find_transition(event, target, *args) end method_definitions["can_#{event.name}_to_#{target.name}?"] = lambda do |*args| state_fu(name).can_transition?(event, target, *args) end method_definitions["#{event.name}_to_#{target.name}!"] = lambda do |*args| state_fu(name).fire_transition!(event, target, *args) end end unless event.targets.nil? end # sugar: query methods for determining the current state machine.states.each do |state| method_definitions["#{state.name}?"] = lambda do state_fu(name).current_state == state end end end end |
.prepare_class_machine(klass, machine, name, options) ⇒ Object
This should be called once per machine bound to a class. It defines methods for the machine as standard methods, if the machine is the default machine or the options passed to the machine include :define_methods => true .
Note this happens when a machine is first bound to the class, not when StateFu is included.
127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/method_factory.rb', line 127 def self.prepare_class_machine(klass, machine, name, ) return unless [:define_methods] method_definitions_for(machine, name).each do |method_name, block| unless klass.respond_to? method_name, true klass.class_eval do define_method method_name, &block end end end end |
Instance Method Details
#install! ⇒ Object
Define the same helper methods on the StateFu::Binding and its object. Any existing methods will not be tampered with, but a warning will be issued in the logs if any methods cannot be defined.
143 144 145 146 |
# File 'lib/method_factory.rb', line 143 def install! define_event_methods_on @binding define_event_methods_on @binding.object if @binding.[:define_methods] && @binding.[:singleton] end |