MINT-statemachine 1.2.2
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 +135 -0
- data/LICENSE +16 -0
- data/MINT-statemachine.gemspec +27 -0
- data/README.rdoc +69 -0
- data/Rakefile +88 -0
- data/TODO +2 -0
- data/lib/statemachine.rb +26 -0
- data/lib/statemachine/action_invokation.rb +83 -0
- data/lib/statemachine/builder.rb +383 -0
- data/lib/statemachine/generate/dot_graph.rb +1 -0
- data/lib/statemachine/generate/dot_graph/dot_graph_statemachine.rb +127 -0
- data/lib/statemachine/generate/java.rb +1 -0
- data/lib/statemachine/generate/java/java_statemachine.rb +265 -0
- data/lib/statemachine/generate/src_builder.rb +48 -0
- data/lib/statemachine/generate/util.rb +50 -0
- data/lib/statemachine/parallelstate.rb +196 -0
- data/lib/statemachine/state.rb +102 -0
- data/lib/statemachine/statemachine.rb +279 -0
- data/lib/statemachine/stub_context.rb +26 -0
- data/lib/statemachine/superstate.rb +53 -0
- data/lib/statemachine/transition.rb +76 -0
- data/lib/statemachine/version.rb +17 -0
- data/spec/action_invokation_spec.rb +101 -0
- data/spec/builder_spec.rb +243 -0
- data/spec/default_transition_spec.rb +111 -0
- data/spec/generate/dot_graph/dot_graph_stagemachine_spec.rb +27 -0
- data/spec/generate/java/java_statemachine_spec.rb +349 -0
- data/spec/history_spec.rb +107 -0
- data/spec/noodle.rb +23 -0
- data/spec/sm_action_parameterization_spec.rb +99 -0
- data/spec/sm_activation_spec.rb +116 -0
- data/spec/sm_entry_exit_actions_spec.rb +99 -0
- data/spec/sm_odds_n_ends_spec.rb +67 -0
- data/spec/sm_parallel_state_spec.rb +207 -0
- data/spec/sm_simple_spec.rb +26 -0
- data/spec/sm_super_state_spec.rb +55 -0
- data/spec/sm_turnstile_spec.rb +76 -0
- data/spec/spec_helper.rb +121 -0
- data/spec/transition_spec.rb +107 -0
- metadata +115 -0
@@ -0,0 +1 @@
|
|
1
|
+
require 'statemachine/generate/java/java_statemachine'
|
@@ -0,0 +1,265 @@
|
|
1
|
+
require 'statemachine/generate/util'
|
2
|
+
require 'statemachine/generate/src_builder'
|
3
|
+
|
4
|
+
module Statemachine
|
5
|
+
class Statemachine
|
6
|
+
|
7
|
+
attr_reader :states
|
8
|
+
|
9
|
+
def to_java(options = {})
|
10
|
+
generator = Generate::Java::JavaStatemachine.new(self, options)
|
11
|
+
generator.generate!
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
module Generate
|
17
|
+
module Java
|
18
|
+
class JavaStatemachine
|
19
|
+
|
20
|
+
include Generate::Util
|
21
|
+
|
22
|
+
HEADER1 = "// This file was generated by the Ruby Statemachine Library (http://slagyr.github.com/statemachine)."
|
23
|
+
HEADER2 = "// Generated at "
|
24
|
+
|
25
|
+
def initialize(sm, options)
|
26
|
+
@sm = sm
|
27
|
+
@output_dir = options[:output]
|
28
|
+
@classname = options[:name]
|
29
|
+
@context_classname = "#{@classname}Context"
|
30
|
+
@package = options[:package]
|
31
|
+
raise "Please specify an output directory. (:output => 'where/you/want/your/code')" if @output_dir.nil?
|
32
|
+
raise "Output dir '#{@output_dir}' doesn't exist." if !File.exist?(@output_dir)
|
33
|
+
raise "Please specify a name for the statemachine. (:name => 'SomeName')" if @classname.nil?
|
34
|
+
end
|
35
|
+
|
36
|
+
def generate!
|
37
|
+
explore_sm
|
38
|
+
create_file(src_file(@classname), build_statemachine_src)
|
39
|
+
create_file(src_file(@context_classname), build_context_src)
|
40
|
+
say "Statemachine generated."
|
41
|
+
end
|
42
|
+
|
43
|
+
private ###########################################
|
44
|
+
|
45
|
+
def explore_sm
|
46
|
+
events = []
|
47
|
+
actions = []
|
48
|
+
@sm.states.values.each do |state|
|
49
|
+
state.transitions.values.each do |transition|
|
50
|
+
events << transition.event
|
51
|
+
add_action(actions, transition.action)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
@event_names = events.uniq.map {|e| e.to_s.camalized(:lower)}.sort
|
55
|
+
|
56
|
+
@sm.states.values.each do |state|
|
57
|
+
add_action(actions, state.entry_action)
|
58
|
+
add_action(actions, state.exit_action)
|
59
|
+
end
|
60
|
+
@action_names = actions.uniq.map {|e| e.to_s.camalized(:lower)}.sort
|
61
|
+
|
62
|
+
@startstate = @sm.get_state(@sm.startstate).resolve_startstate
|
63
|
+
end
|
64
|
+
|
65
|
+
def add_action(actions, action)
|
66
|
+
return if action.nil?
|
67
|
+
raise "Actions must be symbols in order to generation Java code. (#{action})" unless action.is_a?(Symbol)
|
68
|
+
actions << action
|
69
|
+
end
|
70
|
+
|
71
|
+
def build_statemachine_src
|
72
|
+
src = begin_src
|
73
|
+
src << "public class #{@classname}" << endl
|
74
|
+
begin_scope(src)
|
75
|
+
|
76
|
+
add_instance_variables(src)
|
77
|
+
add_constructor(src)
|
78
|
+
add_statemachine_boilerplate_code(src)
|
79
|
+
add_event_delegation(src)
|
80
|
+
add_statemachine_exception(src)
|
81
|
+
add_base_state(src)
|
82
|
+
add_state_implementations(src)
|
83
|
+
|
84
|
+
end_scope(src)
|
85
|
+
return src.to_s
|
86
|
+
end
|
87
|
+
|
88
|
+
def add_instance_variables (src)
|
89
|
+
src << "// Instance variables" << endl
|
90
|
+
concrete_states = @sm.states.values.reject { |state| state.id.nil? || !state.concrete? }.sort { |a, b| a.id <=> b.id }
|
91
|
+
concrete_states.each do |state|
|
92
|
+
name = state.id.to_s
|
93
|
+
src << "public final State #{name.upcase} = new #{name.camalized}State(this);" << endl
|
94
|
+
end
|
95
|
+
superstates = @sm.states.values.reject { |state| state.concrete? }.sort { |a, b| a.id <=> b.id }
|
96
|
+
superstates.each do |superstate|
|
97
|
+
startstate = superstate.resolve_startstate
|
98
|
+
src << "public final State #{superstate.id.to_s.upcase} = #{startstate.id.to_s.upcase};" << endl
|
99
|
+
end
|
100
|
+
src << "private State state = #{@startstate.id.to_s.upcase};" << endl
|
101
|
+
src << endl
|
102
|
+
src << "private #{@context_classname} context;" << endl
|
103
|
+
src << endl
|
104
|
+
end
|
105
|
+
|
106
|
+
def add_constructor(src)
|
107
|
+
src << "// Statemachine constructor" << endl
|
108
|
+
add_method(src, nil, @classname, "#{@context_classname} context") do
|
109
|
+
src << "this.context = context;" << endl
|
110
|
+
entered_states = []
|
111
|
+
entry_state = @startstate
|
112
|
+
while entry_state != @sm.root
|
113
|
+
entered_states << entry_state
|
114
|
+
entry_state = entry_state.superstate
|
115
|
+
end
|
116
|
+
entered_states.reverse.each do |state|
|
117
|
+
src << "context.#{state.entry_action.to_s.camalized(:lower)}();" << endl if state.entry_action
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def add_statemachine_boilerplate_code(src)
|
123
|
+
src << "// The following is boiler plate code standard to all statemachines" << endl
|
124
|
+
add_one_liner(src, @context_classname, "getContext", nil, "return context")
|
125
|
+
add_one_liner(src, "State", "getState", nil, "return state")
|
126
|
+
add_one_liner(src, "void", "setState", "State newState", "state = newState")
|
127
|
+
end
|
128
|
+
|
129
|
+
def add_event_delegation(src)
|
130
|
+
src << "// Event delegation" << endl
|
131
|
+
@event_names.each do |event|
|
132
|
+
add_one_liner(src, "void", event, nil, "state.#{event}()")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def add_statemachine_exception(src)
|
137
|
+
src << "// Standard exception class added to all statemachines." << endl
|
138
|
+
src << "public static class StatemachineException extends RuntimeException" << endl
|
139
|
+
begin_scope(src)
|
140
|
+
src << "public StatemachineException(State state, String event)" << endl
|
141
|
+
begin_scope(src)
|
142
|
+
src << "super(\"Missing transition from '\" + state.getClass().getSimpleName() + \"' with the '\" + event + \"' event.\");" << endl
|
143
|
+
end_scope(src)
|
144
|
+
end_scope(src)
|
145
|
+
src << endl
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_base_state(src)
|
149
|
+
src << "// The base state" << endl
|
150
|
+
src << "public static abstract class State" << endl
|
151
|
+
begin_scope(src)
|
152
|
+
src << "protected #{@classname} statemachine;" << endl
|
153
|
+
src << endl
|
154
|
+
add_one_liner(src, nil, "State", "#{@classname} statemachine", "this.statemachine = statemachine")
|
155
|
+
@event_names.each do |event|
|
156
|
+
add_one_liner(src, "void", event, nil, "throw new StatemachineException(this, \"#{event}\")")
|
157
|
+
end
|
158
|
+
end_scope(src)
|
159
|
+
src << endl
|
160
|
+
end
|
161
|
+
|
162
|
+
def add_state_implementations(src)
|
163
|
+
src << "// State implementations" << endl
|
164
|
+
@sm.states.keys.reject{|k| k.nil? }.sort.each do |state_id|
|
165
|
+
state = @sm.states[state_id]
|
166
|
+
state_name = state.id.to_s.camalized
|
167
|
+
base_class = state.superstate == @sm.root ? "State" : state.superstate.id.to_s.camalized
|
168
|
+
|
169
|
+
add_concrete_state_class(src, state, state_name, base_class) if state_id
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def add_concrete_state_class(src, state, state_name, base_class)
|
174
|
+
src << "public static class #{state_name}State extends State" << endl
|
175
|
+
src << "{" << endl
|
176
|
+
src.indent!
|
177
|
+
add_one_liner(src, nil, "#{state_name}State", "#{@classname} statemachine", "super(statemachine)")
|
178
|
+
state.transitions.keys.sort.each do |event_id|
|
179
|
+
transition = state.transitions[event_id]
|
180
|
+
add_state_event_handler(transition, src)
|
181
|
+
end
|
182
|
+
src.undent!
|
183
|
+
src << "}" << endl
|
184
|
+
src << endl
|
185
|
+
end
|
186
|
+
|
187
|
+
def add_state_event_handler(transition, src)
|
188
|
+
event_name = transition.event.to_s.camalized(:lower)
|
189
|
+
exits, entries = transition.exits_and_entries(@sm.get_state(transition.origin_id), @sm.get_state(transition.destination_id))
|
190
|
+
add_method(src, "void", event_name, nil) do
|
191
|
+
exits.each do |exit|
|
192
|
+
src << "statemachine.getContext().#{exit.exit_action.to_s.camalized(:lower)}();" << endl if exit.exit_action
|
193
|
+
end
|
194
|
+
src << "statemachine.getContext().#{transition.action.to_s.camalized(:lower)}();" << endl if transition.action
|
195
|
+
src << "statemachine.setState(statemachine.#{transition.destination_id.to_s.upcase});" << endl
|
196
|
+
entries.each do |entry|
|
197
|
+
src << "statemachine.getContext().#{entry.entry_action.to_s.camalized(:lower)}();" << endl if entry.entry_action
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def add_one_liner(src, return_type, name, params, body)
|
203
|
+
add_method(src, return_type, name, params) do
|
204
|
+
src << "#{body};" << endl
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def add_method(src, return_type, name, params)
|
209
|
+
src << "public #{return_type} #{name}(#{params})".sub(' ' * 2, ' ') << endl
|
210
|
+
begin_scope(src)
|
211
|
+
yield
|
212
|
+
end_scope(src)
|
213
|
+
src << endl
|
214
|
+
end
|
215
|
+
|
216
|
+
def begin_scope(src)
|
217
|
+
src << "{" << endl
|
218
|
+
src.indent!
|
219
|
+
end
|
220
|
+
|
221
|
+
def end_scope(src)
|
222
|
+
src.undent! << "}" << endl
|
223
|
+
end
|
224
|
+
|
225
|
+
def build_context_src
|
226
|
+
src = begin_src
|
227
|
+
src << "public interface #{@context_classname}" << endl
|
228
|
+
begin_scope(src)
|
229
|
+
src << "// Actions" << endl
|
230
|
+
@action_names.each do |event|
|
231
|
+
src << "void #{event}();" << endl
|
232
|
+
end
|
233
|
+
end_scope(src)
|
234
|
+
return src.to_s
|
235
|
+
end
|
236
|
+
|
237
|
+
def begin_src
|
238
|
+
src = SrcBuilder.new
|
239
|
+
src << HEADER1 << endl
|
240
|
+
src << HEADER2 << timestamp << endl
|
241
|
+
src << "package #{@package};" << endl
|
242
|
+
src << endl
|
243
|
+
return src
|
244
|
+
end
|
245
|
+
|
246
|
+
def create_file(filename, content)
|
247
|
+
establish_directory(File.dirname(filename))
|
248
|
+
say "Writing to file: #{filename}"
|
249
|
+
File.open(filename, 'w') do |file|
|
250
|
+
file.write(content)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
def src_file(name)
|
255
|
+
path = @output_dir
|
256
|
+
if @package
|
257
|
+
@package.split(".").each { |segment| path = File.join(path, segment) }
|
258
|
+
end
|
259
|
+
return File.join(path, "#{name}.java")
|
260
|
+
end
|
261
|
+
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Statemachine
|
2
|
+
module Generate
|
3
|
+
class SrcBuilder
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@src = ""
|
7
|
+
@is_newline = true
|
8
|
+
@indents = 0
|
9
|
+
@indent_size = 2
|
10
|
+
end
|
11
|
+
|
12
|
+
def <<(content)
|
13
|
+
if content == :endl
|
14
|
+
newline!
|
15
|
+
else
|
16
|
+
add_indents if @is_newline
|
17
|
+
@src += content.to_s
|
18
|
+
end
|
19
|
+
return self
|
20
|
+
end
|
21
|
+
|
22
|
+
def newline!
|
23
|
+
@src += "\n"
|
24
|
+
@is_newline = true
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
return @src
|
29
|
+
end
|
30
|
+
|
31
|
+
def indent!
|
32
|
+
@indents += 1
|
33
|
+
return self
|
34
|
+
end
|
35
|
+
|
36
|
+
def undent!
|
37
|
+
@indents -= 1
|
38
|
+
return self
|
39
|
+
end
|
40
|
+
|
41
|
+
def add_indents
|
42
|
+
@src += (" " * (@indent_size * @indents))
|
43
|
+
@is_newline = false
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
3
|
+
module Statemachine
|
4
|
+
module Generate
|
5
|
+
module Util
|
6
|
+
|
7
|
+
def create_file(filename, content)
|
8
|
+
establish_directory(File.dirname(filename))
|
9
|
+
File.open(filename, 'w') do |file|
|
10
|
+
file.write(content)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def establish_directory(path)
|
15
|
+
return if File.exist?(path)
|
16
|
+
establish_directory(File.dirname(path))
|
17
|
+
Dir.mkdir(path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def timestamp
|
21
|
+
return DateTime.now.strftime("%H:%M:%S %B %d, %Y")
|
22
|
+
end
|
23
|
+
|
24
|
+
def endl
|
25
|
+
return :endl
|
26
|
+
end
|
27
|
+
|
28
|
+
def say(message)
|
29
|
+
if !defined?($IS_TEST)
|
30
|
+
puts message
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class String
|
39
|
+
def camalized(starting_case = :upper)
|
40
|
+
value = self.downcase.gsub(/[_| |\-][a-z]/) { |match| match[-1..-1].upcase }
|
41
|
+
value = value[0..0].upcase + value[1..-1] if starting_case == :upper
|
42
|
+
return value
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class Symbol
|
47
|
+
def <=>(other)
|
48
|
+
return to_s <=> other.to_s
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
module Statemachine
|
2
|
+
|
3
|
+
class Parallelstate< Superstate
|
4
|
+
|
5
|
+
attr_accessor :parallel_statemachines, :id
|
6
|
+
attr_reader :startstate_ids
|
7
|
+
|
8
|
+
def initialize(id, superstate, statemachine)
|
9
|
+
super(id, superstate, statemachine)
|
10
|
+
@parallel_statemachines=[]
|
11
|
+
@startstate_ids=[]
|
12
|
+
end
|
13
|
+
|
14
|
+
# def startstate_id= id
|
15
|
+
# if @parallel_statemachines.size>0
|
16
|
+
# @startstate_ids[@parallel_statemachines.size-1]= id
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# def startstate_id
|
21
|
+
# if (@parallel_statemachines.size>0 and @parallel_statemachines.size==@startstate_ids.size)
|
22
|
+
# return true
|
23
|
+
# end
|
24
|
+
# nil
|
25
|
+
# end
|
26
|
+
|
27
|
+
def context= c
|
28
|
+
@parallel_statemachines.each do |s|
|
29
|
+
s.context=c
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def activate(terminal_state = nil)
|
34
|
+
@statemachine.state = self
|
35
|
+
|
36
|
+
@parallel_statemachines.each_with_index do |s,i|
|
37
|
+
s.activation = @statemachine.activation
|
38
|
+
s.reset(@startstate_ids[i])
|
39
|
+
end
|
40
|
+
@parallel_statemachines.each do |s|
|
41
|
+
next if terminal_state and s.has_state(terminal_state)
|
42
|
+
@statemachine.activation.call(s.state,self.abstract_states,self.states) if @statemachine.activation
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
def add_statemachine(statemachine)
|
48
|
+
statemachine.is_parallel=self
|
49
|
+
@parallel_statemachines.push(statemachine)
|
50
|
+
statemachine.context = @statemachine.context
|
51
|
+
@startstate_ids << @startstate_id
|
52
|
+
@startstate_id = nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_statemachine_with(id)
|
56
|
+
@parallel_statemachines.each do |s|
|
57
|
+
return s if s.has_state(id)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def non_default_transition_for(event)
|
62
|
+
p "check parallel for #{event}"
|
63
|
+
transition = @transitions[event]
|
64
|
+
return transition if transition
|
65
|
+
|
66
|
+
transition = transition_for(event)
|
67
|
+
|
68
|
+
transition = @superstate.non_default_transition_for(event) if @superstate and not transition
|
69
|
+
return transition
|
70
|
+
end
|
71
|
+
|
72
|
+
def In(id)
|
73
|
+
@parallel_statemachines.each do |s|
|
74
|
+
return true if s.In(id.to_sym)
|
75
|
+
end
|
76
|
+
return false
|
77
|
+
end
|
78
|
+
|
79
|
+
def state= id
|
80
|
+
@parallel_statemachines.each do |s|
|
81
|
+
if s.has_state(id)
|
82
|
+
s.state=id
|
83
|
+
return true
|
84
|
+
end
|
85
|
+
end
|
86
|
+
return false
|
87
|
+
end
|
88
|
+
|
89
|
+
def has_state(id)
|
90
|
+
@parallel_statemachines.each do |s|
|
91
|
+
if s.has_state(id)
|
92
|
+
return true
|
93
|
+
end
|
94
|
+
end
|
95
|
+
return false
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_state(id)
|
99
|
+
# if state = @statemachine.get_state(id)
|
100
|
+
# return state
|
101
|
+
# end
|
102
|
+
@parallel_statemachines.each do |s|
|
103
|
+
if state = s.get_state(id)
|
104
|
+
return state
|
105
|
+
end
|
106
|
+
end
|
107
|
+
return nil
|
108
|
+
end
|
109
|
+
|
110
|
+
def process_event(event, *args)
|
111
|
+
exceptions = []
|
112
|
+
result = false
|
113
|
+
# TODO fix needed: respond_to checks superstates lying out of the parallel state as well, in case an event is
|
114
|
+
# defined outside the parallel statemachine it gets processed twice!
|
115
|
+
|
116
|
+
@parallel_statemachines.each_with_index do |s,i|
|
117
|
+
if s.respond_to? event
|
118
|
+
s.process_event(event,*args)
|
119
|
+
result = true
|
120
|
+
end
|
121
|
+
end
|
122
|
+
result
|
123
|
+
end
|
124
|
+
|
125
|
+
# Resets all of the statemachines back to theirs starting state.
|
126
|
+
def reset
|
127
|
+
@parallel_statemachines.each_with_index do |s,i|
|
128
|
+
s.reset(@startstate_ids[i])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def concrete?
|
133
|
+
return true
|
134
|
+
end
|
135
|
+
|
136
|
+
def startstate
|
137
|
+
return @statemachine.get_state(@startstate_id)
|
138
|
+
end
|
139
|
+
|
140
|
+
def resolve_startstate
|
141
|
+
return self
|
142
|
+
end
|
143
|
+
|
144
|
+
def substate_exiting(substate)
|
145
|
+
@history_id = substate.id
|
146
|
+
end
|
147
|
+
|
148
|
+
def add_substates(*substate_ids)
|
149
|
+
do_substate_adding(substate_ids)
|
150
|
+
end
|
151
|
+
|
152
|
+
def default_history=(state_id)
|
153
|
+
@history_id = @default_history_id = state_id
|
154
|
+
end
|
155
|
+
|
156
|
+
def states
|
157
|
+
return @parallel_statemachines.map &:state
|
158
|
+
end
|
159
|
+
|
160
|
+
def transition_for(event)
|
161
|
+
@parallel_statemachines.each do |s|
|
162
|
+
# puts "checke parallel #{s.id} for #{event}"
|
163
|
+
transition = s.get_state(s.state).non_default_transition_for(event)
|
164
|
+
transition = s.get_state(s.state).default_transition if not transition
|
165
|
+
return transition if transition
|
166
|
+
end
|
167
|
+
return @superstate.default_transition if @superstate
|
168
|
+
|
169
|
+
# super.transition_for(event)
|
170
|
+
end
|
171
|
+
|
172
|
+
def enter(args=[])
|
173
|
+
# reset
|
174
|
+
super(args)
|
175
|
+
end
|
176
|
+
def to_s
|
177
|
+
return "'#{id}' parallel"
|
178
|
+
end
|
179
|
+
|
180
|
+
def abstract_states
|
181
|
+
abstract_states=[]
|
182
|
+
|
183
|
+
if (@superstate)
|
184
|
+
abstract_states=@superstate.abstract_states
|
185
|
+
end
|
186
|
+
@parallel_statemachines.each do |s|
|
187
|
+
abstract_states += s.abstract_states
|
188
|
+
end
|
189
|
+
abstract_states.uniq
|
190
|
+
end
|
191
|
+
def is_parallel
|
192
|
+
true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|