MINT-statemachine 1.2.2 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
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