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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5f79354b244926e7be655b02df501cfed437ab2da6e869ec8db35097bb5ef372
4
- data.tar.gz: 2b6ad54a68b6bca463c00c9e09a83d2d2d9d47d984fad212da77b0b0fd8a18a9
3
+ metadata.gz: 137c7306b24f584a5b3e442ef5326ac210518c6ec64b3955106803b4d9bcddcc
4
+ data.tar.gz: 88cc9d95d0b6ff92a257e7afdc9510bd372b562e0aeaa92403bc51b762485f1f
5
5
  SHA512:
6
- metadata.gz: e66962ac0dd871627bdf6c53c5282e140bd109c3fcd0ba2ebd25504c490e3ddf2050132aabdf143c35aff09330e229afe8ec57c7d7fc43552bcff8140f8f0fa0
7
- data.tar.gz: 9e3fa636071bcd530b177e80bf1014071d38601da2076e5258ffed22f41eec388255db2b03b79710130624c5fb6c60009af511b76d478be718f5fc69a6f0e933
6
+ metadata.gz: 6c5f8ad449fcea9f476d990048348eb766e2b65cf6f188118fc45162764f64656f6fec5ea65fbd797a999b517402501b5edbe2d45a834d5dcaf492f566b47f53
7
+ data.tar.gz: '038b822e77c6a07df87cc8d4ab792b8bf5f7c61ed7f38548a6751d579fca3b988ef32a8f2cd6d609cf25b521218a87952cf4590400584add3031ff4cfe895eff'
@@ -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
- ![Statesman](http://f.cl.ly/items/410n2A0S3l1W0i3i0o2K/statesman.png)
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.0.0'
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 is passed as an argument to the callback.
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 is passed as an argument to the callback.
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 `extend " \
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.map(&:to_s)
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.map(&:to_s)
74
+ states = states.flatten
75
75
 
76
76
  joins(most_recent_transition_join).
77
77
  where("NOT (#{query_builder.states_where(states)})", states)
@@ -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
- class GuardFailedError < StandardError; end
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
 
@@ -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
@@ -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
- execute(:after_transition_failure, initial_state, new_state)
234
+ rescue TransitionFailedError => e
235
+ execute_on_failure(:after_transition_failure, initial_state, new_state, e)
236
236
  raise
237
- rescue GuardFailedError
238
- execute(:after_guard_failure, initial_state, new_state)
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 execute(phase, initial_state, new_state, transition = nil)
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
@@ -1,3 +1,3 @@
1
1
  module Statesman
2
- VERSION = "5.0.0".freeze
2
+ VERSION = "5.1.0".freeze
3
3
  end
@@ -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, nil
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
- with(my_model, nil).and_return(true)
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.0.0
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-11 00:00:00.000000000 Z
11
+ date: 2019-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ammeter