statesman 3.5.0 → 6.0.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 +5 -5
- data/.circleci/config.yml +45 -225
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +26 -6
- data/CHANGELOG.md +69 -0
- data/Gemfile +9 -3
- data/Guardfile +2 -0
- data/README.md +77 -47
- data/Rakefile +2 -4
- data/lib/generators/statesman/active_record_transition_generator.rb +2 -0
- data/lib/generators/statesman/generator_helpers.rb +2 -0
- data/lib/generators/statesman/migration_generator.rb +2 -0
- data/lib/statesman/adapters/active_record.rb +88 -6
- data/lib/statesman/adapters/active_record_queries.rb +100 -36
- data/lib/statesman/adapters/active_record_transition.rb +2 -0
- data/lib/statesman/adapters/memory.rb +2 -0
- data/lib/statesman/adapters/memory_transition.rb +2 -0
- data/lib/statesman/callback.rb +2 -0
- data/lib/statesman/config.rb +2 -0
- data/lib/statesman/exceptions.rb +29 -2
- data/lib/statesman/guard.rb +3 -4
- data/lib/statesman/machine.rb +29 -7
- data/lib/statesman/railtie.rb +2 -0
- data/lib/statesman/utils.rb +2 -0
- data/lib/statesman/version.rb +3 -1
- data/lib/statesman.rb +2 -3
- data/lib/tasks/statesman.rake +3 -1
- data/spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_with_partial_index.rb +2 -0
- data/spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_without_partial_index.rb +2 -0
- data/spec/fixtures/add_most_recent_to_bacon_transitions.rb +2 -0
- data/spec/generators/statesman/active_record_transition_generator_spec.rb +2 -0
- data/spec/generators/statesman/migration_generator_spec.rb +2 -0
- data/spec/spec_helper.rb +3 -30
- data/spec/statesman/adapters/active_record_queries_spec.rb +165 -91
- data/spec/statesman/adapters/active_record_spec.rb +4 -0
- data/spec/statesman/adapters/active_record_transition_spec.rb +2 -0
- data/spec/statesman/adapters/memory_spec.rb +2 -0
- data/spec/statesman/adapters/memory_transition_spec.rb +2 -0
- data/spec/statesman/adapters/shared_examples.rb +2 -0
- data/spec/statesman/callback_spec.rb +2 -0
- data/spec/statesman/config_spec.rb +2 -0
- data/spec/statesman/guard_spec.rb +2 -0
- data/spec/statesman/machine_spec.rb +79 -4
- data/spec/statesman/utils_spec.rb +2 -0
- data/spec/support/active_record.rb +9 -12
- data/spec/support/generators_shared_examples.rb +2 -0
- data/statesman.gemspec +5 -3
- metadata +17 -22
- data/lib/generators/statesman/mongoid_transition_generator.rb +0 -25
- data/lib/generators/statesman/templates/mongoid_transition_model.rb.erb +0 -14
- data/lib/statesman/adapters/mongoid.rb +0 -66
- data/lib/statesman/adapters/mongoid_transition.rb +0 -10
- data/spec/generators/statesman/mongoid_transition_generator_spec.rb +0 -23
- data/spec/statesman/adapters/mongoid_spec.rb +0 -86
- data/spec/support/mongoid.rb +0 -28
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "spec_helper"
|
2
4
|
|
3
5
|
describe Statesman::Machine do
|
@@ -57,7 +59,11 @@ describe Statesman::Machine do
|
|
57
59
|
expect(instance).
|
58
60
|
to receive(:transition_to).once.
|
59
61
|
and_raise(StandardError)
|
60
|
-
|
62
|
+
begin
|
63
|
+
transition_state
|
64
|
+
rescue StandardError
|
65
|
+
nil
|
66
|
+
end
|
61
67
|
end
|
62
68
|
|
63
69
|
it "re-raises the exception" do
|
@@ -86,7 +92,11 @@ describe Statesman::Machine do
|
|
86
92
|
to receive(:transition_to).
|
87
93
|
exactly(retry_attempts + 1).times.
|
88
94
|
and_raise(Statesman::TransitionConflictError)
|
89
|
-
|
95
|
+
begin
|
96
|
+
transition_state
|
97
|
+
rescue StandardError
|
98
|
+
nil
|
99
|
+
end
|
90
100
|
end
|
91
101
|
|
92
102
|
it "re-raises the conflict" do
|
@@ -320,6 +330,16 @@ describe Statesman::Machine do
|
|
320
330
|
it_behaves_like "a callback store", :guard_transition, :guards
|
321
331
|
end
|
322
332
|
|
333
|
+
describe ".after_transition_failure" do
|
334
|
+
it_behaves_like "a callback store",
|
335
|
+
:after_transition_failure,
|
336
|
+
:after_transition_failure
|
337
|
+
end
|
338
|
+
|
339
|
+
describe ".after_guard_failure" do
|
340
|
+
it_behaves_like "a callback store", :after_guard_failure, :after_guard_failure
|
341
|
+
end
|
342
|
+
|
323
343
|
describe "#initialize" do
|
324
344
|
it "accepts an object to manipulate" do
|
325
345
|
machine_instance = machine.new(my_model)
|
@@ -609,8 +629,12 @@ describe Statesman::Machine do
|
|
609
629
|
|
610
630
|
context "when the state cannot be transitioned to" do
|
611
631
|
it "raises an error" do
|
632
|
+
# Hardcoding error message here to ensure backward
|
633
|
+
# compatibility as people may have been parsing the string
|
634
|
+
# to figure out the transitions involved.
|
612
635
|
expect { instance.transition_to!(:z) }.
|
613
|
-
to raise_error(Statesman::TransitionFailedError
|
636
|
+
to raise_error(Statesman::TransitionFailedError,
|
637
|
+
"Cannot transition from 'x' to 'z'")
|
614
638
|
end
|
615
639
|
end
|
616
640
|
|
@@ -658,6 +682,24 @@ describe Statesman::Machine do
|
|
658
682
|
end
|
659
683
|
end
|
660
684
|
|
685
|
+
context "which covers all transitions" do
|
686
|
+
let(:result) { true }
|
687
|
+
let(:guard_cb) { ->(*_args) { false } }
|
688
|
+
|
689
|
+
before { machine.guard_transition(from: :x, to: :y, &guard_cb) }
|
690
|
+
|
691
|
+
it "raises an exception with the transition information" do
|
692
|
+
expect(guard_cb).to receive(:call).once.with(
|
693
|
+
my_model, instance.last_transition, {}
|
694
|
+
).and_return(false)
|
695
|
+
expect { instance.transition_to!(:y) }.
|
696
|
+
to raise_error(
|
697
|
+
an_instance_of(Statesman::GuardFailedError).
|
698
|
+
and(having_attributes(from: "x", to: ["y"])),
|
699
|
+
)
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
661
703
|
context "which passes" do
|
662
704
|
it "changes state" do
|
663
705
|
instance.transition_to!(:y)
|
@@ -672,6 +714,39 @@ describe Statesman::Machine do
|
|
672
714
|
expect { instance.transition_to!(:y) }.
|
673
715
|
to raise_error(Statesman::GuardFailedError)
|
674
716
|
end
|
717
|
+
|
718
|
+
context "and a guard failed callback defined" do
|
719
|
+
let(:guard_failure_result) { true }
|
720
|
+
let(:guard_failure_cb) { ->(*_args) { guard_failure_result } }
|
721
|
+
|
722
|
+
before { machine.after_guard_failure(from: :x, to: :y, &guard_failure_cb) }
|
723
|
+
|
724
|
+
it "calls the failure callback" do
|
725
|
+
expect(guard_failure_cb).to receive(:call).once.with(
|
726
|
+
my_model, instance_of(Statesman::GuardFailedError)
|
727
|
+
).and_return(guard_failure_result)
|
728
|
+
expect { instance.transition_to!(:y) }.
|
729
|
+
to raise_error(Statesman::GuardFailedError)
|
730
|
+
end
|
731
|
+
end
|
732
|
+
end
|
733
|
+
end
|
734
|
+
|
735
|
+
context "with a transition failed callback" do
|
736
|
+
let(:result) { true }
|
737
|
+
let(:transition_failed_cb) { ->(*_args) { result } }
|
738
|
+
let(:instance) { machine.new(my_model) }
|
739
|
+
|
740
|
+
before do
|
741
|
+
machine.after_transition_failure(&transition_failed_cb)
|
742
|
+
end
|
743
|
+
|
744
|
+
it "raises and exception and calls the callback" do
|
745
|
+
expect(transition_failed_cb).to receive(:call).once.with(
|
746
|
+
my_model, instance_of(Statesman::TransitionFailedError)
|
747
|
+
).and_return(true)
|
748
|
+
expect { instance.transition_to!(:z) }.
|
749
|
+
to raise_error(Statesman::TransitionFailedError)
|
675
750
|
end
|
676
751
|
end
|
677
752
|
end
|
@@ -695,7 +770,7 @@ describe Statesman::Machine do
|
|
695
770
|
context "when it is unsuccesful" do
|
696
771
|
before do
|
697
772
|
allow(instance).to receive(:transition_to!).
|
698
|
-
and_raise(Statesman::GuardFailedError)
|
773
|
+
and_raise(Statesman::GuardFailedError.new(:x, :some_state))
|
699
774
|
end
|
700
775
|
|
701
776
|
it { is_expected.to be_falsey }
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "json"
|
2
4
|
|
3
5
|
MIGRATION_CLASS = if Rails.version.split(".").map(&:to_i).first >= 5
|
@@ -94,14 +96,12 @@ class CreateMyActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
94
96
|
%i[my_active_record_model_id most_recent],
|
95
97
|
unique: true,
|
96
98
|
where: "most_recent",
|
97
|
-
name: "
|
98
|
-
"parent_most_recent"
|
99
|
+
name: "index_my_active_record_model_transitions_parent_latest"
|
99
100
|
else
|
100
101
|
add_index :my_active_record_model_transitions,
|
101
102
|
%i[my_active_record_model_id most_recent],
|
102
103
|
unique: true,
|
103
|
-
name: "
|
104
|
-
"parent_most_recent"
|
104
|
+
name: "index_my_active_record_model_transitions_parent_latest"
|
105
105
|
end
|
106
106
|
end
|
107
107
|
end
|
@@ -173,13 +173,13 @@ class CreateOtherActiveRecordModelTransitionMigration < MIGRATION_CLASS
|
|
173
173
|
unique: true,
|
174
174
|
where: "most_recent",
|
175
175
|
name: "index_other_active_record_model_transitions_"\
|
176
|
-
"
|
176
|
+
"parent_latest"
|
177
177
|
else
|
178
178
|
add_index :other_active_record_model_transitions,
|
179
179
|
%i[other_active_record_model_id most_recent],
|
180
180
|
unique: true,
|
181
181
|
name: "index_other_active_record_model_transitions_"\
|
182
|
-
"
|
182
|
+
"parent_latest"
|
183
183
|
end
|
184
184
|
end
|
185
185
|
end
|
@@ -188,8 +188,7 @@ end
|
|
188
188
|
class DropMostRecentColumn < MIGRATION_CLASS
|
189
189
|
def change
|
190
190
|
remove_index :my_active_record_model_transitions,
|
191
|
-
name: "
|
192
|
-
"parent_most_recent"
|
191
|
+
name: "index_my_active_record_model_transitions_parent_latest"
|
193
192
|
remove_column :my_active_record_model_transitions, :most_recent
|
194
193
|
end
|
195
194
|
end
|
@@ -270,14 +269,12 @@ class CreateNamespacedARModelTransitionMigration < MIGRATION_CLASS
|
|
270
269
|
%i[my_active_record_model_id most_recent],
|
271
270
|
unique: true,
|
272
271
|
where: "most_recent",
|
273
|
-
name: "
|
274
|
-
"parent_most_recent"
|
272
|
+
name: "index_namespace_model_transitions_parent_latest"
|
275
273
|
else
|
276
274
|
add_index :my_namespace_my_active_record_model_transitions,
|
277
275
|
%i[my_active_record_model_id most_recent],
|
278
276
|
unique: true,
|
279
|
-
name: "
|
280
|
-
"parent_most_recent"
|
277
|
+
name: "index_namespace_model_transitions_parent_latest"
|
281
278
|
end
|
282
279
|
end
|
283
280
|
# rubocop:enable MethodLength
|
data/statesman.gemspec
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
lib = File.expand_path("lib", __dir__)
|
2
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
5
|
require "statesman/version"
|
@@ -22,15 +24,15 @@ Gem::Specification.new do |spec|
|
|
22
24
|
spec.add_development_dependency "ammeter", "~> 1.1"
|
23
25
|
spec.add_development_dependency "bundler", "~> 1.3"
|
24
26
|
spec.add_development_dependency "gc_ruboconfig", "~> 2.3.9"
|
25
|
-
spec.add_development_dependency "mysql2", "
|
27
|
+
spec.add_development_dependency "mysql2", ">= 0.4", "< 0.6"
|
26
28
|
spec.add_development_dependency "pg", "~> 0.18"
|
27
29
|
spec.add_development_dependency "pry"
|
28
30
|
spec.add_development_dependency "rails", ">= 3.2"
|
29
|
-
spec.add_development_dependency "rake", "~>
|
31
|
+
spec.add_development_dependency "rake", "~> 13.0.0"
|
30
32
|
spec.add_development_dependency "rspec", "~> 3.1"
|
31
33
|
spec.add_development_dependency "rspec-its", "~> 1.1"
|
32
34
|
spec.add_development_dependency "rspec-rails", "~> 3.1"
|
33
35
|
spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.0"
|
34
|
-
spec.add_development_dependency "sqlite3", "~> 1.3"
|
36
|
+
spec.add_development_dependency "sqlite3", "~> 1.3.6"
|
35
37
|
spec.add_development_dependency "timecop", "~> 0.9.1"
|
36
38
|
end
|
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:
|
4
|
+
version: 6.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- GoCardless
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ammeter
|
@@ -56,16 +56,22 @@ dependencies:
|
|
56
56
|
name: mysql2
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.4
|
61
|
+
version: '0.4'
|
62
|
+
- - "<"
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0.6'
|
62
65
|
type: :development
|
63
66
|
prerelease: false
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
65
68
|
requirements:
|
66
|
-
- - "
|
69
|
+
- - ">="
|
67
70
|
- !ruby/object:Gem::Version
|
68
|
-
version: 0.4
|
71
|
+
version: '0.4'
|
72
|
+
- - "<"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '0.6'
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: pg
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|
@@ -114,14 +120,14 @@ dependencies:
|
|
114
120
|
requirements:
|
115
121
|
- - "~>"
|
116
122
|
- !ruby/object:Gem::Version
|
117
|
-
version:
|
123
|
+
version: 13.0.0
|
118
124
|
type: :development
|
119
125
|
prerelease: false
|
120
126
|
version_requirements: !ruby/object:Gem::Requirement
|
121
127
|
requirements:
|
122
128
|
- - "~>"
|
123
129
|
- !ruby/object:Gem::Version
|
124
|
-
version:
|
130
|
+
version: 13.0.0
|
125
131
|
- !ruby/object:Gem::Dependency
|
126
132
|
name: rspec
|
127
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -184,14 +190,14 @@ dependencies:
|
|
184
190
|
requirements:
|
185
191
|
- - "~>"
|
186
192
|
- !ruby/object:Gem::Version
|
187
|
-
version:
|
193
|
+
version: 1.3.6
|
188
194
|
type: :development
|
189
195
|
prerelease: false
|
190
196
|
version_requirements: !ruby/object:Gem::Requirement
|
191
197
|
requirements:
|
192
198
|
- - "~>"
|
193
199
|
- !ruby/object:Gem::Version
|
194
|
-
version:
|
200
|
+
version: 1.3.6
|
195
201
|
- !ruby/object:Gem::Dependency
|
196
202
|
name: timecop
|
197
203
|
requirement: !ruby/object:Gem::Requirement
|
@@ -228,10 +234,8 @@ files:
|
|
228
234
|
- lib/generators/statesman/active_record_transition_generator.rb
|
229
235
|
- lib/generators/statesman/generator_helpers.rb
|
230
236
|
- lib/generators/statesman/migration_generator.rb
|
231
|
-
- lib/generators/statesman/mongoid_transition_generator.rb
|
232
237
|
- lib/generators/statesman/templates/active_record_transition_model.rb.erb
|
233
238
|
- lib/generators/statesman/templates/create_migration.rb.erb
|
234
|
-
- lib/generators/statesman/templates/mongoid_transition_model.rb.erb
|
235
239
|
- lib/generators/statesman/templates/update_migration.rb.erb
|
236
240
|
- lib/statesman.rb
|
237
241
|
- lib/statesman/adapters/active_record.rb
|
@@ -239,8 +243,6 @@ files:
|
|
239
243
|
- lib/statesman/adapters/active_record_transition.rb
|
240
244
|
- lib/statesman/adapters/memory.rb
|
241
245
|
- lib/statesman/adapters/memory_transition.rb
|
242
|
-
- lib/statesman/adapters/mongoid.rb
|
243
|
-
- lib/statesman/adapters/mongoid_transition.rb
|
244
246
|
- lib/statesman/callback.rb
|
245
247
|
- lib/statesman/config.rb
|
246
248
|
- lib/statesman/exceptions.rb
|
@@ -255,14 +257,12 @@ files:
|
|
255
257
|
- spec/fixtures/add_most_recent_to_bacon_transitions.rb
|
256
258
|
- spec/generators/statesman/active_record_transition_generator_spec.rb
|
257
259
|
- spec/generators/statesman/migration_generator_spec.rb
|
258
|
-
- spec/generators/statesman/mongoid_transition_generator_spec.rb
|
259
260
|
- spec/spec_helper.rb
|
260
261
|
- spec/statesman/adapters/active_record_queries_spec.rb
|
261
262
|
- spec/statesman/adapters/active_record_spec.rb
|
262
263
|
- spec/statesman/adapters/active_record_transition_spec.rb
|
263
264
|
- spec/statesman/adapters/memory_spec.rb
|
264
265
|
- spec/statesman/adapters/memory_transition_spec.rb
|
265
|
-
- spec/statesman/adapters/mongoid_spec.rb
|
266
266
|
- spec/statesman/adapters/shared_examples.rb
|
267
267
|
- spec/statesman/callback_spec.rb
|
268
268
|
- spec/statesman/config_spec.rb
|
@@ -271,7 +271,6 @@ files:
|
|
271
271
|
- spec/statesman/utils_spec.rb
|
272
272
|
- spec/support/active_record.rb
|
273
273
|
- spec/support/generators_shared_examples.rb
|
274
|
-
- spec/support/mongoid.rb
|
275
274
|
- statesman.gemspec
|
276
275
|
homepage: https://github.com/gocardless/statesman
|
277
276
|
licenses:
|
@@ -292,8 +291,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
292
291
|
- !ruby/object:Gem::Version
|
293
292
|
version: '0'
|
294
293
|
requirements: []
|
295
|
-
|
296
|
-
rubygems_version: 2.6.14
|
294
|
+
rubygems_version: 3.1.1
|
297
295
|
signing_key:
|
298
296
|
specification_version: 4
|
299
297
|
summary: A statesman-like state machine library
|
@@ -303,14 +301,12 @@ test_files:
|
|
303
301
|
- spec/fixtures/add_most_recent_to_bacon_transitions.rb
|
304
302
|
- spec/generators/statesman/active_record_transition_generator_spec.rb
|
305
303
|
- spec/generators/statesman/migration_generator_spec.rb
|
306
|
-
- spec/generators/statesman/mongoid_transition_generator_spec.rb
|
307
304
|
- spec/spec_helper.rb
|
308
305
|
- spec/statesman/adapters/active_record_queries_spec.rb
|
309
306
|
- spec/statesman/adapters/active_record_spec.rb
|
310
307
|
- spec/statesman/adapters/active_record_transition_spec.rb
|
311
308
|
- spec/statesman/adapters/memory_spec.rb
|
312
309
|
- spec/statesman/adapters/memory_transition_spec.rb
|
313
|
-
- spec/statesman/adapters/mongoid_spec.rb
|
314
310
|
- spec/statesman/adapters/shared_examples.rb
|
315
311
|
- spec/statesman/callback_spec.rb
|
316
312
|
- spec/statesman/config_spec.rb
|
@@ -319,4 +315,3 @@ test_files:
|
|
319
315
|
- spec/statesman/utils_spec.rb
|
320
316
|
- spec/support/active_record.rb
|
321
317
|
- spec/support/generators_shared_examples.rb
|
322
|
-
- spec/support/mongoid.rb
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require "rails/generators"
|
2
|
-
require "generators/statesman/generator_helpers"
|
3
|
-
|
4
|
-
module Statesman
|
5
|
-
class MongoidTransitionGenerator < Rails::Generators::Base
|
6
|
-
include Statesman::GeneratorHelpers
|
7
|
-
|
8
|
-
desc "Create a Mongoid-based transition model with the required attributes"
|
9
|
-
|
10
|
-
argument :parent, type: :string, desc: "Your parent model name"
|
11
|
-
argument :klass, type: :string, desc: "Your transition model name"
|
12
|
-
|
13
|
-
source_root File.expand_path("templates", __dir__)
|
14
|
-
|
15
|
-
def create_model_file
|
16
|
-
template("mongoid_transition_model.rb.erb", model_file_name)
|
17
|
-
end
|
18
|
-
|
19
|
-
private
|
20
|
-
|
21
|
-
def collection_name
|
22
|
-
klass.underscore.pluralize
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
class <%= klass %>
|
2
|
-
include Mongoid::Document
|
3
|
-
include Mongoid::Timestamps
|
4
|
-
|
5
|
-
field :to_state, type: String
|
6
|
-
field :sort_key, type: Integer
|
7
|
-
field :statesman_metadata, type: Hash
|
8
|
-
|
9
|
-
include Statesman::Adapters::MongoidTransition
|
10
|
-
|
11
|
-
index({ sort_key: 1 })
|
12
|
-
|
13
|
-
belongs_to :<%= parent %><%= class_name_option %>, index: true
|
14
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
require_relative "../exceptions"
|
2
|
-
|
3
|
-
module Statesman
|
4
|
-
module Adapters
|
5
|
-
class Mongoid
|
6
|
-
attr_reader :transition_class
|
7
|
-
attr_reader :parent_model
|
8
|
-
|
9
|
-
def initialize(transition_class, parent_model, observer, _opts = {})
|
10
|
-
@transition_class = transition_class
|
11
|
-
@parent_model = parent_model
|
12
|
-
@observer = observer
|
13
|
-
unless transition_class_hash_fields.include?("statesman_metadata")
|
14
|
-
raise UnserializedMetadataError, metadata_field_error_message
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def create(from, to, metadata = {})
|
19
|
-
from = from.to_s
|
20
|
-
to = to.to_s
|
21
|
-
transition = transitions_for_parent.build(to_state: to,
|
22
|
-
sort_key: next_sort_key,
|
23
|
-
statesman_metadata: metadata)
|
24
|
-
|
25
|
-
@observer.execute(:before, from, to, transition)
|
26
|
-
transition.save!
|
27
|
-
@last_transition = transition
|
28
|
-
@observer.execute(:after, from, to, transition)
|
29
|
-
@observer.execute(:after_commit, from, to, transition)
|
30
|
-
transition
|
31
|
-
ensure
|
32
|
-
@last_transition = nil
|
33
|
-
end
|
34
|
-
|
35
|
-
def history(*)
|
36
|
-
transitions_for_parent.asc(:sort_key)
|
37
|
-
end
|
38
|
-
|
39
|
-
def last(force_reload: false)
|
40
|
-
if force_reload
|
41
|
-
@last_transition = history.last
|
42
|
-
else
|
43
|
-
@last_transition ||= history.last
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
def transition_class_hash_fields
|
50
|
-
transition_class.fields.select { |_, v| v.type == Hash }.keys
|
51
|
-
end
|
52
|
-
|
53
|
-
def metadata_field_error_message
|
54
|
-
"#{transition_class.name}#statesman_metadata is not of type 'Hash'"
|
55
|
-
end
|
56
|
-
|
57
|
-
def transitions_for_parent
|
58
|
-
@parent_model.send(@transition_class.collection_name)
|
59
|
-
end
|
60
|
-
|
61
|
-
def next_sort_key
|
62
|
-
(last && last.sort_key + 10) || 10
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "support/generators_shared_examples"
|
3
|
-
require "generators/statesman/mongoid_transition_generator"
|
4
|
-
|
5
|
-
describe Statesman::MongoidTransitionGenerator, type: :generator do
|
6
|
-
describe "the model contains the correct words" do
|
7
|
-
subject { file("app/models/yummy/bacon_transition.rb") }
|
8
|
-
|
9
|
-
before { run_generator %w[Yummy::Bacon Yummy::BaconTransition] }
|
10
|
-
|
11
|
-
it { is_expected.to_not contain(%r{:yummy/bacon}) }
|
12
|
-
it { is_expected.to contain(/class_name: 'Yummy::Bacon'/) }
|
13
|
-
end
|
14
|
-
|
15
|
-
describe "the model contains the correct words" do
|
16
|
-
subject { file("app/models/bacon_transition.rb") }
|
17
|
-
|
18
|
-
before { run_generator %w[Bacon BaconTransition] }
|
19
|
-
|
20
|
-
it { is_expected.to_not contain(/class_name:/) }
|
21
|
-
it { is_expected.to_not contain(/CreateYummy::Bacon/) }
|
22
|
-
end
|
23
|
-
end
|
@@ -1,86 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
require "statesman/adapters/shared_examples"
|
3
|
-
require "statesman/exceptions"
|
4
|
-
require "support/mongoid"
|
5
|
-
require "mongoid"
|
6
|
-
|
7
|
-
describe Statesman::Adapters::Mongoid, mongo: true do
|
8
|
-
after { Mongoid.purge! }
|
9
|
-
|
10
|
-
let(:observer) { double(Statesman::Machine, execute: nil) }
|
11
|
-
let(:model) { MyMongoidModel.create(current_state: :pending) }
|
12
|
-
|
13
|
-
it_behaves_like "an adapter", described_class, MyMongoidModelTransition
|
14
|
-
|
15
|
-
describe "#initialize" do
|
16
|
-
context "with unserialized metadata" do
|
17
|
-
before do
|
18
|
-
allow_any_instance_of(described_class).
|
19
|
-
to receive_messages(transition_class_hash_fields: [])
|
20
|
-
end
|
21
|
-
|
22
|
-
it "raises an exception if metadata is not serialized" do
|
23
|
-
expect do
|
24
|
-
described_class.new(MyMongoidModelTransition, MyMongoidModel,
|
25
|
-
observer)
|
26
|
-
end.to raise_exception(Statesman::UnserializedMetadataError)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
describe "#last" do
|
32
|
-
let(:adapter) do
|
33
|
-
described_class.new(MyMongoidModelTransition, model, observer)
|
34
|
-
end
|
35
|
-
|
36
|
-
context "with a previously looked up transition" do
|
37
|
-
before { adapter.create(:x, :y) }
|
38
|
-
|
39
|
-
before { adapter.last }
|
40
|
-
|
41
|
-
it "caches the transition" do
|
42
|
-
expect_any_instance_of(MyMongoidModel).
|
43
|
-
to_not receive(:my_mongoid_model_transitions)
|
44
|
-
adapter.last
|
45
|
-
end
|
46
|
-
|
47
|
-
context "and a new transition" do
|
48
|
-
before { adapter.create(:y, :z) }
|
49
|
-
|
50
|
-
it "retrieves the new transition from the database" do
|
51
|
-
expect(adapter.last.to_state).to eq("z")
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context "when a new transition has been created elsewhere" do
|
57
|
-
let(:alternate_adapter) do
|
58
|
-
described_class.new(MyMongoidModelTransition, model, observer)
|
59
|
-
end
|
60
|
-
|
61
|
-
context "when explicitly not using the cache" do
|
62
|
-
context "when the transitions are in memory" do
|
63
|
-
before do
|
64
|
-
model.my_mongoid_model_transitions.entries
|
65
|
-
alternate_adapter.create(:y, :z)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "reloads the value" do
|
69
|
-
expect(adapter.last(force_reload: true).to_state).to eq("z")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
context "when the transitions are not in memory" do
|
74
|
-
before do
|
75
|
-
model.my_mongoid_model_transitions.reset
|
76
|
-
alternate_adapter.create(:y, :z)
|
77
|
-
end
|
78
|
-
|
79
|
-
it "reloads the value" do
|
80
|
-
expect(adapter.last(force_reload: true).to_state).to eq("z")
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
data/spec/support/mongoid.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
require "mongoid"
|
2
|
-
|
3
|
-
Mongoid.configure do |config|
|
4
|
-
config.connect_to("statesman_test")
|
5
|
-
end
|
6
|
-
|
7
|
-
class MyMongoidModel
|
8
|
-
include Mongoid::Document
|
9
|
-
|
10
|
-
field :current_state, type: String
|
11
|
-
|
12
|
-
has_many :my_mongoid_model_transitions
|
13
|
-
end
|
14
|
-
|
15
|
-
class MyMongoidModelTransition
|
16
|
-
include Mongoid::Document
|
17
|
-
include Mongoid::Timestamps
|
18
|
-
|
19
|
-
field :to_state, type: String
|
20
|
-
field :sort_key, type: Integer
|
21
|
-
field :statesman_metadata, type: Hash
|
22
|
-
|
23
|
-
index(sort_key: 1)
|
24
|
-
|
25
|
-
belongs_to :my_mongoid_model, index: true
|
26
|
-
|
27
|
-
include Statesman::Adapters::MongoidTransition
|
28
|
-
end
|