finite_machine 0.7.1 → 0.8.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.
@@ -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