finite_machine 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,6 +3,13 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe FiniteMachine, 'can?' do
6
+ before(:each) {
7
+ Bug = Class.new do
8
+ def pending?
9
+ false
10
+ end
11
+ end
12
+ }
6
13
 
7
14
  it "allows to check if event can be fired" do
8
15
  fsm = FiniteMachine.define do
@@ -19,7 +26,7 @@ describe FiniteMachine, 'can?' do
19
26
  expect(fsm.current).to eql(:green)
20
27
 
21
28
  expect(fsm.can?(:slow)).to be_true
22
- expect(fsm.can?(:stop)).to be_false
29
+ expect(fsm.cannot?(:stop)).to be_true
23
30
  expect(fsm.can?(:ready)).to be_false
24
31
  expect(fsm.can?(:go)).to be_false
25
32
 
@@ -47,4 +54,45 @@ describe FiniteMachine, 'can?' do
47
54
  expect(fsm.can?(:ready)).to be_false
48
55
  expect(fsm.can?(:go)).to be_true
49
56
  end
57
+
58
+ context 'with conditionl transition' do
59
+ it "evalutes condition with parameters" do
60
+ fsm = FiniteMachine.define do
61
+ initial :green
62
+
63
+ events {
64
+ event :slow, :green => :yellow
65
+ event :stop, :yellow => :red, if: proc { |_, state| state }
66
+ }
67
+ end
68
+ expect(fsm.current).to eq(:green)
69
+ expect(fsm.can?(:slow)).to be_true
70
+ expect(fsm.can?(:stop)).to be_false
71
+
72
+ fsm.slow
73
+ expect(fsm.current).to eq(:yellow)
74
+ expect(fsm.can?(:stop, false)).to be_false
75
+ expect(fsm.can?(:stop, true)).to be_true
76
+ end
77
+
78
+ it "checks against target and grouped events" do
79
+ bug = Bug.new
80
+ fsm = FiniteMachine.define do
81
+ initial :initial
82
+
83
+ target bug
84
+
85
+ events {
86
+ event :bump, :initial => :low
87
+ event :bump, :low => :medium, if: :pending?
88
+ event :bump, :medium => :high
89
+ }
90
+ end
91
+ expect(fsm.current).to eq(:initial)
92
+
93
+ expect(fsm.can?(:bump)).to be_true
94
+ fsm.bump
95
+ expect(fsm.can?(:bump)).to be_false
96
+ end
97
+ end
50
98
  end
@@ -0,0 +1,137 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine, '#choice' do
6
+ before(:each) {
7
+ User = Class.new do
8
+ def promo?(token = false)
9
+ token == :yes
10
+ end
11
+ end
12
+ }
13
+
14
+ it "allows for static choice based on conditional branching" do
15
+ called = []
16
+ fsm = FiniteMachine.define do
17
+ initial :company_form
18
+
19
+ events {
20
+ event :next, from: :company_form do
21
+ choice :agreement_form, if: -> { false }
22
+ choice :promo_form, if: -> { false }
23
+ choice :official_form, if: -> { true }
24
+ end
25
+ }
26
+
27
+ callbacks {
28
+ on_exit do |event| called << "on_exit_#{event.from}" end
29
+ on_enter do |event| called << "on_enter_#{event.to}" end
30
+ }
31
+ end
32
+ expect(fsm.current).to eq(:company_form)
33
+ fsm.next
34
+ expect(fsm.current).to eq(:official_form)
35
+ expect(called).to eq([
36
+ 'on_exit_company_form',
37
+ 'on_enter_official_form'
38
+ ])
39
+ end
40
+
41
+ it "allows for dynamic choice based on conditional branching" do
42
+ fsm = FiniteMachine.define do
43
+ initial :company_form
44
+
45
+ events {
46
+ event :next, from: :company_form do
47
+ choice :agreement_form, if: proc { |_, a| a < 1 }
48
+ choice :promo_form, if: proc { |_, a| a == 1 }
49
+ choice :official_form, if: proc { |_, a| a > 1 }
50
+ end
51
+ }
52
+ end
53
+ expect(fsm.current).to eq(:company_form)
54
+ fsm.next(0)
55
+ expect(fsm.current).to eq(:agreement_form)
56
+
57
+ fsm.restore!(:company_form)
58
+ fsm.next(1)
59
+ expect(fsm.current).to eq(:promo_form)
60
+
61
+ fsm.restore!(:company_form)
62
+ fsm.next(2)
63
+ expect(fsm.current).to eq(:official_form)
64
+ end
65
+
66
+ it "allows for dynamic choice based on conditional branching and target" do
67
+ user = User.new
68
+ fsm = FiniteMachine.define do
69
+ initial :company_form
70
+
71
+ target user
72
+
73
+ events {
74
+ event :next, from: :company_form do
75
+ choice :agreement_form, if: proc { |_user, token| _user.promo?(token) }
76
+ choice :promo_form, unless: proc { |_user, token| _user.promo?(token) }
77
+ end
78
+ }
79
+ end
80
+ expect(fsm.current).to eq(:company_form)
81
+ fsm.next(:no)
82
+ expect(fsm.current).to eq(:promo_form)
83
+ fsm.restore!(:company_form)
84
+ fsm.next(:yes)
85
+ expect(fsm.current).to eq(:agreement_form)
86
+ end
87
+
88
+ it "choses state when skipped if/unless" do
89
+ fsm = FiniteMachine.define do
90
+ initial :company_form
91
+
92
+ events {
93
+ event :next, from: :company_form do
94
+ choice :agreement_form, if: -> { false }
95
+ choice :promo_form
96
+ choice :official_form, if: -> { true }
97
+ end
98
+ }
99
+ end
100
+ expect(fsm.current).to eq(:company_form)
101
+ fsm.next
102
+ expect(fsm.current).to eq(:promo_form)
103
+ end
104
+
105
+ it "choice default state when branching conditions don't match" do
106
+ fsm = FiniteMachine.define do
107
+ initial :company_form
108
+
109
+ events {
110
+ event :next, from: :company_form do
111
+ choice :agreement_form, if: -> { false }
112
+ choice :promo_form, if: -> { false }
113
+ default :official_form
114
+ end
115
+ }
116
+ end
117
+ expect(fsm.current).to eq(:company_form)
118
+ fsm.next
119
+ expect(fsm.current).to eq(:official_form)
120
+ end
121
+
122
+ it "fails to transition when no condition matches without default state" do
123
+ fsm = FiniteMachine.define do
124
+ initial :company_form
125
+
126
+ events {
127
+ event :next, from: :company_form do
128
+ choice :agreement_form, if: -> { false }
129
+ choice :promo_form, if: -> { false }
130
+ end
131
+ }
132
+ end
133
+ expect(fsm.current).to eq(:company_form)
134
+ fsm.next
135
+ expect(fsm.current).to eq(:company_form)
136
+ end
137
+ end
@@ -19,6 +19,12 @@ describe FiniteMachine, ':if, :unless' do
19
19
  !!@engine_on
20
20
  end
21
21
  end
22
+
23
+ class Bug
24
+ def pending?
25
+ false
26
+ end
27
+ end
22
28
  }
23
29
 
24
30
  it "allows to cancel event with :if option" do
@@ -225,12 +231,6 @@ describe FiniteMachine, ':if, :unless' do
225
231
  end
226
232
 
227
233
  context 'when same event name' do
228
- class Bug
229
- def pending?
230
- false
231
- end
232
- end
233
-
234
234
  it "preservers conditions for the same named event" do
235
235
  bug = Bug.new
236
236
  fsm = FiniteMachine.define do
@@ -250,5 +250,46 @@ describe FiniteMachine, ':if, :unless' do
250
250
  fsm.bump
251
251
  expect(fsm.current).to eq(:low)
252
252
  end
253
+
254
+ it "allows for static choice based on branching condition" do
255
+ fsm = FiniteMachine.define do
256
+ initial :company_form
257
+
258
+ events {
259
+ event :next, :company_form => :agreement_form, if: -> { false }
260
+ event :next, :company_form => :promo_form, if: -> { false }
261
+ event :next, :company_form => :official_form, if: -> { true }
262
+ }
263
+ end
264
+ expect(fsm.current).to eq(:company_form)
265
+ fsm.next
266
+ expect(fsm.current).to eq(:official_form)
267
+ end
268
+
269
+ it "allows for dynamic choice based on branching condition" do
270
+ fsm = FiniteMachine.define do
271
+ initial :company_form
272
+
273
+ events {
274
+ event :next, :company_form => :agreement_form, if: proc { |_, a| a < 1 }
275
+ event :next, :company_form => :promo_form, if: proc { |_, a| a == 1 }
276
+ event :next, :company_form => :official_form, if: proc { |_, a| a > 1 }
277
+ }
278
+ end
279
+ expect(fsm.current).to eq(:company_form)
280
+
281
+ fsm.next(0)
282
+ expect(fsm.current).to eq(:agreement_form)
283
+ fsm.restore!(:company_form)
284
+ expect(fsm.current).to eq(:company_form)
285
+
286
+ fsm.next(1)
287
+ expect(fsm.current).to eq(:promo_form)
288
+ fsm.restore!(:company_form)
289
+ expect(fsm.current).to eq(:company_form)
290
+
291
+ fsm.next(2)
292
+ expect(fsm.current).to eq(:official_form)
293
+ end
253
294
  end
254
295
  end
@@ -54,10 +54,7 @@ describe FiniteMachine, 'initialize' do
54
54
  }
55
55
  end
56
56
  expect(fsm.current).to eql(:green)
57
- expect(called).to eq([
58
- 'on_exit_none',
59
- 'on_enter_green'
60
- ])
57
+ expect(called).to be_empty
61
58
  end
62
59
 
63
60
  it "allows to specify initial state through parameter" do
@@ -189,4 +186,37 @@ describe FiniteMachine, 'initialize' do
189
186
  expect(fsm.current).to eq(:green)
190
187
  expect(fsm.initial_state).to eq(:green)
191
188
  end
189
+
190
+ it "allows to trigger callbacks on initial with :silent option" do
191
+ called = []
192
+ fsm = FiniteMachine.define do
193
+ initial state: :green, silent: false
194
+
195
+ events {
196
+ event :slow, :green => :yellow
197
+ }
198
+ callbacks {
199
+ on_enter :green do |event| called << 'on_enter_green' end
200
+ }
201
+ end
202
+ expect(fsm.current).to eq(:green)
203
+ expect(called).to eq(['on_enter_green'])
204
+ end
205
+
206
+ it "allows to trigger callbacks on deferred initial state" do
207
+ called = []
208
+ fsm = FiniteMachine.define do
209
+ initial state: :green, silent: false, defer: true
210
+
211
+ events {
212
+ event :slow, :green => :yellow
213
+ }
214
+ callbacks {
215
+ on_enter :green do |event| called << 'on_enter_green' end
216
+ }
217
+ end
218
+ expect(fsm.current).to eq(:none)
219
+ fsm.init
220
+ expect(called).to eq(['on_enter_green'])
221
+ end
192
222
  end
@@ -16,6 +16,20 @@ describe FiniteMachine, 'states' do
16
16
  }
17
17
  end
18
18
 
19
- expect(fsm.states).to eql([:none, :green, :yellow, :red])
19
+ expect(fsm.states).to match_array([:none, :green, :yellow, :red])
20
+ end
21
+
22
+ it "retrieves all unique states for choice transition" do
23
+ fsm = FiniteMachine.define do
24
+ initial :green
25
+
26
+ events {
27
+ event :next, from: :green do
28
+ choice :yellow, if: -> { false }
29
+ choice :red, if: -> { true }
30
+ end
31
+ }
32
+ end
33
+ expect(fsm.states).to match_array([:none, :green, :yellow, :red])
20
34
  end
21
35
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: finite_machine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-06-08 00:00:00.000000000 Z
11
+ date: 2014-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -51,6 +51,7 @@ files:
51
51
  - lib/finite_machine/async_proxy.rb
52
52
  - lib/finite_machine/callable.rb
53
53
  - lib/finite_machine/catchable.rb
54
+ - lib/finite_machine/choice_merger.rb
54
55
  - lib/finite_machine/dsl.rb
55
56
  - lib/finite_machine/event.rb
56
57
  - lib/finite_machine/event_queue.rb
@@ -73,6 +74,7 @@ files:
73
74
  - spec/unit/callable/call_spec.rb
74
75
  - spec/unit/callbacks_spec.rb
75
76
  - spec/unit/can_spec.rb
77
+ - spec/unit/choice_spec.rb
76
78
  - spec/unit/define_spec.rb
77
79
  - spec/unit/event/add_spec.rb
78
80
  - spec/unit/event/inspect_spec.rb
@@ -130,6 +132,7 @@ test_files:
130
132
  - spec/unit/callable/call_spec.rb
131
133
  - spec/unit/callbacks_spec.rb
132
134
  - spec/unit/can_spec.rb
135
+ - spec/unit/choice_spec.rb
133
136
  - spec/unit/define_spec.rb
134
137
  - spec/unit/event/add_spec.rb
135
138
  - spec/unit/event/inspect_spec.rb