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 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