statemachine 0.1.0 → 0.2.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 +11 -1
- data/Rakefile +4 -4
- data/TODO +1 -2
- data/lib/statemachine/action_invokation.rb +64 -0
- data/lib/statemachine/builder.rb +20 -17
- data/lib/statemachine/state.rb +3 -7
- data/lib/statemachine/state_machine.rb +15 -14
- data/lib/statemachine/super_state.rb +3 -7
- data/lib/statemachine/transition.rb +3 -7
- data/lib/statemachine/version.rb +4 -4
- data/lib/statemachine.rb +1 -1
- data/spec/action_invokation_spec.rb +68 -0
- data/spec/builder_spec.rb +89 -39
- data/spec/sm_action_parameterization_spec.rb +15 -15
- data/spec/sm_entry_exit_actions_spec.rb +16 -14
- data/spec/sm_odds_n_ends_spec.rb +5 -5
- data/spec/sm_simple_spec.rb +4 -3
- data/spec/sm_super_state_spec.rb +11 -10
- data/spec/sm_turnstile_spec.rb +3 -3
- data/spec/spec_helper.rb +17 -15
- data/spec/transition_spec.rb +32 -32
- metadata +7 -5
- data/lib/statemachine/proc_calling.rb +0 -19
data/CHANGES
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
=
|
1
|
+
= Statemachine Changelog
|
2
|
+
|
3
|
+
|
4
|
+
== Version 0.2.0
|
5
|
+
|
6
|
+
Separation of logic from behavior.
|
7
|
+
* Prefered builder syntax implemented
|
8
|
+
* statemachine have a context which defines all the behavior
|
9
|
+
* startstate can be set at any time in the builder
|
10
|
+
* states can be declared without blocks
|
11
|
+
* context can be set in builder
|
2
12
|
|
3
13
|
== Version 0.1.0
|
4
14
|
|
data/Rakefile
CHANGED
@@ -15,8 +15,8 @@ load File.dirname(__FILE__) + '/tasks/failing_examples_with_html.rake'
|
|
15
15
|
load File.dirname(__FILE__) + '/tasks/verify_rcov.rake'"
|
16
16
|
|
17
17
|
PKG_NAME = "statemachine"
|
18
|
-
PKG_VERSION =
|
19
|
-
PKG_TAG =
|
18
|
+
PKG_VERSION = Statemachine::VERSION::STRING
|
19
|
+
PKG_TAG = Statemachine::VERSION::TAG
|
20
20
|
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
21
21
|
PKG_FILES = FileList[
|
22
22
|
'[A-Z]*',
|
@@ -58,9 +58,9 @@ end
|
|
58
58
|
spec = Gem::Specification.new do |s|
|
59
59
|
s.name = PKG_NAME
|
60
60
|
s.version = PKG_VERSION
|
61
|
-
s.summary =
|
61
|
+
s.summary = Statemachine::VERSION::DESCRIPTION
|
62
62
|
s.description = <<-EOF
|
63
|
-
|
63
|
+
Statemachine is a ruby library for building Finite State Machines (FSM), also known as Finite State Automata (FSA).
|
64
64
|
EOF
|
65
65
|
|
66
66
|
s.files = PKG_FILES.to_a
|
data/TODO
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Statemachine
|
2
|
+
|
3
|
+
module ActionInvokation
|
4
|
+
|
5
|
+
def invoke_action(action, args, message)
|
6
|
+
if action.is_a? Symbol
|
7
|
+
invoke_method(action, args, message)
|
8
|
+
elsif action.is_a? Proc
|
9
|
+
invoke_proc(action, args, message)
|
10
|
+
else
|
11
|
+
invoke_string(action)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def invoke_method(symbol, args, message)
|
18
|
+
method = @context.method(symbol)
|
19
|
+
raise StatemachineException.new("No method '#{symbol}' for context. " + message) if not method
|
20
|
+
|
21
|
+
parameters = params_for_block(method, args, message)
|
22
|
+
method.call(*parameters)
|
23
|
+
end
|
24
|
+
|
25
|
+
def invoke_proc(proc, args, message)
|
26
|
+
parameters = params_for_block(proc, args, message)
|
27
|
+
@context.instance_exec(*parameters, &proc)
|
28
|
+
end
|
29
|
+
|
30
|
+
def invoke_string(expression)
|
31
|
+
@context.instance_eval(expression)
|
32
|
+
end
|
33
|
+
|
34
|
+
def params_for_block(block, args, message)
|
35
|
+
arity = block.arity
|
36
|
+
required_params = arity < 0 ? arity.abs - 1 : arity
|
37
|
+
|
38
|
+
raise StatemachineException.new("Insufficient parameters. (#{message})") if required_params > args.length
|
39
|
+
|
40
|
+
return arity < 0 ? args : args[0...arity]
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
class Object
|
48
|
+
|
49
|
+
module InstanceExecHelper; end
|
50
|
+
|
51
|
+
include InstanceExecHelper
|
52
|
+
|
53
|
+
def instance_exec(*args, &block) # !> method redefined; discarding old instance_exec
|
54
|
+
mname = "__instance_exec_#{Thread.current.object_id.abs}_#{object_id.abs}"
|
55
|
+
InstanceExecHelper.module_eval{ define_method(mname, &block) }
|
56
|
+
begin
|
57
|
+
ret = send(mname, *args)
|
58
|
+
ensure
|
59
|
+
InstanceExecHelper.module_eval{ undef_method(mname) } rescue nil
|
60
|
+
end
|
61
|
+
ret
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
data/lib/statemachine/builder.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
module
|
1
|
+
module Statemachine
|
2
2
|
|
3
|
-
def self.build(statemachine = nil)
|
3
|
+
def self.build(statemachine = nil, &block)
|
4
4
|
builder = statemachine ? StatemachineBuilder.new(statemachine) : StatemachineBuilder.new
|
5
|
-
|
5
|
+
builder.instance_eval(&block)
|
6
6
|
builder.statemachine.reset
|
7
7
|
return builder.statemachine
|
8
8
|
end
|
@@ -25,7 +25,7 @@ module StateMachine
|
|
25
25
|
state = State.new(state_id, context, @statemachine)
|
26
26
|
@statemachine.add_state(state)
|
27
27
|
end
|
28
|
-
context.
|
28
|
+
context.startstate_id = state_id if context.startstate_id == nil
|
29
29
|
return state
|
30
30
|
end
|
31
31
|
end
|
@@ -37,11 +37,11 @@ module StateMachine
|
|
37
37
|
@subject.add(Transition.new(@subject.id, destination_id, event, action))
|
38
38
|
end
|
39
39
|
|
40
|
-
def on_entry(
|
40
|
+
def on_entry(entry_action)
|
41
41
|
@subject.entry_action = entry_action
|
42
42
|
end
|
43
43
|
|
44
|
-
def on_exit(
|
44
|
+
def on_exit(exit_action)
|
45
45
|
@subject.exit_action = exit_action
|
46
46
|
end
|
47
47
|
end
|
@@ -49,14 +49,14 @@ module StateMachine
|
|
49
49
|
module SuperstateBuilding
|
50
50
|
attr_reader :subject
|
51
51
|
|
52
|
-
def state(id)
|
52
|
+
def state(id, &block)
|
53
53
|
builder = StateBuilder.new(id, @subject, @statemachine)
|
54
|
-
|
54
|
+
builder.instance_eval(&block) if block
|
55
55
|
end
|
56
56
|
|
57
|
-
def superstate(id)
|
57
|
+
def superstate(id, &block)
|
58
58
|
builder = SuperstateBuilder.new(id, @subject, @statemachine)
|
59
|
-
|
59
|
+
builder.instance_eval(&block)
|
60
60
|
end
|
61
61
|
|
62
62
|
def trans(origin_id, event, destination_id, action = nil)
|
@@ -64,16 +64,15 @@ module StateMachine
|
|
64
64
|
origin.add(Transition.new(origin_id, destination_id, event, action))
|
65
65
|
end
|
66
66
|
|
67
|
-
def
|
68
|
-
@subject.
|
69
|
-
raise "Start state #{start_state_id} not found" if not @subject.start_state
|
67
|
+
def startstate(startstate_id)
|
68
|
+
@subject.startstate_id = startstate_id
|
70
69
|
end
|
71
70
|
|
72
|
-
def on_entry_of(id,
|
71
|
+
def on_entry_of(id, action)
|
73
72
|
@statemachine.get_state(id).entry_action = action
|
74
73
|
end
|
75
74
|
|
76
|
-
def on_exit_of(id,
|
75
|
+
def on_exit_of(id, action)
|
77
76
|
@statemachine.get_state(id).exit_action = action
|
78
77
|
end
|
79
78
|
end
|
@@ -94,7 +93,7 @@ module StateMachine
|
|
94
93
|
def initialize(id, superstate, statemachine)
|
95
94
|
super statemachine
|
96
95
|
@subject = Superstate.new(id, superstate, statemachine)
|
97
|
-
superstate.
|
96
|
+
superstate.startstate_id = id if superstate.startstate_id == nil
|
98
97
|
statemachine.add_state(@subject)
|
99
98
|
end
|
100
99
|
end
|
@@ -102,10 +101,14 @@ module StateMachine
|
|
102
101
|
class StatemachineBuilder < Builder
|
103
102
|
include SuperstateBuilding
|
104
103
|
|
105
|
-
def initialize(statemachine =
|
104
|
+
def initialize(statemachine = Statemachine.new)
|
106
105
|
super statemachine
|
107
106
|
@subject = @statemachine.root
|
108
107
|
end
|
108
|
+
|
109
|
+
def context(a_context)
|
110
|
+
@statemachine.context = a_context
|
111
|
+
end
|
109
112
|
end
|
110
113
|
|
111
114
|
end
|
data/lib/statemachine/state.rb
CHANGED
@@ -1,11 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module StateMachine
|
1
|
+
module Statemachine
|
4
2
|
|
5
3
|
class State
|
6
4
|
|
7
|
-
include ProcCalling
|
8
|
-
|
9
5
|
attr_reader :id, :statemachine, :superstate
|
10
6
|
attr_accessor :entry_action, :exit_action
|
11
7
|
|
@@ -26,13 +22,13 @@ module StateMachine
|
|
26
22
|
|
27
23
|
def exit(args)
|
28
24
|
@statemachine.trace("\texiting #{self}")
|
29
|
-
|
25
|
+
@statemachine.invoke_action(@exit_action, args, "exit action for #{self}") if @exit_action
|
30
26
|
@superstate.substate_exiting(self) if @superstate
|
31
27
|
end
|
32
28
|
|
33
29
|
def enter(args)
|
34
30
|
@statemachine.trace("\tentering #{self}")
|
35
|
-
|
31
|
+
@statemachine.invoke_action(@entry_action, args, "entry action for #{self}") if @entry_action
|
36
32
|
end
|
37
33
|
|
38
34
|
def activate
|
@@ -1,12 +1,13 @@
|
|
1
|
-
module
|
1
|
+
module Statemachine
|
2
2
|
|
3
|
-
class
|
3
|
+
class StatemachineException < Exception
|
4
4
|
end
|
5
5
|
|
6
|
-
class
|
7
|
-
|
6
|
+
class Statemachine
|
7
|
+
|
8
|
+
include ActionInvokation
|
8
9
|
|
9
|
-
attr_accessor :tracer
|
10
|
+
attr_accessor :tracer, :context
|
10
11
|
attr_reader :root
|
11
12
|
|
12
13
|
def initialize(root = Superstate.new(:root, nil, self))
|
@@ -14,16 +15,16 @@ module StateMachine
|
|
14
15
|
@states = {}
|
15
16
|
end
|
16
17
|
|
17
|
-
def
|
18
|
-
return @root.
|
18
|
+
def startstate
|
19
|
+
return @root.startstate_id
|
19
20
|
end
|
20
21
|
|
21
22
|
def reset
|
22
|
-
@state = @root.
|
23
|
+
@state = get_state(@root.startstate_id)
|
23
24
|
while @state and not @state.is_concrete?
|
24
|
-
@state = @state.
|
25
|
+
@state = get_state(@state.startstate_id)
|
25
26
|
end
|
26
|
-
raise
|
27
|
+
raise StatemachineException.new("The state machine doesn't know where to start. Try setting the startstate.") if @state == nil
|
27
28
|
end
|
28
29
|
|
29
30
|
def state
|
@@ -48,10 +49,10 @@ module StateMachine
|
|
48
49
|
if transition
|
49
50
|
transition.invoke(@state, self, args)
|
50
51
|
else
|
51
|
-
raise
|
52
|
+
raise StatemachineException.new("#{@state} does not respond to the '#{event}' event.")
|
52
53
|
end
|
53
54
|
else
|
54
|
-
raise
|
55
|
+
raise StatemachineException.new("The state machine isn't in any state while processing the '#{event}' event.")
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -65,8 +66,8 @@ module StateMachine
|
|
65
66
|
elsif(is_history_state_id?(id))
|
66
67
|
superstate_id = base_id(id)
|
67
68
|
superstate = @states[superstate_id]
|
68
|
-
raise
|
69
|
-
raise
|
69
|
+
raise StatemachineException.new("No history exists for #{superstate} since it is not a super state.") if superstate.is_concrete?
|
70
|
+
raise StatemachineException.new("#{superstate} doesn't have any history yet.") if not superstate.history
|
70
71
|
return superstate.history
|
71
72
|
else
|
72
73
|
state = State.new(id, @root, self)
|
@@ -1,13 +1,13 @@
|
|
1
|
-
module
|
1
|
+
module Statemachine
|
2
2
|
|
3
3
|
class Superstate < State
|
4
4
|
|
5
|
-
|
5
|
+
attr_accessor :startstate_id
|
6
6
|
attr_reader :history
|
7
7
|
|
8
8
|
def initialize(id, superstate, statemachine)
|
9
9
|
super(id, superstate, statemachine)
|
10
|
-
@
|
10
|
+
@startstate = nil
|
11
11
|
@history = nil
|
12
12
|
end
|
13
13
|
|
@@ -15,10 +15,6 @@ module StateMachine
|
|
15
15
|
return false
|
16
16
|
end
|
17
17
|
|
18
|
-
def start_state
|
19
|
-
return @start_state
|
20
|
-
end
|
21
|
-
|
22
18
|
def substate_exiting(substate)
|
23
19
|
@history = substate
|
24
20
|
end
|
@@ -1,11 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
module StateMachine
|
1
|
+
module Statemachine
|
4
2
|
|
5
3
|
class Transition
|
6
4
|
|
7
|
-
include ProcCalling
|
8
|
-
|
9
5
|
attr_reader :origin_id, :event, :action
|
10
6
|
attr_accessor :destination_id
|
11
7
|
|
@@ -21,11 +17,11 @@ module StateMachine
|
|
21
17
|
exits, entries = exits_and_entries(origin, destination)
|
22
18
|
exits.each { |exited_state| exited_state.exit(args) }
|
23
19
|
|
24
|
-
|
20
|
+
origin.statemachine.invoke_action(@action, args, "transition action from #{origin} invoked by '#{@event}' event") if @action
|
25
21
|
|
26
22
|
terminal_state = destination
|
27
23
|
while terminal_state and not terminal_state.is_concrete?
|
28
|
-
terminal_state = terminal_state.
|
24
|
+
terminal_state = statemachine.get_state(terminal_state.startstate_id)
|
29
25
|
entries << terminal_state
|
30
26
|
end
|
31
27
|
terminal_state.activate if terminal_state
|
data/lib/statemachine/version.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
module
|
1
|
+
module Statemachine
|
2
2
|
module VERSION
|
3
3
|
unless defined? MAJOR
|
4
4
|
MAJOR = 0
|
5
|
-
MINOR =
|
5
|
+
MINOR = 2
|
6
6
|
TINY = 0
|
7
7
|
|
8
8
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
9
9
|
TAG = "REL_" + [MAJOR, MINOR, TINY].join('_')
|
10
10
|
|
11
|
-
NAME = "
|
11
|
+
NAME = "Statemachine"
|
12
12
|
URL = "http://statemachine.rubyforge.org/"
|
13
13
|
|
14
|
-
DESCRIPTION = "#{NAME}-#{STRING} -
|
14
|
+
DESCRIPTION = "#{NAME}-#{STRING} - Statemachine Library for Ruby\n#{URL}"
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/statemachine.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
+
require 'statemachine/action_invokation'
|
1
2
|
require 'statemachine/state'
|
2
3
|
require 'statemachine/super_state'
|
3
4
|
require 'statemachine/transition'
|
4
|
-
require 'statemachine/proc_calling'
|
5
5
|
require 'statemachine/state_machine'
|
6
6
|
require 'statemachine/builder'
|
7
7
|
require 'statemachine/version'
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
class Noodle
|
4
|
+
|
5
|
+
attr_accessor :shape, :cooked
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@shape = "farfalla"
|
9
|
+
@cooked = false
|
10
|
+
end
|
11
|
+
|
12
|
+
def cook
|
13
|
+
@cooked = true
|
14
|
+
end
|
15
|
+
|
16
|
+
def transform(shape)
|
17
|
+
@shape = shape
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "Action Invokation" do
|
23
|
+
|
24
|
+
setup do
|
25
|
+
@noodle = Noodle.new
|
26
|
+
end
|
27
|
+
|
28
|
+
specify "Proc actions" do
|
29
|
+
sm = Statemachine.build do |smb|
|
30
|
+
smb.trans :cold, :fire, :hot, Proc.new { @cooked = true }
|
31
|
+
end
|
32
|
+
|
33
|
+
sm.context = @noodle
|
34
|
+
sm.fire
|
35
|
+
|
36
|
+
@noodle.cooked.should_be true
|
37
|
+
end
|
38
|
+
|
39
|
+
specify "Symbol actions" do
|
40
|
+
sm = Statemachine.build do |smb|
|
41
|
+
smb.trans :cold, :fire, :hot, :cook
|
42
|
+
smb.trans :hot, :mold, :changed, :transform
|
43
|
+
end
|
44
|
+
|
45
|
+
sm.context = @noodle
|
46
|
+
sm.fire
|
47
|
+
|
48
|
+
@noodle.cooked.should_be true
|
49
|
+
|
50
|
+
sm.mold "capellini"
|
51
|
+
|
52
|
+
@noodle.shape.should_eql "capellini"
|
53
|
+
end
|
54
|
+
|
55
|
+
specify "String actions" do
|
56
|
+
sm = Statemachine.build do |smb|
|
57
|
+
smb.trans :cold, :fire, :hot, "@shape = 'fettucini'; @cooked = true"
|
58
|
+
end
|
59
|
+
sm.context = @noodle
|
60
|
+
|
61
|
+
sm.fire
|
62
|
+
@noodle.shape.should_eql "fettucini"
|
63
|
+
@noodle.cooked.should_be true
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
end
|
data/spec/builder_spec.rb
CHANGED
@@ -19,34 +19,37 @@ context "Builder" do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
specify "Building a the switch, relaxed" do
|
22
|
-
sm =
|
23
|
-
|
24
|
-
|
22
|
+
sm = Statemachine.build do
|
23
|
+
trans :off, :toggle, :on, Proc.new { @log << "toggle on" }
|
24
|
+
trans :on, :toggle, :off, Proc.new { @log << "toggle off" }
|
25
25
|
end
|
26
|
+
sm.context = self
|
26
27
|
|
27
28
|
check_switch sm
|
28
29
|
end
|
29
30
|
|
30
31
|
specify "Building a the switch, strict" do
|
31
|
-
sm =
|
32
|
-
|
33
|
-
|
32
|
+
sm = Statemachine.build do
|
33
|
+
state(:off) { |s| s.event :toggle, :on, Proc.new { @log << "toggle on" } }
|
34
|
+
state(:on) { |s| s.event :toggle, :off, Proc.new { @log << "toggle off" } }
|
34
35
|
end
|
36
|
+
sm.context = self
|
35
37
|
|
36
38
|
check_switch sm
|
37
39
|
end
|
38
40
|
|
39
41
|
specify "Adding a superstate to the switch" do
|
40
|
-
sm =
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
42
|
+
sm = Statemachine.build do
|
43
|
+
superstate :operation do
|
44
|
+
event :admin, :testing, lambda { @log << "testing" }
|
45
|
+
trans :off, :toggle, :on, lambda { @log << "toggle on" }
|
46
|
+
trans :on, :toggle, :off, lambda { @log << "toggle off" }
|
47
|
+
startstate :on
|
46
48
|
end
|
47
|
-
|
48
|
-
|
49
|
+
trans :testing, :resume, :operation, lambda { @log << "resuming" }
|
50
|
+
startstate :off
|
49
51
|
end
|
52
|
+
sm.context = self
|
50
53
|
|
51
54
|
sm.state.should_be :off
|
52
55
|
sm.toggle
|
@@ -58,14 +61,15 @@ context "Builder" do
|
|
58
61
|
end
|
59
62
|
|
60
63
|
specify "entry exit actions" do
|
61
|
-
sm =
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
64
|
+
sm = Statemachine.build do
|
65
|
+
state :off do
|
66
|
+
on_entry Proc.new { @log << "enter off" }
|
67
|
+
event :toggle, :on, lambda { @log << "toggle on" }
|
68
|
+
on_exit Proc.new { @log << "exit off" }
|
66
69
|
end
|
67
|
-
|
70
|
+
trans :on, :toggle, :off, lambda { @log << "toggle off" }
|
68
71
|
end
|
72
|
+
sm.context = self
|
69
73
|
|
70
74
|
sm.toggle
|
71
75
|
sm.state.should_be :on
|
@@ -76,19 +80,20 @@ context "Builder" do
|
|
76
80
|
end
|
77
81
|
|
78
82
|
specify "History state" do
|
79
|
-
sm =
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
sm = Statemachine.build do
|
84
|
+
superstate :operation do
|
85
|
+
event :admin, :testing, lambda { @log << "testing" }
|
86
|
+
state :off do |off|
|
87
|
+
on_entry Proc.new { @log << "enter off" }
|
88
|
+
event :toggle, :on, lambda { @log << "toggle on" }
|
85
89
|
end
|
86
|
-
|
87
|
-
|
90
|
+
trans :on, :toggle, :off, lambda { @log << "toggle off" }
|
91
|
+
startstate :on
|
88
92
|
end
|
89
|
-
|
90
|
-
|
93
|
+
trans :testing, :resume, :operation_H, lambda { @log << "resuming" }
|
94
|
+
startstate :off
|
91
95
|
end
|
96
|
+
sm.context = self
|
92
97
|
|
93
98
|
sm.admin
|
94
99
|
sm.resume
|
@@ -98,12 +103,13 @@ context "Builder" do
|
|
98
103
|
end
|
99
104
|
|
100
105
|
specify "entry and exit action created from superstate builder" do
|
101
|
-
sm =
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
+
sm = Statemachine.build do
|
107
|
+
trans :off, :toggle, :on, Proc.new { @log << "toggle on" }
|
108
|
+
on_entry_of :off, Proc.new { @log << "entering off" }
|
109
|
+
trans :on, :toggle, :off, Proc.new { @log << "toggle off" }
|
110
|
+
on_exit_of :on, Proc.new { @log << "exiting on" }
|
106
111
|
end
|
112
|
+
sm.context = self
|
107
113
|
|
108
114
|
sm.toggle
|
109
115
|
sm.toggle
|
@@ -115,17 +121,61 @@ context "Builder" do
|
|
115
121
|
specify "superstate as startstate" do
|
116
122
|
|
117
123
|
lambda do
|
118
|
-
sm =
|
119
|
-
|
120
|
-
|
124
|
+
sm = Statemachine.build do
|
125
|
+
superstate :mario_bros do
|
126
|
+
trans :luigi, :bother, :mario
|
121
127
|
end
|
122
128
|
end
|
123
129
|
|
124
130
|
sm.state.should_be :luigi
|
125
131
|
end.should_not_raise(Exception)
|
126
132
|
end
|
127
|
-
|
128
133
|
|
134
|
+
specify "setting the start state before any other states declared" do
|
135
|
+
|
136
|
+
sm = Statemachine.build do
|
137
|
+
startstate :right
|
138
|
+
trans :left, :push, :middle
|
139
|
+
trans :middle, :push, :right
|
140
|
+
trans :right, :pull, :middle
|
141
|
+
end
|
142
|
+
|
143
|
+
sm.state.should_be :right
|
144
|
+
sm.pull
|
145
|
+
sm.state.should_be :middle
|
146
|
+
end
|
147
|
+
|
148
|
+
specify "setting start state which is in a super state" do
|
149
|
+
sm = Statemachine.build do
|
150
|
+
startstate :right
|
151
|
+
superstate :table do
|
152
|
+
event :tilt, :floor
|
153
|
+
trans :left, :push, :middle
|
154
|
+
trans :middle, :push, :right
|
155
|
+
trans :right, :pull, :middle
|
156
|
+
end
|
157
|
+
state :floor
|
158
|
+
end
|
159
|
+
|
160
|
+
sm.state.should_be :right
|
161
|
+
sm.pull
|
162
|
+
sm.state.should_be :middle
|
163
|
+
sm.push
|
164
|
+
sm.state.should_be :right
|
165
|
+
sm.tilt
|
166
|
+
sm.state.should_be :floor
|
167
|
+
end
|
168
|
+
|
169
|
+
specify "can set context" do
|
170
|
+
widget = Object.new
|
171
|
+
sm = Statemachine.build do
|
172
|
+
context widget
|
173
|
+
end
|
174
|
+
|
175
|
+
sm.context.should_be widget
|
176
|
+
end
|
177
|
+
|
129
178
|
|
179
|
+
|
130
180
|
end
|
131
181
|
|
@@ -1,83 +1,83 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
context "State Machine Odds And Ends" do
|
4
|
-
include
|
4
|
+
include SwitchStatemachine
|
5
5
|
|
6
6
|
setup do
|
7
7
|
create_switch
|
8
8
|
end
|
9
9
|
|
10
10
|
specify "action with one parameter" do
|
11
|
-
|
11
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |value| @status = value } }
|
12
12
|
@sm.set "blue"
|
13
13
|
@status.should_eql "blue"
|
14
14
|
@sm.state.should_be :on
|
15
15
|
end
|
16
16
|
|
17
17
|
specify "action with two parameters" do
|
18
|
-
|
18
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b| @status = [a, b].join(",") } }
|
19
19
|
@sm.set "blue", "green"
|
20
20
|
@status.should_eql "blue,green"
|
21
21
|
@sm.state.should_be :on
|
22
22
|
end
|
23
23
|
|
24
24
|
specify "action with three parameters" do
|
25
|
-
|
25
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } }
|
26
26
|
@sm.set "blue", "green", "red"
|
27
27
|
@status.should_eql "blue,green,red"
|
28
28
|
@sm.state.should_be :on
|
29
29
|
end
|
30
30
|
|
31
31
|
specify "action with four parameters" do
|
32
|
-
|
32
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d| @status = [a, b, c, d].join(",") } }
|
33
33
|
@sm.set "blue", "green", "red", "orange"
|
34
34
|
@status.should_eql "blue,green,red,orange"
|
35
35
|
@sm.state.should_be :on
|
36
36
|
end
|
37
37
|
|
38
38
|
specify "action with five parameters" do
|
39
|
-
|
39
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c, d, e| @status = [a, b, c, d, e].join(",") } }
|
40
40
|
@sm.set "blue", "green", "red", "orange", "yellow"
|
41
41
|
@status.should_eql "blue,green,red,orange,yellow"
|
42
42
|
@sm.state.should_be :on
|
43
43
|
end
|
44
44
|
|
45
45
|
specify "action with six parameters" do
|
46
|
-
|
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(",") } }
|
47
47
|
@sm.set "blue", "green", "red", "orange", "yellow", "indigo"
|
48
48
|
@status.should_eql "blue,green,red,orange,yellow,indigo"
|
49
49
|
@sm.state.should_be :on
|
50
50
|
end
|
51
51
|
|
52
52
|
specify "action with seven parameters" do
|
53
|
-
|
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(",") } }
|
54
54
|
@sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet"
|
55
55
|
@status.should_eql "blue,green,red,orange,yellow,indigo,violet"
|
56
56
|
@sm.state.should_be :on
|
57
57
|
end
|
58
58
|
|
59
59
|
specify "action with eight parameters" do
|
60
|
-
|
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(",") } }
|
61
61
|
@sm.set "blue", "green", "red", "orange", "yellow", "indigo", "violet", "ultra-violet"
|
62
62
|
@status.should_eql "blue,green,red,orange,yellow,indigo,violet,ultra-violet"
|
63
63
|
@sm.state.should_be :on
|
64
64
|
end
|
65
65
|
|
66
66
|
specify "calling process_event with parameters" do
|
67
|
-
|
67
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, b, c| @status = [a, b, c].join(",") } }
|
68
68
|
@sm.process_event(:set, "blue", "green", "red")
|
69
69
|
@status.should_eql "blue,green,red"
|
70
70
|
@sm.state.should_be :on
|
71
71
|
end
|
72
72
|
|
73
73
|
specify "Insufficient params" do
|
74
|
-
|
75
|
-
lambda { @sm.set "blue", "green" }.should_raise(
|
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
76
|
"Insufficient parameters. (transition action from 'off' state invoked by 'set' event)")
|
77
77
|
end
|
78
78
|
|
79
79
|
specify "infinate args" do
|
80
|
-
|
80
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |*a| @status = a.join(",") } }
|
81
81
|
@sm.set(1, 2, 3)
|
82
82
|
@status.should_eql "1,2,3"
|
83
83
|
|
@@ -87,13 +87,13 @@ context "State Machine Odds And Ends" do
|
|
87
87
|
end
|
88
88
|
|
89
89
|
specify "Insufficient params when params are infinate" do
|
90
|
-
|
90
|
+
Statemachine.build(@sm) { |s| s.trans :off, :set, :on, Proc.new { |a, *b| @status = a.to_s + ":" + b.join(",") } }
|
91
91
|
@sm.set(1, 2, 3)
|
92
92
|
@status.should_eql "1:2,3"
|
93
93
|
|
94
94
|
@sm.state = :off
|
95
95
|
|
96
|
-
lambda { @sm.set }.should_raise(
|
96
|
+
lambda { @sm.set }.should_raise(Statemachine::StatemachineException,
|
97
97
|
"Insufficient parameters. (transition action from 'off' state invoked by 'set' event)")
|
98
98
|
end
|
99
99
|
end
|
@@ -4,10 +4,11 @@ context "State Machine Entry and Exit Actions" do
|
|
4
4
|
|
5
5
|
setup do
|
6
6
|
@log = []
|
7
|
-
@sm =
|
8
|
-
|
9
|
-
|
7
|
+
@sm = Statemachine.build do
|
8
|
+
trans :off, :toggle, :on, Proc.new { @log << "on" }
|
9
|
+
trans :on, :toggle, :off, Proc.new { @log << "off" }
|
10
10
|
end
|
11
|
+
@sm.context = self
|
11
12
|
end
|
12
13
|
|
13
14
|
specify "entry action" do
|
@@ -54,20 +55,21 @@ context "State Machine Entry and Exit Actions" do
|
|
54
55
|
end
|
55
56
|
|
56
57
|
specify "current state is set prior to exit and entry actions even with super states" do
|
57
|
-
@sm =
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
58
|
+
@sm = Statemachine::Statemachine.new
|
59
|
+
Statemachine.build(@sm) do
|
60
|
+
superstate :off_super do
|
61
|
+
on_exit Proc.new {@log << @sm.state}
|
62
|
+
trans :off, :toggle, :on, Proc.new { @log << "on" }
|
63
|
+
event :toggle, :on, Proc.new { @log << "super_on" }
|
63
64
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
65
|
+
superstate :on_super do
|
66
|
+
on_entry Proc.new { @log << @sm.state }
|
67
|
+
trans :on, :toggle, :off, Proc.new { @log << "off" }
|
68
|
+
event :toggle, :off, Proc.new { @log << "super_off" }
|
68
69
|
end
|
69
|
-
|
70
|
+
startstate :off
|
70
71
|
end
|
72
|
+
@sm.context = self
|
71
73
|
|
72
74
|
@sm.toggle
|
73
75
|
@log.join(",").should_eql "off,super_on,on"
|
data/spec/sm_odds_n_ends_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
context "State Machine Odds And Ends" do
|
4
|
-
include
|
4
|
+
include SwitchStatemachine
|
5
5
|
|
6
6
|
setup do
|
7
7
|
create_switch
|
@@ -33,7 +33,7 @@ end
|
|
33
33
|
context "Special States" do
|
34
34
|
|
35
35
|
setup do
|
36
|
-
@sm =
|
36
|
+
@sm = Statemachine.build do |s|
|
37
37
|
s.superstate :operate do |o|
|
38
38
|
o.trans :on, :toggle, :off
|
39
39
|
o.trans :off, :toggle, :on
|
@@ -42,7 +42,7 @@ context "Special States" do
|
|
42
42
|
s.trans :middle, :fiddle, :operate_H
|
43
43
|
s.trans :middle, :push, :stuck
|
44
44
|
s.trans :middle, :dream, :on_H
|
45
|
-
s.
|
45
|
+
s.startstate :middle
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
@@ -54,13 +54,13 @@ context "Special States" do
|
|
54
54
|
specify "no history allowed for concrete states" do
|
55
55
|
lambda {
|
56
56
|
@sm.dream
|
57
|
-
}.should_raise(
|
57
|
+
}.should_raise(Statemachine::StatemachineException, "No history exists for 'on' state since it is not a super state.")
|
58
58
|
end
|
59
59
|
|
60
60
|
specify "error when trying to use history that doesn't exist yet" do
|
61
61
|
lambda {
|
62
62
|
@sm.fiddle
|
63
|
-
}.should_raise(
|
63
|
+
}.should_raise(Statemachine::StatemachineException, "'operate' superstate doesn't have any history yet.")
|
64
64
|
end
|
65
65
|
|
66
66
|
end
|
data/spec/sm_simple_spec.rb
CHANGED
@@ -2,13 +2,14 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
2
2
|
|
3
3
|
context "simple cases:" do
|
4
4
|
setup do
|
5
|
-
@sm =
|
5
|
+
@sm = Statemachine::Statemachine.new
|
6
|
+
@sm.context = self
|
6
7
|
@count = 0
|
7
8
|
@proc = Proc.new {@count = @count + 1}
|
8
9
|
end
|
9
10
|
|
10
11
|
specify "reset" do
|
11
|
-
|
12
|
+
Statemachine.build(@sm) { |s| s.trans :start, :blah, :end, @proc }
|
12
13
|
@sm.process_event(:blah)
|
13
14
|
|
14
15
|
@sm.reset
|
@@ -17,7 +18,7 @@ context "simple cases:" do
|
|
17
18
|
end
|
18
19
|
|
19
20
|
specify "no proc in transition" do
|
20
|
-
|
21
|
+
Statemachine.build(@sm) { |s| s.trans :on, :flip, :off }
|
21
22
|
|
22
23
|
@sm.flip
|
23
24
|
end
|
data/spec/sm_super_state_spec.rb
CHANGED
@@ -1,24 +1,25 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
context "Turn Stile" do
|
4
|
-
include
|
4
|
+
include TurnstileStatemachine
|
5
5
|
|
6
6
|
setup do
|
7
7
|
create_turnstile
|
8
8
|
|
9
9
|
@out_out_order = false
|
10
10
|
|
11
|
-
@sm =
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
11
|
+
@sm = Statemachine.build do
|
12
|
+
superstate :operative do
|
13
|
+
trans :locked, :coin, :unlocked, Proc.new { @locked = false }
|
14
|
+
trans :unlocked, :pass, :locked, Proc.new { @locked = true }
|
15
|
+
trans :locked, :pass, :locked, Proc.new { @alarm_status = true }
|
16
|
+
trans :unlocked, :coin, :locked, Proc.new { @thankyou_status = true }
|
17
|
+
event :maintain, :maintenance, Proc.new { @out_of_order = true }
|
18
18
|
end
|
19
|
-
|
20
|
-
|
19
|
+
trans :maintenance, :operate, :operative, Proc.new { @out_of_order = false }
|
20
|
+
startstate :locked
|
21
21
|
end
|
22
|
+
@sm.context = self
|
22
23
|
end
|
23
24
|
|
24
25
|
specify "substates respond to superstate transitions" do
|
data/spec/sm_turnstile_spec.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/spec_helper'
|
2
2
|
|
3
3
|
context "Turn Stile" do
|
4
|
-
include
|
4
|
+
include TurnstileStatemachine
|
5
5
|
|
6
6
|
setup do
|
7
7
|
create_turnstile
|
@@ -22,7 +22,7 @@ context "Turn Stile" do
|
|
22
22
|
|
23
23
|
specify "start state" do
|
24
24
|
@sm.reset
|
25
|
-
@sm.
|
25
|
+
@sm.startstate.should.be :locked
|
26
26
|
@sm.state.should.be :locked
|
27
27
|
end
|
28
28
|
|
@@ -31,7 +31,7 @@ context "Turn Stile" do
|
|
31
31
|
@sm.process_event(:blah)
|
32
32
|
self.should.fail_with_message("Exception expected")
|
33
33
|
rescue Exception => e
|
34
|
-
e.class.should.be
|
34
|
+
e.class.should.be Statemachine::StatemachineException
|
35
35
|
e.to_s.should_eql "'locked' state does not respond to the 'blah' event."
|
36
36
|
end
|
37
37
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -6,40 +6,42 @@ require 'statemachine'
|
|
6
6
|
def check_transition(transition, origin_id, destination_id, event, action)
|
7
7
|
transition.should_not_be nil
|
8
8
|
transition.event.should_be event
|
9
|
-
transition.action.should_be action
|
10
9
|
transition.origin_id.should_be origin_id
|
11
10
|
transition.destination_id.should_be destination_id
|
11
|
+
transition.action.should_eql action
|
12
12
|
end
|
13
13
|
|
14
|
-
module
|
14
|
+
module SwitchStatemachine
|
15
15
|
|
16
16
|
def create_switch
|
17
17
|
@status = "off"
|
18
|
-
@sm =
|
19
|
-
|
20
|
-
|
18
|
+
@sm = Statemachine.build do
|
19
|
+
trans :off, :toggle, :on, Proc.new { @status = "on" }
|
20
|
+
trans :on, :toggle, :off, Proc.new { @status = "off" }
|
21
21
|
end
|
22
|
+
@sm.context = self
|
22
23
|
end
|
23
24
|
|
24
25
|
end
|
25
26
|
|
26
|
-
module
|
27
|
+
module TurnstileStatemachine
|
27
28
|
|
28
29
|
def create_turnstile
|
29
30
|
@locked = true
|
30
31
|
@alarm_status = false
|
31
32
|
@thankyou_status = false
|
32
|
-
@lock =
|
33
|
-
@unlock =
|
34
|
-
@alarm =
|
35
|
-
@thankyou =
|
33
|
+
@lock = "@locked = true"
|
34
|
+
@unlock = "@locked = false"
|
35
|
+
@alarm = "@alarm_status = true"
|
36
|
+
@thankyou = "@thankyou_status = true"
|
36
37
|
|
37
|
-
@sm =
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
38
|
+
@sm = Statemachine.build do
|
39
|
+
trans :locked, :coin, :unlocked, "@locked = false"
|
40
|
+
trans :unlocked, :pass, :locked, "@locked = true"
|
41
|
+
trans :locked, :pass, :locked, "@alarm_status = true"
|
42
|
+
trans :unlocked, :coin, :locked, "@thankyou_status = true"
|
42
43
|
end
|
44
|
+
@sm.context = self
|
43
45
|
end
|
44
46
|
|
45
47
|
end
|
data/spec/transition_spec.rb
CHANGED
@@ -3,11 +3,11 @@ require File.dirname(__FILE__) + '/spec_helper'
|
|
3
3
|
context "Transition Calculating Exits and Entries" do
|
4
4
|
|
5
5
|
setup do
|
6
|
-
@transition =
|
6
|
+
@transition = Statemachine::Transition.new(nil, nil, nil, nil)
|
7
7
|
end
|
8
8
|
|
9
9
|
specify "to nil" do
|
10
|
-
@a =
|
10
|
+
@a = Statemachine::State.new("a", nil, nil)
|
11
11
|
exits, entries = @transition.exits_and_entries(@a, nil)
|
12
12
|
exits.to_s.should_eql [@a].to_s
|
13
13
|
entries.to_s.should_eql [].to_s
|
@@ -15,90 +15,90 @@ context "Transition Calculating Exits and Entries" do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
specify "to itself" do
|
18
|
-
@a =
|
18
|
+
@a = Statemachine::State.new("a", nil, nil)
|
19
19
|
exits, entries = @transition.exits_and_entries(@a, @a)
|
20
20
|
exits.to_s.should_eql [@a].to_s
|
21
21
|
entries.to_s.should_eql [@a].to_s
|
22
22
|
end
|
23
23
|
|
24
24
|
specify "to friend" do
|
25
|
-
@a =
|
26
|
-
@b =
|
25
|
+
@a = Statemachine::State.new("a", nil, nil)
|
26
|
+
@b = Statemachine::State.new("b", nil, nil)
|
27
27
|
exits, entries = @transition.exits_and_entries(@a, @b)
|
28
28
|
exits.to_s.should_eql [@a].to_s
|
29
29
|
entries.to_s.should_eql [@b].to_s
|
30
30
|
end
|
31
31
|
|
32
32
|
specify "to parent" do
|
33
|
-
@b =
|
34
|
-
@a =
|
33
|
+
@b = Statemachine::State.new("b", nil, nil)
|
34
|
+
@a = Statemachine::State.new("a", @b, nil)
|
35
35
|
exits, entries = @transition.exits_and_entries(@a, @b)
|
36
36
|
exits.to_s.should_eql [@a, @b].to_s
|
37
37
|
entries.to_s.should_eql [@b].to_s
|
38
38
|
end
|
39
39
|
|
40
40
|
specify "to uncle" do
|
41
|
-
@b =
|
42
|
-
@a =
|
43
|
-
@c =
|
41
|
+
@b = Statemachine::State.new("b", nil, nil)
|
42
|
+
@a = Statemachine::State.new("a", @b, nil)
|
43
|
+
@c = Statemachine::State.new("c", nil, nil)
|
44
44
|
exits, entries = @transition.exits_and_entries(@a, @c)
|
45
45
|
exits.to_s.should_eql [@a, @b].to_s
|
46
46
|
entries.to_s.should_eql [@c].to_s
|
47
47
|
end
|
48
48
|
|
49
49
|
specify "to cousin" do
|
50
|
-
@b =
|
51
|
-
@d =
|
52
|
-
@a =
|
53
|
-
@c =
|
50
|
+
@b = Statemachine::State.new("b", nil, nil)
|
51
|
+
@d = Statemachine::State.new("d", nil, nil)
|
52
|
+
@a = Statemachine::State.new("a", @b, nil)
|
53
|
+
@c = Statemachine::State.new("c", @d, nil)
|
54
54
|
exits, entries = @transition.exits_and_entries(@a, @c)
|
55
55
|
exits.to_s.should_eql [@a, @b].to_s
|
56
56
|
entries.to_s.should_eql [@d, @c].to_s
|
57
57
|
end
|
58
58
|
|
59
59
|
specify "to nephew" do
|
60
|
-
@b =
|
61
|
-
@c =
|
62
|
-
@a =
|
60
|
+
@b = Statemachine::State.new("b", nil, nil)
|
61
|
+
@c = Statemachine::State.new("c", nil, nil)
|
62
|
+
@a = Statemachine::State.new("a", @b, nil)
|
63
63
|
exits, entries = @transition.exits_and_entries(@c, @a)
|
64
64
|
exits.to_s.should_eql [@c].to_s
|
65
65
|
entries.to_s.should_eql [@b,@a].to_s
|
66
66
|
end
|
67
67
|
|
68
68
|
specify "to sister" do
|
69
|
-
@c =
|
70
|
-
@a =
|
71
|
-
@b =
|
69
|
+
@c = Statemachine::State.new("c", nil, nil)
|
70
|
+
@a = Statemachine::State.new("a", @c, nil)
|
71
|
+
@b = Statemachine::State.new("b", @c, nil)
|
72
72
|
exits, entries = @transition.exits_and_entries(@a, @b)
|
73
73
|
exits.to_s.should_eql [@a].to_s
|
74
74
|
entries.to_s.should_eql [@b].to_s
|
75
75
|
end
|
76
76
|
|
77
77
|
specify "to second cousin" do
|
78
|
-
@c =
|
79
|
-
@b =
|
80
|
-
@a =
|
81
|
-
@e =
|
82
|
-
@d =
|
78
|
+
@c = Statemachine::State.new("c", nil, nil)
|
79
|
+
@b = Statemachine::State.new("b", @c, nil)
|
80
|
+
@a = Statemachine::State.new("a", @b, nil)
|
81
|
+
@e = Statemachine::State.new("e", @c, nil)
|
82
|
+
@d = Statemachine::State.new("d", @e, nil)
|
83
83
|
exits, entries = @transition.exits_and_entries(@a, @d)
|
84
84
|
exits.to_s.should_eql [@a, @b].to_s
|
85
85
|
entries.to_s.should_eql [@e, @d].to_s
|
86
86
|
end
|
87
87
|
|
88
88
|
specify "to grandparent" do
|
89
|
-
@c =
|
90
|
-
@b =
|
91
|
-
@a =
|
89
|
+
@c = Statemachine::State.new("c", nil, nil)
|
90
|
+
@b = Statemachine::State.new("b", @c, nil)
|
91
|
+
@a = Statemachine::State.new("a", @b, nil)
|
92
92
|
exits, entries = @transition.exits_and_entries(@a, @c)
|
93
93
|
exits.to_s.should_eql [@a, @b, @c].to_s
|
94
94
|
entries.to_s.should_eql [@c].to_s
|
95
95
|
end
|
96
96
|
|
97
97
|
specify "to parent's grandchild" do
|
98
|
-
@c =
|
99
|
-
@b =
|
100
|
-
@a =
|
101
|
-
@d =
|
98
|
+
@c = Statemachine::State.new("c", nil, nil)
|
99
|
+
@b = Statemachine::State.new("b", @c, nil)
|
100
|
+
@a = Statemachine::State.new("a", @b, nil)
|
101
|
+
@d = Statemachine::State.new("d", @c, nil)
|
102
102
|
exits, entries = @transition.exits_and_entries(@d, @a)
|
103
103
|
exits.to_s.should_eql [@d].to_s
|
104
104
|
entries.to_s.should_eql [@b, @a].to_s
|
metadata
CHANGED
@@ -3,15 +3,15 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: statemachine
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2006-11-
|
8
|
-
summary:
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2006-11-14 00:00:00 -06:00
|
8
|
+
summary: Statemachine-0.2.0 - Statemachine Library for Ruby http://statemachine.rubyforge.org/
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
email: statemachine-devel@rubyforge.org
|
12
12
|
homepage: http://statemachine.rubyforge.org
|
13
13
|
rubyforge_project: statemachine
|
14
|
-
description:
|
14
|
+
description: Statemachine is a ruby library for building Finite State Machines (FSM), also known as Finite State Automata (FSA).
|
15
15
|
autorequire: statemachine
|
16
16
|
default_executable:
|
17
17
|
bindir: bin
|
@@ -33,13 +33,14 @@ files:
|
|
33
33
|
- Rakefile
|
34
34
|
- TODO
|
35
35
|
- lib/statemachine.rb
|
36
|
+
- lib/statemachine/action_invokation.rb
|
36
37
|
- lib/statemachine/builder.rb
|
37
|
-
- lib/statemachine/proc_calling.rb
|
38
38
|
- lib/statemachine/state.rb
|
39
39
|
- lib/statemachine/state_machine.rb
|
40
40
|
- lib/statemachine/super_state.rb
|
41
41
|
- lib/statemachine/transition.rb
|
42
42
|
- lib/statemachine/version.rb
|
43
|
+
- spec/action_invokation_spec.rb
|
43
44
|
- spec/builder_spec.rb
|
44
45
|
- spec/sm_action_parameterization_spec.rb
|
45
46
|
- spec/sm_entry_exit_actions_spec.rb
|
@@ -50,6 +51,7 @@ files:
|
|
50
51
|
- spec/spec_helper.rb
|
51
52
|
- spec/transition_spec.rb
|
52
53
|
test_files:
|
54
|
+
- spec/action_invokation_spec.rb
|
53
55
|
- spec/builder_spec.rb
|
54
56
|
- spec/sm_action_parameterization_spec.rb
|
55
57
|
- spec/sm_entry_exit_actions_spec.rb
|
@@ -1,19 +0,0 @@
|
|
1
|
-
module StateMachine
|
2
|
-
|
3
|
-
module ProcCalling
|
4
|
-
|
5
|
-
private
|
6
|
-
|
7
|
-
def call_proc(proc, args, message)
|
8
|
-
arity = proc.arity
|
9
|
-
required_params = arity < 0 ? arity.abs - 1 : arity
|
10
|
-
|
11
|
-
raise StateMachineException.new("Insufficient parameters. (#{message})") if required_params > args.length
|
12
|
-
|
13
|
-
parameters = arity < 0 ? args : args[0...arity]
|
14
|
-
proc.call(*parameters)
|
15
|
-
end
|
16
|
-
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|