statemachine 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|