statesman 1.2.1 → 1.2.2

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: dc520c4907fb1573b7682bd1db4affe787b1d036
4
- data.tar.gz: 796e3a0482fc5814b9ae9da4ec870dc97d43b851
3
+ metadata.gz: a4cc83b59dfad9ed139c2215211c93550f06d4ea
4
+ data.tar.gz: 170879ce893bcd74ab1742dd609d4a9abb163ffd
5
5
  SHA512:
6
- metadata.gz: 3ae6ba2af2f37b4df09d025d2bdfce5849aba5ba3e23a3d7c341061db4ad8002547177302a155b29c2770bc58d5b0988c1df2854e186a36d0236f9d5f0ca96e9
7
- data.tar.gz: 57d5ab47d228ae72de01cff8e9b03db86bdb755bb70b8231a5f7639d7d45320fc647587061c76053353c4d56004a3dbefa8a52045e4bbd6e6175bc58fbc69cc3
6
+ metadata.gz: a1c4175b5bc89dbe750b758f37cef8e08469515eb94f470f7872b7dcba2c7dec4650e4ed28670e7fc7d2f64647abf8dbc35e6f2ea0b980041fe38586a8eebfd9
7
+ data.tar.gz: fb34e4fd474a1ca62585e7837bc16525b872b9b69f99b65ccb10e69f06b359c2cadc14ef04f75ff90ee459d779e9a15a8769fb7c6b06a2704b84cc6c15869173
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ ## v1.2.2 24 March 2015
2
+
3
+ - Add support for namespaced transition models (patch by [@DanielWright](https://github.com/DanielWright))
4
+
1
5
  ## v1.2.1 24 March 2015
2
6
 
3
7
  - Add support for Postgres 9.4's `jsonb` column type (patch by [@isaacseymour](https://github.com/isaacseymour))
data/README.md CHANGED
@@ -134,11 +134,12 @@ And add an association from the parent model:
134
134
 
135
135
  ```ruby
136
136
  class Order < ActiveRecord::Base
137
- has_many :order_transitions
137
+ has_many :transitions, class_name: "OrderTransition"
138
138
 
139
139
  # Initialize the state machine
140
140
  def state_machine
141
- @state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition)
141
+ @state_machine ||= OrderStateMachine.new(self, transition_class: OrderTransition,
142
+ association_name: :transitions)
142
143
  end
143
144
 
144
145
  # Optionally delegate some methods
@@ -298,6 +299,29 @@ class Order < ActiveRecord::Base
298
299
  end
299
300
  ```
300
301
 
302
+ If the transition class-name differs from the association name, you will also
303
+ need to define a corresponding `transition_name` class method:
304
+
305
+ ```ruby
306
+ class Order < ActiveRecord::Base
307
+ has_many :transitions, class_name: "OrderTransition"
308
+
309
+ private
310
+
311
+ def self.transition_name
312
+ :transitions
313
+ end
314
+
315
+ def self.transition_class
316
+ OrderTransition
317
+ end
318
+
319
+ def self.initial_state
320
+ OrderStateMachine.initial_state
321
+ end
322
+ end
323
+ ```
324
+
301
325
  #### `Model.in_state(:state_1, :state_2, etc)`
302
326
  Returns all models currently in any of the supplied states.
303
327
 
@@ -8,7 +8,7 @@ module Statesman
8
8
 
9
9
  JSON_COLUMN_TYPES = %w(json jsonb).freeze
10
10
 
11
- def initialize(transition_class, parent_model, observer)
11
+ def initialize(transition_class, parent_model, observer, options = {})
12
12
  serialized = serialized?(transition_class)
13
13
  column_type = transition_class.columns_hash['metadata'].sql_type
14
14
  if !serialized && !JSON_COLUMN_TYPES.include?(column_type)
@@ -22,6 +22,8 @@ module Statesman
22
22
  @transition_class = transition_class
23
23
  @parent_model = parent_model
24
24
  @observer = observer
25
+ @association_name =
26
+ options[:association_name] || @transition_class.table_name
25
27
  end
26
28
 
27
29
  def create(from, to, metadata = {})
@@ -76,7 +78,7 @@ module Statesman
76
78
  end
77
79
 
78
80
  def transitions_for_parent
79
- @parent_model.send(@transition_class.table_name)
81
+ @parent_model.send(@association_name)
80
82
  end
81
83
 
82
84
  def unset_old_most_recent
@@ -66,23 +66,31 @@ module Statesman
66
66
  transition_class.table_name.to_sym
67
67
  end
68
68
 
69
+ def transition_reflection
70
+ reflect_on_association(transition_name)
71
+ end
72
+
69
73
  def model_foreign_key
70
- reflect_on_association(transition_name).foreign_key
74
+ transition_reflection.foreign_key
75
+ end
76
+
77
+ def model_table
78
+ transition_reflection.table_name
71
79
  end
72
80
 
73
81
  def transition1_join
74
- "LEFT OUTER JOIN #{transition_name} transition1
82
+ "LEFT OUTER JOIN #{model_table} transition1
75
83
  ON transition1.#{model_foreign_key} = #{table_name}.id"
76
84
  end
77
85
 
78
86
  def transition2_join
79
- "LEFT OUTER JOIN #{transition_name} transition2
87
+ "LEFT OUTER JOIN #{model_table} transition2
80
88
  ON transition2.#{model_foreign_key} = #{table_name}.id
81
89
  AND transition2.sort_key > transition1.sort_key"
82
90
  end
83
91
 
84
92
  def most_recent_transition_join
85
- "LEFT OUTER JOIN #{transition_name} AS last_transition
93
+ "LEFT OUTER JOIN #{model_table} AS last_transition
86
94
  ON #{table_name}.id = last_transition.#{model_foreign_key}
87
95
  AND last_transition.most_recent = #{db_true}"
88
96
  end
@@ -9,7 +9,7 @@ module Statesman
9
9
 
10
10
  # We only accept mode as a parameter to maintain a consistent interface
11
11
  # with other adapters which require it.
12
- def initialize(transition_class, parent_model, observer)
12
+ def initialize(transition_class, parent_model, observer, _ = {})
13
13
  @history = []
14
14
  @transition_class = transition_class
15
15
  @parent_model = parent_model
@@ -6,7 +6,7 @@ module Statesman
6
6
  attr_reader :transition_class
7
7
  attr_reader :parent_model
8
8
 
9
- def initialize(transition_class, parent_model, observer)
9
+ def initialize(transition_class, parent_model, observer, _ = {})
10
10
  @transition_class = transition_class
11
11
  @parent_model = parent_model
12
12
  @observer = observer
@@ -183,7 +183,7 @@ module Statesman
183
183
  @object = object
184
184
  @transition_class = options[:transition_class]
185
185
  @storage_adapter = adapter_class(@transition_class).new(
186
- @transition_class, object, self)
186
+ @transition_class, object, self, options)
187
187
  send(:after_initialize) if respond_to? :after_initialize
188
188
  end
189
189
 
@@ -1,3 +1,3 @@
1
1
  module Statesman
2
- VERSION = "1.2.1"
2
+ VERSION = "1.2.2"
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -39,7 +39,12 @@ RSpec.configure do |config|
39
39
  end
40
40
 
41
41
  config.before(:each, active_record: true) do
42
- tables = %w(my_active_record_models my_active_record_model_transitions)
42
+ tables = %w(
43
+ my_active_record_models
44
+ my_active_record_model_transitions
45
+ my_namespace_my_active_record_models
46
+ my_namespace_my_active_record_model_transitions
47
+ )
43
48
  tables.each do |table_name|
44
49
  sql = "DROP TABLE IF EXISTS #{table_name};"
45
50
  ActiveRecord::Base.connection.execute(sql)
@@ -204,4 +204,25 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
204
204
  end
205
205
  end
206
206
  end
207
+
208
+ context "with a namespaced model" do
209
+ before do
210
+ silence_stream(STDOUT) do
211
+ CreateNamespacedARModelMigration.migrate(:up)
212
+ CreateNamespacedARModelTransitionMigration.migrate(:up)
213
+ end
214
+ end
215
+
216
+ before do
217
+ MyNamespace::MyActiveRecordModelTransition.serialize(:metadata, JSON)
218
+ end
219
+ let(:observer) { double(Statesman::Machine, execute: nil) }
220
+ let(:model) do
221
+ MyNamespace::MyActiveRecordModel.create(current_state: :pending)
222
+ end
223
+
224
+ it_behaves_like "an adapter",
225
+ described_class, MyNamespace::MyActiveRecordModelTransition,
226
+ association_name: :my_active_record_model_transitions
227
+ end
207
228
  end
@@ -11,9 +11,16 @@ require "spec_helper"
11
11
  # history: Returns the full transition history
12
12
  # last: Returns the latest transition history item
13
13
  #
14
- shared_examples_for "an adapter" do |adapter_class, transition_class|
14
+ # rubocop:disable Metrics/LineLength
15
+ # NOTE This line cannot reasonably be shortened.
16
+ shared_examples_for "an adapter" do |adapter_class, transition_class, options = {}|
17
+ # rubocop:enable Metrics/LineLength
18
+
15
19
  let(:observer) { double(Statesman::Machine, execute: nil) }
16
- let(:adapter) { adapter_class.new(transition_class, model, observer) }
20
+ let(:adapter) do
21
+ adapter_class.new(transition_class,
22
+ model, observer, options)
23
+ end
17
24
 
18
25
  describe "#initialize" do
19
26
  subject { adapter }
@@ -316,21 +316,23 @@ describe Statesman::Machine do
316
316
  context "transition class" do
317
317
  it "sets a default" do
318
318
  expect(Statesman.storage_adapter).to receive(:new).once.
319
- with(Statesman::Adapters::MemoryTransition, my_model, anything)
319
+ with(Statesman::Adapters::MemoryTransition,
320
+ my_model, anything, anything)
320
321
  machine.new(my_model)
321
322
  end
322
323
 
323
324
  it "sets the passed class" do
324
325
  my_transition_class = Class.new
325
326
  expect(Statesman.storage_adapter).to receive(:new).once.
326
- with(my_transition_class, my_model, anything)
327
+ with(my_transition_class, my_model, anything, anything)
327
328
  machine.new(my_model, transition_class: my_transition_class)
328
329
  end
329
330
 
330
331
  it "falls back to Memory without transaction_class" do
331
332
  allow(Statesman).to receive(:storage_adapter).and_return(Class.new)
332
333
  expect(Statesman::Adapters::Memory).to receive(:new).once.
333
- with(Statesman::Adapters::MemoryTransition, my_model, anything)
334
+ with(Statesman::Adapters::MemoryTransition,
335
+ my_model, anything, anything)
334
336
  machine.new(my_model)
335
337
  end
336
338
  end
@@ -37,7 +37,7 @@ class CreateMyActiveRecordModelMigration < ActiveRecord::Migration
37
37
  def change
38
38
  create_table :my_active_record_models do |t|
39
39
  t.string :current_state
40
- t.timestamps(null: false)
40
+ t.timestamps null: false
41
41
  end
42
42
  end
43
43
  end
@@ -59,7 +59,7 @@ class CreateMyActiveRecordModelTransitionMigration < ActiveRecord::Migration
59
59
  t.text :metadata, default: '{}'
60
60
  end
61
61
 
62
- t.timestamps(null: false)
62
+ t.timestamps null: false
63
63
  end
64
64
 
65
65
  add_index :my_active_record_model_transitions,
@@ -82,3 +82,65 @@ class DropMostRecentColumn < ActiveRecord::Migration
82
82
  remove_column :my_active_record_model_transitions, :most_recent
83
83
  end
84
84
  end
85
+
86
+ module MyNamespace
87
+ class MyActiveRecordModel < ActiveRecord::Base
88
+ has_many :my_active_record_model_transitions,
89
+ class_name: "MyNamespace::MyActiveRecordModelTransition"
90
+
91
+ def self.table_name_prefix
92
+ "my_namespace_"
93
+ end
94
+
95
+ def state_machine
96
+ @state_machine ||= MyStateMachine.new(
97
+ self, transition_class: MyNameSpace::MyActiveRecordModelTransition,
98
+ association_name: :my_active_record_model_transitions)
99
+ end
100
+
101
+ def metadata
102
+ super || {}
103
+ end
104
+ end
105
+
106
+ class MyActiveRecordModelTransition < ActiveRecord::Base
107
+ belongs_to :my_active_record_model,
108
+ class_name: "MyNamespace::MyActiveRecordModel"
109
+ serialize :metadata, JSON
110
+
111
+ def self.table_name_prefix
112
+ "my_namespace_"
113
+ end
114
+ end
115
+ end
116
+
117
+ class CreateNamespacedARModelMigration < ActiveRecord::Migration
118
+ def change
119
+ create_table :my_namespace_my_active_record_models do |t|
120
+ t.string :current_state
121
+ t.timestamps null: false
122
+ end
123
+ end
124
+ end
125
+
126
+ class CreateNamespacedARModelTransitionMigration < ActiveRecord::Migration
127
+ def change
128
+ create_table :my_namespace_my_active_record_model_transitions do |t|
129
+ t.string :to_state
130
+ t.integer :my_active_record_model_id
131
+ t.integer :sort_key
132
+
133
+ # MySQL doesn't allow default values on text fields
134
+ if ActiveRecord::Base.connection.adapter_name == 'Mysql2'
135
+ t.text :metadata
136
+ else
137
+ t.text :metadata, default: '{}'
138
+ end
139
+
140
+ t.timestamps null: false
141
+ end
142
+
143
+ add_index :my_namespace_my_active_record_model_transitions, :sort_key,
144
+ unique: true, name: 'my_namespaced_key'
145
+ end
146
+ 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: 1.2.1
4
+ version: 1.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Harry Marr