finite_machine 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile +12 -1
- data/README.md +130 -73
- data/Rakefile +3 -36
- data/finite_machine.gemspec +1 -3
- data/lib/finite_machine.rb +4 -1
- data/lib/finite_machine/async_call.rb +47 -0
- data/lib/finite_machine/async_proxy.rb +28 -0
- data/lib/finite_machine/callable.rb +5 -5
- data/lib/finite_machine/catchable.rb +2 -2
- data/lib/finite_machine/dsl.rb +16 -9
- data/lib/finite_machine/event.rb +1 -1
- data/lib/finite_machine/event_queue.rb +123 -0
- data/lib/finite_machine/hooks.rb +33 -0
- data/lib/finite_machine/observer.rb +53 -11
- data/lib/finite_machine/state_machine.rb +70 -2
- data/lib/finite_machine/subscribers.rb +5 -2
- data/lib/finite_machine/thread_context.rb +16 -0
- data/lib/finite_machine/threadable.rb +36 -3
- data/lib/finite_machine/transition.rb +47 -4
- data/lib/finite_machine/version.rb +1 -1
- data/spec/spec_helper.rb +15 -0
- data/spec/unit/async_events_spec.rb +68 -0
- data/spec/unit/callable/call_spec.rb +25 -3
- data/spec/unit/callbacks_spec.rb +110 -4
- data/spec/unit/events_spec.rb +5 -0
- data/spec/unit/handlers_spec.rb +53 -0
- data/spec/unit/if_unless_spec.rb +1 -1
- data/spec/unit/is_spec.rb +22 -0
- data/spec/unit/target_spec.rb +17 -0
- data/tasks/console.rake +10 -0
- data/tasks/coverage.rake +11 -0
- data/tasks/spec.rake +29 -0
- metadata +16 -32
@@ -8,12 +8,16 @@ describe FiniteMachine::Callable, '#call' do
|
|
8
8
|
Car = Class.new do
|
9
9
|
attr_reader :result
|
10
10
|
|
11
|
+
def initialize
|
12
|
+
@engine_on = false
|
13
|
+
end
|
14
|
+
|
11
15
|
def turn_engine_on
|
12
16
|
@result = 'turn_engine_on'
|
13
17
|
@engine_on = true
|
14
18
|
end
|
15
19
|
|
16
|
-
def set_engine(value)
|
20
|
+
def set_engine(value = :on)
|
17
21
|
@result = "set_engine(#{value})"
|
18
22
|
@engine = value.to_sym == :on
|
19
23
|
end
|
@@ -54,12 +58,30 @@ describe FiniteMachine::Callable, '#call' do
|
|
54
58
|
end
|
55
59
|
end
|
56
60
|
|
61
|
+
context 'when string with arguments' do
|
62
|
+
let(:object) { 'set_engine' }
|
63
|
+
|
64
|
+
it 'executes method with arguments' do
|
65
|
+
instance.call(target, :off)
|
66
|
+
expect(target.result).to eql('set_engine(off)')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
57
70
|
context 'when symbol' do
|
58
|
-
let(:object) { :
|
71
|
+
let(:object) { :set_engine }
|
59
72
|
|
60
73
|
it 'executes method on target' do
|
61
74
|
instance.call(target)
|
62
|
-
expect(target.result).to eql('
|
75
|
+
expect(target.result).to eql('set_engine(on)')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'when symbol with arguments' do
|
80
|
+
let(:object) { :set_engine }
|
81
|
+
|
82
|
+
it 'executes method on target' do
|
83
|
+
instance.call(target, :off)
|
84
|
+
expect(target.result).to eql('set_engine(off)')
|
63
85
|
end
|
64
86
|
end
|
65
87
|
|
data/spec/unit/callbacks_spec.rb
CHANGED
@@ -47,6 +47,8 @@ describe FiniteMachine, 'callbacks' do
|
|
47
47
|
}
|
48
48
|
end
|
49
49
|
|
50
|
+
expect(fsm.current).to eql(:green)
|
51
|
+
|
50
52
|
expect(called).to eql([
|
51
53
|
'on_exit_none',
|
52
54
|
'on_exit',
|
@@ -394,9 +396,9 @@ describe FiniteMachine, 'callbacks' do
|
|
394
396
|
|
395
397
|
callbacks {
|
396
398
|
# generic callbacks
|
397
|
-
on_enter
|
398
|
-
on_transition
|
399
|
-
on_exit
|
399
|
+
on_enter(&callback)
|
400
|
+
on_transition(&callback)
|
401
|
+
on_exit(&callback)
|
400
402
|
|
401
403
|
# state callbacks
|
402
404
|
on_enter :green, &callback
|
@@ -471,5 +473,109 @@ describe FiniteMachine, 'callbacks' do
|
|
471
473
|
expect { fsm.slow }.to raise_error(RuntimeError)
|
472
474
|
end
|
473
475
|
|
474
|
-
|
476
|
+
it "executes callbacks with multiple 'from' transitions" do
|
477
|
+
called = []
|
478
|
+
fsm = FiniteMachine.define do
|
479
|
+
initial :green
|
480
|
+
|
481
|
+
events {
|
482
|
+
event :stop, :green => :yellow
|
483
|
+
event :stop, :yellow => :red
|
484
|
+
}
|
485
|
+
|
486
|
+
callbacks {
|
487
|
+
on_enter_stop do |event|
|
488
|
+
called << 'on_enter_stop'
|
489
|
+
end
|
490
|
+
}
|
491
|
+
end
|
492
|
+
expect(fsm.current).to eql(:green)
|
493
|
+
fsm.stop
|
494
|
+
expect(fsm.current).to eql(:yellow)
|
495
|
+
fsm.stop
|
496
|
+
expect(fsm.current).to eql(:red)
|
497
|
+
expect(called).to eql([
|
498
|
+
'on_enter_stop',
|
499
|
+
'on_enter_stop'
|
500
|
+
])
|
501
|
+
end
|
502
|
+
|
503
|
+
it "allows to define callbacks on machine instance" do
|
504
|
+
called = []
|
505
|
+
fsm = FiniteMachine.define do
|
506
|
+
initial :green
|
507
|
+
|
508
|
+
events {
|
509
|
+
event :slow, :green => :yellow
|
510
|
+
event :stop, :yellow => :red
|
511
|
+
event :ready, :red => :yellow
|
512
|
+
event :go, :yellow => :green
|
513
|
+
}
|
514
|
+
end
|
515
|
+
|
516
|
+
fsm.on_enter_yellow do |event|
|
517
|
+
called << 'on_enter_yellow'
|
518
|
+
end
|
519
|
+
|
520
|
+
expect(fsm.current).to eql(:green)
|
521
|
+
fsm.slow
|
522
|
+
expect(called).to eql([
|
523
|
+
'on_enter_yellow'
|
524
|
+
])
|
525
|
+
end
|
526
|
+
|
527
|
+
it "raises error for unknown callback" do
|
528
|
+
expect { FiniteMachine.define do
|
529
|
+
initial :green
|
530
|
+
|
531
|
+
events {
|
532
|
+
event :slow, :green => :yellow
|
533
|
+
event :stop, :yellow => :red
|
534
|
+
event :ready, :red => :yellow
|
535
|
+
event :go, :yellow => :green
|
536
|
+
}
|
537
|
+
|
538
|
+
callbacks {
|
539
|
+
on_enter_unknown do |event| end
|
540
|
+
}
|
541
|
+
end }.to raise_error(NoMethodError)
|
542
|
+
end
|
543
|
+
|
544
|
+
it "triggers callbacks only once" do
|
545
|
+
called = []
|
546
|
+
fsm = FiniteMachine.define do
|
547
|
+
initial :green
|
548
|
+
|
549
|
+
events {
|
550
|
+
event :slow, :green => :yellow
|
551
|
+
event :go, :yellow => :green
|
552
|
+
}
|
553
|
+
|
554
|
+
callbacks {
|
555
|
+
once_on_enter_green do |event| called << 'once_on_enter_green' end
|
556
|
+
once_on_enter_yellow do |event| called << 'once_on_enter_yellow' end
|
557
|
+
|
558
|
+
once_on_transition_green do |event| called << 'once_on_transition_green' end
|
559
|
+
once_on_transition_yellow do |event| called << 'once_on_transition_yellow' end
|
560
|
+
|
561
|
+
once_on_exit_green do |event| called << 'once_on_exit_green' end
|
562
|
+
once_on_exit_yellow do |event| called << 'once_on_exit_yellow' end
|
563
|
+
}
|
564
|
+
end
|
565
|
+
expect(fsm.current).to eql(:green)
|
566
|
+
fsm.slow
|
567
|
+
expect(fsm.current).to eql(:yellow)
|
568
|
+
fsm.go
|
569
|
+
expect(fsm.current).to eql(:green)
|
570
|
+
fsm.slow
|
571
|
+
expect(fsm.current).to eql(:yellow)
|
572
|
+
expect(called).to eql([
|
573
|
+
'once_on_transition_green',
|
574
|
+
'once_on_enter_green',
|
575
|
+
'once_on_exit_green',
|
576
|
+
'once_on_transition_yellow',
|
577
|
+
'once_on_enter_yellow',
|
578
|
+
'once_on_exit_yellow'
|
579
|
+
])
|
580
|
+
end
|
475
581
|
end
|
data/spec/unit/events_spec.rb
CHANGED
@@ -216,6 +216,7 @@ describe FiniteMachine, 'events' do
|
|
216
216
|
event :stop, :green => :yellow
|
217
217
|
event :stop, :yellow => :red
|
218
218
|
event :stop, :red => :pink
|
219
|
+
event :cycle, [:yellow, :red, :pink] => :green
|
219
220
|
}
|
220
221
|
end
|
221
222
|
|
@@ -229,6 +230,10 @@ describe FiniteMachine, 'events' do
|
|
229
230
|
expect(fsm.current).to eql(:red)
|
230
231
|
fsm.stop
|
231
232
|
expect(fsm.current).to eql(:pink)
|
233
|
+
fsm.cycle
|
234
|
+
expect(fsm.current).to eql(:green)
|
235
|
+
fsm.stop
|
236
|
+
expect(fsm.current).to eql(:yellow)
|
232
237
|
end
|
233
238
|
|
234
239
|
it "returns values for events" do
|
data/spec/unit/handlers_spec.rb
CHANGED
@@ -96,4 +96,57 @@ describe FiniteMachine, 'handlers' do
|
|
96
96
|
expect(fsm.current).to eql(:green)
|
97
97
|
expect(called).to eql(['invalid_state_error'])
|
98
98
|
end
|
99
|
+
|
100
|
+
it 'allows for empty block handler' do
|
101
|
+
called = []
|
102
|
+
fsm = FiniteMachine.define do
|
103
|
+
initial :green
|
104
|
+
|
105
|
+
events {
|
106
|
+
event :slow, :green => :yellow
|
107
|
+
event :stop, :yellow => :red
|
108
|
+
}
|
109
|
+
|
110
|
+
handlers {
|
111
|
+
handle FiniteMachine::InvalidStateError do
|
112
|
+
called << 'invalidstate'
|
113
|
+
end
|
114
|
+
}
|
115
|
+
end
|
116
|
+
|
117
|
+
expect(fsm.current).to eql(:green)
|
118
|
+
fsm.stop
|
119
|
+
expect(fsm.current).to eql(:green)
|
120
|
+
expect(called).to eql([
|
121
|
+
'invalidstate'
|
122
|
+
])
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'requires error handler' do
|
126
|
+
expect { FiniteMachine.define do
|
127
|
+
initial :green
|
128
|
+
|
129
|
+
events {
|
130
|
+
event :slow, :green => :yellow
|
131
|
+
}
|
132
|
+
|
133
|
+
handlers {
|
134
|
+
handle 'UnknownErrorType'
|
135
|
+
}
|
136
|
+
end }.to raise_error(ArgumentError, /error handler/)
|
137
|
+
end
|
138
|
+
|
139
|
+
it 'checks handler class to be Exception' do
|
140
|
+
expect { FiniteMachine.define do
|
141
|
+
initial :green
|
142
|
+
|
143
|
+
events {
|
144
|
+
event :slow, :green => :yellow
|
145
|
+
}
|
146
|
+
|
147
|
+
handlers {
|
148
|
+
handle Object do end
|
149
|
+
}
|
150
|
+
end }.to raise_error(ArgumentError, /Object isn't an Exception/)
|
151
|
+
end
|
99
152
|
end
|
data/spec/unit/if_unless_spec.rb
CHANGED
@@ -125,7 +125,7 @@ describe FiniteMachine, ':if, :unless' do
|
|
125
125
|
target car
|
126
126
|
|
127
127
|
events {
|
128
|
-
event :start, :neutral => :one, if: proc {|
|
128
|
+
event :start, :neutral => :one, if: proc {|_car| _car.engine_on? }
|
129
129
|
event :shift, :one => :two
|
130
130
|
}
|
131
131
|
end
|
data/spec/unit/is_spec.rb
CHANGED
@@ -30,4 +30,26 @@ describe FiniteMachine, 'is?' do
|
|
30
30
|
expect(fsm.is?([:green, :red])).to be_false
|
31
31
|
expect(fsm.is?([:yellow, :red])).to be_true
|
32
32
|
end
|
33
|
+
|
34
|
+
it "defines helper methods to check current state" do
|
35
|
+
fsm = FiniteMachine.define do
|
36
|
+
initial :green
|
37
|
+
|
38
|
+
events {
|
39
|
+
event :slow, :green => :yellow
|
40
|
+
event :stop, :yellow => :red
|
41
|
+
event :ready, :red => :yellow
|
42
|
+
event :go, :yellow => :green
|
43
|
+
}
|
44
|
+
end
|
45
|
+
expect(fsm.current).to eql(:green)
|
46
|
+
|
47
|
+
expect(fsm.green?).to be_true
|
48
|
+
expect(fsm.yellow?).to be_false
|
49
|
+
|
50
|
+
fsm.slow
|
51
|
+
|
52
|
+
expect(fsm.green?).to be_false
|
53
|
+
expect(fsm.yellow?).to be_true
|
54
|
+
end
|
33
55
|
end
|
data/spec/unit/target_spec.rb
CHANGED
@@ -53,6 +53,23 @@ describe FiniteMachine, '#target' do
|
|
53
53
|
expect(car.reverse_lights).to be_false
|
54
54
|
end
|
55
55
|
|
56
|
+
it "propagates method call" do
|
57
|
+
fsm = FiniteMachine.define do
|
58
|
+
initial :green
|
59
|
+
events {
|
60
|
+
event :slow, :green => :yellow
|
61
|
+
}
|
62
|
+
|
63
|
+
callbacks {
|
64
|
+
on_enter_yellow do |event|
|
65
|
+
uknown_method
|
66
|
+
end
|
67
|
+
}
|
68
|
+
end
|
69
|
+
expect(fsm.current).to eql(:green)
|
70
|
+
expect { fsm.slow }.to raise_error(StandardError)
|
71
|
+
end
|
72
|
+
|
56
73
|
it "references machine methods inside callback" do
|
57
74
|
called = []
|
58
75
|
fsm = FiniteMachine.define do
|
data/tasks/console.rake
ADDED
data/tasks/coverage.rake
ADDED
data/tasks/spec.rake
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
desc 'Run all specs'
|
7
|
+
RSpec::Core::RakeTask.new(:spec) do |task|
|
8
|
+
task.pattern = 'spec/{unit,integration}{,/*/**}/*_spec.rb'
|
9
|
+
end
|
10
|
+
|
11
|
+
namespace :spec do
|
12
|
+
desc 'Run unit specs'
|
13
|
+
RSpec::Core::RakeTask.new(:unit) do |task|
|
14
|
+
task.pattern = 'spec/unit{,/*/**}/*_spec.rb'
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Run integration specs'
|
18
|
+
RSpec::Core::RakeTask.new(:integration) do |task|
|
19
|
+
task.pattern = 'spec/integration{,/*/**}/*_spec.rb'
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
rescue LoadError
|
24
|
+
%w[spec spec:unit spec:integration].each do |name|
|
25
|
+
task name do
|
26
|
+
$stderr.puts "In order to run #{name}, do `gem install rspec`"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
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.
|
4
|
+
version: 0.3.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-
|
11
|
+
date: 2014-03-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,42 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.5'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: rake
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - '>='
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
34
|
-
type: :development
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - '>='
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: rspec
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - '>='
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - '>='
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
26
|
+
version: '1.5'
|
55
27
|
description: A minimal finite state machine with a straightforward syntax. You can
|
56
28
|
quickly model states, add callbacks and use object-oriented techniques to integrate
|
57
29
|
with ORMs.
|
@@ -63,6 +35,8 @@ extra_rdoc_files: []
|
|
63
35
|
files:
|
64
36
|
- .gitignore
|
65
37
|
- .rspec
|
38
|
+
- .ruby-gemset
|
39
|
+
- .ruby-version
|
66
40
|
- .travis.yml
|
67
41
|
- CHANGELOG.md
|
68
42
|
- Gemfile
|
@@ -71,18 +45,23 @@ files:
|
|
71
45
|
- Rakefile
|
72
46
|
- finite_machine.gemspec
|
73
47
|
- lib/finite_machine.rb
|
48
|
+
- lib/finite_machine/async_call.rb
|
49
|
+
- lib/finite_machine/async_proxy.rb
|
74
50
|
- lib/finite_machine/callable.rb
|
75
51
|
- lib/finite_machine/catchable.rb
|
76
52
|
- lib/finite_machine/dsl.rb
|
77
53
|
- lib/finite_machine/event.rb
|
54
|
+
- lib/finite_machine/event_queue.rb
|
78
55
|
- lib/finite_machine/hooks.rb
|
79
56
|
- lib/finite_machine/observer.rb
|
80
57
|
- lib/finite_machine/state_machine.rb
|
81
58
|
- lib/finite_machine/subscribers.rb
|
59
|
+
- lib/finite_machine/thread_context.rb
|
82
60
|
- lib/finite_machine/threadable.rb
|
83
61
|
- lib/finite_machine/transition.rb
|
84
62
|
- lib/finite_machine/version.rb
|
85
63
|
- spec/spec_helper.rb
|
64
|
+
- spec/unit/async_events_spec.rb
|
86
65
|
- spec/unit/callable/call_spec.rb
|
87
66
|
- spec/unit/callbacks_spec.rb
|
88
67
|
- spec/unit/can_spec.rb
|
@@ -96,6 +75,9 @@ files:
|
|
96
75
|
- spec/unit/states_spec.rb
|
97
76
|
- spec/unit/target_spec.rb
|
98
77
|
- spec/unit/transition/parse_states_spec.rb
|
78
|
+
- tasks/console.rake
|
79
|
+
- tasks/coverage.rake
|
80
|
+
- tasks/spec.rake
|
99
81
|
homepage: https://github.com/peter-murach/finite_machine
|
100
82
|
licenses:
|
101
83
|
- MIT
|
@@ -122,6 +104,7 @@ specification_version: 4
|
|
122
104
|
summary: A minimal finite state machine with a straightforward syntax.
|
123
105
|
test_files:
|
124
106
|
- spec/spec_helper.rb
|
107
|
+
- spec/unit/async_events_spec.rb
|
125
108
|
- spec/unit/callable/call_spec.rb
|
126
109
|
- spec/unit/callbacks_spec.rb
|
127
110
|
- spec/unit/can_spec.rb
|
@@ -135,3 +118,4 @@ test_files:
|
|
135
118
|
- spec/unit/states_spec.rb
|
136
119
|
- spec/unit/target_spec.rb
|
137
120
|
- spec/unit/transition/parse_states_spec.rb
|
121
|
+
has_rdoc:
|