statesman 5.0.0 → 5.1.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/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
|