steady_state 1.0.0 → 1.2.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
  SHA256:
3
- metadata.gz: 7b7ad486ead2f7c864e7ba69d8525f7d6e72fbb220c7ebabf866802f1d7ad50b
4
- data.tar.gz: f46001c070069cb44e77aa330170c1204626324c175d3c11ad8d11e21aaa3123
3
+ metadata.gz: 138a31884498cda0cd7785af5ba7a13c59c71459a2970680652edc20bb9a42e8
4
+ data.tar.gz: 224574b15d9664ea395a4c38656bfa9d3c3ddb8fe100018a60cf30b2f35a4422
5
5
  SHA512:
6
- metadata.gz: ac41840168b5cf0aeba5ebf7ba80784fe164013ae2926a0939e713e1fb3d686d30c945c07a1b51a68cdcbfc00b13e9a2ccb2b12480f43a166b83d6bf4d7100ed
7
- data.tar.gz: f74858d2bf2552e4603272f4cf82bee27bbc2930fe2eb1661e5717c34bfd011faf638caaea83b35d230672b07fca2e017a2965c611992aeac8f60d441735cee7
6
+ metadata.gz: 1f7f923baf74fadcfd46973f86a5f67523e8138f65a7bdcdd5e07393468677b96a2e7fafa37c9315099e562d7e467a5d71153152c004bb4c004e1b2224de92ff
7
+ data.tar.gz: d1669039e0f85a5d5926ac35f344f90cf9039e319162b3a1ce47be3a240969e236d2b07ed6d0e12a573fc175d68c812b0b07e92f52e4b02136aea86622257f8a
data/README.md CHANGED
@@ -210,6 +210,22 @@ steady_state :step, scopes: false do
210
210
  end
211
211
  ```
212
212
 
213
+ `steady_state` also follows the same `prefix` api as `delegate` in Rails. You may optionally define your scopes to be prefixed to the name of the state machine with `prefix: true`, or you may provide a custom prefix with `prefix: :some_custom_name`. This may be useful when dealing with multiple state machines on one object.
214
+
215
+ ```ruby
216
+ steady_state :temperature, scopes: { prefix: true } do
217
+ state 'cold', default: true
218
+ end
219
+
220
+ steady_state :color_temperature, scopes: { prefix: 'color' } do
221
+ state 'cold', default: true
222
+ end
223
+
224
+ Material.solid # => query for 'solid' records
225
+ Material.temperature_cold # => query for records with a cold temperature
226
+ Material.color_cold # => query for for records with a cold color temperature
227
+ ```
228
+
213
229
  ### Next and Previous States
214
230
 
215
231
  The `may_become?` method can be used to see if setting the state to a particular value would be allowed (ignoring all other validations):
@@ -277,7 +293,7 @@ class Material
277
293
  self.state = 'liquid'
278
294
  valid? # will return `false` if state transition is invalid
279
295
  end
280
-
296
+
281
297
  def melt!
282
298
  self.state = 'liquid'
283
299
  validate! # will raise an exception if state transition is invalid
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require 'bundler/setup'
3
5
  rescue LoadError
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SteadyState
2
4
  module Attribute
3
5
  class State < SimpleDelegator
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SteadyState
2
4
  module Attribute
3
5
  class StateMachine
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SteadyState
2
4
  module Attribute
3
5
  class TransitionValidator < ActiveModel::EachValidator
4
6
  def validate_each(obj, attr_name, _value)
5
- obj.errors.add(attr_name, :invalid) if obj.instance_variable_defined?("@last_valid_#{attr_name}")
7
+ obj.errors.add(attr_name, :invalid) if obj.instance_variable_defined?(:"@last_valid_#{attr_name}")
6
8
  end
7
9
  end
8
10
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'steady_state/attribute/state'
2
4
  require 'steady_state/attribute/state_machine'
3
5
  require 'steady_state/attribute/transition_validator'
@@ -17,26 +19,26 @@ module SteadyState
17
19
  overrides = Module.new do
18
20
  define_method :"validate_#{attr_name}_transition_to" do |next_value|
19
21
  if public_send(attr_name).may_become?(next_value)
20
- remove_instance_variable("@last_valid_#{attr_name}") if instance_variable_defined?("@last_valid_#{attr_name}")
21
- elsif !instance_variable_defined?("@last_valid_#{attr_name}")
22
- instance_variable_set("@last_valid_#{attr_name}", public_send(attr_name))
22
+ remove_instance_variable(:"@last_valid_#{attr_name}") if instance_variable_defined?(:"@last_valid_#{attr_name}")
23
+ elsif !instance_variable_defined?(:"@last_valid_#{attr_name}")
24
+ instance_variable_set(:"@last_valid_#{attr_name}", public_send(attr_name))
23
25
  end
24
26
  end
25
27
 
26
28
  define_method :"#{attr_name}=" do |value|
27
- unless instance_variable_defined?("@#{attr_name}_state_initialized")
28
- instance_variable_set("@#{attr_name}_state_initialized", true)
29
+ unless instance_variable_defined?(:"@#{attr_name}_state_initialized")
30
+ instance_variable_set(:"@#{attr_name}_state_initialized", true)
29
31
  end
30
32
  public_send(:"validate_#{attr_name}_transition_to", value) if public_send(attr_name).present?
31
33
  super(value)
32
34
  end
33
35
 
34
36
  define_method :"#{attr_name}" do |*args, &blk|
35
- unless instance_variable_defined?("@#{attr_name}_state_initialized")
37
+ unless instance_variable_defined?(:"@#{attr_name}_state_initialized")
36
38
  public_send(:"#{attr_name}=", state_machines[attr_name].start) if super(*args, &blk).blank?
37
- instance_variable_set("@#{attr_name}_state_initialized", true)
39
+ instance_variable_set(:"@#{attr_name}_state_initialized", true)
38
40
  end
39
- last_valid_value = instance_variable_get("@last_valid_#{attr_name}") if instance_variable_defined?("@last_valid_#{attr_name}")
41
+ last_valid_value = instance_variable_get(:"@last_valid_#{attr_name}") if instance_variable_defined?(:"@last_valid_#{attr_name}")
40
42
  state_machines[attr_name].new_state super(*args, &blk), last_valid_value
41
43
  end
42
44
  end
@@ -54,8 +56,11 @@ module SteadyState
54
56
 
55
57
  delegate(*state_machines[attr_name].predicates, to: attr_name, allow_nil: true) if predicates
56
58
  if scopes
59
+ scopes = {} unless scopes.is_a?(Hash)
60
+ prefix = SteadyState::Attribute.build_prefix(attr_name, **scopes)
61
+
57
62
  state_machines[attr_name].states.each do |state|
58
- scope state.to_sym, -> { where(attr_name.to_sym => state) }
63
+ scope :"#{prefix}#{state}", -> { where(attr_name.to_sym => state) }
59
64
  end
60
65
  end
61
66
 
@@ -63,5 +68,13 @@ module SteadyState
63
68
  inclusion: { in: state_machines[attr_name].states }
64
69
  end
65
70
  end
71
+
72
+ def self.build_prefix(attr_name, prefix: false)
73
+ if prefix
74
+ "#{prefix == true ? attr_name : prefix}_"
75
+ else
76
+ ""
77
+ end
78
+ end
66
79
  end
67
80
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module SteadyState
2
- VERSION = '1.0.0'.freeze
4
+ VERSION = '1.2.0'
3
5
  end
data/lib/steady_state.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'active_support'
2
4
  require 'active_support/core_ext'
3
5
  require 'active_model'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: steady_state
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Griffith
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-11 00:00:00.000000000 Z
11
+ date: 2024-06-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -113,13 +113,11 @@ files:
113
113
  - lib/steady_state/attribute/state_machine.rb
114
114
  - lib/steady_state/attribute/transition_validator.rb
115
115
  - lib/steady_state/version.rb
116
- - spec/spec_helper.rb
117
- - spec/steady_state/attribute_spec.rb
118
- homepage:
116
+ homepage:
119
117
  licenses: []
120
118
  metadata:
121
119
  rubygems_mfa_required: 'true'
122
- post_install_message:
120
+ post_install_message:
123
121
  rdoc_options: []
124
122
  require_paths:
125
123
  - lib
@@ -127,17 +125,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
127
125
  requirements:
128
126
  - - ">="
129
127
  - !ruby/object:Gem::Version
130
- version: 2.6.5
128
+ version: '3.0'
131
129
  required_rubygems_version: !ruby/object:Gem::Requirement
132
130
  requirements:
133
131
  - - ">="
134
132
  - !ruby/object:Gem::Version
135
133
  version: '0'
136
134
  requirements: []
137
- rubygems_version: 3.3.5
138
- signing_key:
135
+ rubygems_version: 3.5.14
136
+ signing_key:
139
137
  specification_version: 4
140
138
  summary: Minimalist state management via "an enum with guard rails"
141
- test_files:
142
- - spec/spec_helper.rb
143
- - spec/steady_state/attribute_spec.rb
139
+ test_files: []
data/spec/spec_helper.rb DELETED
@@ -1 +0,0 @@
1
- require 'steady_state'
@@ -1,403 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe SteadyState::Attribute do
4
- let(:steady_state_class) do
5
- Class.new do
6
- include ActiveModel::Model
7
- include SteadyState
8
-
9
- def self.model_name
10
- ActiveModel::Name.new(self, nil, 'steady_state_class')
11
- end
12
- end
13
- end
14
- subject { steady_state_class.new }
15
-
16
- shared_examples 'a basic state machine' do
17
- it 'starts on initial state' do
18
- expect(subject.state).to eq 'solid'
19
- end
20
-
21
- it 'allows initialization to the initial state' do
22
- expect(steady_state_class.new(state: 'solid')).to be_valid
23
- end
24
-
25
- it 'allows initialization to other states' do
26
- expect(steady_state_class.new(state: 'plasma')).to be_valid
27
- end
28
-
29
- it 'adds validation errors when initializing to an invalid state' do
30
- object = steady_state_class.new(state: 'banana')
31
- expect(object).not_to be_valid
32
- expect(object.errors[:state]).to match_array(['is not included in the list'])
33
- end
34
-
35
- it 'allows valid transitions' do
36
- expect(subject.state.may_become?('liquid')).to eq true
37
- expect(subject.state.next_values).to match_array(['liquid'])
38
- expect(subject.state.previous_values).to match_array([])
39
- expect { subject.state = 'liquid' }.to change { subject.state }.from('solid').to('liquid')
40
- expect(subject).to be_valid
41
-
42
- expect(subject.state.may_become?('gas')).to eq true
43
- expect(subject.state.next_values).to match_array(['gas'])
44
- expect(subject.state.previous_values).to match_array(['solid'])
45
- expect { subject.state = 'gas' }.to change { subject.state }.from('liquid').to('gas')
46
- expect(subject).to be_valid
47
-
48
- expect(subject.state.may_become?('plasma')).to eq true
49
- expect(subject.state.next_values).to match_array(['plasma'])
50
- expect(subject.state.previous_values).to match_array(['liquid'])
51
- expect { subject.state = 'plasma' }.to change { subject.state }.from('gas').to('plasma')
52
- expect(subject).to be_valid
53
- expect(subject.state.next_values).to be_empty
54
- expect(subject.state.previous_values).to match_array(['gas'])
55
- end
56
-
57
- it 'adds validation errors for invalid transitions' do
58
- expect(subject.state.may_become?('gas')).to eq false
59
- expect { subject.state = 'gas' }.to change { subject.state }.from('solid').to('gas')
60
- expect(subject).not_to be_valid
61
- expect(subject.errors[:state]).to match_array(['is invalid'])
62
- expect(subject.state.next_values).to match_array(['liquid'])
63
- expect(subject.state.previous_values).to match_array([])
64
-
65
- expect(subject.state.may_become?('plasma')).to eq false
66
- expect { subject.state = 'plasma' }.to change { subject.state }.from('gas').to('plasma')
67
- expect(subject).not_to be_valid
68
- expect(subject.errors[:state]).to match_array(['is invalid'])
69
- expect(subject.state.next_values).to match_array(['liquid'])
70
- expect(subject.state.previous_values).to match_array([])
71
-
72
- expect(subject.state.may_become?('solid')).to eq false
73
- expect { subject.state = 'solid' }.to change { subject.state }.from('plasma').to('solid')
74
- expect(subject).not_to be_valid
75
- expect(subject.errors[:state]).to match_array(['is invalid'])
76
- expect(subject.state.next_values).to match_array(['liquid'])
77
- expect(subject.state.previous_values).to match_array([])
78
- end
79
- end
80
-
81
- context 'with a single field and nothing fancy' do
82
- before do
83
- steady_state_class.module_eval do
84
- attr_accessor :state
85
-
86
- steady_state :state do
87
- state 'solid', default: true
88
- state 'liquid', from: 'solid'
89
- state 'gas', from: 'liquid'
90
- state 'plasma', from: 'gas'
91
- end
92
- end
93
- end
94
-
95
- it_behaves_like 'a basic state machine'
96
-
97
- context 'with inheritance' do
98
- let(:subclass) do
99
- Class.new(steady_state_class) do
100
- def initialize
101
- # I do my own thing.
102
- end
103
- end
104
- end
105
- subject { subclass.new }
106
-
107
- it_behaves_like 'a basic state machine'
108
- end
109
-
110
- context 'with an existing state value' do
111
- before do
112
- steady_state_class.module_eval do
113
- def state
114
- @state ||= 'liquid'
115
- end
116
- end
117
- end
118
-
119
- it 'starts on existing state' do
120
- expect(subject.state).to eq 'liquid'
121
- end
122
-
123
- it 'does not allow initialization to an invalid next state' do
124
- object = steady_state_class.new(state: 'solid')
125
- expect(object).not_to be_valid
126
- expect(object.errors[:state]).to match_array(['is invalid'])
127
- end
128
-
129
- it 'allows initialization to a valid next state' do
130
- expect(steady_state_class.new(state: 'gas')).to be_valid
131
- end
132
-
133
- it 'adds validation errors when initializing to an invalid state' do
134
- object = steady_state_class.new(state: 'banana')
135
- expect(object).not_to be_valid
136
- expect(object.errors[:state]).to match_array(['is invalid', 'is not included in the list'])
137
- end
138
-
139
- it 'allows valid transitions' do
140
- expect(subject).to be_valid
141
- expect(subject.state.may_become?('gas')).to eq true
142
- expect(subject.state.next_values).to match_array(['gas'])
143
- expect(subject.state.previous_values).to match_array(['solid'])
144
- expect { subject.state = 'gas' }.to change { subject.state }.from('liquid').to('gas')
145
- expect(subject).to be_valid
146
-
147
- expect(subject.state.may_become?('plasma')).to eq true
148
- expect(subject.state.next_values).to match_array(['plasma'])
149
- expect(subject.state.previous_values).to match_array(['liquid'])
150
- expect { subject.state = 'plasma' }.to change { subject.state }.from('gas').to('plasma')
151
- expect(subject).to be_valid
152
- expect(subject.state.next_values).to be_empty
153
- expect(subject.state.previous_values).to match_array(['gas'])
154
- end
155
-
156
- it 'adds validation errors for invalid transitions' do
157
- expect(subject.state.may_become?('plasma')).to eq false
158
- expect { subject.state = 'plasma' }.to change { subject.state }.from('liquid').to('plasma')
159
- expect(subject).not_to be_valid
160
- expect(subject.errors[:state]).to match_array(['is invalid'])
161
- expect(subject.state.next_values).to match_array(['gas'])
162
- expect(subject.state.previous_values).to match_array(['solid'])
163
-
164
- expect(subject.state.may_become?('solid')).to eq false
165
- expect { subject.state = 'solid' }.to change { subject.state }.from('plasma').to('solid')
166
- expect(subject).not_to be_valid
167
- expect(subject.errors[:state]).to match_array(['is invalid'])
168
- expect(subject.state.next_values).to match_array(['gas'])
169
- expect(subject.state.previous_values).to match_array(['solid'])
170
- end
171
- end
172
- end
173
-
174
- context 'with a field reachable by multiple states' do
175
- before do
176
- steady_state_class.module_eval do
177
- attr_accessor :step
178
-
179
- steady_state :step do
180
- state 'step-1', default: true
181
- state 'step-2', from: 'step-1'
182
- state 'cancelled', from: %w(step-1 step-2)
183
- end
184
- end
185
- end
186
-
187
- it 'allows transition from first state' do
188
- expect(subject.step.may_become?('step-1')).to eq false
189
- expect(subject.step.may_become?('step-2')).to eq true
190
- expect(subject.step.may_become?('cancelled')).to eq true
191
- expect(subject.step.next_values).to match_array(%w(cancelled step-2))
192
- expect(subject.step.previous_values).to match_array([])
193
- expect { subject.step = 'cancelled' }.to change { subject.step }.from('step-1').to('cancelled')
194
- expect(subject.step.next_values).to match_array([])
195
- expect(subject.step.previous_values).to match_array(%w(step-1 step-2))
196
- expect(subject).to be_valid
197
- end
198
-
199
- it 'allows transition from second state' do
200
- expect(subject.step.may_become?('step-1')).to eq false
201
- expect(subject.step.may_become?('step-2')).to eq true
202
- expect(subject.step.may_become?('cancelled')).to eq true
203
- expect(subject.step.next_values).to match_array(%w(cancelled step-2))
204
- expect(subject.step.previous_values).to match_array([])
205
- expect { subject.step = 'step-2' }.to change { subject.step }.from('step-1').to('step-2')
206
- expect(subject).to be_valid
207
-
208
- expect(subject.step.may_become?('step-1')).to eq false
209
- expect(subject.step.may_become?('step-2')).to eq false
210
- expect(subject.step.may_become?('cancelled')).to eq true
211
- expect(subject.step.next_values).to match_array(['cancelled'])
212
- expect(subject.step.previous_values).to match_array(['step-1'])
213
- expect { subject.step = 'cancelled' }.to change { subject.step }.from('step-2').to('cancelled')
214
- expect(subject.step.next_values).to match_array([])
215
- expect(subject.step.previous_values).to match_array(%w(step-1 step-2))
216
- expect(subject).to be_valid
217
- end
218
- end
219
-
220
- context 'with the predicates option' do
221
- before do
222
- options = opts
223
- steady_state_class.module_eval do
224
- attr_accessor :door
225
-
226
- steady_state :door, **options do
227
- state 'open', default: true
228
- state 'closed', from: 'open'
229
- state 'locked', from: 'closed'
230
- end
231
- end
232
- end
233
-
234
- context 'default' do
235
- let(:opts) { {} }
236
-
237
- it 'defines a predicate method for each state' do
238
- expect(subject).to respond_to(:open?)
239
- expect(subject).to respond_to(:closed?)
240
- expect(subject).to respond_to(:locked?)
241
-
242
- expect(subject.open?).to eq true
243
- expect(subject.closed?).to eq false
244
- expect(subject.locked?).to eq false
245
-
246
- subject.door = 'closed'
247
- expect(subject.open?).to eq false
248
- expect(subject.closed?).to eq true
249
- expect(subject.locked?).to eq false
250
-
251
- subject.door = 'locked'
252
- expect(subject.open?).to eq false
253
- expect(subject.closed?).to eq false
254
- expect(subject.locked?).to eq true
255
- end
256
- end
257
-
258
- context 'enabled' do
259
- let(:opts) { { predicates: true } }
260
-
261
- it 'defines a predicate method for each state' do
262
- expect(subject).to respond_to(:open?)
263
- expect(subject).to respond_to(:closed?)
264
- expect(subject).to respond_to(:locked?)
265
-
266
- expect(subject.open?).to eq true
267
- expect(subject.closed?).to eq false
268
- expect(subject.locked?).to eq false
269
-
270
- subject.door = 'closed'
271
- expect(subject.open?).to eq false
272
- expect(subject.closed?).to eq true
273
- expect(subject.locked?).to eq false
274
-
275
- subject.door = 'locked'
276
- expect(subject.open?).to eq false
277
- expect(subject.closed?).to eq false
278
- expect(subject.locked?).to eq true
279
- end
280
- end
281
-
282
- context 'disabled' do
283
- let(:opts) { { predicates: false } }
284
-
285
- it 'does not define predicate methods' do
286
- expect(subject).not_to respond_to(:open?)
287
- expect(subject).not_to respond_to(:closed?)
288
- expect(subject).not_to respond_to(:locked?)
289
- end
290
- end
291
- end
292
-
293
- context 'with the states_getter option' do
294
- let(:query_object) { double(where: []) } # rubocop:disable RSpec/VerifiedDoubles
295
-
296
- before do
297
- options = opts
298
- steady_state_class.module_eval do
299
- attr_accessor :car
300
-
301
- steady_state :car, **options do
302
- state 'driving', default: true
303
- state 'stopped', from: 'driving'
304
- state 'parked', from: 'stopped'
305
- end
306
- end
307
- end
308
-
309
- context 'default' do
310
- let(:opts) { {} }
311
-
312
- it 'defines states getter method' do
313
- expect(steady_state_class.cars).to eq %w(driving stopped parked)
314
- end
315
- end
316
-
317
- context 'disabled' do
318
- let(:opts) { { states_getter: false } }
319
-
320
- it 'does not define states getter method' do
321
- expect { steady_state_class.cars }.to raise_error(NoMethodError, /undefined method `cars'/)
322
- end
323
- end
324
- end
325
-
326
- context 'with the scopes option' do
327
- let(:query_object) { double(where: []) } # rubocop:disable RSpec/VerifiedDoubles
328
-
329
- before do
330
- options = opts
331
- steady_state_class.module_eval do
332
- attr_accessor :car
333
-
334
- def self.defined_scopes
335
- @defined_scopes ||= {}
336
- end
337
-
338
- def self.scope(name, callable)
339
- defined_scopes[name] ||= callable
340
- end
341
-
342
- steady_state :car, **options do
343
- state 'driving', default: true
344
- state 'stopped', from: 'driving'
345
- state 'parked', from: 'stopped'
346
- end
347
- end
348
- end
349
-
350
- context 'default' do
351
- let(:opts) { {} }
352
-
353
- it 'does not define scope methods' do
354
- expect(steady_state_class.defined_scopes.keys).to eq []
355
- end
356
-
357
- context 'on an ActiveRecord' do
358
- let(:steady_state_class) do
359
- stub_const('ActiveRecord::Base', Class.new)
360
-
361
- Class.new(ActiveRecord::Base) do
362
- include ActiveModel::Model
363
- include SteadyState
364
- end
365
- end
366
-
367
- it 'defines a scope for each state' do
368
- expect(steady_state_class.defined_scopes.keys).to eq %i(driving stopped parked)
369
-
370
- expect(query_object).to receive(:where).with(car: 'driving')
371
- query_object.instance_exec(&steady_state_class.defined_scopes[:driving])
372
- expect(query_object).to receive(:where).with(car: 'stopped')
373
- query_object.instance_exec(&steady_state_class.defined_scopes[:stopped])
374
- expect(query_object).to receive(:where).with(car: 'parked')
375
- query_object.instance_exec(&steady_state_class.defined_scopes[:parked])
376
- end
377
- end
378
- end
379
-
380
- context 'enabled' do
381
- let(:opts) { { scopes: true } }
382
-
383
- it 'defines a scope for each state' do
384
- expect(steady_state_class.defined_scopes.keys).to eq %i(driving stopped parked)
385
-
386
- expect(query_object).to receive(:where).with(car: 'driving')
387
- query_object.instance_exec(&steady_state_class.defined_scopes[:driving])
388
- expect(query_object).to receive(:where).with(car: 'stopped')
389
- query_object.instance_exec(&steady_state_class.defined_scopes[:stopped])
390
- expect(query_object).to receive(:where).with(car: 'parked')
391
- query_object.instance_exec(&steady_state_class.defined_scopes[:parked])
392
- end
393
- end
394
-
395
- context 'disabled' do
396
- let(:opts) { { scopes: false } }
397
-
398
- it 'does not define scope methods' do
399
- expect(steady_state_class.defined_scopes.keys).to eq []
400
- end
401
- end
402
- end
403
- end