MINT-scxml 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source :rubygems
2
- gem "MINT-statemachine", "1.2.3"
3
- gem "rspec", "1.3.1"
2
+ gem "MINT-statemachine","1.3.0"
3
+ gem "rspec","2.8.0"
4
4
  gem "rake","0.9.2"
5
5
  gem "hoe", "2.9.6"
data/Gemfile.lock CHANGED
@@ -1,18 +1,26 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- MINT-statemachine (1.2.3)
4
+ MINT-statemachine (1.3.0)
5
+ diff-lcs (1.1.3)
5
6
  hoe (2.9.6)
6
7
  rake (~> 0.8)
7
8
  rake (0.9.2)
8
- rspec (1.3.1)
9
+ rspec (2.8.0)
10
+ rspec-core (~> 2.8.0)
11
+ rspec-expectations (~> 2.8.0)
12
+ rspec-mocks (~> 2.8.0)
13
+ rspec-core (2.8.0)
14
+ rspec-expectations (2.8.0)
15
+ diff-lcs (~> 1.1.2)
16
+ rspec-mocks (2.8.0)
9
17
 
10
18
  PLATFORMS
11
19
  ruby
12
20
  x86-mingw32
13
21
 
14
22
  DEPENDENCIES
15
- MINT-statemachine (= 1.2.3)
23
+ MINT-statemachine (= 1.3.0)
16
24
  hoe (= 2.9.6)
17
25
  rake (= 0.9.2)
18
- rspec (= 1.3.1)
26
+ rspec (= 2.8.0)
data/History.txt CHANGED
@@ -1,3 +1,17 @@
1
+ === 1.1.0 / 2012-11-20
2
+
3
+ * (Sebastian) fixed bug: root statemachine was wrongly set for states that are nested inside parallel
4
+ * (Sebastian) added test for spontaneous transitions inside parallel states
5
+ * (Sebastian) removed old MINT test state machines
6
+ * (Jessica) transitions now stored as an array
7
+ * (Jessica) fixed parallel superstate bug
8
+ * (Jessica) All tests working. Added on_entry, on_exit and transitions for parallel states
9
+ * (Jessica) added spontaneous transition
10
+ * (Jessica) WIP: script
11
+ * (Jessica) added treatment for ifs
12
+ * (Jessica) fixed history states support and history state tests
13
+ * (Jessica) Removed unnecessary transitions.
14
+
1
15
  === 1.0.0 / 2011-11-01
2
16
 
3
17
  * First version
data/MINT-scxml.gemspec CHANGED
@@ -1,35 +1,41 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{MINT-scxml}
5
- s.version = "1.0.0"
4
+ s.name = "MINT-scxml"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = [%q{Jessica H. Colnago, Sebastian Feuerstack}]
9
- s.date = %q{2011-11-01}
10
- s.description = %q{}
11
- s.email = %q{Sebastian@Feuerstack.org}
12
- s.extra_rdoc_files = [%q{History.txt}, %q{Manifest.txt}, %q{README.txt}]
13
- s.files = [%q{.autotest}, %q{.idea/workspace.xml}, %q{Gemfile}, %q{Gemfile.lock}, %q{History.txt}, %q{MINT-scxml.gemspec}, %q{Manifest.txt}, %q{README.rdoc}, %q{README.txt}, %q{Rakefile}, %q{lib/MINT-scxml.rb}, %q{lib/MINT-scxml/scxml-parser.rb}, %q{spec/atm_spec.rb}, %q{spec/parser_spec.rb}, %q{spec/spec.opts}, %q{spec/spec_helper.rb}, %q{spec/test_handgestures_spec.rb}, %q{spec/testmachines/atm_enhanced.rb}, %q{spec/testmachines/handgestures-scxmlgui.png}, %q{spec/testmachines/handgestures-scxmlgui.scxml}, %q{spec/testmachines/multiplestates.rb}, %q{spec/testmachines/traffic_light_enhanced.rb}, %q{spec/testmachines/vending_machine1.rb}, %q{spec/testmachines/vending_machine2.rb}, %q{spec/testmachines/vending_machine3.rb}, %q{spec/testmachines/vending_machine4.rb}, %q{spec_helper.rb}, %q{statemachines/AICommand_scxml_spec.rb}, %q{statemachines/AIO_scxml_spec.rb}, %q{statemachines/aui-scxml/AIC.scxml}, %q{statemachines/aui-scxml/AICommand.scxml}, %q{statemachines/aui-scxml/AICommand2.scxml}, %q{statemachines/aui-scxml/AIO.scxml}, %q{statemachines/aui/AIC.rb}, %q{statemachines/aui/AIChoiceElement.rb}, %q{statemachines/aui/AICommand.rb}, %q{statemachines/aui/AIIN.rb}, %q{statemachines/aui/AIINContinous.rb}, %q{statemachines/aui/AIMultiChoice.rb}, %q{statemachines/aui/AIMultiChoiceElement.rb}, %q{statemachines/aui/AIOUTContinous.rb}, %q{statemachines/aui/AISingleChoice.rb}, %q{statemachines/aui/AISingleChoiceElement.rb}, %q{statemachines/aui/aio.rb}, %q{statemachines/specs/AICommand_spec.rb}, %q{statemachines/specs/AIINContinous_spec.rb}, %q{statemachines/specs/AIMultiChoiceElement_spec.rb}, %q{statemachines/specs/AIMultiChoice_spec.rb}, %q{statemachines/specs/AIOUTContinous_spec.rb}, %q{statemachines/specs/AIO_spec.rb}, %q{statemachines/specs/AISingleChoiceElement_spec.rb}, %q{statemachines/specs/AISingleChoice_spec.rb}, %q{.gemtest}]
14
- s.homepage = %q{http://www.multi-access.de}
15
- s.rdoc_options = [%q{--main}, %q{README.rdoc}]
16
- s.require_paths = [%q{lib}]
17
- s.rubyforge_project = %q{MINT-scxml}
18
- s.rubygems_version = %q{1.8.5}
19
- s.summary = %q{}
8
+ s.authors = ["Jessica H. Colnago, Sebastian Feuerstack"]
9
+ s.date = "2012-11-20"
10
+ s.description = "This gem implements a state chart XML (SCXML) parser that generates a ruby statemachine."
11
+ s.email = "Sebastian@Feuerstack.org"
12
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
13
+ s.files = ["Gemfile", "Gemfile.lock", "History.txt", "MINT-scxml.gemspec", "Manifest.txt", "README.rdoc", "Rakefile", "lib/MINT-scxml.rb", "lib/MINT-scxml/scxml-parser.rb", "spec/atm_spec.rb", "spec/if_spec.rb", "spec/parser_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/test_handgestures_spec.rb", "spec/testmachines/atm_enhanced.rb", "spec/testmachines/button.scxml", "spec/testmachines/handgestures-scxmlgui.png", "spec/testmachines/handgestures-scxmlgui.scxml", "spec/testmachines/multiplestates.rb", "spec/testmachines/traffic_light_enhanced.rb", "spec/testmachines/vending_machine1.rb", "spec/testmachines/vending_machine2.rb", "spec/testmachines/vending_machine3.rb", "spec/testmachines/vending_machine4.rb", "spec_helper.rb", "statemachines/AICommand_scxml_spec.rb", "statemachines/AIO_scxml_spec.rb", "statemachines/specs/AICommand_spec.rb", "statemachines/specs/AIINContinous_spec.rb", "statemachines/specs/AIMultiChoiceElement_spec.rb", "statemachines/specs/AIMultiChoice_spec.rb", "statemachines/specs/AIOUTContinous_spec.rb", "statemachines/specs/AIO_spec.rb", "statemachines/specs/AISingleChoiceElement_spec.rb", "statemachines/specs/AISingleChoice_spec.rb", ".gemtest"]
14
+ s.homepage = "http://www.multi-access.de"
15
+ s.rdoc_options = ["--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "MINT-scxml"
18
+ s.rubygems_version = "1.8.15"
19
+ s.summary = "This gem implements a state chart XML (SCXML) parser that generates a ruby statemachine."
20
20
 
21
21
  if s.respond_to? :specification_version then
22
22
  s.specification_version = 3
23
23
 
24
24
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
- s.add_runtime_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
26
- s.add_development_dependency(%q<hoe>, ["~> 2.9"])
25
+ s.add_runtime_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
26
+ s.add_development_dependency(%q<rdoc>, ["~> 3.10"])
27
+ s.add_development_dependency(%q<newgem>, [">= 1.5.3"])
28
+ s.add_development_dependency(%q<hoe>, ["~> 3.1"])
27
29
  else
28
- s.add_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
29
- s.add_dependency(%q<hoe>, ["~> 2.9"])
30
+ s.add_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
31
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
32
+ s.add_dependency(%q<newgem>, [">= 1.5.3"])
33
+ s.add_dependency(%q<hoe>, ["~> 3.1"])
30
34
  end
31
35
  else
32
- s.add_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
33
- s.add_dependency(%q<hoe>, ["~> 2.9"])
36
+ s.add_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
37
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
38
+ s.add_dependency(%q<newgem>, [">= 1.5.3"])
39
+ s.add_dependency(%q<hoe>, ["~> 3.1"])
34
40
  end
35
41
  end
data/Manifest.txt CHANGED
@@ -8,11 +8,13 @@ Rakefile
8
8
  lib/MINT-scxml.rb
9
9
  lib/MINT-scxml/scxml-parser.rb
10
10
  spec/atm_spec.rb
11
+ spec/if_spec.rb
11
12
  spec/parser_spec.rb
12
13
  spec/spec.opts
13
14
  spec/spec_helper.rb
14
15
  spec/test_handgestures_spec.rb
15
16
  spec/testmachines/atm_enhanced.rb
17
+ spec/testmachines/button.scxml
16
18
  spec/testmachines/handgestures-scxmlgui.png
17
19
  spec/testmachines/handgestures-scxmlgui.scxml
18
20
  spec/testmachines/multiplestates.rb
@@ -24,21 +26,6 @@ spec/testmachines/vending_machine4.rb
24
26
  spec_helper.rb
25
27
  statemachines/AICommand_scxml_spec.rb
26
28
  statemachines/AIO_scxml_spec.rb
27
- statemachines/aui-scxml/AIC.scxml
28
- statemachines/aui-scxml/AICommand.scxml
29
- statemachines/aui-scxml/AICommand2.scxml
30
- statemachines/aui-scxml/AIO.scxml
31
- statemachines/aui/AIC.rb
32
- statemachines/aui/AIChoiceElement.rb
33
- statemachines/aui/AICommand.rb
34
- statemachines/aui/AIIN.rb
35
- statemachines/aui/AIINContinous.rb
36
- statemachines/aui/AIMultiChoice.rb
37
- statemachines/aui/AIMultiChoiceElement.rb
38
- statemachines/aui/AIOUTContinous.rb
39
- statemachines/aui/AISingleChoice.rb
40
- statemachines/aui/AISingleChoiceElement.rb
41
- statemachines/aui/aio.rb
42
29
  statemachines/specs/AICommand_spec.rb
43
30
  statemachines/specs/AIINContinous_spec.rb
44
31
  statemachines/specs/AIMultiChoiceElement_spec.rb
data/README.rdoc CHANGED
@@ -33,7 +33,7 @@ and generate the RDoc.
33
33
 
34
34
  == LICENSE:
35
35
 
36
- Copyright (C) 2010,2011 Sebastian Feuerstack, Jessica H. Colnago
36
+ Copyright (C) 2010-2012 Sebastian Feuerstack, Jessica H. Colnago
37
37
 
38
38
  This library is free software; you can redistribute it and/or
39
39
  modify it under the terms of the GNU Lesser General Public
data/Rakefile CHANGED
@@ -16,16 +16,10 @@ Hoe.plugin :newgem
16
16
  Hoe.spec 'MINT-scxml' do
17
17
  self.developer 'Jessica H. Colnago, Sebastian Feuerstack', 'Sebastian@Feuerstack.org'
18
18
  self.rubyforge_name = self.name # TODO this is default value
19
- self.extra_deps = [['MINT-statemachine','~> 1.2.3']]
19
+ self.extra_deps = [['MINT-statemachine','~> 1.3.0']]
20
20
  self.email = "Sebastian@Feuerstack.org"
21
21
 
22
- # HEY! If you fill these out in ~/.hoe_template/Rakefile.erb then
23
- # you'll never have to touch them again!
24
- # (delete this comment too, of course)
25
22
 
26
- # developer('FIX', 'FIX@example.com')
27
-
28
- # self.rubyforge_name = 'scxml-gemx' # if different than 'scxml-gem'
29
23
  end
30
24
 
31
25
  # vim: syntax=ruby
data/lib/MINT-scxml.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class SCXML_MINT
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
4
4
 
5
5
  require "MINT-scxml/scxml-parser"
@@ -1,4 +1,3 @@
1
- # -*- coding: raw-text -*-
2
1
  require 'rubygems'
3
2
  require "bundler/setup"
4
3
  require 'statemachine'
@@ -20,98 +19,164 @@ class StatemachineParser < Statemachine::StatemachineBuilder
20
19
 
21
20
  def initialize(context = nil, logger = nil, queue = nil)
22
21
  super()
23
- @actions = Array.new
24
22
  @current_transition = nil
25
23
  @current_state = nil
26
24
  @current_element = nil
27
25
  @parallel = nil
28
- @state = Array.new
26
+ @history_state = nil
29
27
  @statemachine.messenger = logger
30
28
  @statemachine.message_queue = queue
31
29
  @statemachine.context= context
30
+ @actions = Array.new
31
+ @actions_aux = Array.new
32
+ @state = Array.new
32
33
  @substate = Array.new
33
34
  @transitions = Array.new
34
35
  @history_states = Array.new
35
36
  @history_target = Array.new
36
- @history_state = nil
37
+ @parallel_state = Array.new
38
+ @if_actions = Array.new
39
+ @if_actions_aux = Array.new
40
+ @if = Array.new
41
+ @tag = Array.new
42
+ @cond = Array.new
37
43
  @history = false
38
44
  @is_parallel = false
39
45
  @scxml_state = false
40
- @parallel_state = Array.new
41
46
  end
42
47
 
48
+ # This function parses scxml from a file
43
49
  def build_from_scxml(filename)
44
50
  source = File.new filename
45
51
  Document.parse_stream(source, self)
46
- @statemachine.reset
47
- return @statemachine
52
+ #@statemachine.reset
53
+ @statemachine
48
54
  end
49
55
 
50
- # parses scxml directly from string parameter stringbuffer
56
+ # This function parses scxml directly from the string parameter "stringbuffer"
51
57
  def build_from_scxml_string(stringbuffer)
52
58
  Document.parse_stream(stringbuffer, self)
53
- @statemachine.reset
54
- return @statemachine
59
+ #@statemachine.reset
60
+ @statemachine
55
61
  end
56
62
 
63
+
64
+ # This function deals with the different scenarios for the creation of actions with if
65
+ def creating_ifs
66
+ if @if.size == 1
67
+ @if_actions.push(@if_actions_aux.last) if @if_actions_aux.size != 0
68
+ if @actions_aux.size != 0
69
+ @actions_aux.each do |j|
70
+ @if_actions.push(j)
71
+ end
72
+ @actions_aux = []
73
+ end
74
+ @actions.push([@tag.last, @cond.last, @if_actions])
75
+ else
76
+ if @if_actions.size != 0
77
+ @if_actions_aux.push(@if_actions)
78
+ end
79
+ @actions_aux.push([@tag.last, @cond.last, @if_actions_aux.last])
80
+ end
81
+ @if_actions = []
82
+ @cond.pop
83
+ @tag.pop
84
+ @if_actions_aux.pop if @if_actions_aux.size != 0
85
+ end
86
+
87
+ # This function defines the actions to be taken for each different tag when the tag is opened
57
88
  def tag_start(name, attributes)
58
89
  case name
59
90
  when 'scxml'
91
+ # If the initial tag <scxml> has a n ame attribute, define it as the most outer super state
60
92
  if attributes['name']
61
93
  @scxml_state = true
62
- state = nil
63
94
  @current_state = State.new
64
- @current_state.id = attributes['name']
95
+ @current_state.id = attributes['id']
65
96
  @current_state.initial = attributes['initial']
66
97
  state = Statemachine::SuperstateBuilder.new(attributes['name'].to_sym, @subject, @statemachine)
67
- if (@current_state.initial != nil)
98
+ # If the current state has an initial state defined, add it to the state created.
99
+ if @current_state.initial != nil
68
100
  state.startstate(@current_state.initial.to_sym)
69
101
  end
102
+ # Adds it to a list of "open" states
70
103
  @state.push(state)
71
104
  end
72
105
  when 'parallel'
73
- @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
74
106
  @is_parallel = true
75
107
  # If there is a state that encapsulates the parallel state, change it to a superstate
76
- if (not @state.empty? and @state.last.is_a? Statemachine::StateBuilder)
77
- state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
78
- @state.pop # pops the old one
79
- @state.push(state) # pushes the new one
108
+ if not @state.empty? and @state.last.is_a? Statemachine::StateBuilder
109
+ state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
110
+ @state.pop # pops the old one
111
+ @state.push(state) # pushes the new one
112
+ end
113
+ if @state.empty?
114
+ @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
115
+ else
116
+ @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
80
117
  end
118
+
81
119
  when 'state'
82
120
  @current_state = State.new
83
121
  @current_state.id = attributes['id']
84
122
  @current_state.initial = attributes['initial']
85
- if (@state.empty?) # It is not a substate
86
- if (@current_state.initial != nil) # AND it is a superstate
87
- state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
88
- state.startstate(@current_state.initial.to_sym)
89
- else # AND it is a state
90
- state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
91
- end
92
- else # It is a substate
93
- if (@current_state.initial != nil) # AND it is a superstate
94
- state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
123
+ if @state.empty?
124
+ # It is not a substate
125
+ if @current_state.initial != nil
126
+ # and it is a superstate
127
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
95
128
  state.startstate(@current_state.initial.to_sym)
96
- else # AND it is a subsubstate
97
- if (@state.last.is_a? Statemachine::StateBuilder) # but it's parent is not a superstate yet
129
+ else
130
+ # and it is a state
131
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
132
+ end
133
+ else
134
+ #It is a substate
135
+ if @state.last.is_a? Statemachine::StateBuilder
136
+ # Its parent is not a superstate yet
137
+ if @is_parallel and @parallel_state.empty?
138
+ state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @parallel.subject, @state.last.subject.statemachine)
139
+ else
98
140
  state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
99
- @state.pop # pops the old one
100
- @state.push(state) # pushes the new one
101
- if @is_parallel
102
- @parallel_state.pop
103
- @parallel_state.push(state)
104
- end
105
141
  end
106
- state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
142
+ @state.pop # pops the old one
143
+ @state.push(state) # pushes the new one
144
+ if @is_parallel
145
+ @parallel_state.pop
146
+ @parallel_state.push(state)
147
+ end
148
+ end
149
+ if @current_state.initial != nil
150
+ # and it is a superstate
151
+ if @is_parallel and @parallel_state.empty?
152
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @parallel.subject, @statemachine)
153
+ else
154
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
155
+ end
156
+ state.startstate(@current_state.initial.to_sym)
157
+ else
158
+ # and it is a state
159
+ if @is_parallel and @parallel_state.empty?
160
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @parallel.subject, @statemachine)
161
+ else
162
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
163
+ end
107
164
  end
108
165
  end
109
166
  @state.push(state)
110
167
  @parallel_state.push(state) if @is_parallel
111
168
  when 'transition'
112
169
  @current_transition = Transition.new
113
- @current_transition.event = attributes['event']
114
- @current_transition.target = attributes['target']
170
+ if attributes['target'] == @history_state.to_s and @history_state
171
+ @current_transition.target = attributes['target']+"_H"
172
+ else
173
+ @current_transition.target = attributes['target']
174
+ end
175
+ if attributes['event']
176
+ @current_transition.event = attributes['event']
177
+ else
178
+ @current_transition.event = nil
179
+ end
115
180
  if attributes['cond']
116
181
  @current_transition.cond = attributes['cond']
117
182
  else
@@ -121,74 +186,108 @@ class StatemachineParser < Statemachine::StatemachineBuilder
121
186
  when 'onentry'
122
187
  when 'onexit'
123
188
  when 'history'
124
- @history=true
189
+ @history = true
125
190
  @history_states.push(@state.last.subject.id)
126
191
  @history_state = @state.last.subject.id
192
+ when 'if'
193
+ @if.push(true)
194
+ if @if.size >= 1
195
+ @if_actions_aux.push(@if_actions) if @if_actions.size != 0
196
+ @if_actions = []
197
+ end
198
+ @cond.push(attributes['cond'])
199
+ @tag.push("if")
200
+ when 'elseif'
201
+ creating_ifs
202
+ @cond.push(attributes['cond'])
203
+ @tag.push("elseif")
204
+ when 'else'
205
+ creating_ifs
206
+ @cond.push(true)
207
+ @tag.push("else")
127
208
  when 'log'
128
- @actions.push(["log", attributes['expr']])
209
+ if @if.last
210
+ @if_actions.push(["log", attributes['expr']])
211
+ else
212
+ @actions.push(["log", attributes['expr']])
213
+ end
129
214
  when 'send'
130
- @actions.push(["send", attributes['target'], attributes['event']])
215
+ if @if.last
216
+ @if_actions.push(["send", attributes['target'], attributes['event']])
217
+ else
218
+ @actions.push(["send", attributes['target'], attributes['event']])
219
+ end
131
220
  when 'invoke'
132
- @actions.push(["invoke", attributes['src'].to_sym])
221
+ if @if.last
222
+ @if_actions.push(["invoke", attributes['src'].to_sym])
223
+ else
224
+ @actions.push(["invoke", attributes['src'].to_sym])
225
+ end
226
+ when 'script'
227
+ @script = true
228
+ @script_code = ""
133
229
  else
134
230
  @current_element = name
135
- end
231
+ end
136
232
  end
137
233
 
234
+ # This function defines the actions to be taken for each different tag when the tag is closed
138
235
  def tag_end(name)
139
236
  case name
140
237
  when 'parallel'
141
238
  @statemachine.add_state(@parallel.subject)
142
239
  @is_parallel = false
143
240
  when 'state'
144
- if (@state.last.is_a? Statemachine::SuperstateBuilder)
241
+ if @state.last.is_a? Statemachine::SuperstateBuilder
145
242
  s = statemachine.get_state(@state.last.subject.id)
146
243
 
147
- # Changing the state's id
148
244
  if (s.id == @history_state)
149
- s.id = (s.id.to_s + "_H").to_sym
150
- s.default_history=@history_target.last.to_sym
151
- @history_target.pop
245
+ if @history_target.last
246
+ s.default_history = @history_target.last.to_sym
247
+ @history_target.pop
248
+ end
152
249
  end
153
250
 
154
- # Adds the superstate's transitions to all its substates
155
- @substate.each{|j|
156
- if (s)
251
+ # Every state belonging to this superstate should respond to the superstate's transitions
252
+ @substate.each do |j|
253
+ if s
157
254
  s1 = statemachine.get_state(j.subject.id)
158
- s.transitions.each {|v,k|
159
- if (s1)
160
- s1.add(k)
161
- end
162
- }
255
+ s.transitions.each do |k|
256
+ s1.add(k) if s1
257
+ end
163
258
  end
164
- }
259
+ end
165
260
  end
261
+
166
262
  # In case of parallel statemachines the outmost states will become parallel statemachines
167
263
  # only considering parallel on a root level
168
-
169
264
  if @parallel_state.size == 1 and @parallel.is_a? Statemachine::ParallelStateBuilder
170
- statemachine_aux = Statemachine::Statemachine.new(@parallel_state.last.subject)
265
+ statemachine_aux = Statemachine::Statemachine.new(@parallel.subject)
266
+ statemachine_aux.add_state(@parallel_state.last.subject)
267
+ @statemachine.remove_state(@parallel_state.last.subject)
171
268
  @substate.each do |j|
269
+ j.subject.modify_statemachine(statemachine_aux)
172
270
  statemachine_aux.add_state(j.subject)
173
271
  @statemachine.remove_state(j.subject)
174
272
  end
175
- statemachine_aux.reset
273
+ #statemachine_aux.reset
176
274
  @parallel.subject.add_statemachine(statemachine_aux)
177
275
  end
276
+
178
277
  @substate.push(@state.last)
179
278
 
180
279
  if (@state.size == 1 and not @scxml_state) or (@state.size == 2 and @scxml_state) or (@parallel_state.size == 1)
181
280
  @substate = []
182
281
  # TODO make this better. Too inefficient
183
- while (!(@history_states.size == 0))
282
+ while @history_states.size != 0
184
283
  # change every transitions where @history_states.last was the target state to history_states.last+"_H"
185
284
  # for every history state
186
285
  @statemachine.states.each_value do |s|
187
- s.transitions.each_value do |t|
188
- if (t.destination_id == @history_states.last)
189
- t.destination_id = (t.destination_id.to_s + "_H").to_s
190
- end
191
- end
286
+ s.transitions.each do |t|
287
+ if t.destination_id == @history_states.last
288
+ t.destination_id = (t.destination_id.to_s + "_H").to_s
289
+ end
290
+ end
192
291
  end
193
292
  @history_states.pop
194
293
  end
@@ -196,30 +295,69 @@ class StatemachineParser < Statemachine::StatemachineBuilder
196
295
  @state.pop
197
296
  @parallel_state.pop if @is_parallel
198
297
  when 'transition'
199
- if (@transitions.last.event == nil)
298
+ if @transitions.last.event == nil
200
299
  if @history
201
300
  @history_target.push(@transitions.last.target)
202
301
  @history = false
203
302
  else
204
- # TODO spontaneous transitions
303
+ if @is_parallel and @parallel_state.empty?
304
+ @parallel.event(nil, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
305
+ else
306
+ @state.last.event(nil, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
307
+ end
205
308
  end
206
309
  else
207
- if (@transitions.last.target != nil) # if it has a target state
208
- @state.last.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
209
- else # it is its own target state
210
- @state.last.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
310
+ if @transitions.last.target != nil
311
+ if @is_parallel and @parallel_state.empty?
312
+ @parallel.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
313
+ else
314
+ @state.last.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
315
+ end
316
+ else
317
+ # if it doesn't have a target state, it is its own target state
318
+ if @is_parallel and @parallel_state.empty?
319
+ @parallel.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
320
+ else
321
+ @state.last.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
322
+ end
211
323
  end
212
324
  end
213
325
  @actions=[]
214
326
  @transitions.pop
215
327
  when 'onentry'
216
- @state.last.on_entry(@actions)
328
+ if @is_parallel and @parallel_state.empty?
329
+ @parallel.on_entry(@actions)
330
+ else
331
+ @state.last.on_entry(@actions)
332
+ end
217
333
  @actions=[]
218
334
  when 'onexit'
219
- @state.last.on_exit(@actions)
335
+ if @is_parallel and @parallel_state.empty?
336
+ @parallel.on_exit(@actions)
337
+ else
338
+ @state.last.on_exit(@actions)
339
+ end
220
340
  @actions=[]
221
341
  when 'history'
222
342
  @history = false
343
+ when 'if'
344
+ creating_ifs
345
+ @if.pop
346
+ when 'script'
347
+ @script = false
348
+ if @if.last
349
+ @if_actions.push(["script", @script_code])
350
+ else
351
+ @actions.push(["script", @script_code])
352
+ end
353
+ else
354
+
355
+ end
356
+ end
357
+
358
+ def text(text)
359
+ if @script
360
+ @script_code += text
223
361
  end
224
362
  end
225
363