finite_machine 0.8.0 → 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +31 -9
- data/lib/finite_machine.rb +3 -0
- data/lib/finite_machine/event_builder.rb +80 -0
- data/lib/finite_machine/events_chain.rb +118 -0
- data/lib/finite_machine/state_machine.rb +4 -4
- data/lib/finite_machine/transition.rb +23 -45
- data/lib/finite_machine/version.rb +1 -1
- data/spec/unit/event/inspect_spec.rb +4 -0
- data/spec/unit/events_chain/check_choice_conditions_spec.rb +20 -0
- data/spec/unit/events_chain/clear_spec.rb +26 -0
- data/spec/unit/events_chain/insert_spec.rb +26 -0
- data/spec/unit/events_chain/inspect_spec.rb +27 -0
- data/spec/unit/events_chain/select_transition_spec.rb +23 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b14a2db5bcab11179dbd4cd9abd10826cda11e1
|
4
|
+
data.tar.gz: 1b5046cc5cb28b7cd082bce38088ed34c66d6aba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 340d0ff2ea70b6f54127e06c2d2d6f7fe44309e44f5c8c10125aee29a363d8587890369cca037a7b09d614396f8758919f7b2cea67cdca8f15ed5e2679c1315a
|
7
|
+
data.tar.gz: 0372935e0396e9863700879fb906330d191d2f013d844eae8af58b4853a94b23a6b547c797779da77aeaf71db5fb38d38031ef4f7134864b2708aa900633f06a
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -81,7 +81,8 @@ Or install it yourself as:
|
|
81
81
|
* [6. Errors](#6-errors)
|
82
82
|
* [6.1 Using target](#61-using-target)
|
83
83
|
* [7. Integration](#7-integration)
|
84
|
-
* [7.1
|
84
|
+
* [7.1 Plain Ruby Objects](#71-plain-ruby-objects)
|
85
|
+
* [7.2 ActiveRecord](#72-activerecord)
|
85
86
|
* [8. Tips](#7-tips)
|
86
87
|
|
87
88
|
## 1 Usage
|
@@ -988,12 +989,14 @@ end
|
|
988
989
|
|
989
990
|
## 7 Integration
|
990
991
|
|
991
|
-
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.
|
992
|
+
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.
|
993
|
+
|
994
|
+
### 7.1 Plain Ruby Objects
|
995
|
+
|
996
|
+
In order to use **FiniteMachine** with an object, you need to define a method that will construct the state machine. You can implement the state machine using the `define` DSL or create a seperate object that can be instantiated. To complete integration you will need to specify `target` context to allow state machine to communicate with the other methods inside the class like so:
|
992
997
|
|
993
998
|
```ruby
|
994
999
|
class Car
|
995
|
-
attr_accessor :reverse_lights
|
996
|
-
|
997
1000
|
def turn_reverse_lights_off
|
998
1001
|
@reverse_lights = false
|
999
1002
|
end
|
@@ -1002,6 +1005,10 @@ class Car
|
|
1002
1005
|
@reverse_lights = true
|
1003
1006
|
end
|
1004
1007
|
|
1008
|
+
def reverse_lights_on?
|
1009
|
+
@reverse_lights || false
|
1010
|
+
end
|
1011
|
+
|
1005
1012
|
def gears
|
1006
1013
|
context = self
|
1007
1014
|
@gears ||= FiniteMachine.define do
|
@@ -1034,7 +1041,21 @@ class Car
|
|
1034
1041
|
end
|
1035
1042
|
```
|
1036
1043
|
|
1037
|
-
|
1044
|
+
Having written the class, you can use it as follows:
|
1045
|
+
|
1046
|
+
```ruby
|
1047
|
+
car = Car.new
|
1048
|
+
car.gears.current # => :neutral
|
1049
|
+
car.reverse_lights_on? # => false
|
1050
|
+
|
1051
|
+
car.gears.start # => "shifted from neutral to one"
|
1052
|
+
|
1053
|
+
car.gears.back # => "shifted from one to reverse"
|
1054
|
+
car.gears.current # => :reverse
|
1055
|
+
car.reverse_lights_on? # => true
|
1056
|
+
```
|
1057
|
+
|
1058
|
+
### 7.2 ActiveRecord
|
1038
1059
|
|
1039
1060
|
In order to integrate **FiniteMachine** with ActiveRecord use the `target` helper to reference the current class and call ActiveRecord methods inside the callbacks to persist the state.
|
1040
1061
|
|
@@ -1042,8 +1063,9 @@ In order to integrate **FiniteMachine** with ActiveRecord use the `target` helpe
|
|
1042
1063
|
class Account < ActiveRecord::Base
|
1043
1064
|
validates :state, presence: true
|
1044
1065
|
|
1045
|
-
def initialize
|
1046
|
-
|
1066
|
+
def initialize(attrs = {})
|
1067
|
+
super
|
1068
|
+
@manage.restore!(state) if state
|
1047
1069
|
end
|
1048
1070
|
|
1049
1071
|
def manage
|
@@ -1051,7 +1073,7 @@ class Account < ActiveRecord::Base
|
|
1051
1073
|
@manage ||= FiniteMachine.define do
|
1052
1074
|
target context
|
1053
1075
|
|
1054
|
-
initial
|
1076
|
+
initial :unapproved
|
1055
1077
|
|
1056
1078
|
events {
|
1057
1079
|
event :enqueue, :unapproved => :pending
|
@@ -1060,7 +1082,7 @@ class Account < ActiveRecord::Base
|
|
1060
1082
|
|
1061
1083
|
callbacks {
|
1062
1084
|
on_enter_state do |event|
|
1063
|
-
state = event.to
|
1085
|
+
self.state = event.to
|
1064
1086
|
save
|
1065
1087
|
end
|
1066
1088
|
}
|
data/lib/finite_machine.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require "logger"
|
4
4
|
require "thread"
|
5
5
|
require "sync"
|
6
|
+
require "forwardable"
|
6
7
|
|
7
8
|
require "finite_machine/version"
|
8
9
|
require "finite_machine/threadable"
|
@@ -15,7 +16,9 @@ require "finite_machine/async_proxy"
|
|
15
16
|
require "finite_machine/async_call"
|
16
17
|
require "finite_machine/hook_event"
|
17
18
|
require "finite_machine/event"
|
19
|
+
require "finite_machine/event_builder"
|
18
20
|
require "finite_machine/event_queue"
|
21
|
+
require "finite_machine/events_chain"
|
19
22
|
require "finite_machine/hooks"
|
20
23
|
require "finite_machine/logger"
|
21
24
|
require "finite_machine/transition"
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FiniteMachine
|
4
|
+
# A class responsible for building event methods
|
5
|
+
class EventBuilder
|
6
|
+
include Threadable
|
7
|
+
include Safety
|
8
|
+
|
9
|
+
# The current state machine
|
10
|
+
attr_threadsafe :machine
|
11
|
+
|
12
|
+
# Initialize an EventBuilder
|
13
|
+
#
|
14
|
+
# @param [FiniteMachine::StateMachine] machine
|
15
|
+
#
|
16
|
+
# @api private
|
17
|
+
def initialize(machine)
|
18
|
+
@machine = machine
|
19
|
+
end
|
20
|
+
|
21
|
+
# Build state machine events
|
22
|
+
#
|
23
|
+
# @param [FiniteMachine::Transition] transition
|
24
|
+
# the transition for which event is build
|
25
|
+
#
|
26
|
+
# @return [FiniteMachine::Transition]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
def call(transition)
|
30
|
+
name = transition.name
|
31
|
+
detect_event_conflict!(name)
|
32
|
+
if machine.singleton_class.send(:method_defined?, name)
|
33
|
+
machine.events_chain.insert(name, transition)
|
34
|
+
else
|
35
|
+
define_event_transition(name, transition)
|
36
|
+
define_event_bang(name)
|
37
|
+
end
|
38
|
+
transition
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Define transition event
|
44
|
+
#
|
45
|
+
# @param [Symbol] name
|
46
|
+
# the event name
|
47
|
+
#
|
48
|
+
# @param [FiniteMachine::Transition] transition
|
49
|
+
# the transition this event is associated with
|
50
|
+
#
|
51
|
+
# @return [nil]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
def define_event_transition(name, transition)
|
55
|
+
silent = transition.silent
|
56
|
+
_event = FiniteMachine::Event.new(machine, name: name, silent: silent)
|
57
|
+
_event << transition
|
58
|
+
machine.events_chain.add(name, _event)
|
59
|
+
|
60
|
+
machine.send(:define_singleton_method, name) do |*args, &block|
|
61
|
+
_event.call(*args, &block)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Define event that skips validations
|
66
|
+
#
|
67
|
+
# @param [Symbol] name
|
68
|
+
# the event name
|
69
|
+
#
|
70
|
+
# @return [nil]
|
71
|
+
#
|
72
|
+
# @api private
|
73
|
+
def define_event_bang(name)
|
74
|
+
machine.send(:define_singleton_method, "#{name}!") do
|
75
|
+
transitions = machine.transitions[name]
|
76
|
+
machine.state = transitions.values[0]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end # EventBuilder
|
80
|
+
end # FiniteMachine
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module FiniteMachine
|
4
|
+
# A class responsible for storing chain of events
|
5
|
+
class EventsChain
|
6
|
+
include Threadable
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
# The current state machine
|
10
|
+
attr_threadsafe :machine
|
11
|
+
|
12
|
+
# The chain of events
|
13
|
+
attr_threadsafe :chain
|
14
|
+
|
15
|
+
def_delegators :@chain, :[], :empty?
|
16
|
+
|
17
|
+
# Initialize a EventsChain
|
18
|
+
#
|
19
|
+
# @param [FiniteMachine::StateMachine] machine
|
20
|
+
# the state machine
|
21
|
+
#
|
22
|
+
# @api public
|
23
|
+
def initialize(machine)
|
24
|
+
@machine = machine
|
25
|
+
@chain = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Insert transition under given event name
|
29
|
+
#
|
30
|
+
# @param [Symbol] name
|
31
|
+
# the event name
|
32
|
+
#
|
33
|
+
# @param [FiniteMachine::Transition]
|
34
|
+
#
|
35
|
+
# @return [nil]
|
36
|
+
#
|
37
|
+
# @api public
|
38
|
+
def insert(name, transition)
|
39
|
+
return false unless chain[name]
|
40
|
+
chain[name] << transition
|
41
|
+
end
|
42
|
+
|
43
|
+
# Add event under name
|
44
|
+
#
|
45
|
+
# @return [nil]
|
46
|
+
#
|
47
|
+
# @api public
|
48
|
+
def add(name, event)
|
49
|
+
chain[name] = event
|
50
|
+
end
|
51
|
+
|
52
|
+
# Check if event is valid and transition can be performed
|
53
|
+
#
|
54
|
+
# @return [Boolean]
|
55
|
+
#
|
56
|
+
# @api public
|
57
|
+
def valid_event?(event, *args, &block)
|
58
|
+
chain[event].next_transition.valid?(*args, &block)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Select transition that passes constraints condition
|
62
|
+
#
|
63
|
+
# @param [Symbol] name
|
64
|
+
# the event name
|
65
|
+
#
|
66
|
+
# @return [FiniteMachine::Transition]
|
67
|
+
#
|
68
|
+
# @api public
|
69
|
+
def select_transition(name, *args)
|
70
|
+
chain[name].find_transition(*args)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Check if any of the transition constraints passes
|
74
|
+
#
|
75
|
+
# @param [Symbol] name
|
76
|
+
# the event name
|
77
|
+
#
|
78
|
+
# @return [Boolean]
|
79
|
+
#
|
80
|
+
# @api public
|
81
|
+
def check_choice_conditions(name, *args, &block)
|
82
|
+
chain[name].state_transitions.any? do |trans|
|
83
|
+
trans.check_conditions(*args, &block)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Reset chain
|
88
|
+
#
|
89
|
+
# @return [self]
|
90
|
+
#
|
91
|
+
# @api public
|
92
|
+
def clear
|
93
|
+
@chain.clear
|
94
|
+
self
|
95
|
+
end
|
96
|
+
|
97
|
+
# Return string representation of this chain
|
98
|
+
#
|
99
|
+
# @return [String]
|
100
|
+
#
|
101
|
+
# @api public
|
102
|
+
def to_s
|
103
|
+
chain.to_s
|
104
|
+
end
|
105
|
+
|
106
|
+
# Inspect chain content
|
107
|
+
#
|
108
|
+
# @example
|
109
|
+
# events_chain.inspect
|
110
|
+
#
|
111
|
+
# @return [String]
|
112
|
+
#
|
113
|
+
# @api public
|
114
|
+
def inspect
|
115
|
+
"<##{self.class} @chain=#{chain.inspect}>"
|
116
|
+
end
|
117
|
+
end # EventsChain
|
118
|
+
end # FiniteMachine
|
@@ -1,7 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
require 'forwardable'
|
4
|
-
|
5
3
|
module FiniteMachine
|
6
4
|
# Base class for state machine
|
7
5
|
class StateMachine
|
@@ -47,6 +45,8 @@ module FiniteMachine
|
|
47
45
|
|
48
46
|
def_delegator :@events_dsl, :event
|
49
47
|
|
48
|
+
def_delegators :@events_chain, :check_choice_conditions, :select_transition
|
49
|
+
|
50
50
|
# Initialize state machine
|
51
51
|
#
|
52
52
|
# @api private
|
@@ -58,7 +58,7 @@ module FiniteMachine
|
|
58
58
|
@errors = ErrorsDSL.new(self)
|
59
59
|
@observer = Observer.new(self)
|
60
60
|
@transitions = Hash.new { |hash, name| hash[name] = Hash.new }
|
61
|
-
@events_chain =
|
61
|
+
@events_chain = EventsChain.new(self)
|
62
62
|
@env = Environment.new(target: self)
|
63
63
|
@dsl = DSL.new(self, attributes)
|
64
64
|
|
@@ -177,7 +177,7 @@ module FiniteMachine
|
|
177
177
|
event = args.shift
|
178
178
|
valid_state = transitions[event].key?(current)
|
179
179
|
valid_state ||= transitions[event].key?(ANY_STATE)
|
180
|
-
valid_state &&= events_chain
|
180
|
+
valid_state &&= events_chain.valid_event?(event, *args, &block)
|
181
181
|
end
|
182
182
|
|
183
183
|
# Checks if event cannot be triggered
|
@@ -4,7 +4,6 @@ module FiniteMachine
|
|
4
4
|
# Class describing a transition associated with a given event
|
5
5
|
class Transition
|
6
6
|
include Threadable
|
7
|
-
include Safety
|
8
7
|
|
9
8
|
attr_threadsafe :name
|
10
9
|
|
@@ -67,8 +66,9 @@ module FiniteMachine
|
|
67
66
|
_transition = new(machine, attrs)
|
68
67
|
_transition.update_transitions
|
69
68
|
_transition.define_state_methods
|
70
|
-
|
71
|
-
|
69
|
+
|
70
|
+
builder = EventBuilder.new(machine)
|
71
|
+
builder.call(_transition)
|
72
72
|
end
|
73
73
|
|
74
74
|
# Decide :to state from available transitions for this event
|
@@ -77,8 +77,8 @@ module FiniteMachine
|
|
77
77
|
#
|
78
78
|
# @api public
|
79
79
|
def to_state(*args)
|
80
|
-
if
|
81
|
-
found_trans = machine.
|
80
|
+
if transition_choice?
|
81
|
+
found_trans = machine.select_transition(name, *args)
|
82
82
|
found_trans.map[from_state]
|
83
83
|
else
|
84
84
|
machine.transitions[name][from_state]
|
@@ -116,6 +116,15 @@ module FiniteMachine
|
|
116
116
|
map[state] == state || (map[ANY_STATE] == state && from_state == state)
|
117
117
|
end
|
118
118
|
|
119
|
+
# Check if this transition has branching choice or not
|
120
|
+
#
|
121
|
+
# @return [Boolean]
|
122
|
+
#
|
123
|
+
# @api public
|
124
|
+
def transition_choice?
|
125
|
+
machine.transitions[name][from_state].is_a?(Array)
|
126
|
+
end
|
127
|
+
|
119
128
|
# Check if transition can be performed according to constraints
|
120
129
|
#
|
121
130
|
# @param [Array] args
|
@@ -126,10 +135,8 @@ module FiniteMachine
|
|
126
135
|
#
|
127
136
|
# @api public
|
128
137
|
def valid?(*args, &block)
|
129
|
-
if
|
130
|
-
machine.
|
131
|
-
trans.check_conditions(*args, &block)
|
132
|
-
end
|
138
|
+
if transition_choice?
|
139
|
+
machine.check_choice_conditions(name, *args, &block)
|
133
140
|
else
|
134
141
|
check_conditions(*args, &block)
|
135
142
|
end
|
@@ -169,39 +176,16 @@ module FiniteMachine
|
|
169
176
|
end
|
170
177
|
end
|
171
178
|
|
172
|
-
#
|
179
|
+
# Set state on the machine
|
173
180
|
#
|
174
181
|
# @api private
|
175
|
-
def
|
176
|
-
|
177
|
-
|
178
|
-
machine.
|
182
|
+
def update_state(*args)
|
183
|
+
if transition_choice?
|
184
|
+
found_trans = machine.select_transition(name, *args)
|
185
|
+
machine.state = found_trans.to_states.first
|
179
186
|
else
|
180
|
-
define_event_transition(name)
|
181
|
-
define_event_bang(name)
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
# Define transition event
|
186
|
-
#
|
187
|
-
# @api private
|
188
|
-
def define_event_transition(name)
|
189
|
-
_event = FiniteMachine::Event.new(machine, name: name, silent: silent)
|
190
|
-
_event << self
|
191
|
-
machine.events_chain[name] = _event
|
192
|
-
|
193
|
-
machine.send(:define_singleton_method, name) do |*args, &block|
|
194
|
-
_event.call(*args, &block)
|
195
|
-
end
|
196
|
-
end
|
197
|
-
|
198
|
-
# Define event that skips validations
|
199
|
-
#
|
200
|
-
# @api private
|
201
|
-
def define_event_bang(name)
|
202
|
-
machine.send(:define_singleton_method, "#{name}!") do
|
203
187
|
transitions = machine.transitions[name]
|
204
|
-
machine.state = transitions.
|
188
|
+
machine.state = transitions[machine.state] || transitions[ANY_STATE] || name
|
205
189
|
end
|
206
190
|
end
|
207
191
|
|
@@ -213,14 +197,8 @@ module FiniteMachine
|
|
213
197
|
def call(*args)
|
214
198
|
sync_exclusive do
|
215
199
|
return if cancelled
|
216
|
-
transitions = machine.transitions[name]
|
217
200
|
self.from_state = machine.state
|
218
|
-
|
219
|
-
found_trans = machine.events_chain[name].find_transition(*args)
|
220
|
-
machine.state = found_trans.to_states.first
|
221
|
-
else
|
222
|
-
machine.state = transitions[machine.state] || transitions[ANY_STATE] || name
|
223
|
-
end
|
201
|
+
update_state(*args)
|
224
202
|
machine.initial_state = machine.state if from_state == DEFAULT_STATE
|
225
203
|
end
|
226
204
|
end
|
@@ -14,4 +14,8 @@ describe FiniteMachine::Event, '#inspect' do
|
|
14
14
|
event << transition
|
15
15
|
expect(event.inspect).to eq("<#FiniteMachine::Event @name=test, @transitions=[#{transition.inspect}]>")
|
16
16
|
end
|
17
|
+
|
18
|
+
it "prints event name" do
|
19
|
+
expect(event.to_s).to eq('test')
|
20
|
+
end
|
17
21
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::EventsChain, '#clear' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:machine) { double(:machine) }
|
9
|
+
|
10
|
+
subject(:chain) { object.new(machine) }
|
11
|
+
|
12
|
+
it "clears chain events" do
|
13
|
+
event = double(:event)
|
14
|
+
chain.add(:validated, event)
|
15
|
+
expect(chain.empty?).to be_false
|
16
|
+
|
17
|
+
chain.clear
|
18
|
+
expect(chain.empty?).to be_true
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::EventsChain, '#insert' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:machine) { double(:machine) }
|
9
|
+
|
10
|
+
let(:transition) { double(:transition) }
|
11
|
+
|
12
|
+
subject(:chain) { object.new(machine) }
|
13
|
+
|
14
|
+
it "inserts transition" do
|
15
|
+
event = double(:event)
|
16
|
+
chain.add(:validated, event)
|
17
|
+
expect(chain[:validated]).to eq(event)
|
18
|
+
|
19
|
+
expect(event).to receive(:<<).with(transition)
|
20
|
+
chain.insert(:validated, transition)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "fails to insert transition" do
|
24
|
+
expect(chain.insert(:validated, transition)).to be_false
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::EventsChain, '#insert' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:machine) { double(:machine) }
|
9
|
+
|
10
|
+
let(:transition) { double(:transition) }
|
11
|
+
|
12
|
+
subject(:chain) { object.new(machine) }
|
13
|
+
|
14
|
+
it "inserts transition" do
|
15
|
+
event = double(:event)
|
16
|
+
chain.add(:validated, event)
|
17
|
+
expect(chain[:validated]).to eq(event)
|
18
|
+
|
19
|
+
expect(event).to receive(:<<).with(transition)
|
20
|
+
chain.insert(:validated, transition)
|
21
|
+
end
|
22
|
+
|
23
|
+
it "fails to insert transition" do
|
24
|
+
expect(chain.insert(:validated, transition)).to be_false
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::EventsChain, '#insert' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:machine) { double(:machine) }
|
9
|
+
|
10
|
+
subject(:chain) { object.new(machine) }
|
11
|
+
|
12
|
+
it "inspects empty chain" do
|
13
|
+
expect(chain.inspect).to eq("<#FiniteMachine::EventsChain @chain={}>")
|
14
|
+
end
|
15
|
+
|
16
|
+
it "inspect chain" do
|
17
|
+
event = double(:event)
|
18
|
+
chain.add(:validated, event)
|
19
|
+
expect(chain.inspect).to eq("<#FiniteMachine::EventsChain @chain=#{{validated: event}}>")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "prints chain" do
|
23
|
+
event = double(:event)
|
24
|
+
chain.add(:validated, event)
|
25
|
+
expect(chain.to_s).to eq("#{{validated: event}}")
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe FiniteMachine::EventsChain, '#select_transition' do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
let(:machine) { double(:machine) }
|
9
|
+
|
10
|
+
let(:transition) { double(:transition) }
|
11
|
+
|
12
|
+
subject(:chain) { object.new(machine) }
|
13
|
+
|
14
|
+
it "selects transition" do
|
15
|
+
event = double(:event)
|
16
|
+
args = double(:args)
|
17
|
+
chain.add(:validated, event)
|
18
|
+
expect(chain[:validated]).to eq(event)
|
19
|
+
|
20
|
+
expect(event).to receive(:find_transition).with(args)
|
21
|
+
chain.select_transition(:validated, args)
|
22
|
+
end
|
23
|
+
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.8.
|
4
|
+
version: 0.8.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: 2014-
|
11
|
+
date: 2014-07-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -54,7 +54,9 @@ files:
|
|
54
54
|
- lib/finite_machine/choice_merger.rb
|
55
55
|
- lib/finite_machine/dsl.rb
|
56
56
|
- lib/finite_machine/event.rb
|
57
|
+
- lib/finite_machine/event_builder.rb
|
57
58
|
- lib/finite_machine/event_queue.rb
|
59
|
+
- lib/finite_machine/events_chain.rb
|
58
60
|
- lib/finite_machine/hook_event.rb
|
59
61
|
- lib/finite_machine/hooks.rb
|
60
62
|
- lib/finite_machine/listener.rb
|
@@ -80,6 +82,11 @@ files:
|
|
80
82
|
- spec/unit/event/inspect_spec.rb
|
81
83
|
- spec/unit/event/next_transition_spec.rb
|
82
84
|
- spec/unit/event_queue_spec.rb
|
85
|
+
- spec/unit/events_chain/check_choice_conditions_spec.rb
|
86
|
+
- spec/unit/events_chain/clear_spec.rb
|
87
|
+
- spec/unit/events_chain/insert_spec.rb
|
88
|
+
- spec/unit/events_chain/inspect_spec.rb
|
89
|
+
- spec/unit/events_chain/select_transition_spec.rb
|
83
90
|
- spec/unit/events_spec.rb
|
84
91
|
- spec/unit/finished_spec.rb
|
85
92
|
- spec/unit/handlers_spec.rb
|
@@ -138,6 +145,11 @@ test_files:
|
|
138
145
|
- spec/unit/event/inspect_spec.rb
|
139
146
|
- spec/unit/event/next_transition_spec.rb
|
140
147
|
- spec/unit/event_queue_spec.rb
|
148
|
+
- spec/unit/events_chain/check_choice_conditions_spec.rb
|
149
|
+
- spec/unit/events_chain/clear_spec.rb
|
150
|
+
- spec/unit/events_chain/insert_spec.rb
|
151
|
+
- spec/unit/events_chain/inspect_spec.rb
|
152
|
+
- spec/unit/events_chain/select_transition_spec.rb
|
141
153
|
- spec/unit/events_spec.rb
|
142
154
|
- spec/unit/finished_spec.rb
|
143
155
|
- spec/unit/handlers_spec.rb
|