statesman 0.4.0 → 0.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a7c29dcf767aa7177b818dafdc99e8645dddfcc8
4
- data.tar.gz: 1d4db155c8fb031a4e58dafa44febca452110dcd
3
+ metadata.gz: 7705af0277715fcc157ab5d750e870c03ff589fb
4
+ data.tar.gz: e05d77943df6c572a9ea9d45b59f94f2c758cb6c
5
5
  SHA512:
6
- metadata.gz: 1aff94dc8f2c327b232c93123fa781a5f583f4b9fa08b39df79d8dd93c8600992ca67e05b277531fb58da92014eb5c1240a9d622cff3195a84266624bef7e4ef
7
- data.tar.gz: 6882412cf48ed98015601b22a26c4d038405d1b9208a723d0fdeeddb875629e47fb267ba97ceac712bbac5572d6c3f647188047e6f17532a528baa2c6b9897ab
6
+ metadata.gz: ed5f485322fd9c0a906d0a010812e72a704db3669bc915c2aba8b942f6a9f98ff8145907adc5ab023440b997b0f9fdf9758aa7e0e67568afc391df505b7c7476
7
+ data.tar.gz: bd202c6eafdbb989545e5b0f361a9713ef95fe78bb3b7454856a20e266fdd1f5a1b5242d1cc593123bf310aac202be47ccbef4f624c9d12a5dc59129dc6f1649
data/.rubocop.yml CHANGED
@@ -10,6 +10,9 @@ AllCops:
10
10
  StringLiterals:
11
11
  Enabled: false
12
12
 
13
+ LineEndConcatenation:
14
+ Enabled: false
15
+
13
16
  Documentation:
14
17
  Enabled: false
15
18
 
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## v0.5.0, 27 March 2014
2
+ *Additions*
3
+ - Scope methods. Adds a module which can be mixed in to an ActiveRecord model to provide `.in_state` and `.not_in_state` query scopes.
4
+ - Adds `Machine#after_initialize` hook (patch by [@att14](https://github.com/att14))
5
+
6
+ *Fixes*
7
+ - Added MongoidTransition to the autoload statements, fixing [#29](https://github.com/gocardless/statesman/issues/29) (patch by [@tomclose](https://github.com/tomclose))
8
+
1
9
  ## v0.4.0, 27 February 2014
2
10
  *Additions*
3
11
  - Adds after_commit flag to after_transition for callbacks to be executed after the transaction has been
data/README.md CHANGED
@@ -53,11 +53,19 @@ class OrderStateMachine
53
53
  end
54
54
 
55
55
  class Order < ActiveRecord::Base
56
+ include Statesman::Adapters::ActiveRecordModel
57
+
56
58
  has_many :order_transitions
57
59
 
58
60
  def state_machine
59
61
  OrderStateMachine.new(self, transition_class: OrderTransition)
60
62
  end
63
+
64
+ private
65
+
66
+ def transition_class
67
+ OrderTransition
68
+ end
61
69
  end
62
70
 
63
71
  class OrderTransition < ActiveRecord::Base
@@ -78,6 +86,12 @@ Order.first.state_machine.can_transition_to?(:cancelled)
78
86
  Order.first.state_machine.transition_to(:cancelled, optional: :metadata)
79
87
  # => true/false
80
88
 
89
+ Order.in_state(:cancelled)
90
+ # => [#<Order id: "123">]
91
+
92
+ Order.not_in_state(:checking_out)
93
+ # => [#<Order id: "123">]
94
+
81
95
  Order.first.state_machine.transition_to!(:cancelled)
82
96
  # => true/exception
83
97
  ```
@@ -219,6 +233,30 @@ Transition to the passed state, returning `true` on success. Raises
219
233
  Transition to the passed state, returning `true` on success. Swallows all
220
234
  exceptions and returns false on failure.
221
235
 
236
+ ## Model scopes
237
+
238
+ A mixin is provided for the ActiveRecord adapter which adds scopes to easily
239
+ find all models currently in (or not in) a given state. Include it into your
240
+ model and define a `transition_class` method.
241
+
242
+ ```ruby
243
+ class Order < ActiveRecord::Base
244
+ include Statesman::Adapters::ActiveRecordModel
245
+
246
+ private
247
+
248
+ def transition_class
249
+ OrderTransition
250
+ end
251
+ end
252
+ ```
253
+
254
+ #### `Model.in_state(:state_1, :state_2, etc)`
255
+ Returns all models currently in any of the supplied states.
256
+
257
+ #### `Model.not_in_state(:state_1, :state_2, etc)`
258
+ Returns all models not currently in any of the supplied states.
259
+
222
260
  ---
223
261
 
224
262
  GoCardless ♥ open source. If you do too, come [join us](https://gocardless.com/jobs/backend_developer).
data/lib/statesman.rb CHANGED
@@ -9,7 +9,11 @@ module Statesman
9
9
  autoload :ActiveRecord, "statesman/adapters/active_record"
10
10
  autoload :ActiveRecordTransition,
11
11
  "statesman/adapters/active_record_transition"
12
+ autoload :ActiveRecordModel,
13
+ "statesman/adapters/active_record_model"
12
14
  autoload :Mongoid, "statesman/adapters/mongoid"
15
+ autoload :MongoidTransition,
16
+ "statesman/adapters/mongoid_transition"
13
17
  end
14
18
 
15
19
  # Example:
@@ -0,0 +1,46 @@
1
+ module Statesman
2
+ module Adapters
3
+ module ActiveRecordModel
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def in_state(*states)
10
+ joins(transition_name)
11
+ .joins(transition_join)
12
+ .where("#{transition_name}.to_state" => states)
13
+ .where("transition2.id" => nil)
14
+ end
15
+
16
+ def not_in_state(*states)
17
+ joins(transition_name)
18
+ .joins(transition_join)
19
+ .where("#{transition_name}.to_state NOT IN (?)", states)
20
+ .where("transition2.id" => nil)
21
+ end
22
+
23
+ private
24
+
25
+ def transition_class
26
+ raise NotImplementedError, "A transition_class method should be " +
27
+ "defined on the model"
28
+ end
29
+
30
+ def transition_name
31
+ transition_class.table_name.to_sym
32
+ end
33
+
34
+ def model_foreign_key
35
+ reflections[transition_name].foreign_key
36
+ end
37
+
38
+ def transition_join
39
+ "LEFT OUTER JOIN #{transition_name} transition2
40
+ ON transition2.#{model_foreign_key} = #{table_name}.id
41
+ AND transition2.sort_key > #{transition_name}.sort_key"
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -145,6 +145,7 @@ module Statesman
145
145
  @transition_class = options[:transition_class]
146
146
  @storage_adapter = Statesman.storage_adapter.new(
147
147
  @transition_class, object, self)
148
+ send(:after_initialize) if respond_to? :after_initialize
148
149
  end
149
150
 
150
151
  def current_state
@@ -1,3 +1,3 @@
1
1
  module Statesman
2
- VERSION = "0.4.0"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -0,0 +1,57 @@
1
+ require "spec_helper"
2
+
3
+ describe Statesman::Adapters::ActiveRecordModel do
4
+ before do
5
+ prepare_model_table
6
+ prepare_transitions_table
7
+ end
8
+
9
+ before do
10
+ MyActiveRecordModel.send(:include, Statesman::Adapters::ActiveRecordModel)
11
+ MyActiveRecordModel.class_eval do
12
+ def self.transition_class
13
+ MyActiveRecordModelTransition
14
+ end
15
+ end
16
+ end
17
+
18
+ let!(:model) do
19
+ model = MyActiveRecordModel.create
20
+ model.my_active_record_model_transitions.create(to_state: :state_a)
21
+ model
22
+ end
23
+
24
+ let!(:other_model) do
25
+ model = MyActiveRecordModel.create
26
+ model.my_active_record_model_transitions.create(to_state: :state_b)
27
+ model
28
+ end
29
+
30
+ describe ".in_state" do
31
+ context "given a single state" do
32
+ subject { MyActiveRecordModel.in_state(:state_a) }
33
+
34
+ it { should include model }
35
+ end
36
+
37
+ context "given multiple states" do
38
+ subject { MyActiveRecordModel.in_state(:state_a, :state_b) }
39
+
40
+ it { should include model }
41
+ it { should include other_model }
42
+ end
43
+ end
44
+
45
+ describe ".not_in_state" do
46
+ context "given a single state" do
47
+ subject { MyActiveRecordModel.not_in_state(:state_b) }
48
+ it { should include model }
49
+ it { should_not include other_model }
50
+ end
51
+
52
+ context "given multiple states" do
53
+ subject { MyActiveRecordModel.not_in_state(:state_a, :state_b) }
54
+ it { should == [] }
55
+ end
56
+ end
57
+ end
@@ -206,6 +206,16 @@ describe Statesman::Machine do
206
206
  end
207
207
  end
208
208
 
209
+ describe "#after_initialize" do
210
+ it "is called after initialize" do
211
+ machine.class_eval do
212
+ def after_initialize; end
213
+ end
214
+ expect_any_instance_of(machine).to receive :after_initialize
215
+ machine.new(my_model)
216
+ end
217
+ end
218
+
209
219
  describe "#current_state" do
210
220
  before do
211
221
  machine.class_eval do
@@ -1,4 +1,5 @@
1
1
  require "spec_helper"
2
+ require "statesman/adapters/memory_transition"
2
3
 
3
4
  describe Statesman::Adapters::MemoryTransition do
4
5
  describe "#initialize" do
@@ -1,4 +1,5 @@
1
1
  require "support/active_record"
2
+ require "json"
2
3
 
3
4
  DB = Pathname.new("test.sqlite3")
4
5
 
@@ -8,6 +9,7 @@ end
8
9
 
9
10
  class MyActiveRecordModelTransition < ActiveRecord::Base
10
11
  belongs_to :my_active_record_model
12
+ serialize :metadata, JSON
11
13
  end
12
14
 
13
15
  class CreateMyActiveRecordModelMigration < ActiveRecord::Migration
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.0
4
+ version: 0.5.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-03-10 00:00:00.000000000 Z
12
+ date: 2014-03-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -163,6 +163,7 @@ files:
163
163
  - lib/generators/statesman/templates/update_migration.rb.erb
164
164
  - lib/statesman.rb
165
165
  - lib/statesman/adapters/active_record.rb
166
+ - lib/statesman/adapters/active_record_model.rb
166
167
  - lib/statesman/adapters/active_record_transition.rb
167
168
  - lib/statesman/adapters/memory.rb
168
169
  - lib/statesman/adapters/memory_transition.rb
@@ -175,6 +176,7 @@ files:
175
176
  - lib/statesman/machine.rb
176
177
  - lib/statesman/version.rb
177
178
  - spec/spec_helper.rb
179
+ - spec/statesman/adapters/active_record_model_spec.rb
178
180
  - spec/statesman/adapters/active_record_spec.rb
179
181
  - spec/statesman/adapters/active_record_transition_spec.rb
180
182
  - spec/statesman/adapters/memory_spec.rb
@@ -214,6 +216,7 @@ specification_version: 4
214
216
  summary: A statesmanlike state machine library
215
217
  test_files:
216
218
  - spec/spec_helper.rb
219
+ - spec/statesman/adapters/active_record_model_spec.rb
217
220
  - spec/statesman/adapters/active_record_spec.rb
218
221
  - spec/statesman/adapters/active_record_transition_spec.rb
219
222
  - spec/statesman/adapters/memory_spec.rb