statesman 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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