statesman 0.6.1 → 0.7.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/.travis.yml +1 -0
- data/CHANGELOG.md +6 -1
- data/CONTRIBUTING.md +28 -0
- data/README.md +3 -1
- data/lib/statesman/adapters/active_record.rb +31 -14
- data/lib/statesman/adapters/mongoid.rb +2 -1
- data/lib/statesman/exceptions.rb +2 -0
- data/lib/statesman/machine.rb +10 -2
- data/lib/statesman/version.rb +1 -1
- data/spec/statesman/adapters/active_record_spec.rb +65 -3
- data/spec/statesman/machine_spec.rb +7 -0
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 697717ea3c8a4b388c0b43a8777d9c1a18e147c1
|
4
|
+
data.tar.gz: 14051a4eacb2979013b8ff8e88698e9be6cff436
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8fef4baf05db94227a2d3d9b2cbce8b7de0b0cc4eebacc6c3c04d879562b823c0903f8044ed36c2d0ba30443600ce7e04b1d109aa0fd4b501a85be51d2e640cc
|
7
|
+
data.tar.gz: 34deb50e48efc779d09ddff16b61afa90c7a36c263af58f8af8f1995ff8db1ca01a610e00182b9b11eed8d3a665b768c2d4c86dfeecd336e73e47efb90da53f0
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
-
##
|
1
|
+
## v0.7.0 25 June 2014
|
2
|
+
*Additions*
|
3
|
+
|
4
|
+
- `Adapters::ActiveRecord` now handles `ActiveRecord::RecordNotUnique` errors explicitly and re-raises with a `Statesman::TransitionConflictError` if it is due to duplicate sort_keys (patch by [@greysteil](https://github.com/greysteil))
|
5
|
+
|
6
|
+
## v0.6.1 21 May 2014
|
2
7
|
*Fixes*
|
3
8
|
- Fixes an issue where the wrong transition was passed to after_transition callbacks for the second and subsequent transition of a given state machine (patch by [@alan](https://github.com/alan))
|
4
9
|
|
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Thanks for taking an interest in contributing to Statesman, here are a few
|
2
|
+
ways you can help make this project better!
|
3
|
+
|
4
|
+
# Contribute.md
|
5
|
+
|
6
|
+
## Team members
|
7
|
+
|
8
|
+
- [Andy Appleton](https://twitter.com/appltn)
|
9
|
+
- [Harry Marr](https://twitter.com/harrymarr)
|
10
|
+
|
11
|
+
## Contributing
|
12
|
+
|
13
|
+
- Generally we welcome new features but please first open an issue where we
|
14
|
+
can discuss whether it fits with our vision for the project.
|
15
|
+
- Any new feature or bug fix needs an accompanying test case.
|
16
|
+
- No need to add to the changelog, we will take care of updating it as we make
|
17
|
+
releases.
|
18
|
+
|
19
|
+
## Style
|
20
|
+
|
21
|
+
We use [Rubocop](https://github.com/bbatsov/rubocop) to help maintain a
|
22
|
+
consistent code style across the project. Please check that your pull
|
23
|
+
request passes by running `rubocop`.
|
24
|
+
|
25
|
+
## Documentation
|
26
|
+
|
27
|
+
Please add a section to the readme for any new feature additions or behaviour
|
28
|
+
changes.
|
data/README.md
CHANGED
@@ -150,6 +150,8 @@ Statesman defaults to storing transitions in memory. If you're using rails, you
|
|
150
150
|
can instead configure it to persist transitions to the database by using the
|
151
151
|
ActiveRecord or Mongoid adapter.
|
152
152
|
|
153
|
+
Statesman will fallback to memory unless you specify a transition_class when instantiating your state machine. This allows you to only persist transitions on certain state machines in your app.
|
154
|
+
|
153
155
|
|
154
156
|
## Class methods
|
155
157
|
|
@@ -260,4 +262,4 @@ Returns all models not currently in any of the supplied states.
|
|
260
262
|
|
261
263
|
---
|
262
264
|
|
263
|
-
GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs
|
265
|
+
GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs#software-engineer).
|
@@ -7,9 +7,15 @@ module Statesman
|
|
7
7
|
attr_reader :parent_model
|
8
8
|
|
9
9
|
def initialize(transition_class, parent_model, observer)
|
10
|
-
|
10
|
+
serialized = transition_class.serialized_attributes.include?("metadata")
|
11
|
+
column_type = transition_class.columns_hash['metadata'].sql_type
|
12
|
+
if !serialized && column_type != 'json'
|
11
13
|
raise UnserializedMetadataError,
|
12
14
|
"#{transition_class.name}#metadata is not serialized"
|
15
|
+
elsif serialized && column_type == 'json'
|
16
|
+
raise IncompatibleSerializationError,
|
17
|
+
"#{transition_class.name}#metadata column type cannot be json
|
18
|
+
and serialized simultaneously"
|
13
19
|
end
|
14
20
|
@transition_class = transition_class
|
15
21
|
@parent_model = parent_model
|
@@ -17,20 +23,15 @@ module Statesman
|
|
17
23
|
end
|
18
24
|
|
19
25
|
def create(from, to, metadata = {})
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
transition.save!
|
27
|
-
@last_transition = transition
|
28
|
-
@observer.execute(:after, from, to, transition)
|
29
|
-
@last_transition = nil
|
26
|
+
create_transition(from, to, metadata)
|
27
|
+
rescue ::ActiveRecord::RecordNotUnique => e
|
28
|
+
if e.message.include?('sort_key') &&
|
29
|
+
e.message.include?(@transition_class.table_name)
|
30
|
+
raise TransitionConflictError, e.message
|
31
|
+
else raise
|
30
32
|
end
|
31
|
-
|
32
|
-
|
33
|
-
transition
|
33
|
+
ensure
|
34
|
+
@last_transition = nil
|
34
35
|
end
|
35
36
|
|
36
37
|
def history
|
@@ -47,6 +48,22 @@ module Statesman
|
|
47
48
|
|
48
49
|
private
|
49
50
|
|
51
|
+
def create_transition(from, to, metadata)
|
52
|
+
transition = transitions_for_parent.build(to_state: to,
|
53
|
+
sort_key: next_sort_key,
|
54
|
+
metadata: metadata)
|
55
|
+
|
56
|
+
::ActiveRecord::Base.transaction do
|
57
|
+
@observer.execute(:before, from, to, transition)
|
58
|
+
transition.save!
|
59
|
+
@last_transition = transition
|
60
|
+
@observer.execute(:after, from, to, transition)
|
61
|
+
end
|
62
|
+
@observer.execute(:after_commit, from, to, transition)
|
63
|
+
|
64
|
+
transition
|
65
|
+
end
|
66
|
+
|
50
67
|
def transitions_for_parent
|
51
68
|
@parent_model.send(@transition_class.table_name)
|
52
69
|
end
|
@@ -25,8 +25,9 @@ module Statesman
|
|
25
25
|
@last_transition = transition
|
26
26
|
@observer.execute(:after, from, to, transition)
|
27
27
|
@observer.execute(:after_commit, from, to, transition)
|
28
|
-
@last_transition = nil
|
29
28
|
transition
|
29
|
+
ensure
|
30
|
+
@last_transition = nil
|
30
31
|
end
|
31
32
|
|
32
33
|
def history
|
data/lib/statesman/exceptions.rb
CHANGED
@@ -5,4 +5,6 @@ module Statesman
|
|
5
5
|
class GuardFailedError < StandardError; end
|
6
6
|
class TransitionFailedError < StandardError; end
|
7
7
|
class UnserializedMetadataError < StandardError; end
|
8
|
+
class IncompatibleSerializationError < StandardError; end
|
9
|
+
class TransitionConflictError < StandardError; end
|
8
10
|
end
|
data/lib/statesman/machine.rb
CHANGED
@@ -143,8 +143,8 @@ module Statesman
|
|
143
143
|
})
|
144
144
|
@object = object
|
145
145
|
@transition_class = options[:transition_class]
|
146
|
-
@storage_adapter =
|
147
|
-
|
146
|
+
@storage_adapter = adapter_class(@transition_class)
|
147
|
+
.new(@transition_class, object, self)
|
148
148
|
send(:after_initialize) if respond_to? :after_initialize
|
149
149
|
end
|
150
150
|
|
@@ -202,6 +202,14 @@ module Statesman
|
|
202
202
|
|
203
203
|
private
|
204
204
|
|
205
|
+
def adapter_class(transition_class)
|
206
|
+
if transition_class == Statesman::Adapters::MemoryTransition
|
207
|
+
Adapters::Memory
|
208
|
+
else
|
209
|
+
Statesman.storage_adapter
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
205
213
|
def successors_for(from)
|
206
214
|
self.class.successors[from] || []
|
207
215
|
end
|
data/lib/statesman/version.rb
CHANGED
@@ -18,16 +18,78 @@ describe Statesman::Adapters::ActiveRecord do
|
|
18
18
|
it_behaves_like "an adapter", described_class, MyActiveRecordModelTransition
|
19
19
|
|
20
20
|
describe "#initialize" do
|
21
|
-
context "with unserialized metadata" do
|
22
|
-
before
|
21
|
+
context "with unserialized metadata and non json column type" do
|
22
|
+
before do
|
23
|
+
metadata_column = double
|
24
|
+
metadata_column.stub(sql_type: '')
|
25
|
+
MyActiveRecordModelTransition.stub(columns_hash:
|
26
|
+
{ 'metadata' => metadata_column })
|
27
|
+
MyActiveRecordModelTransition.stub(serialized_attributes: {})
|
28
|
+
end
|
23
29
|
|
24
|
-
it "raises an exception
|
30
|
+
it "raises an exception" do
|
25
31
|
expect do
|
26
32
|
described_class.new(MyActiveRecordModelTransition,
|
27
33
|
MyActiveRecordModel, observer)
|
28
34
|
end.to raise_exception(Statesman::UnserializedMetadataError)
|
29
35
|
end
|
30
36
|
end
|
37
|
+
|
38
|
+
context "with serialized metadata and json column type" do
|
39
|
+
before do
|
40
|
+
metadata_column = double
|
41
|
+
metadata_column.stub(sql_type: 'json')
|
42
|
+
MyActiveRecordModelTransition.stub(columns_hash:
|
43
|
+
{ 'metadata' => metadata_column })
|
44
|
+
MyActiveRecordModelTransition.stub(serialized_attributes:
|
45
|
+
{ 'metadata' => '' })
|
46
|
+
end
|
47
|
+
|
48
|
+
it "raises an exception" do
|
49
|
+
expect do
|
50
|
+
described_class.new(MyActiveRecordModelTransition,
|
51
|
+
MyActiveRecordModel, observer)
|
52
|
+
end.to raise_exception(Statesman::IncompatibleSerializationError)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "#create" do
|
58
|
+
let(:adapter) do
|
59
|
+
described_class.new(MyActiveRecordModelTransition, model, observer)
|
60
|
+
end
|
61
|
+
let(:from) { :x }
|
62
|
+
let(:to) { :y }
|
63
|
+
let(:create) { adapter.create(from, to) }
|
64
|
+
subject { -> { create } }
|
65
|
+
|
66
|
+
context "when there is a race" do
|
67
|
+
it "raises a TransitionConflictError" do
|
68
|
+
adapter2 = adapter.dup
|
69
|
+
adapter2.create(:x, :y)
|
70
|
+
adapter.last
|
71
|
+
adapter2.create(:y, :z)
|
72
|
+
expect { adapter.create(:y, :z) }
|
73
|
+
.to raise_exception(Statesman::TransitionConflictError)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
context "when other exceptions occur" do
|
78
|
+
before do
|
79
|
+
allow_any_instance_of(MyActiveRecordModelTransition)
|
80
|
+
.to receive(:save!).and_raise(error)
|
81
|
+
end
|
82
|
+
|
83
|
+
context "ActiveRecord::RecordNotUnique unrelated to this transition" do
|
84
|
+
let(:error) { ActiveRecord::RecordNotUnique.new("unrelated", nil) }
|
85
|
+
it { should raise_exception(ActiveRecord::RecordNotUnique) }
|
86
|
+
end
|
87
|
+
|
88
|
+
context "other errors" do
|
89
|
+
let(:error) { StandardError }
|
90
|
+
it { should raise_exception(StandardError) }
|
91
|
+
end
|
92
|
+
end
|
31
93
|
end
|
32
94
|
|
33
95
|
describe "#last" do
|
@@ -203,6 +203,13 @@ describe Statesman::Machine do
|
|
203
203
|
.with(my_transition_class, my_model, anything)
|
204
204
|
machine.new(my_model, transition_class: my_transition_class)
|
205
205
|
end
|
206
|
+
|
207
|
+
it "falls back to Memory without transaction_class" do
|
208
|
+
Statesman.stub(:storage_adapter).and_return(Class.new)
|
209
|
+
Statesman::Adapters::Memory.should_receive(:new).once
|
210
|
+
.with(Statesman::Adapters::MemoryTransition, my_model, anything)
|
211
|
+
machine.new(my_model)
|
212
|
+
end
|
206
213
|
end
|
207
214
|
end
|
208
215
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statesman
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Harry Marr
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2014-
|
12
|
+
date: 2014-07-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -162,6 +162,7 @@ files:
|
|
162
162
|
- .rubocop.yml
|
163
163
|
- .travis.yml
|
164
164
|
- CHANGELOG.md
|
165
|
+
- CONTRIBUTING.md
|
165
166
|
- Gemfile
|
166
167
|
- Guardfile
|
167
168
|
- LICENSE.txt
|
@@ -229,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
230
|
version: '0'
|
230
231
|
requirements: []
|
231
232
|
rubyforge_project:
|
232
|
-
rubygems_version: 2.
|
233
|
+
rubygems_version: 2.0.14
|
233
234
|
signing_key:
|
234
235
|
specification_version: 4
|
235
236
|
summary: A statesmanlike state machine library
|