statesman 0.0.1 → 0.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 +4 -4
- data/.travis.yml +6 -0
- data/README.md +14 -11
- data/Rakefile +5 -0
- data/lib/generators/statesman/{transition_generator.rb → active_record_transition_generator.rb} +4 -3
- data/lib/generators/statesman/mongoid_transition_generator.rb +31 -0
- data/lib/generators/statesman/templates/{transition_model.rb.erb → active_record_transition_model.rb.erb} +2 -0
- data/lib/generators/statesman/templates/mongoid_transition_model.rb.erb +13 -0
- data/lib/statesman.rb +7 -3
- data/lib/statesman/adapters/active_record.rb +1 -2
- data/lib/statesman/adapters/active_record_transition.rb +11 -0
- data/lib/statesman/adapters/memory_transition.rb +17 -0
- data/lib/statesman/adapters/mongoid.rb +56 -0
- data/lib/statesman/adapters/mongoid_transition.rb +10 -0
- data/lib/statesman/callback.rb +1 -1
- data/lib/statesman/config.rb +1 -6
- data/lib/statesman/guard.rb +2 -2
- data/lib/statesman/machine.rb +7 -6
- data/lib/statesman/version.rb +1 -1
- data/spec/spec_helper.rb +6 -2
- data/spec/statesman/adapters/active_record_spec.rb +9 -7
- data/spec/statesman/adapters/active_record_transition_spec.rb +13 -0
- data/spec/statesman/adapters/memory_spec.rb +3 -1
- data/spec/statesman/adapters/mongoid_spec.rb +53 -0
- data/spec/statesman/adapters/shared_examples.rb +4 -1
- data/spec/statesman/config_spec.rb +0 -8
- data/spec/statesman/machine_spec.rb +3 -2
- data/spec/statesman/transition_spec.rb +3 -3
- data/spec/support/active_record.rb +10 -10
- data/spec/support/mongoid.rb +26 -0
- data/statesman.gemspec +1 -0
- metadata +31 -5
- data/lib/statesman/transition.rb +0 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d60f1115392a3fb65d3911e82fb0afbda37fa632
|
4
|
+
data.tar.gz: 09691527947f5a9b5b788191a84beb6503c1d175
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a3c0edea7bf34a8eccd9106cb916f85599b7afff8b0e8ad781972ac38535e1a325659be2f71a91332323790309cf0103e3034ccc97d43a2d88b416da882a42d
|
7
|
+
data.tar.gz: f53ba2aea159a9e372a26d8b803459317370082631b4070369ba5e8f8e87315fdd0a8a7117db331d509a2635753651123eb667285b5628025b377992457f8248
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -2,6 +2,10 @@
|
|
2
2
|
|
3
3
|
A statesmanlike state machine library for Ruby 2.0.
|
4
4
|
|
5
|
+
[](http://badge.fury.io/rb/statesman)
|
6
|
+
[](https://travis-ci.org/gocardless/statesman)
|
7
|
+
[](https://codeclimate.com/github/gocardless/statesman)
|
8
|
+
|
5
9
|
Statesman is a little different from other state machine libraries which tack state behaviour directly onto a model. A statesman state machine is defined as a separate class which is instantiated with the model to which it should apply. State transitions are also modelled as a class which can optionally be persisted to the database for a full audit history, including JSON metadata which can be set during a transition.
|
6
10
|
|
7
11
|
This data model allows for interesting things like using a different state machine depending on the value of a model attribute.
|
@@ -51,6 +55,8 @@ class Order < ActiveRecord::Base
|
|
51
55
|
end
|
52
56
|
|
53
57
|
class OrderTransition < ActiveRecord::Base
|
58
|
+
include Statesman::Adapters::ActiveRecordTransition
|
59
|
+
|
54
60
|
belongs_to :order, inverse_of: :order_transitions
|
55
61
|
end
|
56
62
|
|
@@ -78,14 +84,13 @@ ActiveRecord within Rails:
|
|
78
84
|
```ruby
|
79
85
|
Statesman.configure do
|
80
86
|
storage_adapter(Statesman::Adapters::ActiveRecord)
|
81
|
-
transition_class(OrderTransition)
|
82
87
|
end
|
83
88
|
```
|
84
89
|
|
85
90
|
Generate the transition model:
|
86
91
|
|
87
92
|
```bash
|
88
|
-
$ rails g statesman:
|
93
|
+
$ rails g statesman:active_record_transition Order OrderTransition
|
89
94
|
```
|
90
95
|
|
91
96
|
And add an association from the parent model:
|
@@ -114,17 +119,11 @@ end
|
|
114
119
|
```ruby
|
115
120
|
Statesman.configure do
|
116
121
|
storage_adapter(Statesman::Adapters::ActiveRecord)
|
122
|
+
# ...or
|
123
|
+
storage_adapter(Statesman::Adapters::Mongoid)
|
117
124
|
end
|
118
125
|
```
|
119
|
-
Statesman defaults to storing transitions in memory. If you're using rails, you can instead configure it to persist transitions to the database by using the ActiveRecord adapter.
|
120
|
-
|
121
|
-
#### `transition_class`
|
122
|
-
```ruby
|
123
|
-
Statesman.configure do
|
124
|
-
transition_class(OrderTransition)
|
125
|
-
end
|
126
|
-
```
|
127
|
-
Configure the transition model. For now that means serializing metadata to JSON.
|
126
|
+
Statesman defaults to storing transitions in memory. If you're using rails, you can instead configure it to persist transitions to the database by using the ActiveRecord or Mongoid adapter.
|
128
127
|
|
129
128
|
|
130
129
|
## Class methods
|
@@ -191,3 +190,7 @@ Transition to the passed state, returning `true` on success. Raises `Statesman::
|
|
191
190
|
|
192
191
|
#### `Machine#transition_to(:state)`
|
193
192
|
Transition to the passed state, returning `true` on success. Swallows all exceptions and returns false on failure.
|
193
|
+
|
194
|
+
---
|
195
|
+
|
196
|
+
GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs/backend_developer).
|
data/Rakefile
CHANGED
data/lib/generators/statesman/{transition_generator.rb → active_record_transition_generator.rb}
RENAMED
@@ -1,8 +1,9 @@
|
|
1
1
|
require "rails/generators"
|
2
2
|
|
3
3
|
module Statesman
|
4
|
-
class
|
5
|
-
desc "Create
|
4
|
+
class ActiveRecordTransitionGenerator < Rails::Generators::Base
|
5
|
+
desc "Create an ActiveRecord-based transition model" +
|
6
|
+
"with the required attributes"
|
6
7
|
|
7
8
|
argument :parent, type: :string, desc: "Your parent model name"
|
8
9
|
argument :klass, type: :string, desc: "Your transition model name"
|
@@ -11,7 +12,7 @@ module Statesman
|
|
11
12
|
|
12
13
|
def create_model_file
|
13
14
|
template("create_migration.rb.erb", migration_file_name)
|
14
|
-
template("
|
15
|
+
template("active_record_transition_model.rb.erb", model_file_name)
|
15
16
|
end
|
16
17
|
|
17
18
|
private
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
|
3
|
+
module Statesman
|
4
|
+
class MongoidTransitionGenerator < Rails::Generators::Base
|
5
|
+
desc "Create a Mongoid-based transition model with the required attributes"
|
6
|
+
|
7
|
+
argument :parent, type: :string, desc: "Your parent model name"
|
8
|
+
argument :klass, type: :string, desc: "Your transition model name"
|
9
|
+
|
10
|
+
source_root File.expand_path('../templates', __FILE__)
|
11
|
+
|
12
|
+
def create_model_file
|
13
|
+
template("mongoid_transition_model.rb.erb", model_file_name)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def model_file_name
|
19
|
+
"app/models/#{klass.underscore}.rb"
|
20
|
+
end
|
21
|
+
|
22
|
+
def collection_name
|
23
|
+
klass.underscore.pluralize
|
24
|
+
end
|
25
|
+
|
26
|
+
def parent_id
|
27
|
+
parent.underscore + "_id"
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class <%= klass %>
|
2
|
+
include Mongoid::Document
|
3
|
+
include Statesman::Adapters::MongoidTransition
|
4
|
+
|
5
|
+
field :to_state, type: String
|
6
|
+
field :sort_key, type: Integer
|
7
|
+
field :statesman_metadata, type: Hash
|
8
|
+
|
9
|
+
index({ sort_key: 1 })
|
10
|
+
|
11
|
+
belongs_to :<%= parent.underscore %>, index: true
|
12
|
+
|
13
|
+
end
|
data/lib/statesman.rb
CHANGED
@@ -3,10 +3,14 @@ module Statesman
|
|
3
3
|
autoload :Machine, 'statesman/machine'
|
4
4
|
autoload :Callback, 'statesman/callback'
|
5
5
|
autoload :Guard, 'statesman/guard'
|
6
|
-
autoload :Transition, 'statesman/transition'
|
7
6
|
autoload :Version, 'statesman/version'
|
8
|
-
|
9
|
-
|
7
|
+
module Adapters
|
8
|
+
autoload :Memory, "statesman/adapters/memory"
|
9
|
+
autoload :ActiveRecord, "statesman/adapters/active_record"
|
10
|
+
autoload :ActiveRecordTransition,
|
11
|
+
"statesman/adapters/active_record_transition"
|
12
|
+
autoload :Mongoid, "statesman/adapters/mongoid"
|
13
|
+
end
|
10
14
|
|
11
15
|
# Example:
|
12
16
|
# Statesman.configure do
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Statesman
|
2
|
+
module Adapters
|
3
|
+
class MemoryTransition
|
4
|
+
attr_accessor :created_at
|
5
|
+
attr_accessor :to_state
|
6
|
+
attr_accessor :sort_key
|
7
|
+
attr_accessor :metadata
|
8
|
+
|
9
|
+
def initialize(to, sort_key, metadata = nil)
|
10
|
+
@created_at = Time.now
|
11
|
+
@to_state = to
|
12
|
+
@sort_key = sort_key
|
13
|
+
@metadata = metadata
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,56 @@
|
|
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)
|
10
|
+
@transition_class = transition_class
|
11
|
+
@parent_model = parent_model
|
12
|
+
unless transition_class_hash_fields.include?('statesman_metadata')
|
13
|
+
raise UnserializedMetadataError, metadata_field_error_message
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def create(to, before_cbs, after_cbs, metadata = {})
|
18
|
+
transition = transitions_for_parent.build(to_state: to,
|
19
|
+
sort_key: next_sort_key,
|
20
|
+
statesman_metadata: metadata)
|
21
|
+
|
22
|
+
before_cbs.each { |cb| cb.call(@parent_model, transition) }
|
23
|
+
transition.save!
|
24
|
+
after_cbs.each { |cb| cb.call(@parent_model, transition) }
|
25
|
+
@last_transition = nil
|
26
|
+
transition
|
27
|
+
end
|
28
|
+
|
29
|
+
def history
|
30
|
+
transitions_for_parent.asc(:sort_key)
|
31
|
+
end
|
32
|
+
|
33
|
+
def last
|
34
|
+
@last_transition ||= history.last
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def transition_class_hash_fields
|
40
|
+
transition_class.fields.select { |k, v| v.type == Hash }.keys
|
41
|
+
end
|
42
|
+
|
43
|
+
def metadata_field_error_message
|
44
|
+
"#{transition_class.name}#statesman_metadata is not of type 'Hash'"
|
45
|
+
end
|
46
|
+
|
47
|
+
def transitions_for_parent
|
48
|
+
@parent_model.send(@transition_class.collection_name)
|
49
|
+
end
|
50
|
+
|
51
|
+
def next_sort_key
|
52
|
+
(last && last.sort_key + 10) || 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
data/lib/statesman/callback.rb
CHANGED
data/lib/statesman/config.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require "json"
|
2
|
-
|
2
|
+
require_relative "exceptions"
|
3
3
|
|
4
4
|
module Statesman
|
5
5
|
class Config
|
@@ -14,10 +14,5 @@ module Statesman
|
|
14
14
|
@adapter_class = adapter_class
|
15
15
|
end
|
16
16
|
# rubocop:enable TrivialAccessors
|
17
|
-
|
18
|
-
def transition_class(*args)
|
19
|
-
args.each { |klass| klass.serialize(:metadata, JSON) }
|
20
|
-
end
|
21
|
-
|
22
17
|
end
|
23
18
|
end
|
data/lib/statesman/guard.rb
CHANGED
data/lib/statesman/machine.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
require_relative "version"
|
2
|
+
require_relative "exceptions"
|
3
|
+
require_relative "guard"
|
4
|
+
require_relative "callback"
|
5
|
+
require_relative "adapters/memory_transition"
|
6
6
|
|
7
7
|
module Statesman
|
8
8
|
# The main module, that should be `extend`ed in to state machine classes.
|
@@ -138,7 +138,8 @@ module Statesman
|
|
138
138
|
end
|
139
139
|
end
|
140
140
|
|
141
|
-
def initialize(object,
|
141
|
+
def initialize(object,
|
142
|
+
transition_class: Statesman::Adapters::MemoryTransition)
|
142
143
|
@object = object
|
143
144
|
@storage_adapter = Statesman.storage_adapter.new(transition_class,
|
144
145
|
object)
|
data/lib/statesman/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -21,11 +21,15 @@ RSpec.configure do |config|
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def prepare_model_table
|
24
|
-
silence_stream(STDOUT)
|
24
|
+
silence_stream(STDOUT) do
|
25
|
+
CreateMyActiveRecordModelMigration.migrate(:up)
|
26
|
+
end
|
25
27
|
end
|
26
28
|
|
27
29
|
def prepare_transitions_table
|
28
|
-
silence_stream(STDOUT)
|
30
|
+
silence_stream(STDOUT) do
|
31
|
+
CreateMyActiveRecordModelTransitionMigration.migrate(:up)
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
35
|
|
@@ -8,25 +8,26 @@ describe Statesman::Adapters::ActiveRecord do
|
|
8
8
|
prepare_transitions_table
|
9
9
|
end
|
10
10
|
|
11
|
-
before {
|
11
|
+
before { MyActiveRecordModelTransition.serialize(:metadata, JSON) }
|
12
12
|
|
13
|
-
let(:model) {
|
14
|
-
it_behaves_like "an adapter", described_class,
|
13
|
+
let(:model) { MyActiveRecordModel.create(current_state: :pending) }
|
14
|
+
it_behaves_like "an adapter", described_class, MyActiveRecordModelTransition
|
15
15
|
|
16
16
|
describe "#initialize" do
|
17
17
|
context "with unserialized metadata" do
|
18
|
-
before {
|
18
|
+
before { MyActiveRecordModelTransition.stub(serialized_attributes: {}) }
|
19
19
|
|
20
20
|
it "raises an exception if metadata is not serialized" do
|
21
21
|
expect do
|
22
|
-
described_class.new(
|
22
|
+
described_class.new(MyActiveRecordModelTransition,
|
23
|
+
MyActiveRecordModel)
|
23
24
|
end.to raise_exception(Statesman::UnserializedMetadataError)
|
24
25
|
end
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
28
29
|
describe "#last" do
|
29
|
-
let(:adapter) { described_class.new(
|
30
|
+
let(:adapter) { described_class.new(MyActiveRecordModelTransition, model) }
|
30
31
|
|
31
32
|
context "with a previously looked up transition" do
|
32
33
|
before do
|
@@ -35,7 +36,8 @@ describe Statesman::Adapters::ActiveRecord do
|
|
35
36
|
end
|
36
37
|
|
37
38
|
it "caches the transition" do
|
38
|
-
|
39
|
+
MyActiveRecordModel.any_instance
|
40
|
+
.should_receive(:my_active_record_model_transitions).never
|
39
41
|
adapter.last
|
40
42
|
end
|
41
43
|
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
describe Statesman::Adapters::ActiveRecordTransition do
|
5
|
+
let(:transition_class) { Class.new }
|
6
|
+
|
7
|
+
describe "including behaviour" do
|
8
|
+
it "calls Class.serialize" do
|
9
|
+
transition_class.should_receive(:serialize).with(:metadata, JSON).once
|
10
|
+
transition_class.send(:include, described_class)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -1,7 +1,9 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
require "statesman/adapters/shared_examples"
|
3
|
+
require "statesman/adapters/memory_transition"
|
3
4
|
|
4
5
|
describe Statesman::Adapters::Memory do
|
5
6
|
let(:model) { Class.new { attr_accessor :current_state }.new }
|
6
|
-
it_behaves_like "an adapter", described_class,
|
7
|
+
it_behaves_like "an adapter", described_class,
|
8
|
+
Statesman::Adapters::MemoryTransition
|
7
9
|
end
|
@@ -0,0 +1,53 @@
|
|
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 do
|
8
|
+
|
9
|
+
after do
|
10
|
+
Mongoid.purge!
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:model) { MyMongoidModel.create(current_state: :pending) }
|
14
|
+
it_behaves_like "an adapter", described_class, MyMongoidModelTransition
|
15
|
+
|
16
|
+
describe "#initialize" do
|
17
|
+
context "with unserialized metadata" do
|
18
|
+
before do
|
19
|
+
described_class.any_instance.stub(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
|
+
end.to raise_exception(Statesman::UnserializedMetadataError)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "#last" do
|
31
|
+
let(:adapter) { described_class.new(MyMongoidModelTransition, model) }
|
32
|
+
|
33
|
+
context "with a previously looked up transition" do
|
34
|
+
before do
|
35
|
+
adapter.create(:y, [], [])
|
36
|
+
adapter.last
|
37
|
+
end
|
38
|
+
|
39
|
+
it "caches the transition" do
|
40
|
+
MyMongoidModel.any_instance
|
41
|
+
.should_receive(:my_mongoid_model_transitions).never
|
42
|
+
adapter.last
|
43
|
+
end
|
44
|
+
|
45
|
+
context "and a new transition" do
|
46
|
+
before { adapter.create(:z, [], []) }
|
47
|
+
it "retrieves the new transition from the database" do
|
48
|
+
expect(adapter.last.to_state).to eq("z")
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -33,7 +33,10 @@ shared_examples_for "an adapter" do |adapter_class, transition_class|
|
|
33
33
|
context "the new transition" do
|
34
34
|
subject { create }
|
35
35
|
it { should be_a(transition_class) }
|
36
|
-
|
36
|
+
|
37
|
+
it "should have the initial state" do
|
38
|
+
expect(subject.to_state.to_sym).to eq(to)
|
39
|
+
end
|
37
40
|
|
38
41
|
context "with no previous transition" do
|
39
42
|
its(:sort_key) { should be(0) }
|
@@ -23,12 +23,4 @@ describe Statesman::Config do
|
|
23
23
|
expect(defined_adapter).to be(new_adapter)
|
24
24
|
end
|
25
25
|
end
|
26
|
-
|
27
|
-
describe "#transition_class" do
|
28
|
-
it "serializes metadata to JSON" do
|
29
|
-
klass = Class.new
|
30
|
-
klass.should_receive(:serialize).once.with(:metadata, JSON)
|
31
|
-
Statesman.configure { transition_class(klass) }
|
32
|
-
end
|
33
|
-
end
|
34
26
|
end
|
@@ -194,7 +194,7 @@ describe Statesman::Machine do
|
|
194
194
|
context "transition class" do
|
195
195
|
it "sets a default" do
|
196
196
|
Statesman.storage_adapter.should_receive(:new).once
|
197
|
-
.with(Statesman::
|
197
|
+
.with(Statesman::Adapters::MemoryTransition, my_model)
|
198
198
|
machine.new(my_model)
|
199
199
|
end
|
200
200
|
|
@@ -314,7 +314,8 @@ describe Statesman::Machine do
|
|
314
314
|
instance.transition_to!(:y)
|
315
315
|
end.to change(instance.history, :count).by(1)
|
316
316
|
|
317
|
-
expect(instance.history.first)
|
317
|
+
expect(instance.history.first)
|
318
|
+
.to be_a(Statesman::Adapters::MemoryTransition)
|
318
319
|
expect(instance.history.first.to_state).to eq("y")
|
319
320
|
end
|
320
321
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
require "spec_helper"
|
2
2
|
|
3
|
-
describe Statesman::
|
3
|
+
describe Statesman::Adapters::MemoryTransition do
|
4
4
|
describe "#initialize" do
|
5
5
|
let(:to) { :y }
|
6
6
|
let(:sort_key) { 0 }
|
7
|
-
let(:create) {
|
7
|
+
let(:create) { described_class.new(to, sort_key) }
|
8
8
|
|
9
9
|
specify { expect(create.to_state).to equal(to) }
|
10
10
|
specify { expect(create.created_at).to be_a(Time) }
|
@@ -12,7 +12,7 @@ describe Statesman::Transition do
|
|
12
12
|
|
13
13
|
context "with metadata passed" do
|
14
14
|
let(:metadata) { { some: :hash } }
|
15
|
-
let(:create) {
|
15
|
+
let(:create) { described_class.new(to, sort_key, metadata) }
|
16
16
|
|
17
17
|
specify { expect(create.metadata).to eq(metadata) }
|
18
18
|
end
|
@@ -2,17 +2,17 @@ require "support/active_record"
|
|
2
2
|
|
3
3
|
DB = Pathname.new("test.sqlite3")
|
4
4
|
|
5
|
-
class
|
6
|
-
has_many :
|
5
|
+
class MyActiveRecordModel < ActiveRecord::Base
|
6
|
+
has_many :my_active_record_model_transitions
|
7
7
|
end
|
8
8
|
|
9
|
-
class
|
10
|
-
belongs_to :
|
9
|
+
class MyActiveRecordModelTransition < ActiveRecord::Base
|
10
|
+
belongs_to :my_active_record_model
|
11
11
|
end
|
12
12
|
|
13
|
-
class
|
13
|
+
class CreateMyActiveRecordModelMigration < ActiveRecord::Migration
|
14
14
|
def change
|
15
|
-
create_table :
|
15
|
+
create_table :my_active_record_models do |t|
|
16
16
|
t.string :current_state
|
17
17
|
t.timestamps
|
18
18
|
end
|
@@ -20,16 +20,16 @@ class CreateMyModelMigration < ActiveRecord::Migration
|
|
20
20
|
end
|
21
21
|
|
22
22
|
# TODO: make this a module we can extend from the app? Or a generator?
|
23
|
-
class
|
23
|
+
class CreateMyActiveRecordModelTransitionMigration < ActiveRecord::Migration
|
24
24
|
def change
|
25
|
-
create_table :
|
25
|
+
create_table :my_active_record_model_transitions do |t|
|
26
26
|
t.string :to_state
|
27
|
-
t.integer :
|
27
|
+
t.integer :my_active_record_model_id
|
28
28
|
t.integer :sort_key
|
29
29
|
t.text :metadata
|
30
30
|
t.timestamps
|
31
31
|
end
|
32
32
|
|
33
|
-
add_index :
|
33
|
+
add_index :my_active_record_model_transitions, :sort_key, unique: true
|
34
34
|
end
|
35
35
|
end
|
@@ -0,0 +1,26 @@
|
|
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
|
+
has_many :my_mongoid_model_transitions
|
11
|
+
end
|
12
|
+
|
13
|
+
class MyMongoidModelTransition
|
14
|
+
include Mongoid::Document
|
15
|
+
|
16
|
+
field :to_state, type: String
|
17
|
+
field :sort_key, type: Integer
|
18
|
+
field :statesman_metadata, type: Hash
|
19
|
+
|
20
|
+
index({ sort_key: 1 })
|
21
|
+
|
22
|
+
belongs_to :my_mongoid_model, index: true
|
23
|
+
|
24
|
+
alias_method :metadata, :statesman_metadata
|
25
|
+
alias_method :metadata=, :statesman_metadata=
|
26
|
+
end
|
data/statesman.gemspec
CHANGED
@@ -26,4 +26,5 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency "guard-rubocop", "~> 0.2.2"
|
27
27
|
spec.add_development_dependency "activerecord", "~> 3.2"
|
28
28
|
spec.add_development_dependency "sqlite3", "~> 1.3.8"
|
29
|
+
spec.add_development_dependency "mongoid", "~> 3.1.5"
|
29
30
|
end
|
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.0
|
4
|
+
version: 0.1.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: 2013-
|
12
|
+
date: 2013-11-05 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -123,6 +123,20 @@ dependencies:
|
|
123
123
|
- - ~>
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: 1.3.8
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: mongoid
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ~>
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: 3.1.5
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ~>
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: 3.1.5
|
126
140
|
description: A statesmanlike state machine library
|
127
141
|
email:
|
128
142
|
- developers@gocardless.com
|
@@ -132,30 +146,38 @@ extra_rdoc_files: []
|
|
132
146
|
files:
|
133
147
|
- .gitignore
|
134
148
|
- .rubocop.yml
|
149
|
+
- .travis.yml
|
135
150
|
- Gemfile
|
136
151
|
- Guardfile
|
137
152
|
- LICENSE.txt
|
138
153
|
- README.md
|
139
154
|
- Rakefile
|
140
155
|
- circle.yml
|
156
|
+
- lib/generators/statesman/active_record_transition_generator.rb
|
141
157
|
- lib/generators/statesman/migration_generator.rb
|
158
|
+
- lib/generators/statesman/mongoid_transition_generator.rb
|
159
|
+
- lib/generators/statesman/templates/active_record_transition_model.rb.erb
|
142
160
|
- lib/generators/statesman/templates/create_migration.rb.erb
|
143
|
-
- lib/generators/statesman/templates/
|
161
|
+
- lib/generators/statesman/templates/mongoid_transition_model.rb.erb
|
144
162
|
- lib/generators/statesman/templates/update_migration.rb.erb
|
145
|
-
- lib/generators/statesman/transition_generator.rb
|
146
163
|
- lib/statesman.rb
|
147
164
|
- lib/statesman/adapters/active_record.rb
|
165
|
+
- lib/statesman/adapters/active_record_transition.rb
|
148
166
|
- lib/statesman/adapters/memory.rb
|
167
|
+
- lib/statesman/adapters/memory_transition.rb
|
168
|
+
- lib/statesman/adapters/mongoid.rb
|
169
|
+
- lib/statesman/adapters/mongoid_transition.rb
|
149
170
|
- lib/statesman/callback.rb
|
150
171
|
- lib/statesman/config.rb
|
151
172
|
- lib/statesman/exceptions.rb
|
152
173
|
- lib/statesman/guard.rb
|
153
174
|
- lib/statesman/machine.rb
|
154
|
-
- lib/statesman/transition.rb
|
155
175
|
- lib/statesman/version.rb
|
156
176
|
- spec/spec_helper.rb
|
157
177
|
- spec/statesman/adapters/active_record_spec.rb
|
178
|
+
- spec/statesman/adapters/active_record_transition_spec.rb
|
158
179
|
- spec/statesman/adapters/memory_spec.rb
|
180
|
+
- spec/statesman/adapters/mongoid_spec.rb
|
159
181
|
- spec/statesman/adapters/shared_examples.rb
|
160
182
|
- spec/statesman/callback_spec.rb
|
161
183
|
- spec/statesman/config_spec.rb
|
@@ -163,6 +185,7 @@ files:
|
|
163
185
|
- spec/statesman/machine_spec.rb
|
164
186
|
- spec/statesman/transition_spec.rb
|
165
187
|
- spec/support/active_record.rb
|
188
|
+
- spec/support/mongoid.rb
|
166
189
|
- statesman.gemspec
|
167
190
|
homepage: https://github.com/gocardless/statesman
|
168
191
|
licenses:
|
@@ -191,7 +214,9 @@ summary: A statesmanlike state machine library
|
|
191
214
|
test_files:
|
192
215
|
- spec/spec_helper.rb
|
193
216
|
- spec/statesman/adapters/active_record_spec.rb
|
217
|
+
- spec/statesman/adapters/active_record_transition_spec.rb
|
194
218
|
- spec/statesman/adapters/memory_spec.rb
|
219
|
+
- spec/statesman/adapters/mongoid_spec.rb
|
195
220
|
- spec/statesman/adapters/shared_examples.rb
|
196
221
|
- spec/statesman/callback_spec.rb
|
197
222
|
- spec/statesman/config_spec.rb
|
@@ -199,3 +224,4 @@ test_files:
|
|
199
224
|
- spec/statesman/machine_spec.rb
|
200
225
|
- spec/statesman/transition_spec.rb
|
201
226
|
- spec/support/active_record.rb
|
227
|
+
- spec/support/mongoid.rb
|
data/lib/statesman/transition.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
module Statesman
|
2
|
-
class Transition
|
3
|
-
attr_accessor :created_at
|
4
|
-
attr_accessor :to_state
|
5
|
-
attr_accessor :sort_key
|
6
|
-
attr_accessor :metadata
|
7
|
-
|
8
|
-
def initialize(to, sort_key, metadata = nil)
|
9
|
-
@created_at = Time.now
|
10
|
-
@to_state = to
|
11
|
-
@sort_key = sort_key
|
12
|
-
@metadata = metadata
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|