statemachine 0.0.3 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGES +15 -0
- data/TODO +4 -0
- data/lib/statemachine.rb +5 -0
- data/lib/statemachine/builder.rb +111 -0
- data/lib/statemachine/proc_calling.rb +6 -41
- data/lib/statemachine/state.rb +7 -30
- data/lib/statemachine/state_machine.rb +63 -54
- data/lib/statemachine/super_state.rb +10 -42
- data/lib/statemachine/transition.rb +23 -21
- data/lib/statemachine/version.rb +2 -2
- data/spec/builder_spec.rb +131 -0
- data/spec/sm_action_parameterization_spec.rb +38 -53
- data/spec/sm_entry_exit_actions_spec.rb +35 -27
- data/spec/sm_odds_n_ends_spec.rb +47 -5
- data/spec/sm_simple_spec.rb +3 -36
- data/spec/sm_super_state_spec.rb +13 -54
- data/spec/sm_turnstile_spec.rb +18 -20
- data/spec/spec_helper.rb +15 -11
- data/spec/transition_spec.rb +68 -58
- metadata +7 -3
| @@ -6,56 +6,58 @@ module StateMachine | |
| 6 6 |  | 
| 7 7 | 
             
                include ProcCalling
         | 
| 8 8 |  | 
| 9 | 
            -
                attr_reader : | 
| 10 | 
            -
                attr_accessor : | 
| 9 | 
            +
                attr_reader :origin_id, :event, :action
         | 
| 10 | 
            +
                attr_accessor :destination_id
         | 
| 11 11 |  | 
| 12 | 
            -
                def initialize( | 
| 13 | 
            -
                  @ | 
| 14 | 
            -
                  @ | 
| 12 | 
            +
                def initialize(origin_id, destination_id, event, action)
         | 
| 13 | 
            +
                  @origin_id = origin_id
         | 
| 14 | 
            +
                  @destination_id = destination_id
         | 
| 15 15 | 
             
                  @event = event
         | 
| 16 16 | 
             
                  @action = action
         | 
| 17 17 | 
             
                end
         | 
| 18 18 |  | 
| 19 | 
            -
                def invoke(origin, args)
         | 
| 20 | 
            -
                   | 
| 19 | 
            +
                def invoke(origin, statemachine, args)
         | 
| 20 | 
            +
                  destination = statemachine.get_state(@destination_id)
         | 
| 21 | 
            +
                  exits, entries = exits_and_entries(origin, destination)
         | 
| 21 22 | 
             
                  exits.each { |exited_state| exited_state.exit(args) }
         | 
| 22 23 |  | 
| 23 | 
            -
                  call_proc(@action, args, "transition action from #{origin} invoked by '#{event}' event") if @action
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  entries.each { |entered_state| entered_state.enter(args) }
         | 
| 24 | 
            +
                  call_proc(@action, args, "transition action from #{origin} invoked by '#{@event}' event") if @action
         | 
| 26 25 |  | 
| 27 | 
            -
                  terminal_state =  | 
| 28 | 
            -
                  while terminal_state and terminal_state. | 
| 26 | 
            +
                  terminal_state = destination
         | 
| 27 | 
            +
                  while terminal_state and not terminal_state.is_concrete?
         | 
| 29 28 | 
             
                    terminal_state = terminal_state.start_state
         | 
| 30 | 
            -
                    terminal_state | 
| 29 | 
            +
                    entries << terminal_state
         | 
| 31 30 | 
             
                  end
         | 
| 31 | 
            +
                  terminal_state.activate if terminal_state
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  entries.each { |entered_state| entered_state.enter(args) }
         | 
| 32 34 | 
             
                end
         | 
| 33 35 |  | 
| 34 | 
            -
                def exits_and_entries(origin)
         | 
| 36 | 
            +
                def exits_and_entries(origin, destination)
         | 
| 35 37 | 
             
                  exits = []
         | 
| 36 | 
            -
                  entries = exits_and_entries_helper(exits, origin)
         | 
| 38 | 
            +
                  entries = exits_and_entries_helper(exits, origin, destination)
         | 
| 37 39 |  | 
| 38 40 | 
             
                  return exits, entries.reverse
         | 
| 39 41 | 
             
                end
         | 
| 40 42 |  | 
| 41 43 | 
             
                def to_s
         | 
| 42 | 
            -
                  return "#{ | 
| 44 | 
            +
                  return "#{@origin_id} ---#{@event}---> #{@destination_id} : #{action}"
         | 
| 43 45 | 
             
                end
         | 
| 44 46 |  | 
| 45 47 | 
             
                private
         | 
| 46 48 |  | 
| 47 | 
            -
                def exits_and_entries_helper(exits, exit_state)
         | 
| 48 | 
            -
                  entries = entries_to_destination(exit_state)
         | 
| 49 | 
            +
                def exits_and_entries_helper(exits, exit_state, destination)
         | 
| 50 | 
            +
                  entries = entries_to_destination(exit_state, destination)
         | 
| 49 51 | 
             
                  return entries if entries
         | 
| 50 52 | 
             
                  return [] if exit_state == nil
         | 
| 51 53 |  | 
| 52 54 | 
             
                  exits << exit_state
         | 
| 53 | 
            -
                  exits_and_entries_helper(exits, exit_state.superstate)
         | 
| 55 | 
            +
                  exits_and_entries_helper(exits, exit_state.superstate, destination)
         | 
| 54 56 | 
             
                end
         | 
| 55 57 |  | 
| 56 | 
            -
                def entries_to_destination(exit_state)
         | 
| 58 | 
            +
                def entries_to_destination(exit_state, destination)
         | 
| 57 59 | 
             
                  entries = []
         | 
| 58 | 
            -
                  state =  | 
| 60 | 
            +
                  state = destination
         | 
| 59 61 | 
             
                  while state    
         | 
| 60 62 | 
             
                    entries << state
         | 
| 61 63 | 
             
                    return entries if exit_state == state.superstate
         | 
    
        data/lib/statemachine/version.rb
    CHANGED
    
    
| @@ -0,0 +1,131 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            context "Builder" do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              setup do
         | 
| 6 | 
            +
                @log = []
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              def check_switch(sm)
         | 
| 10 | 
            +
                sm.state.should_be :off
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                sm.toggle
         | 
| 13 | 
            +
                @log[0].should_eql "toggle on"
         | 
| 14 | 
            +
                sm.state.should_be :on
         | 
| 15 | 
            +
                
         | 
| 16 | 
            +
                sm.toggle
         | 
| 17 | 
            +
                @log[1].should_eql "toggle off"
         | 
| 18 | 
            +
                sm.state.should_be :off
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              specify "Building a the switch, relaxed" do
         | 
| 22 | 
            +
                sm = StateMachine.build do |b|
         | 
| 23 | 
            +
                  b.trans :off, :toggle, :on, Proc.new { @log << "toggle on" }
         | 
| 24 | 
            +
                  b.trans :on, :toggle, :off, Proc.new { @log << "toggle off" }
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
                
         | 
| 27 | 
            +
                check_switch sm
         | 
| 28 | 
            +
              end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              specify "Building a the switch, strict" do
         | 
| 31 | 
            +
                sm = StateMachine.build do |b|
         | 
| 32 | 
            +
                  b.state(:off) { |s| s.event :toggle, :on, Proc.new { @log << "toggle on" } }
         | 
| 33 | 
            +
                  b.state(:on) { |s| s.event :toggle, :off, Proc.new { @log << "toggle off" } }
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                check_switch sm
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
              specify "Adding a superstate to the switch" do
         | 
| 40 | 
            +
                sm = StateMachine.build do |b|
         | 
| 41 | 
            +
                  b.superstate :operation do |o|
         | 
| 42 | 
            +
                    o.event :admin, :testing, lambda { @log << "testing" }
         | 
| 43 | 
            +
                    o.trans :off, :toggle, :on, lambda { @log << "toggle on" }
         | 
| 44 | 
            +
                    o.trans :on, :toggle, :off, lambda { @log << "toggle off" }
         | 
| 45 | 
            +
                    o.start_state :on
         | 
| 46 | 
            +
                  end
         | 
| 47 | 
            +
                  b.trans :testing, :resume, :operation, lambda { @log << "resuming" }
         | 
| 48 | 
            +
                  b.start_state :off
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
                
         | 
| 51 | 
            +
                sm.state.should_be :off
         | 
| 52 | 
            +
                sm.toggle
         | 
| 53 | 
            +
                sm.admin
         | 
| 54 | 
            +
                sm.state.should_be :testing
         | 
| 55 | 
            +
                sm.resume
         | 
| 56 | 
            +
                sm.state.should_be :on
         | 
| 57 | 
            +
                @log.join(",").should_eql "toggle on,testing,resuming"
         | 
| 58 | 
            +
              end
         | 
| 59 | 
            +
              
         | 
| 60 | 
            +
              specify "entry exit actions" do
         | 
| 61 | 
            +
                sm = StateMachine.build do |sm|
         | 
| 62 | 
            +
                  sm.state :off do |off|
         | 
| 63 | 
            +
                    off.on_entry { @log << "enter off" }
         | 
| 64 | 
            +
                    off.event :toggle, :on, lambda { @log << "toggle on" }
         | 
| 65 | 
            +
                    off.on_exit { @log << "exit off" }
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                  sm.trans :on, :toggle, :off, lambda { @log << "toggle off" } 
         | 
| 68 | 
            +
                end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                sm.toggle
         | 
| 71 | 
            +
                sm.state.should_be :on
         | 
| 72 | 
            +
                sm.toggle
         | 
| 73 | 
            +
                sm.state.should_be :off
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                @log.join(",").should_eql "exit off,toggle on,toggle off,enter off"
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
              
         | 
| 78 | 
            +
              specify "History state" do
         | 
| 79 | 
            +
                sm = StateMachine.build do |b|
         | 
| 80 | 
            +
                  b.superstate :operation do |o|
         | 
| 81 | 
            +
                    o.event :admin, :testing, lambda { @log << "testing" }
         | 
| 82 | 
            +
                    o.state :off do |off|
         | 
| 83 | 
            +
                      off.on_entry { @log << "enter off" }
         | 
| 84 | 
            +
                      off.event :toggle, :on, lambda { @log << "toggle on" }
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                    o.trans :on, :toggle, :off, lambda { @log << "toggle off" }
         | 
| 87 | 
            +
                    o.start_state :on
         | 
| 88 | 
            +
                  end
         | 
| 89 | 
            +
                  b.trans :testing, :resume, :operation_H, lambda { @log << "resuming" }
         | 
| 90 | 
            +
                  b.start_state :off
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
                
         | 
| 93 | 
            +
                sm.admin
         | 
| 94 | 
            +
                sm.resume
         | 
| 95 | 
            +
                sm.state.should_be :off
         | 
| 96 | 
            +
                
         | 
| 97 | 
            +
                @log.join(",").should_eql "testing,resuming,enter off"
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              specify "entry and exit action created from superstate builder" do
         | 
| 101 | 
            +
                sm = StateMachine.build do |b|
         | 
| 102 | 
            +
                  b.trans :off, :toggle, :on, Proc.new { @log << "toggle on" }
         | 
| 103 | 
            +
                  b.on_entry_of(:off) { @log << "entering off" }
         | 
| 104 | 
            +
                  b.trans :on, :toggle, :off, Proc.new { @log << "toggle off" }
         | 
| 105 | 
            +
                  b.on_exit_of(:on) { @log << "exiting on" }
         | 
| 106 | 
            +
                end
         | 
| 107 | 
            +
                
         | 
| 108 | 
            +
                sm.toggle
         | 
| 109 | 
            +
                sm.toggle
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                @log.join(",").should_eql "toggle on,exiting on,toggle off,entering off"
         | 
| 112 | 
            +
                
         | 
| 113 | 
            +
              end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
              specify "superstate as startstate" do
         | 
| 116 | 
            +
                
         | 
| 117 | 
            +
                lambda do 
         | 
| 118 | 
            +
                  sm = StateMachine.build do |b|
         | 
| 119 | 
            +
                    b.superstate :mario_bros do |m|
         | 
| 120 | 
            +
                      m.trans :luigi, :bother, :mario
         | 
| 121 | 
            +
                    end
         | 
| 122 | 
            +
                  end
         | 
| 123 | 
            +
                  
         | 
| 124 | 
            +
                  sm.state.should_be :luigi
         | 
| 125 | 
            +
                end.should_not_raise(Exception)
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              
         | 
| 129 | 
            +
              
         | 
| 130 | 
            +
            end
         | 
| 131 | 
            +
             | 
| @@ -5,110 +5,95 @@ context "State Machine Odds And Ends" do | |
| 5 5 |  | 
| 6 6 | 
             
              setup do
         | 
| 7 7 | 
             
                create_switch
         | 
| 8 | 
            -
                @sm.run
         | 
| 9 8 | 
             
              end
         | 
| 10 9 |  | 
| 11 10 | 
             
              specify "action with one parameter" do
         | 
| 12 | 
            -
                @sm. | 
| 11 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |value| @status = value } }
         | 
| 13 12 | 
             
                @sm.set "blue"
         | 
| 14 | 
            -
                @status. | 
| 15 | 
            -
                @sm.state. | 
| 13 | 
            +
                @status.should_eql "blue"
         | 
| 14 | 
            +
                @sm.state.should_be :on
         | 
| 16 15 | 
             
              end
         | 
| 17 16 |  | 
| 18 17 | 
             
              specify "action with two parameters" do
         | 
| 19 | 
            -
                @sm. | 
| 18 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b| @status = [a, b].join(",") } }
         | 
| 20 19 | 
             
                @sm.set "blue", "green"
         | 
| 21 | 
            -
                @status. | 
| 22 | 
            -
                @sm.state. | 
| 20 | 
            +
                @status.should_eql "blue,green"
         | 
| 21 | 
            +
                @sm.state.should_be :on
         | 
| 23 22 | 
             
              end
         | 
| 24 23 |  | 
| 25 24 | 
             
              specify "action with three parameters" do
         | 
| 26 | 
            -
                @sm. | 
| 25 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } }
         | 
| 27 26 | 
             
                @sm.set "blue", "green", "red"
         | 
| 28 | 
            -
                @status. | 
| 29 | 
            -
                @sm.state. | 
| 27 | 
            +
                @status.should_eql "blue,green,red"
         | 
| 28 | 
            +
                @sm.state.should_be :on
         | 
| 30 29 | 
             
              end
         | 
| 31 30 |  | 
| 32 31 | 
             
              specify "action with four parameters" do
         | 
| 33 | 
            -
                @sm. | 
| 32 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d| @status = [a, b, c, d].join(",") } }
         | 
| 34 33 | 
             
                @sm.set "blue", "green", "red", "orange"
         | 
| 35 | 
            -
                @status. | 
| 36 | 
            -
                @sm.state. | 
| 34 | 
            +
                @status.should_eql "blue,green,red,orange"
         | 
| 35 | 
            +
                @sm.state.should_be :on
         | 
| 37 36 | 
             
              end
         | 
| 38 37 |  | 
| 39 38 | 
             
              specify "action with five parameters" do
         | 
| 40 | 
            -
                @sm. | 
| 39 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d, e| @status = [a, b, c, d, e].join(",") } }
         | 
| 41 40 | 
             
                @sm.set "blue", "green", "red", "orange", "yellow"
         | 
| 42 | 
            -
                @status. | 
| 43 | 
            -
                @sm.state. | 
| 41 | 
            +
                @status.should_eql "blue,green,red,orange,yellow"
         | 
| 42 | 
            +
                @sm.state.should_be :on
         | 
| 44 43 | 
             
              end
         | 
| 45 44 |  | 
| 46 45 | 
             
              specify "action with six parameters" do
         | 
| 47 | 
            -
                @sm. | 
| 46 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d, e, f| @status = [a, b, c, d, e, f].join(",") } }
         | 
| 48 47 | 
             
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo"
         | 
| 49 | 
            -
                @status. | 
| 50 | 
            -
                @sm.state. | 
| 48 | 
            +
                @status.should_eql "blue,green,red,orange,yellow,indigo"
         | 
| 49 | 
            +
                @sm.state.should_be :on
         | 
| 51 50 | 
             
              end
         | 
| 52 51 |  | 
| 53 52 | 
             
              specify "action with seven parameters" do
         | 
| 54 | 
            -
                @sm. | 
| 53 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d, e, f, g| @status = [a, b, c, d, e, f, g].join(",") } }
         | 
| 55 54 | 
             
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet"
         | 
| 56 | 
            -
                @status. | 
| 57 | 
            -
                @sm.state. | 
| 55 | 
            +
                @status.should_eql "blue,green,red,orange,yellow,indigo,violet"
         | 
| 56 | 
            +
                @sm.state.should_be :on
         | 
| 58 57 | 
             
              end
         | 
| 59 58 |  | 
| 60 59 | 
             
              specify "action with eight parameters" do
         | 
| 61 | 
            -
                @sm. | 
| 60 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d, e, f, g, h| @status = [a, b, c, d, e, f, g, h].join(",") } }
         | 
| 62 61 | 
             
                @sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet", "ultra-violet"
         | 
| 63 | 
            -
                @status. | 
| 64 | 
            -
                @sm.state. | 
| 65 | 
            -
              end
         | 
| 66 | 
            -
              
         | 
| 67 | 
            -
              specify "To many parameters" do
         | 
| 68 | 
            -
                @sm.add(:off, :set, :on, Proc.new { |a, b, c, d, e, f, g, h, i| @status = [a, b, c, d, e, f, g, h, i].join(",") } )
         | 
| 69 | 
            -
                begin
         | 
| 70 | 
            -
                  @sm.process_event(:set, "blue", "green", "red", "orange", "yellow", "indigo", "violet", "ultra-violet", "Yikes!")
         | 
| 71 | 
            -
                rescue StateMachine::StateMachineException => e
         | 
| 72 | 
            -
                  e.message.should_equal "Too many arguments(9). (transition action from 'off' state invoked by 'set' event)"
         | 
| 73 | 
            -
                end
         | 
| 62 | 
            +
                @status.should_eql "blue,green,red,orange,yellow,indigo,violet,ultra-violet"
         | 
| 63 | 
            +
                @sm.state.should_be :on
         | 
| 74 64 | 
             
              end
         | 
| 75 65 |  | 
| 76 66 | 
             
              specify "calling process_event with parameters" do
         | 
| 77 | 
            -
                @sm. | 
| 67 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } }
         | 
| 78 68 | 
             
                @sm.process_event(:set, "blue", "green", "red")
         | 
| 79 | 
            -
                @status. | 
| 80 | 
            -
                @sm.state. | 
| 69 | 
            +
                @status.should_eql "blue,green,red"
         | 
| 70 | 
            +
                @sm.state.should_be :on
         | 
| 81 71 | 
             
              end
         | 
| 82 72 |  | 
| 83 73 | 
             
              specify "Insufficient params" do
         | 
| 84 | 
            -
                @sm. | 
| 85 | 
            -
                 | 
| 86 | 
            -
                   | 
| 87 | 
            -
                rescue StateMachine::StateMachineException => e
         | 
| 88 | 
            -
                  e.message.should_equal "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)"
         | 
| 89 | 
            -
                end
         | 
| 74 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } }
         | 
| 75 | 
            +
                lambda { @sm.set "blue", "green" }.should_raise(StateMachine::StateMachineException, 
         | 
| 76 | 
            +
                  "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)")
         | 
| 90 77 | 
             
              end
         | 
| 91 78 |  | 
| 92 79 | 
             
              specify "infinate args" do
         | 
| 93 | 
            -
             | 
| 80 | 
            +
               StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |*a| @status = a.join(",") } }
         | 
| 94 81 | 
             
                @sm.set(1, 2, 3)
         | 
| 95 | 
            -
                @status. | 
| 82 | 
            +
                @status.should_eql "1,2,3"
         | 
| 96 83 |  | 
| 97 84 | 
             
                @sm.state = :off
         | 
| 98 85 | 
             
                @sm.set(1, 2, 3, 4, 5, 6)
         | 
| 99 | 
            -
                @status. | 
| 86 | 
            +
                @status.should_eql "1,2,3,4,5,6"
         | 
| 100 87 | 
             
              end
         | 
| 101 88 |  | 
| 102 89 | 
             
              specify "Insufficient params when params are infinate" do
         | 
| 103 | 
            -
                @sm. | 
| 90 | 
            +
                StateMachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, *b| @status = a.to_s + ":" + b.join(",") } }
         | 
| 104 91 | 
             
                @sm.set(1, 2, 3)
         | 
| 105 | 
            -
                @status. | 
| 92 | 
            +
                @status.should_eql "1:2,3"
         | 
| 106 93 |  | 
| 107 94 | 
             
                @sm.state = :off
         | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
             | 
| 111 | 
            -
                  e.message.should_equal "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)"
         | 
| 112 | 
            -
                end
         | 
| 95 | 
            +
               
         | 
| 96 | 
            +
                lambda { @sm.set }.should_raise(StateMachine::StateMachineException, 
         | 
| 97 | 
            +
                  "Insufficient parameters. (transition action from 'off' state invoked by 'set' event)")
         | 
| 113 98 | 
             
              end
         | 
| 114 99 | 
             
            end
         | 
| @@ -4,73 +4,81 @@ context "State Machine Entry and Exit Actions" do | |
| 4 4 |  | 
| 5 5 | 
             
              setup do
         | 
| 6 6 | 
             
                @log = []
         | 
| 7 | 
            -
                @sm = StateMachine | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
                 | 
| 7 | 
            +
                @sm = StateMachine.build do |s|
         | 
| 8 | 
            +
                  s.trans :off, :toggle, :on, Proc.new { @log << "on" }
         | 
| 9 | 
            +
                  s.trans :on, :toggle, :off, Proc.new { @log << "off" }
         | 
| 10 | 
            +
                end
         | 
| 11 11 | 
             
              end
         | 
| 12 12 |  | 
| 13 13 | 
             
              specify "entry action" do
         | 
| 14 | 
            -
                @sm | 
| 14 | 
            +
                @sm.get_state(:on).entry_action = Proc.new { @log << "entered_on" }
         | 
| 15 15 |  | 
| 16 16 | 
             
                @sm.toggle
         | 
| 17 17 |  | 
| 18 | 
            -
                @log.join(","). | 
| 18 | 
            +
                @log.join(",").should_eql "on,entered_on"
         | 
| 19 19 | 
             
              end
         | 
| 20 20 |  | 
| 21 21 | 
             
              specify "exit action" do
         | 
| 22 | 
            -
                @sm | 
| 22 | 
            +
                @sm.get_state(:off).exit_action = Proc.new { @log << "exited_off" }
         | 
| 23 23 |  | 
| 24 24 | 
             
                @sm.toggle
         | 
| 25 25 |  | 
| 26 | 
            -
                @log.join(","). | 
| 26 | 
            +
                @log.join(",").should_eql "exited_off,on"
         | 
| 27 27 | 
             
              end
         | 
| 28 28 |  | 
| 29 29 | 
             
              specify "exit and entry" do
         | 
| 30 | 
            -
                @sm | 
| 31 | 
            -
                @sm | 
| 30 | 
            +
                @sm.get_state(:off).exit_action = Proc.new { @log << "exited_off" }
         | 
| 31 | 
            +
                @sm.get_state(:on).entry_action = Proc.new { @log << "entered_on" }
         | 
| 32 32 |  | 
| 33 33 | 
             
                @sm.toggle
         | 
| 34 34 |  | 
| 35 | 
            -
                @log.join(","). | 
| 35 | 
            +
                @log.join(",").should_eql "exited_off,on,entered_on"
         | 
| 36 36 | 
             
              end
         | 
| 37 37 |  | 
| 38 38 | 
             
              specify "entry and exit actions may be parameterized" do
         | 
| 39 | 
            -
                  @sm | 
| 40 | 
            -
                  @sm | 
| 39 | 
            +
                  @sm.get_state(:off).exit_action = Proc.new { |a| @log << "exited_off(#{a})" }
         | 
| 40 | 
            +
                  @sm.get_state(:on).entry_action = Proc.new { |a, b| @log << "entered_on(#{a},#{b})" }
         | 
| 41 41 |  | 
| 42 42 | 
             
                  @sm.toggle "one", "two"
         | 
| 43 43 |  | 
| 44 | 
            -
                  @log.join(","). | 
| 44 | 
            +
                  @log.join(",").should_eql "exited_off(one),on,entered_on(one,two)"
         | 
| 45 45 | 
             
              end
         | 
| 46 46 |  | 
| 47 47 | 
             
              specify "current state is set prior to exit and entry actions" do
         | 
| 48 | 
            -
                @sm | 
| 49 | 
            -
                @sm | 
| 48 | 
            +
                @sm.get_state(:off).exit_action = Proc.new { @log << @sm.state }
         | 
| 49 | 
            +
                @sm.get_state(:on).entry_action =  Proc.new { @log << @sm.state }
         | 
| 50 50 |  | 
| 51 51 | 
             
                @sm.toggle
         | 
| 52 52 |  | 
| 53 | 
            -
                @log.join(","). | 
| 53 | 
            +
                @log.join(",").should_eql "off,on,on"  
         | 
| 54 54 | 
             
              end
         | 
| 55 55 |  | 
| 56 56 | 
             
              specify "current state is set prior to exit and entry actions even with super states" do
         | 
| 57 | 
            -
                @sm | 
| 58 | 
            -
                 | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 57 | 
            +
                @sm = StateMachine::StateMachine.new
         | 
| 58 | 
            +
                StateMachine.build(@sm) do |s|
         | 
| 59 | 
            +
                  s.superstate :off_super do |off_s|
         | 
| 60 | 
            +
                    off_s.on_exit {@log << @sm.state}
         | 
| 61 | 
            +
                    off_s.trans :off, :toggle, :on, Proc.new { @log << "on" }
         | 
| 62 | 
            +
                    off_s.event :toggle, :on, Proc.new { @log << "super_on" }
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
                  s.superstate :on_super do |on_s|
         | 
| 65 | 
            +
                    on_s.on_entry { @log << @sm.state }
         | 
| 66 | 
            +
                    on_s.trans :on, :toggle, :off, Proc.new { @log << "off" }
         | 
| 67 | 
            +
                    on_s.event :toggle, :off, Proc.new { @log << "super_off" }
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                  s.start_state :off
         | 
| 70 | 
            +
                end
         | 
| 63 71 |  | 
| 64 72 | 
             
                @sm.toggle
         | 
| 65 | 
            -
                @log.join(","). | 
| 73 | 
            +
                @log.join(",").should_eql "off,super_on,on"  
         | 
| 66 74 | 
             
              end
         | 
| 67 75 |  | 
| 68 76 | 
             
              specify "entry actions invokes another event" do
         | 
| 69 | 
            -
                @sm | 
| 77 | 
            +
                @sm.get_state(:on).entry_action = Proc.new { @sm.toggle }
         | 
| 70 78 |  | 
| 71 79 | 
             
                @sm.toggle
         | 
| 72 | 
            -
                @log.join(","). | 
| 73 | 
            -
                @sm.state. | 
| 80 | 
            +
                @log.join(",").should_eql "on,off"
         | 
| 81 | 
            +
                @sm.state.should_be :off
         | 
| 74 82 | 
             
              end
         | 
| 75 83 |  | 
| 76 84 |  |