diff --git a/CHANGELOG.rdoc b/CHANGELOG.rdoc index 0b6fbffe..8a81e04b 100644 --- a/CHANGELOG.rdoc +++ b/CHANGELOG.rdoc @@ -1,5 +1,7 @@ == master +* Add PluginAWeek::StateMachine::Machine#states +* Add PluginAWeek::StateMachine::Event#transitions * Allow creating transitions with no from state (effectively allowing the transition for *any* from state) * Reduce the number of objects created for each transition diff --git a/lib/state_machine/event.rb b/lib/state_machine/event.rb index fcbec804..88068586 100644 --- a/lib/state_machine/event.rb +++ b/lib/state_machine/event.rb @@ -11,6 +11,9 @@ class Event # The name of the action that fires the event attr_reader :name + # The list of transitions that can be made for this event + attr_reader :transitions + delegate :owner_class, :to => :machine @@ -21,6 +24,7 @@ def initialize(machine, name, options = {}) @machine = machine @name = name @options = options.stringify_keys + @transitions = [] add_transition_actions add_transition_callbacks @@ -63,6 +67,7 @@ def transition(options = {}) callback = Proc.new {|record, *args| try_transition(transition, true, record, *args)} owner_class.send("transition_bang_on_#{name}", callback, options) + transitions << transition transition end diff --git a/lib/state_machine/machine.rb b/lib/state_machine/machine.rb index c8b2ee48..5762e15b 100644 --- a/lib/state_machine/machine.rb +++ b/lib/state_machine/machine.rb @@ -15,6 +15,9 @@ class Machine # The events that trigger transitions attr_reader :events + # A list of the states defined in the transitions of all of the events + attr_reader :states + # The attribute for which the state machine is being defined attr_accessor :attribute @@ -44,6 +47,7 @@ def initialize(owner_class, attribute, options = {}) @attribute = attribute.to_s @initial_state = options[:initial] @events = {} + @states = [] add_named_scopes end @@ -110,6 +114,12 @@ def event(name, options = {}, &block) name = name.to_s event = events[name] = Event.new(self, name, options) event.instance_eval(&block) + + # Record the states + event.transitions.each do |transition| + @states |= ([transition.to_state] + transition.from_states) + end + event end diff --git a/test/unit/event_test.rb b/test/unit/event_test.rb index b6697911..c64f685f 100644 --- a/test/unit/event_test.rb +++ b/test/unit/event_test.rb @@ -14,6 +14,10 @@ def test_should_have_a_name assert_equal 'turn_on', @event.name end + def test_should_not_have_any_transitions + assert @event.transitions.empty? + end + def test_should_define_an_event_action_on_the_owner_class switch = new_switch assert switch.respond_to?(:turn_on) @@ -81,6 +85,11 @@ def test_should_allow_transitioning_from_multiple_states assert @event.transition(:to => 'on', :from => %w(off on)) end + def test_should_have_transitions + @event.transition(:to => 'on') + assert @event.transitions.any? + end + def teardown Switch.class_eval do @transition_on_turn_on_callbacks = nil diff --git a/test/unit/machine_test.rb b/test/unit/machine_test.rb index b35e467d..566a7d6c 100644 --- a/test/unit/machine_test.rb +++ b/test/unit/machine_test.rb @@ -20,6 +20,10 @@ def test_should_have_an_owner_class def test_should_not_have_any_events assert @machine.events.empty? end + + def test_should_not_have_any_states + assert @machine.states.empty? + end end class MachineWithInvalidOptionsTest < Test::Unit::TestCase @@ -121,9 +125,27 @@ def test_should_evaluate_block_within_event_context assert responded end - def test_should_store_the_event + def test_should_have_events @machine.event(:turn_on) {} - assert_equal 1, @machine.events.size + assert_equal %w(turn_on), @machine.events.keys + end +end + +class MachineWithEventsAndTransitionsTest < Test::Unit::TestCase + def setup + @machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state') + @machine.event(:turn_on) do + transition :to => 'on', :from => 'off' + transition :to => 'error', :from => 'unknown' + end + end + + def test_should_have_events + assert_equal %w(turn_on), @machine.events.keys + end + + def test_should_have_states + assert_equal %w(on off error unknown), @machine.states end end