statesman 3.5.0 → 7.4.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.
Files changed (56) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +49 -250
  3. data/.rubocop.yml +1 -1
  4. data/.rubocop_todo.yml +26 -6
  5. data/CHANGELOG.md +106 -0
  6. data/Gemfile +10 -4
  7. data/Guardfile +2 -0
  8. data/README.md +78 -48
  9. data/Rakefile +2 -4
  10. data/lib/generators/statesman/active_record_transition_generator.rb +2 -0
  11. data/lib/generators/statesman/generator_helpers.rb +2 -0
  12. data/lib/generators/statesman/migration_generator.rb +2 -0
  13. data/lib/statesman.rb +14 -4
  14. data/lib/statesman/adapters/active_record.rb +259 -37
  15. data/lib/statesman/adapters/active_record_queries.rb +100 -36
  16. data/lib/statesman/adapters/active_record_transition.rb +2 -0
  17. data/lib/statesman/adapters/memory.rb +2 -0
  18. data/lib/statesman/adapters/memory_transition.rb +2 -0
  19. data/lib/statesman/callback.rb +2 -0
  20. data/lib/statesman/config.rb +28 -0
  21. data/lib/statesman/exceptions.rb +34 -2
  22. data/lib/statesman/guard.rb +3 -4
  23. data/lib/statesman/machine.rb +29 -7
  24. data/lib/statesman/railtie.rb +2 -0
  25. data/lib/statesman/utils.rb +2 -0
  26. data/lib/statesman/version.rb +3 -1
  27. data/lib/tasks/statesman.rake +3 -1
  28. data/spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_with_partial_index.rb +2 -0
  29. data/spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions_without_partial_index.rb +2 -0
  30. data/spec/fixtures/add_most_recent_to_bacon_transitions.rb +2 -0
  31. data/spec/generators/statesman/active_record_transition_generator_spec.rb +2 -0
  32. data/spec/generators/statesman/migration_generator_spec.rb +2 -0
  33. data/spec/spec_helper.rb +3 -30
  34. data/spec/statesman/adapters/active_record_queries_spec.rb +167 -91
  35. data/spec/statesman/adapters/active_record_spec.rb +15 -1
  36. data/spec/statesman/adapters/active_record_transition_spec.rb +2 -0
  37. data/spec/statesman/adapters/memory_spec.rb +2 -0
  38. data/spec/statesman/adapters/memory_transition_spec.rb +2 -0
  39. data/spec/statesman/adapters/shared_examples.rb +2 -0
  40. data/spec/statesman/callback_spec.rb +2 -0
  41. data/spec/statesman/config_spec.rb +2 -0
  42. data/spec/statesman/exceptions_spec.rb +88 -0
  43. data/spec/statesman/guard_spec.rb +2 -0
  44. data/spec/statesman/machine_spec.rb +79 -4
  45. data/spec/statesman/utils_spec.rb +2 -0
  46. data/spec/support/active_record.rb +9 -12
  47. data/spec/support/generators_shared_examples.rb +2 -0
  48. data/statesman.gemspec +19 -7
  49. metadata +40 -32
  50. data/lib/generators/statesman/mongoid_transition_generator.rb +0 -25
  51. data/lib/generators/statesman/templates/mongoid_transition_model.rb.erb +0 -14
  52. data/lib/statesman/adapters/mongoid.rb +0 -66
  53. data/lib/statesman/adapters/mongoid_transition.rb +0 -10
  54. data/spec/generators/statesman/mongoid_transition_generator_spec.rb +0 -23
  55. data/spec/statesman/adapters/mongoid_spec.rb +0 -86
  56. data/spec/support/mongoid.rb +0 -28
@@ -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,10 +0,0 @@
1
- module Statesman
2
- module Adapters
3
- module MongoidTransition
4
- def self.included(base)
5
- base.send(:alias_method, :metadata, :statesman_metadata)
6
- base.send(:alias_method, :metadata=, :statesman_metadata=)
7
- end
8
- end
9
- end
10
- 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
@@ -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