statesman 0.0.1 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Gem Version](https://badge.fury.io/rb/statesman.png)](http://badge.fury.io/rb/statesman)
|
6
|
+
[![Build Status](https://travis-ci.org/gocardless/statesman.png?branch=master)](https://travis-ci.org/gocardless/statesman)
|
7
|
+
[![Code Climate](https://codeclimate.com/github/gocardless/statesman.png)](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
|