statesman 5.0.0 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +8 -8
- data/lib/statesman/adapters/active_record_queries.rb +3 -3
- data/lib/statesman/exceptions.rb +15 -1
- data/lib/statesman/guard.rb +1 -4
- data/lib/statesman/machine.rb +10 -5
- data/lib/statesman/version.rb +1 -1
- data/spec/statesman/machine_spec.rb +23 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 137c7306b24f584a5b3e442ef5326ac210518c6ec64b3955106803b4d9bcddcc
|
4
|
+
data.tar.gz: 88cc9d95d0b6ff92a257e7afdc9510bd372b562e0aeaa92403bc51b762485f1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c5f8ad449fcea9f476d990048348eb766e2b65cf6f188118fc45162764f64656f6fec5ea65fbd797a999b517402501b5edbe2d45a834d5dcaf492f566b47f53
|
7
|
+
data.tar.gz: '038b822e77c6a07df87cc8d4ab792b8bf5f7c61ed7f38548a6751d579fca3b988ef32a8f2cd6d609cf25b521218a87952cf4590400584add3031ff4cfe895eff'
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,31 @@
|
|
1
|
+
## v5.1.0, 22th November 2019
|
2
|
+
|
3
|
+
- Correct `Statesman::Adapters::ActiveRecordQueries` error text [@Bramjetten](https://github.com/gocardless/statesman/pull/376)
|
4
|
+
- Removes duplicate `map` call [Isaac Seymour](https://github.com/gocardless/statesman/pull/362)
|
5
|
+
- Update changelog with instructions of how to use `ActiveRecordQueries` added
|
6
|
+
in v5.0.0
|
7
|
+
- Pass exception into `after_transition_failure` and `after_guard_failure` callbacks [@credric-cordenier](https://github.com/gocardless/statesman/pull/378)
|
8
|
+
|
1
9
|
## v5.0.0, 11th November 2019
|
2
10
|
|
3
11
|
- Adds new syntax and restrictions to ActiveRecordQueries [PR#358](https://github.com/gocardless/statesman/pull/358). With the introduction of this, defining `self.transition_class` or `self.initial_state` is deprecated and will be removed in the next major release.
|
12
|
+
Change
|
13
|
+
```ruby
|
14
|
+
include Statesman::Adapters::ActiveRecordQueries
|
15
|
+
def self.initial_state
|
16
|
+
:initial
|
17
|
+
end
|
18
|
+
def self.transition_class
|
19
|
+
MyTransition
|
20
|
+
end
|
21
|
+
```
|
22
|
+
to
|
23
|
+
```ruby
|
24
|
+
include Statesman::Adapters::ActiveRecordQueries[
|
25
|
+
initial_state: :inital,
|
26
|
+
transition_class: MyTransition
|
27
|
+
]
|
28
|
+
```
|
4
29
|
|
5
30
|
## v4.1.4, 11th November 2019
|
6
31
|
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
<p align="center"><img src="http://f.cl.ly/items/410n2A0S3l1W0i3i0o2K/statesman.png" alt="Statesman"></p>
|
2
2
|
|
3
3
|
A statesmanlike state machine library.
|
4
4
|
|
@@ -30,7 +30,7 @@ protection.
|
|
30
30
|
To get started, just add Statesman to your `Gemfile`, and then run `bundle`:
|
31
31
|
|
32
32
|
```ruby
|
33
|
-
gem 'statesman', '~> 5.
|
33
|
+
gem 'statesman', '~> 5.1.0'
|
34
34
|
```
|
35
35
|
|
36
36
|
## Usage
|
@@ -257,28 +257,28 @@ transition has been committed to the database.
|
|
257
257
|
|
258
258
|
#### `Machine.after_transition_failure`
|
259
259
|
```ruby
|
260
|
-
Machine.after_transition_failure(from: :some_state, to: :another_state) do |object|
|
261
|
-
Logger.info("transition failed for #{object.id}")
|
260
|
+
Machine.after_transition_failure(from: :some_state, to: :another_state) do |object, exception|
|
261
|
+
Logger.info("transition to #{exception.to} failed for #{object.id}")
|
262
262
|
end
|
263
263
|
```
|
264
264
|
Define a callback to run if `Statesman::TransitionFailedError` is raised
|
265
265
|
during the execution of transition callbacks. `to` and `from`
|
266
266
|
parameters are optional, a nil parameter means run after all transitions.
|
267
|
-
The model object
|
267
|
+
The model object, and exception are passed as arguments to the callback.
|
268
268
|
This is executed outside of the transaction wrapping other callbacks.
|
269
269
|
If using `transition!` the exception is re-raised after these callbacks are
|
270
270
|
executed.
|
271
271
|
|
272
272
|
#### `Machine.after_guard_failure`
|
273
273
|
```ruby
|
274
|
-
Machine.after_guard_failure(from: :some_state, to: :another_state) do |object|
|
275
|
-
Logger.info("guard failed for #{object.id}")
|
274
|
+
Machine.after_guard_failure(from: :some_state, to: :another_state) do |object, exception|
|
275
|
+
Logger.info("guard failed during transition to #{exception.to} for #{object.id}")
|
276
276
|
end
|
277
277
|
```
|
278
278
|
Define a callback to run if `Statesman::GuardFailedError` is raised
|
279
279
|
during the execution of guard callbacks. `to` and `from`
|
280
280
|
parameters are optional, a nil parameter means run after all transitions.
|
281
|
-
The model object
|
281
|
+
The model object, and exception are passed as arguments to the callback.
|
282
282
|
This is executed outside of the transaction wrapping other callbacks.
|
283
283
|
If using `transition!` the exception is re-raised after these callbacks are
|
284
284
|
executed.
|
@@ -8,7 +8,7 @@ module Statesman
|
|
8
8
|
|
9
9
|
raise NotImplementedError,
|
10
10
|
"#{missing_methods.join(', ')} method(s) should be defined on " \
|
11
|
-
"the model. Alternatively, use the new form of `
|
11
|
+
"the model. Alternatively, use the new form of `include " \
|
12
12
|
"Statesman::Adapters::ActiveRecordQueries[" \
|
13
13
|
"transition_class: MyTransition, " \
|
14
14
|
"initial_state: :some_state]`"
|
@@ -62,7 +62,7 @@ module Statesman
|
|
62
62
|
|
63
63
|
def define_in_state(base, query_builder)
|
64
64
|
base.define_singleton_method(:in_state) do |*states|
|
65
|
-
states = states.flatten
|
65
|
+
states = states.flatten
|
66
66
|
|
67
67
|
joins(most_recent_transition_join).
|
68
68
|
where(query_builder.states_where(states), states)
|
@@ -71,7 +71,7 @@ module Statesman
|
|
71
71
|
|
72
72
|
def define_not_in_state(base, query_builder)
|
73
73
|
base.define_singleton_method(:not_in_state) do |*states|
|
74
|
-
states = states.flatten
|
74
|
+
states = states.flatten
|
75
75
|
|
76
76
|
joins(most_recent_transition_join).
|
77
77
|
where("NOT (#{query_builder.states_where(states)})", states)
|
data/lib/statesman/exceptions.rb
CHANGED
@@ -2,7 +2,7 @@ module Statesman
|
|
2
2
|
class InvalidStateError < StandardError; end
|
3
3
|
class InvalidTransitionError < StandardError; end
|
4
4
|
class InvalidCallbackError < StandardError; end
|
5
|
-
|
5
|
+
|
6
6
|
class TransitionFailedError < StandardError
|
7
7
|
def initialize(from, to)
|
8
8
|
@from = from
|
@@ -15,6 +15,20 @@ module Statesman
|
|
15
15
|
"Cannot transition from '#{from}' to '#{to}'"
|
16
16
|
end
|
17
17
|
end
|
18
|
+
|
19
|
+
class GuardFailedError < StandardError
|
20
|
+
def initialize(from, to)
|
21
|
+
@from = from
|
22
|
+
@to = to
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :from, :to
|
26
|
+
|
27
|
+
def message
|
28
|
+
"Guard on transition from: '#{from}' to '#{to}' returned false"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
18
32
|
class TransitionConflictError < StandardError; end
|
19
33
|
class MissingTransitionAssociation < StandardError; end
|
20
34
|
|
data/lib/statesman/guard.rb
CHANGED
@@ -4,10 +4,7 @@ require_relative "exceptions"
|
|
4
4
|
module Statesman
|
5
5
|
class Guard < Callback
|
6
6
|
def call(*args)
|
7
|
-
unless super(*args)
|
8
|
-
raise GuardFailedError,
|
9
|
-
"Guard on transition from: '#{from}' to '#{to}' returned false"
|
10
|
-
end
|
7
|
+
raise GuardFailedError.new(from, to) unless super(*args)
|
11
8
|
end
|
12
9
|
end
|
13
10
|
end
|
data/lib/statesman/machine.rb
CHANGED
@@ -231,15 +231,20 @@ module Statesman
|
|
231
231
|
@storage_adapter.create(initial_state, new_state, metadata)
|
232
232
|
|
233
233
|
true
|
234
|
-
rescue TransitionFailedError
|
235
|
-
|
234
|
+
rescue TransitionFailedError => e
|
235
|
+
execute_on_failure(:after_transition_failure, initial_state, new_state, e)
|
236
236
|
raise
|
237
|
-
rescue GuardFailedError
|
238
|
-
|
237
|
+
rescue GuardFailedError => e
|
238
|
+
execute_on_failure(:after_guard_failure, initial_state, new_state, e)
|
239
239
|
raise
|
240
240
|
end
|
241
241
|
|
242
|
-
def
|
242
|
+
def execute_on_failure(phase, initial_state, new_state, exception)
|
243
|
+
callbacks = callbacks_for(phase, from: initial_state, to: new_state)
|
244
|
+
callbacks.each { |cb| cb.call(@object, exception) }
|
245
|
+
end
|
246
|
+
|
247
|
+
def execute(phase, initial_state, new_state, transition)
|
243
248
|
callbacks = callbacks_for(phase, from: initial_state, to: new_state)
|
244
249
|
callbacks.each { |cb| cb.call(@object, transition) }
|
245
250
|
end
|
data/lib/statesman/version.rb
CHANGED
@@ -680,6 +680,24 @@ describe Statesman::Machine do
|
|
680
680
|
end
|
681
681
|
end
|
682
682
|
|
683
|
+
context "which covers all transitions" do
|
684
|
+
let(:result) { true }
|
685
|
+
let(:guard_cb) { ->(*_args) { false } }
|
686
|
+
|
687
|
+
before { machine.guard_transition(from: :x, to: :y, &guard_cb) }
|
688
|
+
|
689
|
+
it "raises an exception with the transition information" do
|
690
|
+
expect(guard_cb).to receive(:call).once.with(
|
691
|
+
my_model, instance.last_transition, {}
|
692
|
+
).and_return(false)
|
693
|
+
expect { instance.transition_to!(:y) }.
|
694
|
+
to raise_error(
|
695
|
+
an_instance_of(Statesman::GuardFailedError).
|
696
|
+
and(having_attributes(from: "x", to: ["y"])),
|
697
|
+
)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
|
683
701
|
context "which passes" do
|
684
702
|
it "changes state" do
|
685
703
|
instance.transition_to!(:y)
|
@@ -703,7 +721,7 @@ describe Statesman::Machine do
|
|
703
721
|
|
704
722
|
it "calls the failure callback" do
|
705
723
|
expect(guard_failure_cb).to receive(:call).once.with(
|
706
|
-
my_model,
|
724
|
+
my_model, instance_of(Statesman::GuardFailedError)
|
707
725
|
).and_return(guard_failure_result)
|
708
726
|
expect { instance.transition_to!(:y) }.
|
709
727
|
to raise_error(Statesman::GuardFailedError)
|
@@ -722,8 +740,9 @@ describe Statesman::Machine do
|
|
722
740
|
end
|
723
741
|
|
724
742
|
it "raises and exception and calls the callback" do
|
725
|
-
expect(transition_failed_cb).to receive(:call).once.
|
726
|
-
|
743
|
+
expect(transition_failed_cb).to receive(:call).once.with(
|
744
|
+
my_model, instance_of(Statesman::TransitionFailedError)
|
745
|
+
).and_return(true)
|
727
746
|
expect { instance.transition_to!(:z) }.
|
728
747
|
to raise_error(Statesman::TransitionFailedError)
|
729
748
|
end
|
@@ -749,7 +768,7 @@ describe Statesman::Machine do
|
|
749
768
|
context "when it is unsuccesful" do
|
750
769
|
before do
|
751
770
|
allow(instance).to receive(:transition_to!).
|
752
|
-
and_raise(Statesman::GuardFailedError)
|
771
|
+
and_raise(Statesman::GuardFailedError.new(:x, :some_state))
|
753
772
|
end
|
754
773
|
|
755
774
|
it { is_expected.to be_falsey }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statesman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GoCardless
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-
|
11
|
+
date: 2019-12-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ammeter
|