MINT-statemachine 1.2.2 → 1.2.3

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 CHANGED
@@ -1,5 +1,9 @@
1
1
  = Statemachine Changelog
2
2
 
3
+ == Version 1.2.3
4
+
5
+ * Added Gemfile for bundler
6
+
3
7
  == Version 1.2.2
4
8
 
5
9
  * Transitions can fail
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source :rubygems
2
+
3
+ gem "rspec", "1.3.1"
4
+ gem "rake","0.9.2"
data/Gemfile.lock ADDED
@@ -0,0 +1,12 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ rake (0.9.2)
5
+ rspec (1.3.1)
6
+
7
+ PLATFORMS
8
+ ruby
9
+
10
+ DEPENDENCIES
11
+ rake (= 0.9.2)
12
+ rspec (= 1.3.1)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{MINT-statemachine}
5
- s.version = "1.2.2"
5
+ s.version = "1.2.3"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = [%q{Sebastian Feuerstack}]
@@ -13,7 +13,7 @@ Gem::Specification.new do |s|
13
13
  s.homepage = %q{http://www.multi-access.de}
14
14
  s.require_paths = [%q{lib}]
15
15
  s.rubygems_version = %q{1.8.5}
16
- s.summary = %q{MINT-Statemachine-1.2.2 - Statemachine Library for Ruby based on statemachine from http://slagyr.github.com/statemachine http://www.multi-access.de/open-source-software/third-party-software-extensions/}
16
+ s.summary = %q{MINT-Statemachine-1.2.3 - Statemachine Library for Ruby based on statemachine from http://slagyr.github.com/statemachine http://www.multi-access.de/open-source-software/third-party-software-extensions/}
17
17
  s.test_files = [%q{spec/sm_turnstile_spec.rb}, %q{spec/sm_odds_n_ends_spec.rb}, %q{spec/sm_entry_exit_actions_spec.rb}, %q{spec/default_transition_spec.rb}, %q{spec/action_invokation_spec.rb}, %q{spec/sm_parallel_state_spec.rb}, %q{spec/builder_spec.rb}, %q{spec/sm_activation_spec.rb}, %q{spec/sm_super_state_spec.rb}, %q{spec/transition_spec.rb}, %q{spec/sm_simple_spec.rb}, %q{spec/sm_action_parameterization_spec.rb}, %q{spec/history_spec.rb}]
18
18
 
19
19
  if s.respond_to? :specification_version then
@@ -13,12 +13,19 @@ module Statemachine
13
13
  elsif a.is_a? Proc
14
14
  result = invoke_proc(a, args, message)
15
15
  elsif a.is_a? Array
16
- result = send(a[0],a[1])
16
+ if a[0] == "log"
17
+ log("#{a[1]}")
18
+ result = invoke_string(a[1]) if not messenger
19
+ elsif a[0] == "send"
20
+ result = send(a[1],a[2])
21
+ elsif a[0] == 'invoke'
22
+ result = invoke_method(a[1],args, message)
23
+ end
17
24
  else
18
25
  log("#{a}")
19
- result =invoke_string(a) if not messenger
26
+ result = invoke_string(a) if not messenger
20
27
  end
21
- return false if result ==false
28
+ return false if result == false
22
29
  }
23
30
  result
24
31
  end
@@ -26,7 +33,11 @@ module Statemachine
26
33
  private
27
34
 
28
35
  def send(target,event)
29
- @message_queue.send(target, event) if @message_queue
36
+ if @message_queue
37
+ @message_queue.send(target, event)
38
+ return true
39
+ end
40
+ false
30
41
  end
31
42
 
32
43
  def log(message)
@@ -39,6 +50,7 @@ module Statemachine
39
50
 
40
51
  parameters = params_for_block(method, args, message)
41
52
  method.call(*parameters)
53
+ return true
42
54
  end
43
55
 
44
56
  def invoke_proc(proc, args, message)
@@ -47,7 +59,11 @@ module Statemachine
47
59
  end
48
60
 
49
61
  def invoke_string(expression)
50
- @context.instance_eval(expression)
62
+ if @context==nil
63
+ instance_eval(expression)
64
+ else
65
+ @context.instance_eval(expression)
66
+ end
51
67
  end
52
68
 
53
69
  def params_for_block(block, args, message)
@@ -56,7 +72,7 @@ module Statemachine
56
72
 
57
73
  raise StatemachineException.new("Insufficient parameters. (#{message})") if required_params > args.length
58
74
 
59
- return arity < 0 ? args : args[0...arity]
75
+ arity < 0 ? args : args[0...arity]
60
76
  end
61
77
 
62
78
  end
@@ -256,13 +256,15 @@ module Statemachine
256
256
  super statemachine
257
257
  @subject = Superstate.new(id, superstate, statemachine)
258
258
  superstate.startstate_id = id if superstate.startstate_id == nil
259
-
260
259
  # small patch to support redefinition of already existing states without
261
260
  # loosing the already existing transformations. Used to overwrite states
262
261
  # with superstates.
263
-
262
+ if not statemachine.has_state(id)
263
+ statemachine.add_state(@subject)
264
+ end
264
265
  s = statemachine.get_state(id)
265
266
  if (s)
267
+ statemachine.remove_state(@subject)
266
268
  s.transitions.each {|k,v|
267
269
  @subject.add(v)
268
270
  }
@@ -320,6 +322,7 @@ module Statemachine
320
322
  def statemachine (id, &block)
321
323
  builder = StatemachineBuilder.new(Statemachine.new(@subject))
322
324
  #builder = StatemachineBuilder.new
325
+ builder.statemachine.is_parallel = @subject if @subject.is_a? Parallelstate
323
326
  builder.instance_eval(&block) if block
324
327
  if not @subject.is_a? Parallelstate
325
328
  # Only reset statemachine if it's the root one. Otherwise
@@ -31,14 +31,8 @@ module Statemachine
31
31
  end
32
32
 
33
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
34
  @parallel_statemachines.each do |s|
41
- next if terminal_state and s.has_state(terminal_state)
35
+ # next if terminal_state and s.has_state(terminal_state)
42
36
  @statemachine.activation.call(s.state,self.abstract_states,self.states) if @statemachine.activation
43
37
  end
44
38
 
@@ -58,14 +52,13 @@ module Statemachine
58
52
  end
59
53
  end
60
54
 
61
- def non_default_transition_for(event)
62
- p "check parallel for #{event}"
55
+ def non_default_transition_for(event,check_superstates=true)
63
56
  transition = @transitions[event]
64
57
  return transition if transition
65
58
 
66
- transition = transition_for(event)
59
+ transition = transition_for(event,check_superstates)
67
60
 
68
- transition = @superstate.non_default_transition_for(event) if @superstate and not transition
61
+ transition = @superstate.non_default_transition_for(event) if check_superstates and @superstate and not transition
69
62
  return transition
70
63
  end
71
64
 
@@ -154,25 +147,42 @@ module Statemachine
154
147
  end
155
148
 
156
149
  def states
157
- return @parallel_statemachines.map &:state
150
+ result =[]
151
+ @parallel_statemachines.each do |s|
152
+ state = s.state
153
+ r,p = s.belongs_to_parallel(state)
154
+ if r
155
+ result += p.states
156
+ else
157
+ result << state
158
+ end
159
+ end
160
+ result
158
161
  end
159
162
 
160
- def transition_for(event)
163
+ def transition_for(event,check_superstates=true)
161
164
  @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)
165
+ transition = s.get_state(s.state).non_default_transition_for(event,false)
164
166
  transition = s.get_state(s.state).default_transition if not transition
165
167
  return transition if transition
166
168
  end
167
- return @superstate.default_transition if @superstate
169
+ return @superstate.transition_for(event,check_superstates) if (@superstate and check_superstates and @superstate!=self)
168
170
 
169
- # super.transition_for(event)
171
+ #super.transition_for(event)
170
172
  end
171
173
 
172
174
  def enter(args=[])
173
175
  # reset
174
- super(args)
176
+ #super(args)
177
+ @statemachine.state = self
178
+
179
+ @parallel_statemachines.each_with_index do |s,i|
180
+ s.activation = @statemachine.activation
181
+ s.reset(@startstate_ids[i]) if not s.state
182
+ s.get_state(@startstate_ids[i]).enter(args)
183
+ end
175
184
  end
185
+
176
186
  def to_s
177
187
  return "'#{id}' parallel"
178
188
  end
@@ -2,8 +2,8 @@ module Statemachine
2
2
 
3
3
  class State #:nodoc:
4
4
 
5
- attr_reader :id, :statemachine
6
- attr_accessor :entry_action, :exit_action, :superstate
5
+ attr_reader :statemachine
6
+ attr_accessor :id, :entry_action, :exit_action, :superstate
7
7
  attr_writer :default_transition
8
8
 
9
9
  def initialize(id, superstate, state_machine)
@@ -21,9 +21,9 @@ module Statemachine
21
21
  return @superstate ? @transitions.merge(@superstate.transitions) : @transitions
22
22
  end
23
23
 
24
- def non_default_transition_for(event)
24
+ def non_default_transition_for(event,check_superstates = true)
25
25
  transition = @transitions[event]
26
- if @superstate
26
+ if check_superstates and @superstate
27
27
  transition = @superstate.non_default_transition_for(event) if @superstate and @superstate.is_parallel == false and not transition
28
28
  end
29
29
  return transition
@@ -35,8 +35,8 @@ module Statemachine
35
35
  return nil
36
36
  end
37
37
 
38
- def transition_for(event)
39
- transition = non_default_transition_for(event)
38
+ def transition_for(event,check_superstate=true)
39
+ transition = non_default_transition_for(event,check_superstate)
40
40
  transition = default_transition if not transition
41
41
  return transition
42
42
  end
@@ -58,12 +58,11 @@ module Statemachine
58
58
 
59
59
  def activate
60
60
  @statemachine.state = self
61
- if (@statemachine.is_parallel)
62
- @statemachine.activation.call(self.id,@statemachine.is_parallel.abstract_states,@statemachine.is_parallel.statemachine.states_id) if @statemachine.activation
63
- else
64
-
65
- @statemachine.activation.call(self.id,@statemachine.abstract_states,@statemachine.states_id) if @statemachine.activation
66
- end
61
+ # if (@statemachine.is_parallel)
62
+ # @statemachine.activation.call(self.id,@statemachine.is_parallel.abstract_states,@statemachine.is_parallel.statemachine.states_id) if @statemachine.activation
63
+ #else
64
+ @statemachine.activation.call(self.id,@statemachine.abstract_states,@statemachine.states_id) if @statemachine.activation
65
+ # end
67
66
  end
68
67
 
69
68
  def concrete?
@@ -78,7 +78,8 @@ module Statemachine
78
78
 
79
79
  #Return the id of the current state of the statemachine.
80
80
  def state
81
- return @state.id
81
+ return @state.id if @state
82
+ nil
82
83
  end
83
84
 
84
85
  # returns an array with the ids of the current active states of the machine.
@@ -143,10 +144,8 @@ module Statemachine
143
144
  transition = @state.transition_for(event)
144
145
  if transition
145
146
  cond = true
146
- if transition.cond!=true and transition.cond.is_a? Proc
147
- cond = @state.statemachine.invoke_action(transition.cond, [], "condition from #{@state} invoked by '#{event}' event", nil, nil)
148
- else
149
- cond = instance_eval(transition.cond) if transition.cond != true and @is_parallel == nil
147
+ if transition.cond!=true
148
+ cond = @state.statemachine.invoke_action(transition.cond, [], "condition from #{@state} invoked by '#{event}' event", nil, nil)
150
149
  end
151
150
  if cond
152
151
  transition.invoke(@state, self, args)
@@ -183,17 +182,28 @@ module Statemachine
183
182
  def get_state(id) #:nodoc:
184
183
  if @states.has_key? id
185
184
  return @states[id]
186
- elsif @is_parallel and @is_parallel.statemachine.get_state(id)
187
- return @is_parallel.statemachine.states[id]
188
- elsif p = get_parallel and s = p.get_state(id)
189
- return s
190
185
  elsif(is_history_state_id?(id))
191
186
  superstate_id = base_id(id)
192
- superstate = @states[superstate_id]
187
+ if @is_parallel
188
+ superstate = @is_parallel.get_state(superstate_id)
189
+ else
190
+ superstate = @states[superstate_id]
191
+ end
193
192
  raise StatemachineException.new("No history exists for #{superstate} since it is not a super state.") if superstate.concrete?
194
193
  return load_history(superstate)
195
- elsif @is_parallel and @is_parallel.has_state(id)
196
- @is_parallel.get_state(id)
194
+ elsif @is_parallel
195
+ isp = @is_parallel
196
+ @is_parallel = nil
197
+ if isp.has_state(id)
198
+ state = isp.get_state(id)
199
+ elsif state = isp.statemachine.get_state(id)
200
+ @is_parallel = isp
201
+ return @is_parallel.statemachine.states[id] if @is_parallel.statemachine.states[id]
202
+ end
203
+ @is_parallel = isp
204
+ return state
205
+ elsif p = get_parallel and s = p.get_state(id)
206
+ return s
197
207
  else
198
208
  state = State.new(id, @root, self)
199
209
  @states[id] = state
@@ -264,7 +274,7 @@ module Statemachine
264
274
 
265
275
  def load_history(superstate)
266
276
  100.times do
267
- history = superstate.history_id ? get_state(superstate.history_id) : nil
277
+ history = superstate.history_id ? get_state(superstate.history_id) : get_state(superstate.startstate_id) #nil
268
278
  raise StatemachineException.new("#{superstate} doesn't have any history yet.") if not history
269
279
  if history.concrete?
270
280
  return history
@@ -23,18 +23,19 @@ module Statemachine
23
23
  if @action # changed this if statement to return if action fails
24
24
  if not origin.statemachine.invoke_action(@action, args, "transition action from #{origin} invoked by '#{@event}' event", messenger, message_queue)
25
25
  raise StatemachineException.new("Transition to state #{destination.id} failed because action for event #{@event} return false.")
26
- return
27
26
  end
28
27
  end
29
28
 
30
29
  # origin.statemachine.invoke_action(@action, args, "transition action from #{origin} invoked by '#{@event}' event", messenger, message_queue) if @action
31
30
 
32
31
  terminal_state = entries.last
33
- entries.each { |entered_state| entered_state.activate(terminal_state.id) if entered_state.is_parallel }
34
32
 
35
33
  terminal_state.activate if terminal_state and not terminal_state.is_parallel
36
34
 
37
35
  entries.each { |entered_state| entered_state.enter(args) }
36
+ entries.each { |entered_state| entered_state.activate(terminal_state.id) if entered_state.is_parallel }
37
+ statemachine.state = terminal_state if statemachine.has_state(terminal_state.id) and statemachine.is_parallel
38
+
38
39
  end
39
40
 
40
41
  def exits_and_entries(origin, destination)
@@ -3,7 +3,7 @@ module Statemachine
3
3
  unless defined? MAJOR
4
4
  MAJOR = 1
5
5
  MINOR = 2
6
- TINY = 2
6
+ TINY = 3
7
7
 
8
8
  STRING = [MAJOR, MINOR, TINY].join('.')
9
9
  TAG = "REL_" + [MAJOR, MINOR, TINY].join('_')
@@ -14,4 +14,4 @@ module Statemachine
14
14
  DESCRIPTION = "#{NAME}-#{STRING} - Statemachine Library for Ruby based on statemachine from http://slagyr.github.com/statemachine\n#{URL}"
15
15
  end
16
16
  end
17
- end
17
+ end
data/spec/history_spec.rb CHANGED
@@ -22,11 +22,14 @@ describe "History States" do
22
22
  }.should raise_error(Statemachine::StatemachineException, "No history exists for 'on' state since it is not a super state.")
23
23
  end
24
24
 
25
+ # This behaviour was changed
26
+ =begin
25
27
  it "error when trying to use history that doesn't exist yet" do
26
28
  lambda {
27
29
  @sm.fiddle
28
30
  }.should raise_error(Statemachine::StatemachineException, "'operate' superstate doesn't have any history yet.")
29
31
  end
32
+ =end
30
33
 
31
34
  it "reseting the statemachine resets history" do
32
35
  @sm.faddle
@@ -87,7 +87,7 @@ describe "State Activation Callback" do
87
87
  @callback.abstract_states.last.should == [:root]
88
88
  end
89
89
 
90
- it "should activate corretly on direct entry to parallel state" do
90
+ it "should activate correctly on direct entry to parallel state" do
91
91
  @sm = Statemachine.build do
92
92
  trans :start,:go, :unlocked
93
93
  parallel :p do
@@ -112,7 +112,7 @@ describe "Nested parallel" do
112
112
  parallel :p do
113
113
  statemachine :s1 do
114
114
  superstate :operative do
115
- trans :locked, :coin, :unlocked, Proc.new { @cooked = true }
115
+ trans :locked, :coin, :unlocked, Proc.new { @cooked = true }, "In(:on)"
116
116
  trans :unlocked, :coin, :locked
117
117
  event :maintain, :maintenance, Proc.new { @out_of_order = true }
118
118
  end
@@ -128,8 +128,10 @@ describe "Nested parallel" do
128
128
  end
129
129
 
130
130
  @sm.go
131
- @sm.states.should.eql? [:locked,:off]
132
-
131
+ @sm.states_id.should == [:locked,:on]
132
+ @sm.toggle
133
+ @sm.states_id.should == [:locked,:off]
134
+ @sm.coin
133
135
  end
134
136
 
135
137
  it "should support direct transitions into an atomic state of a parallel state set" do
@@ -156,15 +158,14 @@ describe "Nested parallel" do
156
158
  end
157
159
 
158
160
  @sm.go
159
- @sm.state.should eql :p
161
+ @sm.state.should == :p
160
162
  @sm.states_id.should == [:unlocked,:on]
161
163
  @sm.maintain
162
- @sm.state.should eql :maintenance
164
+ @sm.state.should == :maintenance
163
165
  @sm.states_id.should == [:maintenance]
164
166
  end
165
167
 
166
168
  it "should support leaving a parallel state by an event from a super state of the parallel state" do
167
- pending ("superstates have problems with late defined events ")
168
169
  @sm = Statemachine.build do
169
170
  trans :start,:go, :unlocked
170
171
  state :maintenance
@@ -184,7 +185,7 @@ describe "Nested parallel" do
184
185
  end
185
186
  end
186
187
  end
187
- event :repair, :maintenance # this one does not work, event has to be defined directly after superstate definition!
188
+ event :repair, :maintenance
188
189
  end
189
190
  end
190
191
 
@@ -203,5 +204,51 @@ describe "Nested parallel" do
203
204
  end
204
205
 
205
206
 
207
+ it "should support entering a nested parallel states" do
208
+ @sm = Statemachine.build do
209
+ trans :start,:go, :unlocked
210
+ state :maintenance
211
+ superstate :test do
212
+ superstate :s do
213
+ event :m, :maintenance
214
+ parallel :p do
215
+ statemachine :s1 do
216
+ trans :locked, :coin, :unlocked, Proc.new { @cooked = true }
217
+ trans :unlocked, :coin, :locked
218
+ end
219
+ statemachine :s2 do
220
+ #superstate :r2 do
221
+ parallel :p2 do
222
+ statemachine :s21 do
223
+ superstate :onoff do
224
+ trans :on, :toggle, :off
225
+ trans :off, :toggle, :on
226
+ end
227
+ end
228
+ statemachine :s22 do
229
+ superstate :onoff2 do
230
+ trans :on2, :toggle2, :off2
231
+ trans :off2, :toggle2, :on2
232
+ end
233
+ end
234
+ end
235
+ #end
236
+ end
237
+ end
238
+ end
239
+ event :repair, :maintenance
240
+ end
241
+ end
242
+
243
+ @sm.go
244
+ @sm.state.should eql :p
245
+ @sm.states_id.should == [:unlocked,:on,:on2]
246
+ @sm.toggle2
247
+ @sm.states_id.should == [:unlocked,:on,:off2]
248
+ @sm.repair
249
+ @sm.state.should eql :maintenance
250
+ @sm.states_id.should == [:maintenance]
251
+ end
252
+
206
253
 
207
254
  end
data/spec/spec_helper.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  $:.unshift(File.dirname(__FILE__) + '/../lib')
2
2
  require 'rubygems'
3
+ require "bundler/setup"
3
4
  require 'spec'
4
5
  require 'statemachine'
5
6
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: MINT-statemachine
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 2
9
- - 2
10
- version: 1.2.2
9
+ - 3
10
+ version: 1.2.3
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sebastian Feuerstack
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-06-30 00:00:00 Z
18
+ date: 2011-11-01 00:00:00 Z
19
19
  dependencies: []
20
20
 
21
21
  description: The MINT Statemachine is a ruby library for building Finite State Machines, based on the Statemachine gem by Micah Martin.
@@ -27,9 +27,11 @@ extensions: []
27
27
  extra_rdoc_files: []
28
28
 
29
29
  files:
30
+ - Gemfile
30
31
  - Rakefile
31
32
  - README.rdoc
32
33
  - MINT-statemachine.gemspec
34
+ - Gemfile.lock
33
35
  - CHANGES
34
36
  - TODO
35
37
  - LICENSE
@@ -98,7 +100,7 @@ rubyforge_project:
98
100
  rubygems_version: 1.8.5
99
101
  signing_key:
100
102
  specification_version: 3
101
- summary: MINT-Statemachine-1.2.2 - Statemachine Library for Ruby based on statemachine from http://slagyr.github.com/statemachine http://www.multi-access.de/open-source-software/third-party-software-extensions/
103
+ summary: MINT-Statemachine-1.2.3 - Statemachine Library for Ruby based on statemachine from http://slagyr.github.com/statemachine http://www.multi-access.de/open-source-software/third-party-software-extensions/
102
104
  test_files:
103
105
  - spec/sm_turnstile_spec.rb
104
106
  - spec/sm_odds_n_ends_spec.rb