finite_machine 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -150,6 +150,21 @@ describe FiniteMachine, 'events' do
150
150
  expect { fsm.stop }.to raise_error(FiniteMachine::InvalidStateError, /state 'green'/)
151
151
  end
152
152
 
153
+ it "allows to transition to any state" do
154
+ fsm = FiniteMachine.define do
155
+ initial :green
156
+
157
+ events {
158
+ event :slow, from: :green, to: :yellow
159
+ event :stop, from: :yellow, to: :red
160
+ }
161
+ end
162
+ expect(fsm.current).to eql(:green)
163
+ expect(fsm.can?(:stop)).to be_false
164
+ fsm.stop!
165
+ expect(fsm.current).to eql(:red)
166
+ end
167
+
153
168
  context 'when multiple from states' do
154
169
  it "allows for array from key" do
155
170
  fsm = FiniteMachine.define do
@@ -5,6 +5,8 @@ require 'spec_helper'
5
5
  describe FiniteMachine, ':if, :unless' do
6
6
  before(:each) {
7
7
  Car = Class.new do
8
+ attr_accessor :engine_on
9
+
8
10
  def turn_engine_on
9
11
  @engine_on = true
10
12
  end
@@ -116,81 +118,109 @@ describe FiniteMachine, ':if, :unless' do
116
118
  ])
117
119
  end
118
120
 
119
- it "specifies :if and :unless with proc" do
120
- car = Car.new
121
+ context 'when proc' do
122
+ it "specifies :if and :unless" do
123
+ car = Car.new
121
124
 
122
- fsm = FiniteMachine.define do
123
- initial :neutral
125
+ fsm = FiniteMachine.define do
126
+ initial :neutral
124
127
 
125
- target car
128
+ target car
126
129
 
127
- events {
128
- event :start, :neutral => :one, if: proc {|_car| _car.engine_on? }
129
- event :shift, :one => :two
130
- }
130
+ events {
131
+ event :start, :neutral => :one, if: proc {|_car| _car.engine_on? }
132
+ event :shift, :one => :two
133
+ }
134
+ end
135
+ car.turn_engine_off
136
+ expect(car.engine_on?).to be_false
137
+ expect(fsm.current).to eql(:neutral)
138
+ fsm.start
139
+ expect(fsm.current).to eql(:neutral)
140
+
141
+ car.turn_engine_on
142
+ expect(car.engine_on?).to be_true
143
+ expect(fsm.current).to eql(:neutral)
144
+ fsm.start
145
+ expect(fsm.current).to eql(:one)
146
+ end
147
+
148
+ it "passes arguments to the scope" do
149
+ car = Car.new
150
+
151
+ fsm = FiniteMachine.define do
152
+ initial :neutral
153
+
154
+ target car
155
+
156
+ events {
157
+ event :start, :neutral => :one, if: proc { |_car, state|
158
+ _car.engine_on = state
159
+ _car.engine_on?
160
+ }
161
+ event :shift, :one => :two
162
+ }
163
+ end
164
+ fsm.start(false)
165
+ expect(fsm.current).to eql(:neutral)
166
+ fsm.start(true)
167
+ expect(fsm.current).to eql(:one)
131
168
  end
132
- car.turn_engine_off
133
- expect(car.engine_on?).to be_false
134
- expect(fsm.current).to eql(:neutral)
135
- fsm.start
136
- expect(fsm.current).to eql(:neutral)
137
-
138
- car.turn_engine_on
139
- expect(car.engine_on?).to be_true
140
- expect(fsm.current).to eql(:neutral)
141
- fsm.start
142
- expect(fsm.current).to eql(:one)
143
169
  end
144
170
 
145
- it "specifies :if and :unless with symbol" do
146
- car = Car.new
171
+ context 'when symbol' do
172
+ it "specifies :if and :unless" do
173
+ car = Car.new
147
174
 
148
- fsm = FiniteMachine.define do
149
- initial :neutral
175
+ fsm = FiniteMachine.define do
176
+ initial :neutral
150
177
 
151
- target car
178
+ target car
152
179
 
153
- events {
154
- event :start, :neutral => :one, if: :engine_on?
155
- event :shift, :one => :two
156
- }
180
+ events {
181
+ event :start, :neutral => :one, if: :engine_on?
182
+ event :shift, :one => :two
183
+ }
184
+ end
185
+ car.turn_engine_off
186
+ expect(car.engine_on?).to be_false
187
+ expect(fsm.current).to eql(:neutral)
188
+ fsm.start
189
+ expect(fsm.current).to eql(:neutral)
190
+
191
+ car.turn_engine_on
192
+ expect(car.engine_on?).to be_true
193
+ expect(fsm.current).to eql(:neutral)
194
+ fsm.start
195
+ expect(fsm.current).to eql(:one)
157
196
  end
158
- car.turn_engine_off
159
- expect(car.engine_on?).to be_false
160
- expect(fsm.current).to eql(:neutral)
161
- fsm.start
162
- expect(fsm.current).to eql(:neutral)
163
-
164
- car.turn_engine_on
165
- expect(car.engine_on?).to be_true
166
- expect(fsm.current).to eql(:neutral)
167
- fsm.start
168
- expect(fsm.current).to eql(:one)
169
197
  end
170
198
 
171
- it "specifies :if and :unless with string" do
172
- car = Car.new
199
+ context 'when string' do
200
+ it "specifies :if and :unless" do
201
+ car = Car.new
173
202
 
174
- fsm = FiniteMachine.define do
175
- initial :neutral
203
+ fsm = FiniteMachine.define do
204
+ initial :neutral
176
205
 
177
- target car
206
+ target car
178
207
 
179
- events {
180
- event :start, :neutral => :one, if: "engine_on?"
181
- event :shift, :one => :two
182
- }
208
+ events {
209
+ event :start, :neutral => :one, if: "engine_on?"
210
+ event :shift, :one => :two
211
+ }
212
+ end
213
+ car.turn_engine_off
214
+ expect(car.engine_on?).to be_false
215
+ expect(fsm.current).to eql(:neutral)
216
+ fsm.start
217
+ expect(fsm.current).to eql(:neutral)
218
+
219
+ car.turn_engine_on
220
+ expect(car.engine_on?).to be_true
221
+ expect(fsm.current).to eql(:neutral)
222
+ fsm.start
223
+ expect(fsm.current).to eql(:one)
183
224
  end
184
- car.turn_engine_off
185
- expect(car.engine_on?).to be_false
186
- expect(fsm.current).to eql(:neutral)
187
- fsm.start
188
- expect(fsm.current).to eql(:neutral)
189
-
190
- car.turn_engine_on
191
- expect(car.engine_on?).to be_true
192
- expect(fsm.current).to eql(:neutral)
193
- fsm.start
194
- expect(fsm.current).to eql(:one)
195
225
  end
196
226
  end
@@ -25,7 +25,22 @@ describe FiniteMachine, 'initialize' do
25
25
  expect(fsm.current).to eql(:none)
26
26
  end
27
27
 
28
+ it "requires initial state transition from :none" do
29
+ fsm = FiniteMachine.define do
30
+ events {
31
+ event :init, :none => :green
32
+ event :slow, :green => :yellow
33
+ event :stop, :yellow => :red
34
+ }
35
+ end
36
+
37
+ expect(fsm.current).to eql(:none)
38
+ fsm.init
39
+ expect(fsm.current).to eql(:green)
40
+ end
41
+
28
42
  it "allows to specify inital state" do
43
+ called = []
29
44
  fsm = FiniteMachine.define do
30
45
  initial :green
31
46
 
@@ -33,9 +48,12 @@ describe FiniteMachine, 'initialize' do
33
48
  event :slow, :green => :yellow
34
49
  event :stop, :yellow => :red
35
50
  }
51
+ callbacks {
52
+ on_enter :green do |event| called << 'on_enter_green' end
53
+ }
36
54
  end
37
-
38
55
  expect(fsm.current).to eql(:green)
56
+ expect(called).to be_empty
39
57
  end
40
58
 
41
59
  it "allows to specify deferred inital state" do
@@ -48,10 +66,24 @@ describe FiniteMachine, 'initialize' do
48
66
  }
49
67
  end
50
68
 
69
+ expect(fsm.current).to eql(:none)
51
70
  fsm.init
52
71
  expect(fsm.current).to eql(:green)
53
72
  end
54
73
 
74
+ it "raises error when specyfying initial without state name" do
75
+ expect {
76
+ FiniteMachine.define do
77
+ initial defer: true
78
+
79
+ events {
80
+ event :slow, :green => :yellow
81
+ event :stop, :yellow => :red
82
+ }
83
+ end
84
+ }.to raise_error(FiniteMachine::MissingInitialStateError)
85
+ end
86
+
55
87
  it "allows to specify inital start event" do
56
88
  fsm = FiniteMachine.define do
57
89
  initial state: :green, event: :start
@@ -96,4 +128,19 @@ describe FiniteMachine, 'initialize' do
96
128
  end
97
129
  expect(fsm.current).to eql(:pending)
98
130
  end
131
+
132
+ it "doesn't care about state type" do
133
+ fsm = FiniteMachine.define do
134
+ initial 1
135
+ events {
136
+ event :a, 1 => 2
137
+ event :b, 2 => 3
138
+ }
139
+ end
140
+ expect(fsm.current).to eql(1)
141
+ fsm.a
142
+ expect(fsm.current).to eql(2)
143
+ fsm.b
144
+ expect(fsm.current).to eql(3)
145
+ end
99
146
  end
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine::Transition, 'inspect' do
6
+ let(:machine) { double }
7
+
8
+ subject(:transition) { described_class.new(machine, attrs) }
9
+
10
+ context 'when inspecting' do
11
+ let(:attrs) { {name: :start, :foo => :bar } }
12
+
13
+ it "displays name and transitions" do
14
+ expect(transition.inspect).to eql("<FiniteMachine::Transition name: start, transitions: [:foo] => bar, when: []>")
15
+ end
16
+ end
17
+
18
+ context 'when converting to string' do
19
+ let(:attrs) { {name: :start, :foo => :bar } }
20
+
21
+ it "displays name and transitions" do
22
+ expect(transition.to_s).to eql("start")
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+ require 'logger'
5
+
6
+ describe FiniteMachine::Logger do
7
+ let(:message) { 'error' }
8
+ let(:log) { double }
9
+
10
+ subject(:logger) { described_class }
11
+
12
+ before { FiniteMachine.stub(:logger) { log } }
13
+
14
+ it "debugs message call" do
15
+ expect(log).to receive(:debug).with(message)
16
+ logger.debug(message)
17
+ end
18
+
19
+ it "informs message call" do
20
+ expect(log).to receive(:info).with(message)
21
+ logger.info(message)
22
+ end
23
+
24
+ it "warns message call" do
25
+ expect(log).to receive(:warn).with(message)
26
+ logger.warn(message)
27
+ end
28
+
29
+ it "errors message call" do
30
+ expect(log).to receive(:error).with(message)
31
+ logger.error(message)
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe FiniteMachine::Subscribers do
6
+ let(:machine) { double }
7
+ let(:event) { double }
8
+ let(:listener) { double }
9
+
10
+ subject(:subscribers) { described_class.new(machine) }
11
+
12
+ before { subscribers.subscribe(listener) }
13
+
14
+ it "checks if any subscribers exist" do
15
+ expect(subscribers.empty?).to be_false
16
+ end
17
+
18
+ it "returns index for the subscriber" do
19
+ expect(subscribers.index(listener)).to eql(0)
20
+ end
21
+
22
+ it "visits all subscribed listeners for the event" do
23
+ expect(event).to receive(:notify).with(listener)
24
+ subscribers.visit(event)
25
+ end
26
+
27
+ it "resets the subscribers" do
28
+ subscribers.reset
29
+ expect(subscribers.empty?).to be_true
30
+ end
31
+ 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.3.0
4
+ version: 0.4.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-03-30 00:00:00.000000000 Z
11
+ date: 2014-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -43,6 +43,8 @@ files:
43
43
  - LICENSE.txt
44
44
  - README.md
45
45
  - Rakefile
46
+ - examples/atm.rb
47
+ - examples/bug_system.rb
46
48
  - finite_machine.gemspec
47
49
  - lib/finite_machine.rb
48
50
  - lib/finite_machine/async_call.rb
@@ -53,6 +55,7 @@ files:
53
55
  - lib/finite_machine/event.rb
54
56
  - lib/finite_machine/event_queue.rb
55
57
  - lib/finite_machine/hooks.rb
58
+ - lib/finite_machine/logger.rb
56
59
  - lib/finite_machine/observer.rb
57
60
  - lib/finite_machine/state_machine.rb
58
61
  - lib/finite_machine/subscribers.rb
@@ -71,8 +74,11 @@ files:
71
74
  - spec/unit/handlers_spec.rb
72
75
  - spec/unit/if_unless_spec.rb
73
76
  - spec/unit/initialize_spec.rb
77
+ - spec/unit/inspect_spec.rb
74
78
  - spec/unit/is_spec.rb
79
+ - spec/unit/logger_spec.rb
75
80
  - spec/unit/states_spec.rb
81
+ - spec/unit/subscribers_spec.rb
76
82
  - spec/unit/target_spec.rb
77
83
  - spec/unit/transition/parse_states_spec.rb
78
84
  - tasks/console.rake
@@ -114,8 +120,11 @@ test_files:
114
120
  - spec/unit/handlers_spec.rb
115
121
  - spec/unit/if_unless_spec.rb
116
122
  - spec/unit/initialize_spec.rb
123
+ - spec/unit/inspect_spec.rb
117
124
  - spec/unit/is_spec.rb
125
+ - spec/unit/logger_spec.rb
118
126
  - spec/unit/states_spec.rb
127
+ - spec/unit/subscribers_spec.rb
119
128
  - spec/unit/target_spec.rb
120
129
  - spec/unit/transition/parse_states_spec.rb
121
130
  has_rdoc: