finite_machine 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/CHANGELOG.md +7 -0
- data/Gemfile +5 -4
- data/README.md +49 -9
- data/lib/finite_machine.rb +1 -2
- data/lib/finite_machine/choice_merger.rb +5 -5
- data/lib/finite_machine/definition.rb +9 -0
- data/lib/finite_machine/dsl.rb +16 -13
- data/lib/finite_machine/env.rb +19 -0
- data/lib/finite_machine/state_machine.rb +3 -3
- data/lib/finite_machine/version.rb +1 -1
- data/spec/spec_helper.rb +7 -14
- data/spec/unit/alias_target_spec.rb +3 -3
- data/spec/unit/async_events_spec.rb +1 -1
- data/spec/unit/callable/call_spec.rb +3 -3
- data/spec/unit/callbacks_spec.rb +1 -1
- data/spec/unit/can_spec.rb +3 -3
- data/spec/unit/choice_spec.rb +31 -3
- data/spec/unit/define_spec.rb +1 -1
- data/spec/unit/definition_spec.rb +48 -5
- data/spec/unit/event/add_spec.rb +1 -1
- data/spec/unit/event/eql_spec.rb +1 -1
- data/spec/unit/event/initialize_spec.rb +1 -1
- data/spec/unit/event/inspect_spec.rb +1 -1
- data/spec/unit/event/next_transition_spec.rb +1 -1
- data/spec/unit/event_queue_spec.rb +1 -1
- data/spec/unit/events_chain/check_choice_conditions_spec.rb +1 -1
- data/spec/unit/events_chain/clear_spec.rb +1 -1
- data/spec/unit/events_chain/insert_spec.rb +1 -1
- data/spec/unit/events_chain/inspect_spec.rb +1 -1
- data/spec/unit/events_chain/select_transition_spec.rb +1 -1
- data/spec/unit/events_spec.rb +1 -1
- data/spec/unit/handlers_spec.rb +3 -3
- data/spec/unit/hook_event/eql_spec.rb +1 -1
- data/spec/unit/hook_event/initialize_spec.rb +1 -1
- data/spec/unit/hooks/call_spec.rb +1 -1
- data/spec/unit/hooks/inspect_spec.rb +1 -1
- data/spec/unit/hooks/register_spec.rb +1 -1
- data/spec/unit/if_unless_spec.rb +5 -5
- data/spec/unit/initialize_spec.rb +3 -3
- data/spec/unit/inspect_spec.rb +1 -2
- data/spec/unit/is_spec.rb +1 -1
- data/spec/unit/log_transitions_spec.rb +1 -1
- data/spec/unit/logger_spec.rb +1 -2
- data/spec/unit/respond_to_spec.rb +4 -3
- data/spec/unit/state_parser/inspect_spec.rb +1 -1
- data/spec/unit/state_parser/parse_states_spec.rb +1 -1
- data/spec/unit/states_spec.rb +1 -2
- data/spec/unit/subscribers_spec.rb +1 -1
- data/spec/unit/target_spec.rb +7 -8
- data/spec/unit/terminated_spec.rb +1 -1
- data/spec/unit/transition/inspect_spec.rb +1 -1
- data/spec/unit/transition/parse_states_spec.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ec0da72426b4f28c1b3e06cb7bce0de974ac4445
|
4
|
+
data.tar.gz: 36d0560b1fc8148cf9c3d194aff3843148e56854
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57dbe7dada41dcfe1fafda95f2a5e7664cdaa62c506e9afdf5f943aa561bae2ea2d9a9a399bc910a08c82e3c76e5350345f89471c90e4deb9e8133a4a37c3a73
|
7
|
+
data.tar.gz: a14127d9c43b5bcb68b0223c4b5dc3f807c48513ba6fe89fda7e0f4e191e849ac013d2144bf489c54fbe71b9b7c61d0999bef986e436159a3de287acdae807e8
|
data/.travis.yml
CHANGED
@@ -5,6 +5,7 @@ rvm:
|
|
5
5
|
- 1.9.3
|
6
6
|
- 2.0.0
|
7
7
|
- 2.1.0
|
8
|
+
- 2.2.0
|
8
9
|
- ruby-head
|
9
10
|
matrix:
|
10
11
|
include:
|
@@ -16,8 +17,6 @@ matrix:
|
|
16
17
|
allow_failures:
|
17
18
|
- rvm: ruby-head
|
18
19
|
- rvm: jruby-head
|
19
|
-
- rvm: jruby-20mode
|
20
|
-
- rvm: jruby-21mode
|
21
20
|
- rvm: rbx-2
|
22
21
|
fast_finish: true
|
23
22
|
branches:
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
0.10.1 (May 24, 2015)
|
2
|
+
|
3
|
+
* Add ability to inherit state machine definitions
|
4
|
+
* Add Env class for holiding machine envionment references
|
5
|
+
* Change DSL to delegate calls to machine instance
|
6
|
+
* Change ChoiceMerger to use machine directly
|
7
|
+
|
1
8
|
0.10.0 (November 16, 2014)
|
2
9
|
|
3
10
|
* Add #alias_target to allow renaming of target object by @reggieb
|
data/Gemfile
CHANGED
@@ -3,13 +3,14 @@ source 'https://rubygems.org'
|
|
3
3
|
gemspec
|
4
4
|
|
5
5
|
group :development do
|
6
|
-
gem '
|
7
|
-
gem '
|
6
|
+
gem 'pry', '~> 0.10.1'
|
7
|
+
gem 'rake', '~> 10.4.2'
|
8
|
+
gem 'rspec', '~> 3.2.0'
|
8
9
|
gem 'yard', '~> 0.8.7'
|
9
10
|
end
|
10
11
|
|
11
12
|
group :metrics do
|
12
|
-
gem 'coveralls', '~> 0.
|
13
|
-
gem 'simplecov', '~> 0.
|
13
|
+
gem 'coveralls', '~> 0.8.1'
|
14
|
+
gem 'simplecov', '~> 0.10.0'
|
14
15
|
gem 'yardstick', '~> 0.9.9'
|
15
16
|
end
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# FiniteMachine
|
2
|
-
[![Gem Version](https://badge.fury.io/rb/finite_machine.
|
3
|
-
[![Build Status](https://secure.travis-ci.org/peter-murach/finite_machine.
|
4
|
-
[![Code Climate](https://codeclimate.com/github/peter-murach/finite_machine.
|
5
|
-
[![Coverage Status](https://coveralls.io/repos/peter-murach/finite_machine/badge.
|
6
|
-
[![Inline docs](http://inch-ci.org/github/peter-murach/finite_machine.
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/finite_machine.svg)][gem]
|
3
|
+
[![Build Status](https://secure.travis-ci.org/peter-murach/finite_machine.svg?branch=master)][travis]
|
4
|
+
[![Code Climate](https://codeclimate.com/github/peter-murach/finite_machine/badges/gpa.svg)][codeclimate]
|
5
|
+
[![Coverage Status](https://coveralls.io/repos/peter-murach/finite_machine/badge.svg)][coverage]
|
6
|
+
[![Inline docs](http://inch-ci.org/github/peter-murach/finite_machine.svg)][inchpages]
|
7
7
|
[![Gitter](https://badges.gitter.im/Join Chat.svg)][gitter]
|
8
8
|
|
9
9
|
[gem]: http://badge.fury.io/rb/finite_machine
|
@@ -13,7 +13,7 @@
|
|
13
13
|
[inchpages]: http://inch-ci.org/github/peter-murach/finite_machine
|
14
14
|
[gitter]: https://gitter.im/peter-murach/finite_machine?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
|
15
15
|
|
16
|
-
A minimal finite state machine with a straightforward and intuitive syntax. You can quickly model states and add callbacks that can be triggered synchronously or asynchronously. The machine is event driven with a focus on passing synchronous and asynchronous messages to trigger state transitions.
|
16
|
+
> A minimal finite state machine with a straightforward and intuitive syntax. You can quickly model states and add callbacks that can be triggered synchronously or asynchronously. The machine is event driven with a focus on passing synchronous and asynchronous messages to trigger state transitions.
|
17
17
|
|
18
18
|
## Features
|
19
19
|
|
@@ -91,6 +91,7 @@ Or install it yourself as:
|
|
91
91
|
* [7. Stand-Alone FiniteMachine](#7-stand-alone-finitemachine)
|
92
92
|
* [7.1 Creating a Definition](#71-creating-a-definition)
|
93
93
|
* [7.2 Targeting definition](#72-targeting-definition)
|
94
|
+
* [7.3 Definition inheritance](#73-definition-inheritance)
|
94
95
|
* [8. Integration](#8-integration)
|
95
96
|
* [8.1 Plain Ruby Objects](#81-plain-ruby-objects)
|
96
97
|
* [8.2 ActiveRecord](#82-activerecord)
|
@@ -232,7 +233,7 @@ end
|
|
232
233
|
|
233
234
|
### 1.3 terminal
|
234
235
|
|
235
|
-
To specify a final state **FiniteMachine** uses the `terminal` method. The `terminal` can
|
236
|
+
To specify a final state **FiniteMachine** uses the `terminal` method. The `terminal` can accept more than one state.
|
236
237
|
|
237
238
|
```ruby
|
238
239
|
fm = FiniteMachine.define do
|
@@ -1213,6 +1214,45 @@ class Car
|
|
1213
1214
|
end
|
1214
1215
|
```
|
1215
1216
|
|
1217
|
+
### 7.3 Definition inheritance
|
1218
|
+
|
1219
|
+
You can create more specialised versions of a generic definition by using inheritance. Assuming a generic state machine definition:
|
1220
|
+
|
1221
|
+
```ruby
|
1222
|
+
class GenericStateMachine < FiniteMachine::Definition
|
1223
|
+
initial :red
|
1224
|
+
|
1225
|
+
events {
|
1226
|
+
event :start, :red => :green
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
callbacks {
|
1230
|
+
on_enter { |event| ... }
|
1231
|
+
}
|
1232
|
+
end
|
1233
|
+
```
|
1234
|
+
|
1235
|
+
we can easily create a more specifc definition that adds new event and more specifc callback to the mix.
|
1236
|
+
|
1237
|
+
```ruby
|
1238
|
+
class SpecificStateMachine < GenericStateMachine
|
1239
|
+
events {
|
1240
|
+
event :stop, :green => :yellow
|
1241
|
+
}
|
1242
|
+
|
1243
|
+
callbacks {
|
1244
|
+
on_enter(:yellow) { |event| ... }
|
1245
|
+
}
|
1246
|
+
end
|
1247
|
+
```
|
1248
|
+
|
1249
|
+
Finally to use the specific state machine definition do:
|
1250
|
+
|
1251
|
+
```ruby
|
1252
|
+
specific_fsm = SpecificStateMachine.new
|
1253
|
+
specific_fsm.target ... # Target specific object
|
1254
|
+
```
|
1255
|
+
|
1216
1256
|
## 8 Integration
|
1217
1257
|
|
1218
1258
|
Since **FiniteMachine** is an object in its own right, it leaves integration with other systems up to you. In contrast to other Ruby libraries, it does not extend from models (i.e. ActiveRecord) to transform them into a state machine or require mixing into exisiting classes.
|
@@ -1318,7 +1358,7 @@ class Account < ActiveRecord::Base
|
|
1318
1358
|
|
1319
1359
|
callbacks {
|
1320
1360
|
on_enter do |event|
|
1321
|
-
target.state =
|
1361
|
+
target.state = state
|
1322
1362
|
end
|
1323
1363
|
}
|
1324
1364
|
end
|
@@ -1363,4 +1403,4 @@ Creating a standalone **FiniteMachine** brings a number of benefits, one of them
|
|
1363
1403
|
|
1364
1404
|
## Copyright
|
1365
1405
|
|
1366
|
-
Copyright (c) 2014 Piotr Murach. See LICENSE for further details.
|
1406
|
+
Copyright (c) 2014-2015 Piotr Murach. See LICENSE for further details.
|
data/lib/finite_machine.rb
CHANGED
@@ -15,6 +15,7 @@ require "finite_machine/choice_merger"
|
|
15
15
|
require "finite_machine/async_proxy"
|
16
16
|
require "finite_machine/async_call"
|
17
17
|
require "finite_machine/hook_event"
|
18
|
+
require "finite_machine/env"
|
18
19
|
require "finite_machine/event"
|
19
20
|
require "finite_machine/event_builder"
|
20
21
|
require "finite_machine/event_queue"
|
@@ -78,8 +79,6 @@ module FiniteMachine
|
|
78
79
|
# Raised when argument is already defined
|
79
80
|
AlreadyDefinedError = Class.new(::ArgumentError)
|
80
81
|
|
81
|
-
Environment = Struct.new(:target, :aliases)
|
82
|
-
|
83
82
|
class << self
|
84
83
|
attr_accessor :logger
|
85
84
|
|
@@ -6,16 +6,16 @@ module FiniteMachine
|
|
6
6
|
include Threadable
|
7
7
|
|
8
8
|
# The context where choice is executed
|
9
|
-
attr_threadsafe :
|
9
|
+
attr_threadsafe :machine
|
10
10
|
|
11
|
-
# The options passed in to the
|
11
|
+
# The options passed in to the machine
|
12
12
|
attr_threadsafe :options
|
13
13
|
|
14
14
|
# Initialize a ChoiceMerger
|
15
15
|
#
|
16
16
|
# @api private
|
17
|
-
def initialize(
|
18
|
-
self.
|
17
|
+
def initialize(machine, options)
|
18
|
+
self.machine = machine
|
19
19
|
self.options = options
|
20
20
|
end
|
21
21
|
|
@@ -36,7 +36,7 @@ module FiniteMachine
|
|
36
36
|
def choice(to, attrs = {})
|
37
37
|
opts = options.dup
|
38
38
|
opts.merge!(attrs)
|
39
|
-
transition_builder = TransitionBuilder.new(
|
39
|
+
transition_builder = TransitionBuilder.new(machine, opts)
|
40
40
|
transition_builder.call(options[:from] => to)
|
41
41
|
end
|
42
42
|
alias_method :default, :choice
|
@@ -43,6 +43,15 @@ module FiniteMachine
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
# Set deferrerd methods on the subclass
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def self.inherited(subclass)
|
50
|
+
super
|
51
|
+
|
52
|
+
self.deferreds.each { |d| subclass.add_deferred(d) }
|
53
|
+
end
|
54
|
+
|
46
55
|
# Delay lookup of DSL method
|
47
56
|
#
|
48
57
|
# @param [Symbol] method_name
|
data/lib/finite_machine/dsl.rb
CHANGED
@@ -22,9 +22,12 @@ module FiniteMachine
|
|
22
22
|
self.machine = machine
|
23
23
|
end
|
24
24
|
|
25
|
+
# Delegate attributes to machine instance
|
26
|
+
#
|
27
|
+
# @api private
|
25
28
|
def method_missing(method_name, *args, &block)
|
26
|
-
if
|
27
|
-
|
29
|
+
if machine.respond_to?(method_name)
|
30
|
+
machine.send(method_name, *args, &block)
|
28
31
|
else
|
29
32
|
super
|
30
33
|
end
|
@@ -88,7 +91,7 @@ module FiniteMachine
|
|
88
91
|
state = (value && !value.is_a?(Hash)) ? value : raise_missing_state
|
89
92
|
name, self.defer, silent = parse(options)
|
90
93
|
self.initial_event = name
|
91
|
-
|
94
|
+
event(name, FiniteMachine::DEFAULT_STATE => state, silent: silent)
|
92
95
|
end
|
93
96
|
|
94
97
|
# Trigger initial event
|
@@ -97,7 +100,7 @@ module FiniteMachine
|
|
97
100
|
#
|
98
101
|
# @api private
|
99
102
|
def trigger_init
|
100
|
-
|
103
|
+
public_send(:"#{initial_event}") unless defer
|
101
104
|
end
|
102
105
|
|
103
106
|
# Attach state machine to an object
|
@@ -117,9 +120,9 @@ module FiniteMachine
|
|
117
120
|
# @api public
|
118
121
|
def target(object = nil)
|
119
122
|
if object.nil?
|
120
|
-
|
123
|
+
env.target
|
121
124
|
else
|
122
|
-
|
125
|
+
env.target = object
|
123
126
|
end
|
124
127
|
end
|
125
128
|
|
@@ -141,7 +144,7 @@ module FiniteMachine
|
|
141
144
|
#
|
142
145
|
# @api public
|
143
146
|
def alias_target(alias_name)
|
144
|
-
|
147
|
+
env.aliases << alias_name.to_sym
|
145
148
|
end
|
146
149
|
|
147
150
|
# Define terminal state
|
@@ -153,7 +156,7 @@ module FiniteMachine
|
|
153
156
|
#
|
154
157
|
# @api public
|
155
158
|
def terminal(*values)
|
156
|
-
|
159
|
+
self.final_state = values
|
157
160
|
end
|
158
161
|
|
159
162
|
# Define state machine events
|
@@ -167,7 +170,7 @@ module FiniteMachine
|
|
167
170
|
#
|
168
171
|
# @api public
|
169
172
|
def events(&block)
|
170
|
-
|
173
|
+
events_dsl.call(&block)
|
171
174
|
end
|
172
175
|
|
173
176
|
# Define state machine callbacks
|
@@ -181,21 +184,21 @@ module FiniteMachine
|
|
181
184
|
#
|
182
185
|
# @api public
|
183
186
|
def callbacks(&block)
|
184
|
-
|
187
|
+
observer.call(&block)
|
185
188
|
end
|
186
189
|
|
187
190
|
# Error handler that throws exception when machine is in illegal state
|
188
191
|
#
|
189
192
|
# @api public
|
190
193
|
def handlers(&block)
|
191
|
-
|
194
|
+
errors.call(&block)
|
192
195
|
end
|
193
196
|
|
194
197
|
# Decide whether to log transitions
|
195
198
|
#
|
196
199
|
# @api public
|
197
200
|
def log_transitions(value)
|
198
|
-
|
201
|
+
self.log_transitions = value
|
199
202
|
end
|
200
203
|
|
201
204
|
private
|
@@ -256,7 +259,7 @@ module FiniteMachine
|
|
256
259
|
sync_exclusive do
|
257
260
|
attributes = attrs.merge!(name: name)
|
258
261
|
if block_given?
|
259
|
-
merger = ChoiceMerger.new(
|
262
|
+
merger = ChoiceMerger.new(machine, attributes)
|
260
263
|
merger.instance_eval(&block)
|
261
264
|
else
|
262
265
|
transition_builder = TransitionBuilder.new(machine, attributes)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FiniteMachine
|
4
|
+
# Holds references to targets and aliases
|
5
|
+
#
|
6
|
+
# @api public
|
7
|
+
class Env
|
8
|
+
include Threadable
|
9
|
+
|
10
|
+
attr_threadsafe :target
|
11
|
+
|
12
|
+
attr_threadsafe :aliases
|
13
|
+
|
14
|
+
def initialize(target, aliases)
|
15
|
+
@target = target
|
16
|
+
@aliases = aliases
|
17
|
+
end
|
18
|
+
end # Env
|
19
|
+
end # FiniteMachine
|
@@ -62,12 +62,12 @@ module FiniteMachine
|
|
62
62
|
attributes = args.last.is_a?(Hash) ? args.pop : {}
|
63
63
|
@initial_state = DEFAULT_STATE
|
64
64
|
@subscribers = Subscribers.new(self)
|
65
|
-
@events_dsl = EventsDSL.new(self)
|
66
|
-
@errors = ErrorsDSL.new(self)
|
67
65
|
@observer = Observer.new(self)
|
68
66
|
@transitions = Hash.new { |hash, name| hash[name] = Hash.new }
|
69
67
|
@events_chain = EventsChain.new(self)
|
70
|
-
@env =
|
68
|
+
@env = Env.new(self, [])
|
69
|
+
@events_dsl = EventsDSL.new(self)
|
70
|
+
@errors = ErrorsDSL.new(self)
|
71
71
|
@dsl = DSL.new(self, attributes)
|
72
72
|
|
73
73
|
@dsl.call(&block) if block_given?
|
data/spec/spec_helper.rb
CHANGED
@@ -21,19 +21,12 @@ RSpec.configure do |config|
|
|
21
21
|
config.run_all_when_everything_filtered = true
|
22
22
|
config.filter_run :focus
|
23
23
|
config.raise_errors_for_deprecations!
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# Remove defined constants
|
32
|
-
config.before :each do
|
33
|
-
[:Car, :DummyLogger, :Bug, :User, :Engine].each do |class_name|
|
34
|
-
if Object.const_defined?(class_name)
|
35
|
-
Object.send(:remove_const, class_name)
|
36
|
-
end
|
37
|
-
end
|
24
|
+
config.mock_with :rspec do |mocks|
|
25
|
+
mocks.verify_partial_doubles = true
|
26
|
+
end
|
27
|
+
config.disable_monkey_patching!
|
28
|
+
if config.files_to_run.one?
|
29
|
+
config.default_formatter = 'doc'
|
38
30
|
end
|
31
|
+
config.order = :random
|
39
32
|
end
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine::Definition, '#alias_target' do
|
5
|
+
RSpec.describe FiniteMachine::Definition, '#alias_target' do
|
6
6
|
|
7
7
|
before do
|
8
|
-
Car
|
8
|
+
stub_const("Car", Class.new do
|
9
9
|
def turn_reverse_lights_off
|
10
10
|
@reverse_lights = false
|
11
11
|
end
|
@@ -17,7 +17,7 @@ describe FiniteMachine::Definition, '#alias_target' do
|
|
17
17
|
def reverse_lights?
|
18
18
|
@reverse_lights ||= false
|
19
19
|
end
|
20
|
-
end
|
20
|
+
end)
|
21
21
|
end
|
22
22
|
|
23
23
|
it "aliases target" do
|
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine::Callable, '#call' do
|
5
|
+
RSpec.describe FiniteMachine::Callable, '#call' do
|
6
6
|
|
7
7
|
before(:each) {
|
8
|
-
Car
|
8
|
+
stub_const("Car", Class.new do
|
9
9
|
attr_reader :result
|
10
10
|
|
11
11
|
def initialize
|
@@ -31,7 +31,7 @@ describe FiniteMachine::Callable, '#call' do
|
|
31
31
|
@result = 'engine_on'
|
32
32
|
!!@engine_on
|
33
33
|
end
|
34
|
-
end
|
34
|
+
end)
|
35
35
|
}
|
36
36
|
|
37
37
|
let(:called) { [] }
|
data/spec/unit/callbacks_spec.rb
CHANGED
data/spec/unit/can_spec.rb
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, 'can?' do
|
5
|
+
RSpec.describe FiniteMachine, 'can?' do
|
6
6
|
before(:each) {
|
7
|
-
Bug
|
7
|
+
stub_const("Bug", Class.new do
|
8
8
|
def pending?
|
9
9
|
false
|
10
10
|
end
|
11
|
-
end
|
11
|
+
end)
|
12
12
|
}
|
13
13
|
|
14
14
|
it "allows to check if event can be fired" do
|
data/spec/unit/choice_spec.rb
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, '#choice' do
|
5
|
+
RSpec.describe FiniteMachine, '#choice' do
|
6
6
|
before(:each) {
|
7
|
-
User
|
7
|
+
stub_const("User", Class.new do
|
8
8
|
def promo?(token = false)
|
9
9
|
token == :yes
|
10
10
|
end
|
11
|
-
end
|
11
|
+
end)
|
12
12
|
}
|
13
13
|
|
14
14
|
it "allows for static choice based on conditional branching" do
|
@@ -185,6 +185,34 @@ describe FiniteMachine, '#choice' do
|
|
185
185
|
expect(fsm.current).to eq(:green)
|
186
186
|
end
|
187
187
|
|
188
|
+
it "performs matching transitions for multiple event definitions with the same name" do
|
189
|
+
ticket = double(:ticket, :pending? => true, :finished? => true)
|
190
|
+
fsm = FiniteMachine.define do
|
191
|
+
initial :inactive
|
192
|
+
|
193
|
+
target ticket
|
194
|
+
|
195
|
+
events {
|
196
|
+
event :advance, from: [:inactive, :paused, :fulfilled] do
|
197
|
+
choice :active, if: proc { |_ticket| !_ticket.pending? }
|
198
|
+
end
|
199
|
+
|
200
|
+
event :advance, from: [:inactive, :active, :fulfilled] do
|
201
|
+
choice :paused, if: proc { |_ticket| _ticket.pending? }
|
202
|
+
end
|
203
|
+
|
204
|
+
event :advance, from: [:inactive, :active, :paused] do
|
205
|
+
choice :fulfilled, if: proc { |_ticket| _ticket.finished? }
|
206
|
+
end
|
207
|
+
}
|
208
|
+
end
|
209
|
+
expect(fsm.current).to eq(:inactive)
|
210
|
+
fsm.advance
|
211
|
+
expect(fsm.current).to eq(:paused)
|
212
|
+
fsm.advance
|
213
|
+
expect(fsm.current).to eq(:fulfilled)
|
214
|
+
end
|
215
|
+
|
188
216
|
it "sets callback properties correctly" do
|
189
217
|
expected = {name: :init, from: :none, to: :red, a: nil, b: nil, c: nil }
|
190
218
|
|
data/spec/unit/define_spec.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine::Definition, 'definition' do
|
5
|
+
RSpec.describe FiniteMachine::Definition, 'definition' do
|
6
6
|
|
7
7
|
before do
|
8
8
|
class Engine < FiniteMachine::Definition
|
@@ -42,7 +42,7 @@ describe FiniteMachine::Definition, 'definition' do
|
|
42
42
|
end
|
43
43
|
|
44
44
|
it "allows to create standalone machine" do
|
45
|
-
Car
|
45
|
+
stub_const("Car", Class.new do
|
46
46
|
def turn_reverse_lights_off
|
47
47
|
@reverse_lights = false
|
48
48
|
end
|
@@ -54,7 +54,7 @@ describe FiniteMachine::Definition, 'definition' do
|
|
54
54
|
def reverse_lights?
|
55
55
|
@reverse_lights ||= false
|
56
56
|
end
|
57
|
-
end
|
57
|
+
end)
|
58
58
|
|
59
59
|
car = Car.new
|
60
60
|
engine = Engine.new
|
@@ -63,10 +63,53 @@ describe FiniteMachine::Definition, 'definition' do
|
|
63
63
|
|
64
64
|
engine.forward
|
65
65
|
expect(engine.current).to eq(:one)
|
66
|
-
expect(car.reverse_lights?).to
|
66
|
+
expect(car.reverse_lights?).to eq(false)
|
67
67
|
|
68
68
|
engine.back
|
69
69
|
expect(engine.current).to eq(:reverse)
|
70
|
-
expect(car.reverse_lights?).to
|
70
|
+
expect(car.reverse_lights?).to eq(true)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "supports inheritance of definitions" do
|
74
|
+
class GenericStateMachine < FiniteMachine::Definition
|
75
|
+
initial :red
|
76
|
+
|
77
|
+
events {
|
78
|
+
event :start, :red => :green
|
79
|
+
}
|
80
|
+
|
81
|
+
callbacks {
|
82
|
+
on_enter { |event| target << 'generic' }
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
class SpecificStateMachine < GenericStateMachine
|
87
|
+
events {
|
88
|
+
event :stop, :green => :yellow
|
89
|
+
}
|
90
|
+
|
91
|
+
callbacks {
|
92
|
+
on_enter(:yellow) { |event| target << 'specific' }
|
93
|
+
}
|
94
|
+
end
|
95
|
+
|
96
|
+
generic_fsm = GenericStateMachine.new
|
97
|
+
specific_fsm = SpecificStateMachine.new
|
98
|
+
called = []
|
99
|
+
generic_fsm.target called
|
100
|
+
specific_fsm.target called
|
101
|
+
|
102
|
+
expect(generic_fsm.states).to match_array([:none, :red, :green])
|
103
|
+
expect(specific_fsm.states).to match_array([:none, :red, :green, :yellow])
|
104
|
+
|
105
|
+
expect(specific_fsm.current).to eq(:red)
|
106
|
+
|
107
|
+
specific_fsm.start
|
108
|
+
expect(specific_fsm.current).to eq(:green)
|
109
|
+
expect(called).to match_array(['generic'])
|
110
|
+
|
111
|
+
specific_fsm.stop
|
112
|
+
expect(specific_fsm.current).to eq(:yellow)
|
113
|
+
expect(called).to match_array(['generic', 'generic', 'specific'])
|
71
114
|
end
|
72
115
|
end
|
data/spec/unit/event/add_spec.rb
CHANGED
data/spec/unit/event/eql_spec.rb
CHANGED
data/spec/unit/events_spec.rb
CHANGED
data/spec/unit/handlers_spec.rb
CHANGED
@@ -2,10 +2,10 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, 'handlers' do
|
5
|
+
RSpec.describe FiniteMachine, 'handlers' do
|
6
6
|
|
7
7
|
before(:each) {
|
8
|
-
DummyLogger
|
8
|
+
stub_const("DummyLogger", Class.new do
|
9
9
|
attr_reader :result
|
10
10
|
|
11
11
|
def log_error(exception)
|
@@ -15,7 +15,7 @@ describe FiniteMachine, 'handlers' do
|
|
15
15
|
def raise_error
|
16
16
|
raise FiniteMachine::TransitionError
|
17
17
|
end
|
18
|
-
end
|
18
|
+
end)
|
19
19
|
}
|
20
20
|
|
21
21
|
it "allows to customise error handling" do
|
data/spec/unit/if_unless_spec.rb
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, ':if, :unless' do
|
5
|
+
RSpec.describe FiniteMachine, ':if, :unless' do
|
6
6
|
before(:each) {
|
7
|
-
Car
|
7
|
+
stub_const("Car", Class.new do
|
8
8
|
attr_accessor :engine_on
|
9
9
|
|
10
10
|
def turn_engine_on
|
@@ -18,13 +18,13 @@ describe FiniteMachine, ':if, :unless' do
|
|
18
18
|
def engine_on?
|
19
19
|
!!@engine_on
|
20
20
|
end
|
21
|
-
end
|
21
|
+
end)
|
22
22
|
|
23
|
-
|
23
|
+
stub_const("Bug", Class.new do
|
24
24
|
def pending?
|
25
25
|
false
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end)
|
28
28
|
}
|
29
29
|
|
30
30
|
it "passes context to conditionals" do
|
@@ -2,16 +2,16 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, 'initialize' do
|
5
|
+
RSpec.describe FiniteMachine, 'initialize' do
|
6
6
|
|
7
7
|
before(:each) {
|
8
|
-
DummyLogger
|
8
|
+
stub_const("DummyLogger", Class.new do
|
9
9
|
attr_accessor :level
|
10
10
|
|
11
11
|
def initialize
|
12
12
|
@level = :pending
|
13
13
|
end
|
14
|
-
end
|
14
|
+
end)
|
15
15
|
}
|
16
16
|
|
17
17
|
it "defaults initial state to :none" do
|
data/spec/unit/inspect_spec.rb
CHANGED
data/spec/unit/is_spec.rb
CHANGED
data/spec/unit/logger_spec.rb
CHANGED
@@ -2,14 +2,15 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, '#respond_to' do
|
5
|
+
RSpec.describe FiniteMachine, '#respond_to' do
|
6
6
|
|
7
7
|
subject(:fsm) {
|
8
|
-
Car
|
8
|
+
stub_const("Car", Class.new do
|
9
9
|
def engine_on?
|
10
10
|
true
|
11
11
|
end
|
12
|
-
end
|
12
|
+
end)
|
13
|
+
|
13
14
|
FiniteMachine.new target: Car.new do
|
14
15
|
initial :green
|
15
16
|
|
data/spec/unit/states_spec.rb
CHANGED
data/spec/unit/target_spec.rb
CHANGED
@@ -2,10 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
|
-
describe FiniteMachine, '#target' do
|
6
|
-
|
5
|
+
RSpec.describe FiniteMachine, '#target' do
|
7
6
|
it "allows to target external object" do
|
8
|
-
Car
|
7
|
+
stub_const("Car", Class.new do
|
9
8
|
attr_accessor :reverse_lights
|
10
9
|
|
11
10
|
def turn_reverse_lights_off
|
@@ -45,7 +44,7 @@ describe FiniteMachine, '#target' do
|
|
45
44
|
}
|
46
45
|
end
|
47
46
|
end
|
48
|
-
end
|
47
|
+
end)
|
49
48
|
car = Car.new
|
50
49
|
expect(car.reverse_lights?).to be(false)
|
51
50
|
expect(car.engine.current).to eql(:neutral)
|
@@ -104,7 +103,7 @@ describe FiniteMachine, '#target' do
|
|
104
103
|
end
|
105
104
|
|
106
105
|
it "allows context methods take precedence over machine ones" do
|
107
|
-
Car
|
106
|
+
stub_const("Car", Class.new do
|
108
107
|
attr_accessor :reverse_lights
|
109
108
|
attr_accessor :called
|
110
109
|
|
@@ -147,7 +146,7 @@ describe FiniteMachine, '#target' do
|
|
147
146
|
}
|
148
147
|
end
|
149
148
|
end
|
150
|
-
end
|
149
|
+
end)
|
151
150
|
|
152
151
|
car = Car.new
|
153
152
|
expect(car.reverse_lights?).to be(false)
|
@@ -185,14 +184,14 @@ describe FiniteMachine, '#target' do
|
|
185
184
|
|
186
185
|
it "allows to differentiate between same named methods" do
|
187
186
|
called = []
|
188
|
-
Car
|
187
|
+
stub_const("Car", Class.new do
|
189
188
|
def initialize(called)
|
190
189
|
@called = called
|
191
190
|
end
|
192
191
|
def save
|
193
192
|
@called << 'car save called'
|
194
193
|
end
|
195
|
-
end
|
194
|
+
end)
|
196
195
|
|
197
196
|
car = Car.new(called)
|
198
197
|
fsm = FiniteMachine.define do
|
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.10.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Murach
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -54,6 +54,7 @@ files:
|
|
54
54
|
- lib/finite_machine/choice_merger.rb
|
55
55
|
- lib/finite_machine/definition.rb
|
56
56
|
- lib/finite_machine/dsl.rb
|
57
|
+
- lib/finite_machine/env.rb
|
57
58
|
- lib/finite_machine/event.rb
|
58
59
|
- lib/finite_machine/event_builder.rb
|
59
60
|
- lib/finite_machine/event_queue.rb
|