simply_fsm 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eb54d24c49d69bc4cb382e6c4181a586fe9eef471dd1e44bcef0d95555fb33ae
4
- data.tar.gz: 2f336e971e10827c1b731948376b4f2a177e012093c3f66457380df21c0f110c
3
+ metadata.gz: e96963bd4f2d0cf605ca52b79cc74c3b3ba29d66df452683c6425f6e4243cf62
4
+ data.tar.gz: ca0ad99246f5f27eb9749ba2dd41c652bd424c55828cdeb4f6365478d8866488
5
5
  SHA512:
6
- metadata.gz: 9afdd28a4281a6d6c4d40abe7d52e5ab674e9bf1e626a9bc2bf47ee678e047f0fd3c4e5ab3f6857a01fc6fd6647a5eab416a6cc1c03f7ebbbdda1a72b6b1d71b
7
- data.tar.gz: 21c938cbced1efb61d61c0cc62c4887d1f8084c4b42c6bc2effd0cda358a9cbade73a958250fdb9d81a17a183ed2b092e7d6896ae043fc1dfcc2afa7c9914134
6
+ metadata.gz: 37de0fd3446033ef390fb8aa6bf616c936de2125e65b876724904b989163d816f52971198a5fb2055a9412589565633a5fbaaa93eaed35912da549bc366d1446
7
+ data.tar.gz: 97165581f0a8f1955ffbb568d99958e84a99de955041ead58b52a5ed100eee52fd8cc58175f32702a11c0d4d9c86a62ff858cc306b3b3a0efd52ec5e3cfdcf02
data/.gitignore CHANGED
@@ -10,3 +10,6 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+
14
+ # Mac temps
15
+ .DS_Store
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
- --format documentation
1
+ --format progress
2
2
  --color
3
3
  --require spec_helper
data/.yardopts ADDED
@@ -0,0 +1 @@
1
+ --no-private
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
2
2
 
3
3
  - None right now
4
4
 
5
+ ## [0.3.0]
6
+
7
+ - Moving main source under the `lib/simply_fsm` folder to remove `require` statement
8
+ - Why? Eventually want to be able to use this with `mruby`
9
+
10
+ ## [0.2.3] - 2022-04-09
11
+
12
+ - Add `rake yard` to generate local documentation
13
+ - Clean up API documentation
14
+ - Privatise some internal methods
15
+
16
+ ## [0.2.2] - 2022-03-08
17
+
18
+ - Call `fail` lambda without wrapping it in a lambda
19
+
20
+ ## [0.2.1] - 2022-03-05
21
+
22
+ - Fixed bug where named fail handlers were not called properly for multi-transition events.
23
+
5
24
  ## [0.2.0] - 2022-03-01
6
25
 
7
26
  - *Breaks API* (sorry!)
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- simply_fsm (0.1.1)
4
+ simply_fsm (0.3.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -46,6 +46,9 @@ GEM
46
46
  ruby-progressbar (1.11.0)
47
47
  stringio (3.0.1)
48
48
  unicode-display_width (2.1.0)
49
+ webrick (1.7.0)
50
+ yard (0.9.27)
51
+ webrick (~> 1.7.0)
49
52
 
50
53
  PLATFORMS
51
54
  ruby
@@ -56,6 +59,7 @@ DEPENDENCIES
56
59
  rspec (~> 3.0)
57
60
  rubocop (~> 1.21)
58
61
  simply_fsm!
62
+ yard
59
63
 
60
64
  BUNDLED WITH
61
65
  2.1.4
data/Rakefile CHANGED
@@ -17,6 +17,13 @@ Rake::RDocTask.new do |rdoc|
17
17
  rdoc.rdoc_files.include("lib/**/*.rb")
18
18
  end
19
19
 
20
+ require "yard"
21
+
22
+ YARD::Rake::YardocTask.new do |t|
23
+ t.files = ["lib/**/*.rb"]
24
+ t.stats_options = ["--list-undoc"]
25
+ end
26
+
20
27
  RuboCop::RakeTask.new
21
28
 
22
29
  task default: %i[spec rubocop]
@@ -0,0 +1,278 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Include *SimplyFSM* in a class to be able to defined state machines.
5
+ #
6
+ module SimplyFSM
7
+ #
8
+ # Provides a +state_machine+ for the including class.
9
+ def self.included(base)
10
+ base.extend(ClassMethods)
11
+ end
12
+
13
+ #
14
+ # Defines the constructor for defining a state machine
15
+ module ClassMethods
16
+ #
17
+ # Declare a state machine called +name+ which can then be defined
18
+ # by a DSL defined by the methods of *StateMachine*.
19
+ #
20
+ # @param [String] name of the state machine.
21
+ # @param [Hash] opts to specify options such as:
22
+ # - +fail+ lambda that is called with the event name when any event fails to transition
23
+ #
24
+ def state_machine(name, opts = {}, &block)
25
+ fsm = StateMachine.new(name, self, fail: opts[:fail])
26
+ fsm.instance_eval(&block)
27
+ end
28
+ end
29
+
30
+ ##
31
+ # The DSL for defining a state machine. These methods are used within the declaration of a +state_machine+.
32
+ #
33
+ # @attr_reader [String] initial_state The initial state of the state machine
34
+ # @attr_reader [Array] states All the states of the state machine
35
+ # @attr_reader [Array] events All the events of the state machine
36
+ # @attr_reader [String] name
37
+ # @attr_reader [String] full_name The name of the owning class combined with the state machine's name
38
+ #
39
+ class StateMachine
40
+ attr_reader :initial_state, :states, :events, :name, :full_name
41
+
42
+ #
43
+ # @!visibility private
44
+ def initialize(name, owner_class, fail: nil)
45
+ @owner_class = owner_class
46
+ @name = name.to_sym
47
+ @full_name = "#{owner_class.name}/#{name}"
48
+ @states = []
49
+ @events = []
50
+ @initial_state = nil
51
+ @fail_handler = fail
52
+
53
+ setup_base_methods
54
+ end
55
+
56
+ #
57
+ # Declare a supported +state_name+, and optionally specify one as the +initial+ state.
58
+ #
59
+ # @param [String] state_name
60
+ # @param [Boolean] initial to indicate if this is the initial state of the state machine
61
+ #
62
+ def state(state_name, initial: false)
63
+ return if state_name.nil? || @states.include?(state_name)
64
+
65
+ status = state_name.to_sym
66
+ state_machine_name = @name
67
+ @states << status
68
+ @initial_state = status if initial
69
+
70
+ make_owner_method "#{state_name}?", lambda {
71
+ send(state_machine_name) == status
72
+ }
73
+ end
74
+
75
+ ##
76
+ # Define an event by +event_name+
77
+ #
78
+ # @param [String] event_name
79
+ # @param [Hash,Array] transitions either one (Hash) or many (Array of Hashes) transitions +from+ one state +to+ another state.
80
+ # @param [Lambda] guard if specified must return +true+ before any transitions are attempted
81
+ # @param [Lambda] fail called with event name if specified when all the attempted transitions fail
82
+ # @yield when the transition attempt succeeds.
83
+ def event(event_name, transitions:, guard: nil, fail: nil, &after)
84
+ return unless event_exists?(event_name) && transitions
85
+
86
+ @events << event_name
87
+ may_event_name = "may_#{event_name}?"
88
+
89
+ if transitions.is_a?(Array)
90
+ setup_multi_transition_may_event_method transitions: transitions, guard: guard,
91
+ may_event_name: may_event_name
92
+ setup_multi_transition_event_method event_name,
93
+ transitions: transitions, guard: guard,
94
+ var_name: "@#{@name}", fail: fail || @fail_handler
95
+ return
96
+ end
97
+
98
+ to = transitions[:to]
99
+ setup_may_event_method may_event_name, transitions[:from] || :any, transitions[:when], guard
100
+ setup_event_method event_name, var_name: "@#{@name}",
101
+ may_event_name: may_event_name, to: to,
102
+ fail: fail || @fail_handler, &after
103
+ end
104
+
105
+ private
106
+
107
+ def setup_multi_transition_may_event_method(transitions:, guard:, may_event_name:)
108
+ state_machine_name = @name
109
+
110
+ make_owner_method may_event_name, lambda {
111
+ if !guard || instance_exec(&guard)
112
+ current = send(state_machine_name)
113
+ # Check each transition, and first one that succeeds ends the scan
114
+ transitions.each do |t|
115
+ next if cannot_transition?(t[:from], t[:when], current)
116
+
117
+ return true
118
+ end
119
+ end
120
+ false
121
+ }
122
+ end
123
+
124
+ def setup_fail_lambda_for(fail)
125
+ return unless fail
126
+
127
+ if fail.is_a?(String) || fail.is_a?(Symbol)
128
+ ->(event_name) { send(fail, event_name) }
129
+ else
130
+ fail
131
+ end
132
+ end
133
+
134
+ def setup_multi_transition_event_method(event_name, transitions:, guard:, var_name:, fail:)
135
+ state_machine_name = @name
136
+ fail_lambda = setup_fail_lambda_for(fail)
137
+ make_owner_method event_name, lambda {
138
+ if !guard || instance_exec(&guard)
139
+ current = send(state_machine_name)
140
+ # Check each transition, and first one that succeeds ends the scan
141
+ transitions.each do |t|
142
+ next if cannot_transition?(t[:from], t[:when], current)
143
+
144
+ instance_variable_set(var_name, t[:to])
145
+ return true
146
+ end
147
+ end
148
+ instance_exec(event_name, &fail_lambda) if fail_lambda
149
+ false
150
+ }
151
+ end
152
+
153
+ def event_exists?(event_name)
154
+ event_name && !@events.include?(event_name)
155
+ end
156
+
157
+ def setup_event_method(event_name, var_name:, may_event_name:, to:, fail:, &after)
158
+ fail_lambda = setup_fail_lambda_for(fail)
159
+ method_lambda = lambda {
160
+ if send(may_event_name)
161
+ instance_variable_set(var_name, to)
162
+ instance_exec(&after) if after
163
+ return true
164
+ end
165
+ instance_exec(event_name, &fail_lambda) if fail_lambda
166
+ false
167
+ }
168
+ make_owner_method event_name, method_lambda
169
+ end
170
+
171
+ def setup_may_event_method(may_event_name, from, cond, guard)
172
+ state_machine_name = @name
173
+ #
174
+ # Instead of one "may_event?" method that checks all variations every time it's called, here we check
175
+ # the event definition and define the most optimal lambda to ensure the check is as fast as possible
176
+ method_lambda = if from == :any
177
+ from_any_may_event_lambda(guard, cond, state_machine_name)
178
+ else
179
+ guarded_or_conditional_may_event_lambda(from, guard, cond, state_machine_name)
180
+ end
181
+ make_owner_method may_event_name, method_lambda
182
+ end
183
+
184
+ def from_any_may_event_lambda(guard, cond, _state_machine_name)
185
+ if !guard && !cond
186
+ -> { true } # unguarded transition from any state
187
+ elsif !cond
188
+ guard # guarded transition from any state
189
+ elsif !guard
190
+ cond # conditional unguarded transition from any state
191
+ else
192
+ -> { instance_exec(&guard) && instance_exec(&cond) }
193
+ end
194
+ end
195
+
196
+ def guarded_or_conditional_may_event_lambda(from, guard, cond, state_machine_name)
197
+ if !guard && !cond
198
+ guardless_may_event_lambda(from, state_machine_name)
199
+ elsif !cond
200
+ guarded_may_event_lambda(from, guard, state_machine_name)
201
+ elsif !guard
202
+ guarded_may_event_lambda(from, cond, state_machine_name)
203
+ else
204
+ guarded_and_conditional_may_event_lambda(from, guard, cond, state_machine_name)
205
+ end
206
+ end
207
+
208
+ def guarded_may_event_lambda(from, guard, state_machine_name)
209
+ if from.is_a?(Array)
210
+ lambda { # guarded transition from choice of states
211
+ current = send(state_machine_name)
212
+ from.include?(current) && instance_exec(&guard)
213
+ }
214
+ else
215
+ lambda { # guarded transition from one state
216
+ current = send(state_machine_name)
217
+ from == current && instance_exec(&guard)
218
+ }
219
+ end
220
+ end
221
+
222
+ def guarded_and_conditional_may_event_lambda(from, guard, cond, state_machine_name)
223
+ if from.is_a?(Array)
224
+ lambda { # guarded transition from choice of states
225
+ current = send(state_machine_name)
226
+ from.include?(current) && instance_exec(&guard) && instance_exec(&cond)
227
+ }
228
+ else
229
+ lambda { # guarded transition from one state
230
+ current = send(state_machine_name)
231
+ from == current && instance_exec(&guard) && instance_exec(&cond)
232
+ }
233
+ end
234
+ end
235
+
236
+ def guardless_may_event_lambda(from, state_machine_name)
237
+ if from.is_a?(Array)
238
+ lambda { # unguarded transition from choice of states
239
+ current = send(state_machine_name)
240
+ from.include?(current)
241
+ }
242
+ else
243
+ lambda { # unguarded transition from one state
244
+ current = send(state_machine_name)
245
+ from == current
246
+ }
247
+ end
248
+ end
249
+
250
+ def setup_base_methods
251
+ var_name = "@#{name}"
252
+ fsm = self
253
+ make_owner_method @name, lambda {
254
+ instance_variable_get(var_name) ||
255
+ fsm.initial_state
256
+ }
257
+ make_owner_method "#{@name}_states", -> { fsm.states }
258
+ make_owner_method "#{@name}_events", -> { fsm.events }
259
+ end
260
+
261
+ def make_owner_method(method_name, method_definition)
262
+ @owner_class.define_method(method_name, method_definition)
263
+ end
264
+ end
265
+
266
+ private
267
+
268
+ def state_match?(from, current)
269
+ return true if from == :any
270
+ return from.include?(current) if from.is_a?(Array)
271
+
272
+ from == current
273
+ end
274
+
275
+ def cannot_transition?(from, cond, current)
276
+ (from && !state_match?(from, current)) || (cond && !instance_exec(&cond))
277
+ end
278
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimplyFSM
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/simply_fsm.rb CHANGED
@@ -1,252 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "simply_fsm/version"
4
-
5
- ##
6
- # Defines the `SimplyFSM` module
7
- module SimplyFSM
8
- def self.included(base)
9
- base.extend(ClassMethods)
10
- end
11
-
12
- def state_match?(from, current)
13
- return true if from == :any
14
- return from.include?(current) if from.is_a?(Array)
15
-
16
- from == current
17
- end
18
-
19
- def cannot_transition?(from, cond, current)
20
- (from && !state_match?(from, current)) || (cond && !instance_exec(&cond))
21
- end
22
-
23
- ##
24
- # Defines the constructor for defining a state machine
25
- module ClassMethods
26
- ##
27
- # Declare a state machine called +name+ which can then be defined
28
- # by a DSL defined by the methods of `StateMachine`, with the following +opts+:
29
- # - an optional +fail+ lambda that is called when any event fails to transition)
30
- def state_machine(name, opts = {}, &block)
31
- fsm = StateMachine.new(name, self, fail: opts[:fail])
32
- fsm.instance_eval(&block)
33
- end
34
- end
35
-
36
- ##
37
- # The DSL for defining a state machine
38
- class StateMachine
39
- attr_reader :initial_state, :states, :events, :name, :full_name
40
-
41
- def initialize(name, owner_class, fail: nil)
42
- @owner_class = owner_class
43
- @name = name.to_sym
44
- @full_name = "#{owner_class.name}/#{name}"
45
- @states = []
46
- @events = []
47
- @initial_state = nil
48
- @fail_handler = fail
49
-
50
- setup_base_methods
51
- end
52
-
53
- ##
54
- # Declare a supported +state_name+, and optionally specify one as the +initial+ state.
55
- def state(state_name, initial: false)
56
- return if state_name.nil? || @states.include?(state_name)
57
-
58
- status = state_name.to_sym
59
- state_machine_name = @name
60
- @states << status
61
- @initial_state = status if initial
62
-
63
- make_owner_method "#{state_name}?", lambda {
64
- send(state_machine_name) == status
65
- }
66
- end
67
-
68
- ##
69
- # Define an event by +event_name+
70
- #
71
- # - which +transitions+ as a hash with a +from+ state or array of states and the +to+ state,
72
- # - an optional +guard+ lambda which must return true for the transition to occur,
73
- # - an optional +fail+ lambda that is called when the transition fails (overrides top-level fail handler), and
74
- # - an optional do block that is called +after+ the transition succeeds
75
- def event(event_name, transitions:, guard: nil, fail: nil, &after)
76
- return unless event_exists?(event_name) && transitions
77
-
78
- @events << event_name
79
- may_event_name = "may_#{event_name}?"
80
-
81
- if transitions.is_a?(Array)
82
- setup_multi_transition_may_event_method transitions: transitions, guard: guard,
83
- may_event_name: may_event_name
84
- setup_multi_transition_event_method event_name,
85
- transitions: transitions, guard: guard,
86
- var_name: "@#{@name}", fail: fail || @fail_handler
87
- return
88
- end
89
-
90
- to = transitions[:to]
91
- setup_may_event_method may_event_name, transitions[:from] || :any, transitions[:when], guard
92
- setup_event_method event_name, var_name: "@#{@name}",
93
- may_event_name: may_event_name, to: to,
94
- fail: fail || @fail_handler, &after
95
- end
96
-
97
- private
98
-
99
- def setup_multi_transition_may_event_method(transitions:, guard:, may_event_name:)
100
- state_machine_name = @name
101
-
102
- make_owner_method may_event_name, lambda {
103
- if !guard || instance_exec(&guard)
104
- current = send(state_machine_name)
105
- # Check each transition, and first one that succeeds ends the scan
106
- transitions.each do |t|
107
- next if cannot_transition?(t[:from], t[:when], current)
108
-
109
- return true
110
- end
111
- end
112
- false
113
- }
114
- end
115
-
116
- def setup_multi_transition_event_method(event_name, transitions:, guard:, var_name:, fail:)
117
- state_machine_name = @name
118
- make_owner_method event_name, lambda {
119
- if !guard || instance_exec(&guard)
120
- current = send(state_machine_name)
121
- # Check each transition, and first one that succeeds ends the scan
122
- transitions.each do |t|
123
- next if cannot_transition?(t[:from], t[:when], current)
124
-
125
- instance_variable_set(var_name, t[:to])
126
- return true
127
- end
128
- end
129
- instance_exec(&fail) if fail
130
- false
131
- }
132
- end
133
-
134
- def event_exists?(event_name)
135
- event_name && !@events.include?(event_name)
136
- end
137
-
138
- def setup_event_method(event_name, var_name:, may_event_name:, to:, fail:, &after)
139
- method_lambda = lambda {
140
- if send(may_event_name)
141
- instance_variable_set(var_name, to)
142
- instance_exec(&after) if after
143
- return true
144
- end
145
- # unable to satisfy pre-conditions for the event
146
- if fail
147
- if fail.is_a?(String) || fail.is_a?(Symbol)
148
- send(fail, event_name)
149
- else
150
- instance_exec(event_name, &fail)
151
- end
152
- end
153
- false
154
- }
155
- make_owner_method event_name, method_lambda
156
- end
157
-
158
- def setup_may_event_method(may_event_name, from, cond, guard)
159
- state_machine_name = @name
160
- #
161
- # Instead of one "may_event?" method that checks all variations every time it's called, here we check
162
- # the event definition and define the most optimal lambda to ensure the check is as fast as possible
163
- method_lambda = if from == :any
164
- from_any_may_event_lambda(guard, cond, state_machine_name)
165
- else
166
- guarded_or_conditional_may_event_lambda(from, guard, cond, state_machine_name)
167
- end
168
- make_owner_method may_event_name, method_lambda
169
- end
170
-
171
- def from_any_may_event_lambda(guard, cond, _state_machine_name)
172
- if !guard && !cond
173
- -> { true } # unguarded transition from any state
174
- elsif !cond
175
- guard # guarded transition from any state
176
- elsif !guard
177
- cond # conditional unguarded transition from any state
178
- else
179
- -> { instance_exec(&guard) && instance_exec(&cond) }
180
- end
181
- end
182
-
183
- def guarded_or_conditional_may_event_lambda(from, guard, cond, state_machine_name)
184
- if !guard && !cond
185
- guardless_may_event_lambda(from, state_machine_name)
186
- elsif !cond
187
- guarded_may_event_lambda(from, guard, state_machine_name)
188
- elsif !guard
189
- guarded_may_event_lambda(from, cond, state_machine_name)
190
- else
191
- guarded_and_conditional_may_event_lambda(from, guard, cond, state_machine_name)
192
- end
193
- end
194
-
195
- def guarded_may_event_lambda(from, guard, state_machine_name)
196
- if from.is_a?(Array)
197
- lambda { # guarded transition from choice of states
198
- current = send(state_machine_name)
199
- from.include?(current) && instance_exec(&guard)
200
- }
201
- else
202
- lambda { # guarded transition from one state
203
- current = send(state_machine_name)
204
- from == current && instance_exec(&guard)
205
- }
206
- end
207
- end
208
-
209
- def guarded_and_conditional_may_event_lambda(from, guard, cond, state_machine_name)
210
- if from.is_a?(Array)
211
- lambda { # guarded transition from choice of states
212
- current = send(state_machine_name)
213
- from.include?(current) && instance_exec(&guard) && instance_exec(&cond)
214
- }
215
- else
216
- lambda { # guarded transition from one state
217
- current = send(state_machine_name)
218
- from == current && instance_exec(&guard) && instance_exec(&cond)
219
- }
220
- end
221
- end
222
-
223
- def guardless_may_event_lambda(from, state_machine_name)
224
- if from.is_a?(Array)
225
- lambda { # unguarded transition from choice of states
226
- current = send(state_machine_name)
227
- from.include?(current)
228
- }
229
- else
230
- lambda { # unguarded transition from one state
231
- current = send(state_machine_name)
232
- from == current
233
- }
234
- end
235
- end
236
-
237
- def setup_base_methods
238
- var_name = "@#{name}"
239
- fsm = self
240
- make_owner_method @name, lambda {
241
- instance_variable_get(var_name) ||
242
- fsm.initial_state
243
- }
244
- make_owner_method "#{@name}_states", -> { fsm.states }
245
- make_owner_method "#{@name}_events", -> { fsm.events }
246
- end
247
-
248
- def make_owner_method(method_name, method_definition)
249
- @owner_class.define_method(method_name, method_definition)
250
- end
251
- end
252
- end
4
+ require "simply_fsm/simply_fsm"
data/simply_fsm.gemspec CHANGED
@@ -27,5 +27,6 @@ Gem::Specification.new do |spec|
27
27
 
28
28
  # development
29
29
  spec.add_development_dependency "rdoc"
30
+ spec.add_development_dependency "yard"
30
31
  spec.add_development_dependency "rspec", "~> 3.0"
31
32
  end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ class MultiTransitionFailHandlingStateMachine
4
+ class Error < StandardError; end
5
+ class RunError < StandardError; end
6
+
7
+ include SimplyFSM
8
+
9
+ state_machine :activity, fail: :on_any_fail do
10
+ state :sleeping, initial: true
11
+ state :running
12
+ state :cleaning
13
+
14
+ event :run,
15
+ fail: ->(_event) { raise RunError, "Cannot run" },
16
+ transitions: [{ from: :sleeping, to: :running }]
17
+
18
+ event :clean, transitions: [
19
+ { from: :running, to: :cleaning }
20
+ ]
21
+
22
+ event :sleep, transitions: [
23
+ { from: :running, to: :sleeping },
24
+ { when: -> { cleaning? }, to: :sleeping }
25
+ ]
26
+ end
27
+
28
+ def on_any_fail(event_name)
29
+ raise Error, "Cannot do: #{event_name}"
30
+ end
31
+ end
32
+
33
+ RSpec.describe MultiTransitionFailHandlingStateMachine do
34
+ describe "#sleep" do
35
+ it "error if already sleeping" do
36
+ expect { subject.sleep }.to raise_error(MultiTransitionFailHandlingStateMachine::Error)
37
+ end
38
+ end
39
+
40
+ describe "#run" do
41
+ it "custom error if already running" do
42
+ subject.run
43
+ expect { subject.run }.to raise_error(MultiTransitionFailHandlingStateMachine::RunError)
44
+ end
45
+
46
+ it "custom error if cleaning" do
47
+ subject.run
48
+ subject.clean
49
+ expect { subject.run }.to raise_error(MultiTransitionFailHandlingStateMachine::RunError)
50
+ end
51
+ end
52
+
53
+ describe "#clean" do
54
+ it "error if sleeping" do
55
+ expect { subject.clean }.to raise_error(MultiTransitionFailHandlingStateMachine::Error)
56
+ end
57
+
58
+ it "error if already cleaning" do
59
+ subject.run
60
+ subject.clean
61
+ expect { subject.clean }.to raise_error(MultiTransitionFailHandlingStateMachine::Error)
62
+ end
63
+ end
64
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simply_fsm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nogginly
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-01 00:00:00.000000000 Z
11
+ date: 2022-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: yard
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'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rspec
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -49,6 +63,7 @@ files:
49
63
  - ".rspec"
50
64
  - ".rubocop.yml"
51
65
  - ".ruby-version"
66
+ - ".yardopts"
52
67
  - CHANGELOG.md
53
68
  - CODE_OF_CONDUCT.md
54
69
  - Gemfile
@@ -59,12 +74,14 @@ files:
59
74
  - bin/console
60
75
  - bin/setup
61
76
  - lib/simply_fsm.rb
77
+ - lib/simply_fsm/simply_fsm.rb
62
78
  - lib/simply_fsm/version.rb
63
79
  - simply_fsm.gemspec
64
80
  - spec/spec_helper.rb
65
81
  - spec/support/state_machine_examples.rb
66
82
  - spec/unit/fail_events_spec.rb
67
83
  - spec/unit/guard_events_spec.rb
84
+ - spec/unit/multi_transition_fail_events_spec.rb
68
85
  - spec/unit/multi_transition_state_machine_spec.rb
69
86
  - spec/unit/one_state_machine_spec.rb
70
87
  - spec/unit/simply_fsm_spec.rb
@@ -100,6 +117,7 @@ test_files:
100
117
  - spec/support/state_machine_examples.rb
101
118
  - spec/unit/fail_events_spec.rb
102
119
  - spec/unit/guard_events_spec.rb
120
+ - spec/unit/multi_transition_fail_events_spec.rb
103
121
  - spec/unit/multi_transition_state_machine_spec.rb
104
122
  - spec/unit/one_state_machine_spec.rb
105
123
  - spec/unit/simply_fsm_spec.rb