MINT-scxml 1.1.0 → 1.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -2
- data/History.txt +9 -0
- data/README.rdoc +40 -13
- data/lib/MINT-scxml.rb +1 -1
- data/lib/MINT-scxml/scxml-parser.rb +49 -10
- data/spec/parser_spec.rb +105 -0
- metadata +14 -36
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
-
MINT-statemachine (1.3.
|
4
|
+
MINT-statemachine (1.3.2)
|
5
5
|
diff-lcs (1.1.3)
|
6
6
|
hoe (2.9.6)
|
7
7
|
rake (~> 0.8)
|
@@ -20,7 +20,7 @@ PLATFORMS
|
|
20
20
|
x86-mingw32
|
21
21
|
|
22
22
|
DEPENDENCIES
|
23
|
-
MINT-statemachine (= 1.3.
|
23
|
+
MINT-statemachine (= 1.3.2)
|
24
24
|
hoe (= 2.9.6)
|
25
25
|
rake (= 0.9.2)
|
26
26
|
rspec (= 2.8.0)
|
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
=== 1.1.2 / 2013-02-28
|
2
|
+
|
3
|
+
* Another bugfix for spontaneous transitions to parallel states, now depends on MINT-statemachine version 1.3.2
|
4
|
+
* improved documentation
|
5
|
+
|
6
|
+
=== 1.1.1 / 2013-02-26
|
7
|
+
|
8
|
+
* Bugfix for spontaneous transitions to parallel states.
|
9
|
+
|
1
10
|
=== 1.1.0 / 2012-11-20
|
2
11
|
|
3
12
|
* (Sebastian) fixed bug: root statemachine was wrongly set for states that are nested inside parallel
|
data/README.rdoc
CHANGED
@@ -4,36 +4,63 @@
|
|
4
4
|
|
5
5
|
== DESCRIPTION:
|
6
6
|
|
7
|
-
This gem implements
|
7
|
+
This gem implements all core constucts of the state chart XML (SCXML) specification of the W3C.
|
8
|
+
(http://www.w3.org/TR/scxml/)
|
9
|
+
|
10
|
+
Instead of implementing an interpreter, this gem implements a parser that create a ruby statemachine instance based
|
11
|
+
on the MINT-statemachine gem (https://github.com/sfeu/statemachine).
|
8
12
|
|
9
13
|
== FEATURES/PROBLEMS:
|
10
14
|
|
11
|
-
|
15
|
+
We currently do not support the definition of a data model. Instead the ruby class that contains the statemachine
|
16
|
+
instance can be used to store data. Conditions can be defined using ruby inside the SCXML definition and member
|
17
|
+
functionc can be called using SCXML script or invoke.
|
18
|
+
|
19
|
+
== EXAMPLE:
|
20
|
+
|
21
|
+
Parses an SCXML string and creates a statemachine instance in @sm. The messenger object
|
22
|
+
can be used to capture the SCXML log messenges (using the log statement).
|
23
|
+
|
24
|
+
@messenger = mock("messenger" )
|
25
|
+
|
26
|
+
parser = StatemachineParser.new(nil,@messenger)
|
27
|
+
|
28
|
+
scxml = <<EOS
|
29
|
+
<scxml name="SCXML" xmlns="http://www.w3.org/2005/07/scxml">
|
30
|
+
<state id="state1">
|
31
|
+
<transition event="event1" target="state2"/>
|
32
|
+
<transition event="event4" target="state2">
|
33
|
+
<log expr="transition executing"/>
|
34
|
+
</transition>
|
35
|
+
</state>
|
12
36
|
|
13
|
-
|
37
|
+
<state id="state2">
|
38
|
+
<transition event="event2" target="state3"/>
|
39
|
+
</state>
|
40
|
+
|
41
|
+
<state id="state3">
|
42
|
+
<transition event="event3" target="state1"/>
|
43
|
+
</state>
|
44
|
+
</scxml>
|
45
|
+
EOS
|
46
|
+
|
47
|
+
@sm = parser.build_from_scxml_string scxml
|
48
|
+
@sm.reset
|
14
49
|
|
15
50
|
See tests
|
16
51
|
|
17
52
|
== REQUIREMENTS:
|
18
53
|
|
19
|
-
* Depends on MINT-statemachine gem
|
54
|
+
* Depends on MINT-statemachine gem (https://github.com/sfeu/statemachine)
|
20
55
|
|
21
56
|
== INSTALL:
|
22
57
|
|
23
58
|
* sudo gem install MINT-scxml
|
24
59
|
|
25
|
-
== DEVELOPERS:
|
26
|
-
|
27
|
-
After checking out the source, run:
|
28
|
-
|
29
|
-
$ rake newb
|
30
|
-
|
31
|
-
This task will install any missing dependencies, run the tests/specs,
|
32
|
-
and generate the RDoc.
|
33
60
|
|
34
61
|
== LICENSE:
|
35
62
|
|
36
|
-
Copyright (C) 2010-
|
63
|
+
Copyright (C) 2010-2013 Sebastian Feuerstack, Jessica H. Colnago
|
37
64
|
|
38
65
|
This library is free software; you can redistribute it and/or
|
39
66
|
modify it under the terms of the GNU Lesser General Public
|
data/lib/MINT-scxml.rb
CHANGED
@@ -19,27 +19,59 @@ class StatemachineParser < Statemachine::StatemachineBuilder
|
|
19
19
|
|
20
20
|
def initialize(context = nil, logger = nil, queue = nil)
|
21
21
|
super()
|
22
|
-
|
23
|
-
@current_state = nil
|
24
|
-
@current_element = nil
|
25
|
-
@parallel = nil
|
26
|
-
@history_state = nil
|
22
|
+
|
27
23
|
@statemachine.messenger = logger
|
28
24
|
@statemachine.message_queue = queue
|
29
25
|
@statemachine.context= context
|
30
|
-
|
26
|
+
|
27
|
+
# The current variables are used to temporarily store the value of the _"type"
|
28
|
+
# in order to acquire the necessary data before adding the to its proper stack
|
29
|
+
@current_transition = nil
|
30
|
+
@current_state = nil
|
31
|
+
@current_element = nil
|
32
|
+
|
33
|
+
# Stacks
|
34
|
+
# These stacks (created as Arrays but used as stacks: push & pop) are used
|
35
|
+
# to store and treat the structure of the scxml file read.
|
36
|
+
# Some require auxiliary stacks due to the necessity of different treatments
|
37
|
+
# in different situations (e.g.: substate_aux is necessary due to the fact that
|
38
|
+
# a parallel state's superstate can have substates that would only be treated when
|
39
|
+
# the superstate is closed, which only happens after the parallel state is treated.
|
40
|
+
# Which in turn can have its own set of substates).
|
41
|
+
# Obs: These variables are used as stacks due to two basic situations: the ability of
|
42
|
+
# nested elements in statemachines and the need to create a single structure to be
|
43
|
+
# passed to element's constructors.
|
44
|
+
@actions = Array.new # stores the actions to later be added to the transition they belong.
|
31
45
|
@actions_aux = Array.new
|
32
|
-
@state = Array.new
|
33
|
-
@substate = Array.new
|
34
|
-
|
46
|
+
@state = Array.new # stores the order of nested states to be treated and used further on.
|
47
|
+
@substate = Array.new # similar to state, it stores the substates in order to later be added
|
48
|
+
# and have the proper transition treatment related to its parent state
|
49
|
+
@substate_aux = Array.new
|
50
|
+
@transitions = Array.new # stores the transitions in order to be later added to its proper state.
|
51
|
+
# so on and so forth.
|
52
|
+
@parallel_state = Array.new
|
35
53
|
@history_states = Array.new
|
36
54
|
@history_target = Array.new
|
37
|
-
|
55
|
+
|
56
|
+
# These variables are used to store the value of the element that gives its
|
57
|
+
# name in order to be used as parameters or "situation check" in future parts
|
58
|
+
# of the parser.
|
59
|
+
@parallel = nil
|
60
|
+
@history_state = nil
|
61
|
+
|
62
|
+
# These variables are used to help in the creation of actions that have if clauses.
|
38
63
|
@if_actions = Array.new
|
39
64
|
@if_actions_aux = Array.new
|
40
65
|
@if = Array.new
|
41
66
|
@tag = Array.new
|
42
67
|
@cond = Array.new
|
68
|
+
|
69
|
+
# These boolean variables are used to determine in which case we are on
|
70
|
+
# so to treat each case properly.
|
71
|
+
# If a history state was read, if inside a parallel state and if it has
|
72
|
+
# an outermost scxml_state (the latter implicates on different treatments due
|
73
|
+
# to the fact that it is added to the states stack and therefore it might not be
|
74
|
+
# empty as expected in certain situations)
|
43
75
|
@history = false
|
44
76
|
@is_parallel = false
|
45
77
|
@scxml_state = false
|
@@ -104,6 +136,11 @@ class StatemachineParser < Statemachine::StatemachineBuilder
|
|
104
136
|
end
|
105
137
|
when 'parallel'
|
106
138
|
@is_parallel = true
|
139
|
+
# If the parent superstate of the parallel state has substates, save them for later
|
140
|
+
if not @substate.empty?
|
141
|
+
@substate_aux = @substate
|
142
|
+
@substate = []
|
143
|
+
end
|
107
144
|
# If there is a state that encapsulates the parallel state, change it to a superstate
|
108
145
|
if not @state.empty? and @state.last.is_a? Statemachine::StateBuilder
|
109
146
|
state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
|
@@ -237,6 +274,8 @@ class StatemachineParser < Statemachine::StatemachineBuilder
|
|
237
274
|
when 'parallel'
|
238
275
|
@statemachine.add_state(@parallel.subject)
|
239
276
|
@is_parallel = false
|
277
|
+
@substate = @substate_aux
|
278
|
+
@substate_aux = []
|
240
279
|
when 'state'
|
241
280
|
if @state.last.is_a? Statemachine::SuperstateBuilder
|
242
281
|
s = statemachine.get_state(@state.last.subject.id)
|
data/spec/parser_spec.rb
CHANGED
@@ -644,7 +644,112 @@ EOS
|
|
644
644
|
@sm.disconnect
|
645
645
|
@log.should=="Goodbye cruel world!"
|
646
646
|
end
|
647
|
+
|
648
|
+
|
649
|
+
end
|
650
|
+
end
|
651
|
+
end
|
652
|
+
|
653
|
+
describe "with spontaneous transitions to parallel states" do
|
654
|
+
it "should enter using spontaneous transitions " do
|
655
|
+
|
656
|
+
class ActivationCallback
|
657
|
+
attr_reader :called
|
658
|
+
attr_reader :new_states
|
659
|
+
attr_reader :abstract_states
|
660
|
+
attr_reader :atomic_states
|
661
|
+
|
662
|
+
def initialize
|
663
|
+
@called = []
|
664
|
+
@new_states = []
|
665
|
+
@abstract_states = []
|
666
|
+
@atomic_states =[]
|
667
|
+
|
668
|
+
end
|
669
|
+
def activate(new_states,abstract_states, atomic_states)
|
670
|
+
@called << true
|
671
|
+
@new_states<< new_states
|
672
|
+
@abstract_states << abstract_states
|
673
|
+
@atomic_states << atomic_states
|
674
|
+
puts "activate #{@new_states.last} #{@abstract_states.last} #{@atomic_states.last}"
|
675
|
+
end
|
647
676
|
end
|
677
|
+
|
678
|
+
@callback = ActivationCallback.new
|
679
|
+
|
680
|
+
|
681
|
+
def isInstant?
|
682
|
+
true
|
683
|
+
end
|
684
|
+
|
685
|
+
def isContinuous?
|
686
|
+
true
|
687
|
+
end
|
688
|
+
|
689
|
+
def isOnChange?
|
690
|
+
false
|
691
|
+
end
|
692
|
+
|
693
|
+
def evaluate
|
694
|
+
true
|
695
|
+
end
|
696
|
+
parser = StatemachineParser.new(nil,nil)
|
697
|
+
|
698
|
+
scxml = <<EOS
|
699
|
+
<scxml initial="inactive" name="StateObservation" version="0.9" xmlns="http://www.w3.org/2005/07/scxml"><!-- node-size-and-position x=0.0 y=0.0 w=868.0 h=725.0 -->
|
700
|
+
<state id="inactive"><!-- node-size-and-position x=180.0 y=40.0 w=80.0 h=50.0 -->
|
701
|
+
<transition event="start" target="active"><!-- edge-path [active] x=170.0 y=120.0 pointx=0.0 pointy=-29.0 offsetx=-12.0 offsety=14.0 --></transition>
|
702
|
+
</state>
|
703
|
+
<state id="active" initial="init"><!-- node-size-and-position x=160.0 y=140.0 w=610.0 h=450.0 -->
|
704
|
+
<transition event="stop" target="inactive"></transition>
|
705
|
+
<state id="init"><!-- node-size-and-position x=20.0 y=30.0 w=60.0 h=40.0 -->
|
706
|
+
<transition cond="isInstant? or isContinuous?" target="instant_evaluation">
|
707
|
+
<script>evaluate</script>
|
708
|
+
</transition>
|
709
|
+
<transition cond="isOnChange?" target="subscribing"></transition>
|
710
|
+
</state>
|
711
|
+
<state id="instant_evaluation"><!-- node-size-and-position x=180.0 y=30.0 w=130.0 h=40.0 -->
|
712
|
+
<transition cond="(not @result.nil?) and @result.length>0" target="true">
|
713
|
+
<invoke src="@varmap.merge! @result" type="x-mint"></invoke>
|
714
|
+
</transition>
|
715
|
+
<transition cond="@result.nil?" target="false"></transition>
|
716
|
+
</state>
|
717
|
+
<parallel id="running"><!-- node-size-and-position x=40.0 y=130.0 w=480.0 h=300.0 -->
|
718
|
+
<state id="result" initial="false"><!-- node-size-and-position x=200.0 y=60.0 w=270.0 h=90.0 -->
|
719
|
+
<state id="true"><!-- node-size-and-position x=170.0 y=40.0 w=50.0 h=30.0 -->
|
720
|
+
<transition event="false" target="false"></transition>
|
721
|
+
</state>
|
722
|
+
<state id="false"><!-- node-size-and-position x=10.0 y=40.0 w=80.0 h=30.0 -->
|
723
|
+
<transition event="true" target="true"><!-- edge-path [true] x=130.0 y=40.0 pointx=0.0 pointy=14.0 offsetx=17.0 offsety=4.0 --></transition>
|
724
|
+
</state>
|
725
|
+
</state>
|
726
|
+
<state id="subscription" initial="check"><!-- node-size-and-position x=30.0 y=40.0 w=150.0 h=250.0 -->
|
727
|
+
<state id="subscribing"><!-- node-size-and-position x=40.0 y=110.0 w=80.0 h=40.0 -->
|
728
|
+
<onentry>@subscribed=true</onentry>
|
729
|
+
<transition event="subscribed" target="subscribed"></transition>
|
730
|
+
</state>
|
731
|
+
<state id="subscribed"><!-- node-size-and-position x=40.0 y=190.0 w=80.0 h=40.0 --></state>
|
732
|
+
<state id="check"><!-- node-size-and-position x=40.0 y=30.0 w=80.0 h=40.0 -->
|
733
|
+
<transition cond="isOnChange? or isContinuous?" target="subscribing"></transition>
|
734
|
+
</state>
|
735
|
+
</state>
|
736
|
+
</parallel>
|
737
|
+
</state>
|
738
|
+
</scxml>
|
739
|
+
EOS
|
740
|
+
|
741
|
+
@sm = parser.build_from_scxml_string scxml
|
742
|
+
@sm.reset
|
743
|
+
@sm.activation=@callback.method(:activate)
|
744
|
+
@sm.context = self
|
745
|
+
@sm.start
|
746
|
+
|
747
|
+
@callback.called.length.should == 4
|
748
|
+
|
749
|
+
@callback.new_states[0].should == [:active,:init]
|
750
|
+
@callback.new_states[1].should == [:instant_evaluation]
|
751
|
+
@callback.new_states[2].should == [:running, :result, :subscription, :false, :check]
|
752
|
+
@callback.new_states[3].should == [:subscribing]
|
648
753
|
end
|
649
754
|
end
|
650
755
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: MINT-scxml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-02-28 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: MINT-statemachine
|
16
|
-
requirement: &
|
16
|
+
requirement: &87413670 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,49 +21,25 @@ dependencies:
|
|
21
21
|
version: 1.3.0
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: rdoc
|
27
|
-
requirement: &73710560 !ruby/object:Gem::Requirement
|
28
|
-
none: false
|
29
|
-
requirements:
|
30
|
-
- - ~>
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '3.10'
|
33
|
-
type: :development
|
34
|
-
prerelease: false
|
35
|
-
version_requirements: *73710560
|
36
|
-
- !ruby/object:Gem::Dependency
|
37
|
-
name: newgem
|
38
|
-
requirement: &73710050 !ruby/object:Gem::Requirement
|
39
|
-
none: false
|
40
|
-
requirements:
|
41
|
-
- - ! '>='
|
42
|
-
- !ruby/object:Gem::Version
|
43
|
-
version: 1.5.3
|
44
|
-
type: :development
|
45
|
-
prerelease: false
|
46
|
-
version_requirements: *73710050
|
24
|
+
version_requirements: *87413670
|
47
25
|
- !ruby/object:Gem::Dependency
|
48
26
|
name: hoe
|
49
|
-
requirement: &
|
27
|
+
requirement: &87413430 !ruby/object:Gem::Requirement
|
50
28
|
none: false
|
51
29
|
requirements:
|
52
30
|
- - ~>
|
53
31
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
32
|
+
version: '2.9'
|
55
33
|
type: :development
|
56
34
|
prerelease: false
|
57
|
-
version_requirements: *
|
58
|
-
description:
|
59
|
-
ruby statemachine.
|
35
|
+
version_requirements: *87413430
|
36
|
+
description: ''
|
60
37
|
email: Sebastian@Feuerstack.org
|
61
38
|
executables: []
|
62
39
|
extensions: []
|
63
40
|
extra_rdoc_files:
|
64
41
|
- History.txt
|
65
42
|
- Manifest.txt
|
66
|
-
- README.rdoc
|
67
43
|
files:
|
68
44
|
- Gemfile
|
69
45
|
- Gemfile.lock
|
@@ -102,12 +78,12 @@ files:
|
|
102
78
|
- statemachines/specs/AISingleChoiceElement_spec.rb
|
103
79
|
- statemachines/specs/AISingleChoice_spec.rb
|
104
80
|
- .gemtest
|
105
|
-
homepage:
|
81
|
+
homepage:
|
106
82
|
licenses: []
|
107
83
|
post_install_message:
|
108
84
|
rdoc_options:
|
109
85
|
- --main
|
110
|
-
- README.
|
86
|
+
- README.txt
|
111
87
|
require_paths:
|
112
88
|
- lib
|
113
89
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -116,6 +92,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
116
92
|
- - ! '>='
|
117
93
|
- !ruby/object:Gem::Version
|
118
94
|
version: '0'
|
95
|
+
segments:
|
96
|
+
- 0
|
97
|
+
hash: -834397197
|
119
98
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
99
|
none: false
|
121
100
|
requirements:
|
@@ -127,6 +106,5 @@ rubyforge_project: MINT-scxml
|
|
127
106
|
rubygems_version: 1.8.15
|
128
107
|
signing_key:
|
129
108
|
specification_version: 3
|
130
|
-
summary:
|
131
|
-
statemachine.
|
109
|
+
summary: ''
|
132
110
|
test_files: []
|