statemachine 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +1 -1
- data/lib/statemachine/builder.rb +14 -0
- data/lib/statemachine/generate/java/java_statemachine.rb +54 -28
- data/lib/statemachine/state.rb +5 -1
- data/lib/statemachine/statemachine.rb +3 -3
- data/lib/statemachine/stub_context.rb +24 -0
- data/lib/statemachine/superstate.rb +10 -2
- data/lib/statemachine/transition.rb +4 -7
- data/lib/statemachine/version.rb +1 -1
- data/spec/generate/java/java_statemachine_spec.rb +114 -25
- data/spec/transition_spec.rb +2 -2
- metadata +14 -6
data/README.rdoc
CHANGED
@@ -14,7 +14,7 @@ Where to start:
|
|
14
14
|
== Documentation
|
15
15
|
|
16
16
|
Some documentation is available here in this RDOC documentation.
|
17
|
-
You may also find useful documentation on the Statemachine website: http://
|
17
|
+
You may also find useful documentation on the Statemachine website: http://slagyr.github.com/statemachine
|
18
18
|
|
19
19
|
A detailed tutorial and overview of Finite State Machines and this library can be found
|
20
20
|
at http://blog.8thlight.com/articles/2006/11/17/understanding-statemachines-part-1-states-and-transitions.
|
data/lib/statemachine/builder.rb
CHANGED
@@ -261,6 +261,20 @@ module Statemachine
|
|
261
261
|
@statemachine.context = a_context
|
262
262
|
a_context.statemachine = @statemachine if a_context.respond_to?(:statemachine=)
|
263
263
|
end
|
264
|
+
|
265
|
+
# Stubs the context. This makes statemachine immediately useable, even if functionless.
|
266
|
+
# The stub will print all the actions called so it's nice for trial runs.
|
267
|
+
#
|
268
|
+
# sm = Statemachine.build do
|
269
|
+
# ...
|
270
|
+
# stub_context :verbose => true
|
271
|
+
# end
|
272
|
+
#
|
273
|
+
# Statemachine.context may also be used.
|
274
|
+
def stub_context(options={})
|
275
|
+
require 'statemachine/stub_context'
|
276
|
+
context StubContext.new(options)
|
277
|
+
end
|
264
278
|
end
|
265
279
|
|
266
280
|
end
|
@@ -42,8 +42,6 @@ module Statemachine
|
|
42
42
|
private ###########################################
|
43
43
|
|
44
44
|
def explore_sm
|
45
|
-
@state_names = @sm.states.keys.reject{|k| k.nil? }.map { |id| id.to_s.camalized }.sort
|
46
|
-
|
47
45
|
events = []
|
48
46
|
actions = []
|
49
47
|
@sm.states.values.each do |state|
|
@@ -59,6 +57,8 @@ module Statemachine
|
|
59
57
|
add_action(actions, state.exit_action)
|
60
58
|
end
|
61
59
|
@action_names = actions.uniq.map {|e| e.to_s.camalized(:lower)}.sort
|
60
|
+
|
61
|
+
@startstate = @sm.get_state(@sm.startstate).resolve_startstate
|
62
62
|
end
|
63
63
|
|
64
64
|
def add_action(actions, action)
|
@@ -72,7 +72,8 @@ module Statemachine
|
|
72
72
|
src << "public class #{@classname}" << endl
|
73
73
|
begin_scope(src)
|
74
74
|
|
75
|
-
|
75
|
+
add_instance_variables(src)
|
76
|
+
add_constructor(src)
|
76
77
|
add_statemachine_boilerplate_code(src)
|
77
78
|
add_event_delegation(src)
|
78
79
|
add_statemachine_exception(src)
|
@@ -83,20 +84,42 @@ module Statemachine
|
|
83
84
|
return src.to_s
|
84
85
|
end
|
85
86
|
|
86
|
-
def
|
87
|
-
src << "//
|
88
|
-
@
|
89
|
-
|
87
|
+
def add_instance_variables (src)
|
88
|
+
src << "// Instance variables" << endl
|
89
|
+
concrete_states = @sm.states.values.reject { |state| state.id.nil? || !state.concrete? }.sort { |a, b| a.id <=> b.id }
|
90
|
+
concrete_states.each do |state|
|
91
|
+
name = state.id.to_s.camalized
|
92
|
+
src << "public final State #{name.upcase} = new #{name}State(this);" << endl
|
90
93
|
end
|
91
|
-
|
94
|
+
superstates = @sm.states.values.reject { |state| state.concrete? }.sort { |a, b| a.id <=> b.id }
|
95
|
+
superstates.each do |superstate|
|
96
|
+
startstate = superstate.resolve_startstate
|
97
|
+
src << "public final State #{superstate.id.to_s.upcase} = #{startstate.id.to_s.upcase};" << endl
|
98
|
+
end
|
99
|
+
src << "private State state = #{@startstate.id.to_s.upcase};" << endl
|
100
|
+
src << endl
|
101
|
+
src << "private #{@context_classname} context;" << endl
|
92
102
|
src << endl
|
93
103
|
end
|
94
104
|
|
105
|
+
def add_constructor(src)
|
106
|
+
src << "// Statemachine constructor" << endl
|
107
|
+
add_method(src, nil, @classname, "#{@context_classname} context") do
|
108
|
+
src << "this.context = context;" << endl
|
109
|
+
entered_states = []
|
110
|
+
entry_state = @startstate
|
111
|
+
while entry_state != @sm.root
|
112
|
+
entered_states << entry_state
|
113
|
+
entry_state = entry_state.superstate
|
114
|
+
end
|
115
|
+
entered_states.reverse.each do |state|
|
116
|
+
src << "context.#{state.entry_action.to_s.camalized(:lower)}();" << endl if state.entry_action
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
95
121
|
def add_statemachine_boilerplate_code(src)
|
96
122
|
src << "// The following is boiler plate code standard to all statemachines" << endl
|
97
|
-
src << "private #{@context_classname} context;" << endl
|
98
|
-
src << endl
|
99
|
-
add_one_liner(src, nil, @classname, "#{@context_classname} context", "this.context = context")
|
100
123
|
add_one_liner(src, @context_classname, "getContext", nil, "return context")
|
101
124
|
add_one_liner(src, "State", "getState", nil, "return state")
|
102
125
|
add_one_liner(src, "void", "setState", "State newState", "state = newState")
|
@@ -115,7 +138,7 @@ module Statemachine
|
|
115
138
|
begin_scope(src)
|
116
139
|
src << "public StatemachineException(State state, String event)" << endl
|
117
140
|
begin_scope(src)
|
118
|
-
src << "super(\"Missing transition from
|
141
|
+
src << "super(\"Missing transition from '\" + state.getClass().getSimpleName() + \"' with the '\" + event + \"' event.\");" << endl
|
119
142
|
end_scope(src)
|
120
143
|
end_scope(src)
|
121
144
|
src << endl
|
@@ -137,34 +160,41 @@ module Statemachine
|
|
137
160
|
|
138
161
|
def add_state_implementations(src)
|
139
162
|
src << "// State implementations" << endl
|
140
|
-
@sm.states.keys.sort.each do |state_id|
|
141
|
-
|
163
|
+
@sm.states.keys.reject{|k| k.nil? }.sort.each do |state_id|
|
164
|
+
state = @sm.states[state_id]
|
165
|
+
state_name = state.id.to_s.camalized
|
166
|
+
base_class = state.superstate == @sm.root ? "State" : state.superstate.id.to_s.camalized
|
167
|
+
|
168
|
+
add_concrete_state_class(src, state, state_name, base_class) if state_id
|
142
169
|
end
|
143
170
|
end
|
144
171
|
|
145
|
-
def
|
146
|
-
state = @sm.states[state_id]
|
147
|
-
state_name = state_id.to_s.camalized
|
172
|
+
def add_concrete_state_class(src, state, state_name, base_class)
|
148
173
|
src << "public static class #{state_name}State extends State" << endl
|
149
174
|
src << "{" << endl
|
150
175
|
src.indent!
|
151
176
|
add_one_liner(src, nil, "#{state_name}State", "#{@classname} statemachine", "super(statemachine)")
|
152
177
|
state.transitions.keys.sort.each do |event_id|
|
153
|
-
|
178
|
+
transition = state.transitions[event_id]
|
179
|
+
add_state_event_handler(transition, src)
|
154
180
|
end
|
155
181
|
src.undent!
|
156
182
|
src << "}" << endl
|
157
183
|
src << endl
|
158
184
|
end
|
159
185
|
|
160
|
-
def add_state_event_handler(
|
161
|
-
|
162
|
-
|
186
|
+
def add_state_event_handler(transition, src)
|
187
|
+
event_name = transition.event.to_s.camalized(:lower)
|
188
|
+
exits, entries = transition.exits_and_entries(@sm.get_state(transition.origin_id), @sm.get_state(transition.destination_id))
|
163
189
|
add_method(src, "void", event_name, nil) do
|
164
|
-
|
165
|
-
src << "statemachine.getContext().#{
|
190
|
+
exits.each do |exit|
|
191
|
+
src << "statemachine.getContext().#{exit.exit_action.to_s.camalized(:lower)}();" << endl if exit.exit_action
|
166
192
|
end
|
193
|
+
src << "statemachine.getContext().#{transition.action.to_s.camalized(:lower)}();" << endl if transition.action
|
167
194
|
src << "statemachine.setState(statemachine.#{transition.destination_id.to_s.upcase});" << endl
|
195
|
+
entries.each do |entry|
|
196
|
+
src << "statemachine.getContext().#{entry.entry_action.to_s.camalized(:lower)}();" << endl if entry.entry_action
|
197
|
+
end
|
168
198
|
end
|
169
199
|
end
|
170
200
|
|
@@ -175,7 +205,7 @@ module Statemachine
|
|
175
205
|
end
|
176
206
|
|
177
207
|
def add_method(src, return_type, name, params)
|
178
|
-
src << "public #{return_type} #{name}(#{params})".sub('
|
208
|
+
src << "public #{return_type} #{name}(#{params})".sub(' ' * 2, ' ') << endl
|
179
209
|
begin_scope(src)
|
180
210
|
yield
|
181
211
|
end_scope(src)
|
@@ -191,10 +221,6 @@ module Statemachine
|
|
191
221
|
src.undent! << "}" << endl
|
192
222
|
end
|
193
223
|
|
194
|
-
def default_state_name
|
195
|
-
@sm.startstate.nil? ? "null" : @sm.startstate.to_s.upcase
|
196
|
-
end
|
197
|
-
|
198
224
|
def build_context_src
|
199
225
|
src = begin_src
|
200
226
|
src << "public interface #{@context_classname}" << endl
|
data/lib/statemachine/state.rb
CHANGED
@@ -50,7 +50,7 @@ module Statemachine
|
|
50
50
|
# Resets the statemachine back to its starting state.
|
51
51
|
def reset
|
52
52
|
@state = get_state(@root.startstate_id)
|
53
|
-
while @state and not @state.
|
53
|
+
while @state and not @state.concrete?
|
54
54
|
@state = get_state(@state.startstate_id)
|
55
55
|
end
|
56
56
|
raise StatemachineException.new("The state machine doesn't know where to start. Try setting the startstate.") if @state == nil
|
@@ -106,7 +106,7 @@ module Statemachine
|
|
106
106
|
elsif(is_history_state_id?(id))
|
107
107
|
superstate_id = base_id(id)
|
108
108
|
superstate = @states[superstate_id]
|
109
|
-
raise StatemachineException.new("No history exists for #{superstate} since it is not a super state.") if superstate.
|
109
|
+
raise StatemachineException.new("No history exists for #{superstate} since it is not a super state.") if superstate.concrete?
|
110
110
|
return load_history(superstate)
|
111
111
|
else
|
112
112
|
state = State.new(id, @root, self)
|
@@ -162,7 +162,7 @@ module Statemachine
|
|
162
162
|
100.times do
|
163
163
|
history = superstate.history_id ? get_state(superstate.history_id) : nil
|
164
164
|
raise StatemachineException.new("#{superstate} doesn't have any history yet.") if not history
|
165
|
-
if history.
|
165
|
+
if history.concrete?
|
166
166
|
return history
|
167
167
|
else
|
168
168
|
superstate = history
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Statemachine
|
2
|
+
|
3
|
+
class StubContext
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
@verbose = options[:verbose]
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :statemachine
|
10
|
+
|
11
|
+
def method(name)
|
12
|
+
super(name)
|
13
|
+
rescue
|
14
|
+
self.class.class_eval "def #{name}(*args, &block); __generic_method(:#{name}, *args, &block); end"
|
15
|
+
return super(name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def __generic_method(name, *args)
|
19
|
+
puts "action invoked: #{name}(#{args.join(", ")}) #{block_given? ? "with block" : ""}" if @verbose
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -11,10 +11,18 @@ module Statemachine
|
|
11
11
|
@history_id = nil
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
14
|
+
def concrete?
|
15
15
|
return false
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
|
+
def startstate
|
19
|
+
return @statemachine.get_state(@startstate_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
def resolve_startstate
|
23
|
+
return startstate.resolve_startstate
|
24
|
+
end
|
25
|
+
|
18
26
|
def substate_exiting(substate)
|
19
27
|
@history_id = substate.id
|
20
28
|
end
|
@@ -19,20 +19,16 @@ module Statemachine
|
|
19
19
|
|
20
20
|
origin.statemachine.invoke_action(@action, args, "transition action from #{origin} invoked by '#{@event}' event") if @action
|
21
21
|
|
22
|
-
terminal_state =
|
23
|
-
while terminal_state and not terminal_state.is_concrete?
|
24
|
-
terminal_state = statemachine.get_state(terminal_state.startstate_id)
|
25
|
-
entries << terminal_state
|
26
|
-
end
|
22
|
+
terminal_state = entries.last
|
27
23
|
terminal_state.activate if terminal_state
|
28
24
|
|
29
25
|
entries.each { |entered_state| entered_state.enter(args) }
|
30
26
|
end
|
31
27
|
|
32
28
|
def exits_and_entries(origin, destination)
|
29
|
+
return [], [] if origin == destination
|
33
30
|
exits = []
|
34
31
|
entries = exits_and_entries_helper(exits, origin, destination)
|
35
|
-
|
36
32
|
return exits, entries.reverse
|
37
33
|
end
|
38
34
|
|
@@ -52,8 +48,9 @@ module Statemachine
|
|
52
48
|
end
|
53
49
|
|
54
50
|
def entries_to_destination(exit_state, destination)
|
51
|
+
return nil if destination.nil?
|
55
52
|
entries = []
|
56
|
-
state = destination
|
53
|
+
state = destination.resolve_startstate
|
57
54
|
while state
|
58
55
|
entries << state
|
59
56
|
return entries if exit_state == state.superstate
|
data/lib/statemachine/version.rb
CHANGED
@@ -20,26 +20,58 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
20
20
|
@sm.to_java(:output => @output, :name => "JavaTurnstile", :package => "test.turnstile")
|
21
21
|
end
|
22
22
|
|
23
|
+
def generate_complex_turnstile_sm
|
24
|
+
@sm = Statemachine.build do
|
25
|
+
superstate :operational do
|
26
|
+
on_entry :operate
|
27
|
+
on_exit :beep
|
28
|
+
state :locked do
|
29
|
+
on_entry :lock
|
30
|
+
event :coin, :unlocked
|
31
|
+
event :pass, :locked, :alarm
|
32
|
+
end
|
33
|
+
state :unlocked do
|
34
|
+
on_entry :unlock
|
35
|
+
event :coin, :unlocked, :thanks
|
36
|
+
event :pass, :locked
|
37
|
+
end
|
38
|
+
event :diagnose, :diagnostics
|
39
|
+
end
|
40
|
+
state :diagnostics do
|
41
|
+
on_entry :disable
|
42
|
+
on_exit :beep
|
43
|
+
event :operate, :operational
|
44
|
+
end
|
45
|
+
stub_context :verbose => true
|
46
|
+
end
|
47
|
+
|
48
|
+
@sm.to_java(:output => @output, :name => "JavaTurnstile", :package => "test.turnstile")
|
49
|
+
end
|
50
|
+
|
51
|
+
def load_lines(*segs)
|
52
|
+
filename = File.join(*segs)
|
53
|
+
File.should exist( filename)
|
54
|
+
return IO.read(filename).split("\n")
|
55
|
+
end
|
56
|
+
|
23
57
|
def empty_sm_lines
|
24
58
|
@sm.to_java(:name => "JavaTest", :output => @output, :package => "test.blank")
|
25
|
-
|
26
|
-
File.should exist( filename)
|
27
|
-
lines = IO.read(filename).split("\n")
|
28
|
-
return lines
|
59
|
+
return load_lines(@output, "test", "blank", "JavaTest.java")
|
29
60
|
end
|
30
61
|
|
31
|
-
def
|
62
|
+
def turnstile_lines
|
32
63
|
generate_turnstile_sm
|
33
|
-
|
34
|
-
File.should exist( filename)
|
35
|
-
return IO.read(filename).split("\n")
|
64
|
+
return load_lines(@output, "test", "turnstile", "JavaTurnstile.java")
|
36
65
|
end
|
37
66
|
|
38
|
-
def
|
67
|
+
def turnstile_context_lines
|
39
68
|
generate_turnstile_sm
|
40
|
-
|
41
|
-
|
42
|
-
|
69
|
+
return load_lines(@output, "test", "turnstile", "JavaTurnstileContext.java")
|
70
|
+
end
|
71
|
+
|
72
|
+
def complex_turnstile_lines
|
73
|
+
generate_complex_turnstile_sm
|
74
|
+
return load_lines(@output, "test", "turnstile", "JavaTurnstile.java")
|
43
75
|
end
|
44
76
|
|
45
77
|
def find_lines_after(lines, goose)
|
@@ -78,17 +110,19 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
78
110
|
lines.last.should == "}"
|
79
111
|
end
|
80
112
|
|
81
|
-
it "should generate
|
82
|
-
lines = empty_sm_lines
|
83
|
-
lines = find_lines_after(lines, "// The following is boiler plate code standard to all statemachines")
|
113
|
+
it "should generate the constructor" do
|
114
|
+
lines = find_lines_after(empty_sm_lines, "// Statemachine constructor")
|
84
115
|
|
85
|
-
lines.shift.should == " private JavaTestContext context;"
|
86
|
-
lines.shift.should == ""
|
87
116
|
lines.shift.should == " public JavaTest(JavaTestContext context)"
|
88
117
|
lines.shift.should == " {"
|
89
118
|
lines.shift.should == " this.context = context;"
|
90
119
|
lines.shift.should == " }"
|
91
120
|
lines.shift.should == ""
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should generate sm boilerplate code" do
|
124
|
+
lines = find_lines_after(empty_sm_lines, "// The following is boiler plate code standard to all statemachines")
|
125
|
+
|
92
126
|
lines.shift.should == " public JavaTestContext getContext()"
|
93
127
|
lines.shift.should == " {"
|
94
128
|
lines.shift.should == " return context;"
|
@@ -113,9 +147,9 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
113
147
|
lines.shift.should == " {"
|
114
148
|
lines.shift.should == " public StatemachineException(State state, String event)"
|
115
149
|
lines.shift.should == " {"
|
116
|
-
lines.shift.should == " super(\"Missing transition from
|
150
|
+
lines.shift.should == " super(\"Missing transition from '\" + state.getClass().getSimpleName() + \"' with the '\" + event + \"' event.\");"
|
117
151
|
lines.shift.should == " }"
|
118
|
-
lines.shift.should == " }"
|
152
|
+
lines.shift.should == " }"
|
119
153
|
end
|
120
154
|
|
121
155
|
it "should generate base state" do
|
@@ -136,7 +170,7 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
136
170
|
|
137
171
|
it "should generate the context" do
|
138
172
|
@sm.to_java(:name => "JavaTest", :output => @output, :package => "com.blah")
|
139
|
-
|
173
|
+
|
140
174
|
filename = File.join(@output, "com", "blah", "JavaTestContext.java")
|
141
175
|
File.should exist(filename)
|
142
176
|
lines = IO.read(filename).split("\n")
|
@@ -153,15 +187,17 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
153
187
|
end
|
154
188
|
|
155
189
|
it "should generate the state instance variables" do
|
156
|
-
lines = find_lines_after(
|
190
|
+
lines = find_lines_after(turnstile_lines, "// Instance variables")
|
157
191
|
|
158
192
|
lines.shift.should == " public final State LOCKED = new LockedState(this);"
|
159
193
|
lines.shift.should == " public final State UNLOCKED = new UnlockedState(this);"
|
160
194
|
lines.shift.should == " private State state = LOCKED;"
|
195
|
+
lines.shift.should == ""
|
196
|
+
lines.shift.should == " private JavaTurnstileContext context;"
|
161
197
|
end
|
162
198
|
|
163
199
|
it "should generate all the sm event handlers" do
|
164
|
-
lines = find_lines_after(
|
200
|
+
lines = find_lines_after(turnstile_lines, "// Event delegation")
|
165
201
|
|
166
202
|
lines.shift.should == " public void coin()"
|
167
203
|
lines.shift.should == " {"
|
@@ -176,7 +212,7 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
176
212
|
end
|
177
213
|
|
178
214
|
it "should generate all the default event handlers" do
|
179
|
-
lines = find_lines_after(
|
215
|
+
lines = find_lines_after(turnstile_lines, "// The base state")
|
180
216
|
|
181
217
|
lines.shift.should == " public static abstract class State"
|
182
218
|
lines.shift.should == " {"
|
@@ -201,7 +237,7 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
201
237
|
end
|
202
238
|
|
203
239
|
it "should generate state classes" do
|
204
|
-
lines = find_lines_after(
|
240
|
+
lines = find_lines_after(turnstile_lines, "// State implementations")
|
205
241
|
|
206
242
|
lines.shift.should == " public static class LockedState extends State"
|
207
243
|
lines.shift.should == " {"
|
@@ -248,7 +284,7 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
248
284
|
end
|
249
285
|
|
250
286
|
it "should generate all the context methods" do
|
251
|
-
lines = find_lines_after(
|
287
|
+
lines = find_lines_after(turnstile_context_lines, "// Actions")
|
252
288
|
|
253
289
|
lines.shift.should == " void alarm();"
|
254
290
|
lines.shift.should == " void lock();"
|
@@ -256,4 +292,57 @@ describe Statemachine::Statemachine, "(Java)" do
|
|
256
292
|
lines.shift.should == " void unlock();"
|
257
293
|
end
|
258
294
|
|
295
|
+
it "should generate complext state instances" do
|
296
|
+
lines = find_lines_after(complex_turnstile_lines, "// Instance variables")
|
297
|
+
|
298
|
+
lines.shift.should == " public final State DIAGNOSTICS = new DiagnosticsState(this);"
|
299
|
+
lines.shift.should == " public final State LOCKED = new LockedState(this);"
|
300
|
+
lines.shift.should == " public final State UNLOCKED = new UnlockedState(this);"
|
301
|
+
lines.shift.should == " public final State OPERATIONAL = LOCKED;"
|
302
|
+
lines.shift.should == " private State state = LOCKED;"
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should generate entry actions on startup" do
|
306
|
+
lines = find_lines_after(complex_turnstile_lines, "// Statemachine constructor")
|
307
|
+
|
308
|
+
lines.shift.should == " public JavaTurnstile(JavaTurnstileContext context)"
|
309
|
+
lines.shift.should == " {"
|
310
|
+
lines.shift.should == " this.context = context;"
|
311
|
+
lines.shift.should == " context.operate();"
|
312
|
+
lines.shift.should == " context.lock();"
|
313
|
+
lines.shift.should == " }"
|
314
|
+
lines.shift.should == ""
|
315
|
+
end
|
316
|
+
|
317
|
+
it "should add entry/exit actions to each transition" do
|
318
|
+
lines = find_lines_after(complex_turnstile_lines, "public static class LockedState extends State")
|
319
|
+
|
320
|
+
lines.shift.should == " {"
|
321
|
+
lines.shift.should == " public LockedState(JavaTurnstile statemachine)"
|
322
|
+
lines.shift.should == " {"
|
323
|
+
lines.shift.should == " super(statemachine);"
|
324
|
+
lines.shift.should == " }"
|
325
|
+
lines.shift.should == ""
|
326
|
+
lines.shift.should == " public void coin()"
|
327
|
+
lines.shift.should == " {"
|
328
|
+
lines.shift.should == " statemachine.setState(statemachine.UNLOCKED);"
|
329
|
+
lines.shift.should == " statemachine.getContext().unlock();"
|
330
|
+
lines.shift.should == " }"
|
331
|
+
lines.shift.should == ""
|
332
|
+
lines.shift.should == " public void diagnose()"
|
333
|
+
lines.shift.should == " {"
|
334
|
+
lines.shift.should == " statemachine.getContext().beep();"
|
335
|
+
lines.shift.should == " statemachine.setState(statemachine.DIAGNOSTICS);"
|
336
|
+
lines.shift.should == " statemachine.getContext().disable();"
|
337
|
+
lines.shift.should == " }"
|
338
|
+
lines.shift.should == ""
|
339
|
+
lines.shift.should == " public void pass()"
|
340
|
+
lines.shift.should == " {"
|
341
|
+
lines.shift.should == " statemachine.getContext().alarm();"
|
342
|
+
lines.shift.should == " statemachine.setState(statemachine.LOCKED);"
|
343
|
+
lines.shift.should == " }"
|
344
|
+
lines.shift.should == ""
|
345
|
+
lines.shift.should == " }"
|
346
|
+
end
|
347
|
+
|
259
348
|
end
|
data/spec/transition_spec.rb
CHANGED
@@ -17,8 +17,8 @@ describe "Transition Calculating Exits and Entries" do
|
|
17
17
|
it "to itself" do
|
18
18
|
@a = Statemachine::State.new("a", nil, nil)
|
19
19
|
exits, entries = @transition.exits_and_entries(@a, @a)
|
20
|
-
exits.
|
21
|
-
entries.
|
20
|
+
exits.should == []
|
21
|
+
entries.should == []
|
22
22
|
end
|
23
23
|
|
24
24
|
it "to friend" do
|
metadata
CHANGED
@@ -1,7 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statemachine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 5
|
8
|
+
- 1
|
9
|
+
version: 0.5.1
|
5
10
|
platform: ruby
|
6
11
|
authors:
|
7
12
|
- Micah Martin
|
@@ -9,7 +14,7 @@ autorequire: statemachine
|
|
9
14
|
bindir: bin
|
10
15
|
cert_chain: []
|
11
16
|
|
12
|
-
date: 2010-03-
|
17
|
+
date: 2010-03-25 00:00:00 -05:00
|
13
18
|
default_executable:
|
14
19
|
dependencies: []
|
15
20
|
|
@@ -35,6 +40,7 @@ files:
|
|
35
40
|
- lib/statemachine/generate/util.rb
|
36
41
|
- lib/statemachine/state.rb
|
37
42
|
- lib/statemachine/statemachine.rb
|
43
|
+
- lib/statemachine/stub_context.rb
|
38
44
|
- lib/statemachine/superstate.rb
|
39
45
|
- lib/statemachine/transition.rb
|
40
46
|
- lib/statemachine/version.rb
|
@@ -65,21 +71,23 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
65
71
|
requirements:
|
66
72
|
- - ">="
|
67
73
|
- !ruby/object:Gem::Version
|
74
|
+
segments:
|
75
|
+
- 0
|
68
76
|
version: "0"
|
69
|
-
version:
|
70
77
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
78
|
requirements:
|
72
79
|
- - ">="
|
73
80
|
- !ruby/object:Gem::Version
|
81
|
+
segments:
|
82
|
+
- 0
|
74
83
|
version: "0"
|
75
|
-
version:
|
76
84
|
requirements: []
|
77
85
|
|
78
86
|
rubyforge_project: statemachine
|
79
|
-
rubygems_version: 1.3.
|
87
|
+
rubygems_version: 1.3.6
|
80
88
|
signing_key:
|
81
89
|
specification_version: 3
|
82
|
-
summary: Statemachine-0.5.
|
90
|
+
summary: Statemachine-0.5.1 - Statemachine Library for Ruby http://slagyr.github.com/statemachine
|
83
91
|
test_files:
|
84
92
|
- spec/action_invokation_spec.rb
|
85
93
|
- spec/builder_spec.rb
|