lib/state_fu/method_factory.rb in davidlee-state-fu-0.10.0 vs lib/state_fu/method_factory.rb in davidlee-state-fu-0.11.0
- old
+ new
@@ -4,67 +4,107 @@
# 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
class MethodFactory
-
+ attr_accessor :method_definitions
+ attr_reader :binding
+
# An instance of MethodFactory is created to define methods on a specific StateFu::Binding, and
- # the object it is bound to.
- #
- # During the initializer, it will call define_event_methods_on(the binding), which installs
- #
+ # on the object it is bound to.
+
def initialize( _binding )
- # store @binding in a local variable so it's accessible within
- # the closures below (for define_singleton_method ).
+ @binding = _binding
+ simple_events, complex_events = @binding.machine.events.partition(&:simple?)
+ @method_definitions = {}
+
+ # simple event methods
+ # all arguments are passed into the transition / transition query
+
+ simple_events.each do |event|
+ method_definitions["#{event.name}"] = lambda do |*args|
+ _binding.find_transition(event, event.target, *args)
+ end
+
+ method_definitions["can_#{event.name}?"] = lambda do |*args|
+ _binding.can_transition?(event, event.target, *args)
+ end
- # i.e, we're embedding a reference to @binding inside the method
- @binding = _binding
- @defs = {}
-
- @binding.machine.states.each do |state|
- @defs[:"#{state.name}?"] = lambda { _binding.current_state.name == state.name }
+ method_definitions["#{event.name}!"] = lambda do |*args|
+ _binding.fire_transition!(event, event.target, *args)
+ end
end
+
+ # complex event methods
+ # 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)
- # method definitions for simple events (only one possible target)
- @binding.machine.events.each do |event|
- @defs[event.name] = lambda \
- {|*args| _binding._event_method :get_transition, event, args.shift, *args }
- @defs[:"can_#{event.name}?"] = lambda \
- {|*args| _binding._event_method :query_transition, event, args.shift, *args }
- @defs[:"#{event.name}!"] = lambda \
- {|*args| _binding._event_method :fire_transition, event, args.shift, *args }
+ # 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|
+ _binding.find_transition(event, target, *args)
+ end
- #if !event.targets.blank? # && event.targets.length > 1
- event.targets.each do |target_state|
- method_name = "#{event.name}_to_#{target_state.name}"
+ method_definitions["can_#{event.name}?"] = lambda do |target, *args|
+ begin
+ t = _binding.find_transition(event, target, *args)
+ t.valid?
+ rescue IllegalTransition
+ false
+ end
+ end
- # object.event_name [:target], *arguments
- #
- # returns a new transition. Will raise an InvalidTransition if
- # it is not given arguments which result in a valid combination
- # of event and target state being deducted.
- #
- # object.event_name suffices without any arguments if the event
- # has only one possible target, or only one valid target for
-
- # object.event_name! [:target], *arguments
- #
- # as per the method above, except that it also
-
- @defs[method_name.to_sym] = lambda \
- {|*args| _binding._event_method :get_transition, event, target_state, *args }
-
- # object.event_name! [:]
- @defs[:"can_#{method_name}?"] = lambda \
- {|*args| _binding._event_method :query_transition, event, target_state, *args }
-
- @defs[:"#{method_name}!"] = lambda \
- {|*args| _binding._event_method :fire_transition, event, target_state, *args }
-
+ method_definitions["#{event.name}!"] = lambda do |target, *args|
+ _binding.fire_transition!(event, target, *args)
+ end
+ end
+
+ # methods dedicated to a combination of event and target
+ # all arguments are passed into the transition / transition query
+
+ (simple_events + complex_events).each do |event|
+ event.targets.each do |target|
+ method_definitions["#{event.name}_to_#{target.name}"] = lambda do |*args|
+ _binding.find_transition(event, target, *args)
+ end
+
+ method_definitions["can_#{event.name}_to_#{target.name}?"] = lambda do |*args|
+ _binding.can_transition?(event, target, *args)
+ end
+
+ method_definitions["#{event.name}_to_#{target.name}!"] = lambda do |*args|
+ _binding.fire_transition!(event, target, *args)
+ end
end unless event.targets.nil?
- end
- end
+ end
+
+ @binding.machine.states.each do |state|
+ method_definitions["#{state.name}?"] = lambda do
+ _binding.current_state == state
+ end
+ end
+
+ end
+
#
# Class Methods
#
@@ -161,11 +201,11 @@
# Symbol containing a valid target State's name, or the State
# itself. The remaining arguments are passed into the transition,
# as with simple event methods.
#
def define_event_methods_on( obj )
- @defs.each do |method_name, method_body|
+ method_definitions.each do |method_name, method_body|
define_singleton_method( obj, method_name, &method_body)
end
end # define_event_methods_on
def define_singleton_method( object, method_name, &block )
@@ -194,10 +234,10 @@
define_method( method_name, &block )
end
end
end
alias_method :define_singleton_method, :define_singleton_method
-
+
end # class MethodFactory
end # module StateFu