stator 0.8.0 → 0.9.0.beta

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/build.yml +10 -5
  3. data/.gitignore +1 -0
  4. data/.ruby-version +1 -1
  5. data/Appraisals +12 -15
  6. data/Gemfile +7 -6
  7. data/README.md +4 -20
  8. data/gemfiles/{activerecord_7.2.gemfile → activerecord_5.1.gemfile} +2 -1
  9. data/gemfiles/activerecord_5.1.gemfile.lock +74 -0
  10. data/gemfiles/{activerecord_8.0.gemfile → activerecord_5.2.gemfile} +2 -1
  11. data/gemfiles/activerecord_5.2.gemfile.lock +74 -0
  12. data/gemfiles/{activerecord_7.1.gemfile → activerecord_5.gemfile} +2 -1
  13. data/gemfiles/activerecord_5.gemfile.lock +74 -0
  14. data/gemfiles/activerecord_6.0.gemfile +2 -2
  15. data/gemfiles/activerecord_6.0.gemfile.lock +41 -69
  16. data/gemfiles/activerecord_6.1.gemfile +2 -2
  17. data/gemfiles/activerecord_6.1.gemfile.lock +41 -68
  18. data/gemfiles/activerecord_7.0.gemfile +2 -2
  19. data/gemfiles/activerecord_7.0.gemfile.lock +40 -66
  20. data/lib/stator/alias.rb +51 -30
  21. data/lib/stator/integration.rb +42 -49
  22. data/lib/stator/machine.rb +59 -58
  23. data/lib/stator/model.rb +78 -73
  24. data/lib/stator/transition.rb +61 -60
  25. data/lib/stator/version.rb +3 -5
  26. data/lib/stator.rb +13 -0
  27. data/spec/model_spec.rb +203 -318
  28. data/spec/spec_helper.rb +6 -2
  29. data/spec/support/models.rb +26 -45
  30. data/spec/support/schema.rb +42 -42
  31. data/stator.gemspec +3 -10
  32. metadata +19 -75
  33. data/.github/CODEOWNERS +0 -1
  34. data/.github/dependabot.yml +0 -24
  35. data/gemfiles/activerecord_7.1.gemfile.lock +0 -114
  36. data/gemfiles/activerecord_7.2.gemfile.lock +0 -113
  37. data/gemfiles/activerecord_8.0.gemfile.lock +0 -116
data/spec/model_spec.rb CHANGED
@@ -1,239 +1,201 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
3
+ require 'spec_helper'
4
4
 
5
5
  describe Stator::Model do
6
6
 
7
- it "should set the default state after initialization" do
8
- u = User.new
9
- u.state.should eql("pending")
10
- end
11
-
12
- it "should see the initial setting of the state as a change with the initial state as the previous value" do
13
- u = User.new
14
- u.state = "activated"
15
- u.state_in_database.should eql("pending")
16
- end
17
-
18
- it "should not obstruct normal validations" do
19
- u = User.new
20
- u.should_not be_valid
21
- u.errors[:email].grep(/length/).should_not be_empty
22
- end
23
-
24
- it "should ensure a valid state transition when given a bogus state" do
25
- u = User.new
26
- u.state = "anythingelse"
27
-
28
- u.should_not be_valid
29
- u.errors[:state].should eql(["is not a valid state"])
30
- end
31
-
32
- it "should allow creation at any state" do
33
- u = User.new(email: "doug@example.com")
34
- u.state = "hyperactivated"
35
-
36
- u.should be_valid
37
- end
7
+ let(:u) { User.new }
38
8
 
39
- it "should work normally with active_record dirty methods" do
40
- u = User.new(email: "doug@example.com")
9
+ describe "basic operations" do
41
10
 
42
- u.will_save_change_to_state?.should_not be true
43
- u.state_in_database.should eq("pending")
44
- u.state_before_last_save.should be nil
11
+ it 'should set the default state after initialization' do
12
+ u.state.to_sym.should eql(:pending)
13
+ end
45
14
 
46
- u.state = "hyperactivated"
15
+ it 'should see the initial setting of the state as a change with the initial state as the previous value' do
16
+ u.state = :activated
17
+ u.state_was.to_sym.should eql(:pending)
18
+ end
47
19
 
48
- u.will_save_change_to_state?.should be true
49
- u.state_in_database.should eq("pending")
50
- u.state_before_last_save.should be nil
20
+ it 'should not obstruct normal validations' do
21
+ u.should_not be_valid
22
+ u.errors[:email].grep(/length/).should_not be_empty
23
+ end
51
24
 
52
- u.save!
25
+ it 'should ensure a valid state transition when given a bogus state' do
26
+ u.state = :anythingelse
53
27
 
54
- u.will_save_change_to_state?.should_not be true
55
- u.state_in_database.should eq("hyperactivated")
56
- u.state_before_last_save.should eq("pending")
57
- end
28
+ u.should_not be_valid
29
+ u.errors[:state].should eql(['is not a valid state'])
30
+ end
58
31
 
59
- it "should ensure a valid state transition when given an illegal state based on the current state" do
60
- u = User.new
32
+ it 'should allow creation at any state' do
33
+ u.email = 'doug@example.com'
34
+ u.state = :hyperactivated
61
35
 
62
- allow(u).to receive(:new_record?).and_return(false)
36
+ u.should be_valid
37
+ end
63
38
 
64
- u.state = "hyperactivated"
39
+ it 'should ensure a valid state transition when given an illegal state based on the current state' do
40
+ allow(u).to receive(:new_record?).and_return(false)
65
41
 
66
- u.should_not be_valid
67
- u.errors[:state].should_not be_empty
68
- end
42
+ u.state = 'hyperactivated'
69
43
 
70
- it "should not allow a transition that is currently in a `to` state" do
71
- u = User.new(email: "fred@example.com")
72
- u.activate!
73
- u.hyperactivate!
44
+ u.should_not be_valid
45
+ u.errors[:state].should_not be_empty
46
+ end
74
47
 
75
- lambda {
48
+ it 'should not allow a transition that is currently in a `to` state' do
49
+ u.email = 'fred@example.com'
50
+ u.activate!
76
51
  u.hyperactivate!
77
- }.should raise_error(/cannot transition to \"hyperactivated\" from \"hyperactivated\"/)
78
- end
79
-
80
- it "should run conditional validations" do
81
- u = User.new
82
- u.state = "semiactivated"
83
- u.should_not be_valid
84
52
 
85
- u.errors[:state].should be_empty
86
- u.errors[:email].grep(/format/).should_not be_empty
87
- end
88
-
89
- it "should invoke callbacks" do
90
- u = User.new(activated: true, email: "doug@example.com", name: "doug")
91
- u.activated.should == true
53
+ lambda {
54
+ u.hyperactivate!
55
+ }.should raise_error(/cannot transition to hyperactivated from hyperactivated/)
56
+ end
92
57
 
93
- u.deactivate
58
+ it 'should run conditional validations' do
59
+ u.state = 'semiactivated'
60
+ u.should_not be_valid
94
61
 
95
- u.activated.should == false
96
- u.state.should eql("deactivated")
97
- u.activated_state_at.should be_nil
98
- u.should be_persisted
99
- end
100
-
101
- it "should conditionally invoke after_save callbacks when use_previous is true" do
102
- u = User.new
103
- u.email = "doug@example.com"
62
+ u.errors[:state].should be_empty
63
+ u.errors[:email].should_not be_empty
64
+ end
104
65
 
105
- u.semiactivate!
66
+ it 'should invoke callbacks' do
67
+ u.assign_attributes(activated: true, email: 'doug@example.com', name: 'doug')
68
+ u.activated.should == true
106
69
 
107
- u.state.should eql("semiactivated")
108
- u.activation_notification_published.should_not be true
70
+ u.deactivate
109
71
 
110
- u.activate!
72
+ u.activated.should == false
73
+ u.state.should eql :deactivated
74
+ u.activated_state_at.should be_nil
75
+ u.should be_persisted
76
+ end
111
77
 
112
- u.state.should eql("activated")
113
- u.activation_notification_published.should be true
114
- end
78
+ it 'should blow up if the record is invalid and a bang method is used' do
79
+ u.assign_attributes(email: 'doug@other.com', name: 'doug')
80
+ -> { u.activate! }.should raise_error(ActiveRecord::RecordInvalid)
81
+ end
115
82
 
116
- it "should blow up if the record is invalid and a bang method is used" do
117
- u = User.new(email: "doug@other.com", name: "doug")
118
- lambda {
119
- u.activate!
120
- }.should raise_error(ActiveRecord::RecordInvalid)
121
- end
83
+ it 'should allow for other fields to be used other than state' do
84
+ a = Animal.new
85
+ a.should be_valid
122
86
 
123
- it "should allow for other fields to be used other than state" do
124
- a = Animal.new
125
- a.should be_valid
87
+ a.birth!
88
+ end
126
89
 
127
- a.birth!
128
- end
90
+ it 'should create implicit transitions for state declarations' do
91
+ a = Animal.new
92
+ a.should_not be_grown_up
93
+ a.status = 'grown_up'
94
+ a.save
95
+ end
129
96
 
130
- it "should create implicit transitions for state declarations" do
131
- a = Animal.new
132
- a.should_not be_grown_up
133
- a.status = "grown_up"
134
- a.save
135
- end
97
+ it 'should allow multiple machines in the same model' do
98
+ f = Farm.new
136
99
 
137
- it "should allow multiple machines in the same model" do
138
- f = Farm.new
139
- f.should be_dirty
140
- f.should be_house_dirty
100
+ f.should be_dirty
101
+ f.should be_house_dirty
141
102
 
142
- f.cleanup
103
+ f.cleanup
143
104
 
144
- f.should_not be_dirty
145
- f.should be_house_dirty
105
+ f.should_not be_dirty
106
+ f.should be_house_dirty
146
107
 
147
- f.house_cleanup
108
+ f.house_cleanup # the house namespace
148
109
 
149
- f.should_not be_house_dirty
150
- end
110
+ f.should_not be_dirty
111
+ f.should_not be_house_dirty
112
+ end
151
113
 
152
- it "should allow saving to be skipped" do
153
- f = Farm.new
154
- f.cleanup(false)
114
+ it 'should allow saving to be skipped' do
115
+ f = Farm.new
116
+ f.cleanup(false)
155
117
 
156
- f.should_not be_persisted
157
- end
118
+ f.should_not be_persisted
119
+ end
158
120
 
159
- it "should allow no initial state" do
160
- f = Factory.new
161
- f.state.should be_nil
121
+ it 'should allow no initial state' do
122
+ f = Factory.new
123
+ f.state.should be_nil
162
124
 
163
- f.construct.should eql(true)
125
+ f.construct.should eql(true)
164
126
 
165
- f.state.should eql("constructed")
166
- end
127
+ f.state.should eql(:constructed)
128
+ end
167
129
 
168
- it "should allow any transition if validations are opted out of" do
169
- u = User.new
170
- u.email = "doug@example.com"
130
+ it 'should allow any transition if validations are opted out of' do
131
+ u.email = 'doug@example.com'
171
132
 
172
- u.can_hyperactivate?.should eql(false)
173
- u.hyperactivate.should eql(false)
133
+ u.can_hyperactivate?.should eql(false)
134
+ u.hyperactivate.should eql(false)
174
135
 
175
- u.state.should eql("pending")
136
+ u.current_state.should eql :pending
176
137
 
177
- u.without_state_transition_validations do
178
- u.can_hyperactivate?.should eql(true)
179
- u.hyperactivate.should eql(true)
138
+ u.without_state_transition_validations do
139
+ u.can_hyperactivate?.should eql(true)
140
+ u.hyperactivate.should eql(true)
141
+ end
180
142
  end
181
- end
182
143
 
183
- it "should skip tracking timestamps if opted out of" do
184
- u = User.new
185
- u.email = "doug@example.com"
144
+ it 'should skip tracking timestamps if opted out of' do
145
+ u.email = 'doug@example.com'
186
146
 
187
- u.without_state_transition_tracking do
188
- u.semiactivate!
189
- u.state.should eql("semiactivated")
190
- u.semiactivated_state_at.should be_nil
147
+ u.without_state_transition_tracking do
148
+ u.semiactivate!
149
+ u.state.should eql :semiactivated
150
+ u.semiactivated_state_at.should be_nil
151
+ end
152
+
153
+ # Make sure that tracking is ensured back to
154
+ # original value
155
+ u.activate!
156
+ u.activated_state_at.should_not be_nil
191
157
  end
192
158
 
193
- # Make sure that tracking is ensured back to
194
- # original value
195
- u.activate!
196
- u.activated_state_at.should_not be_nil
197
- end
159
+ it 'should skip tracking timestamps if opted out of with thread safety' do
160
+ threads = []
161
+ skip = User.new(email: 'skip@example.com', state: :pending)
162
+ nope = User.new(email: 'nope@example.com', state: :pending)
198
163
 
199
- it "should skip tracking timestamps if opted out of with thread safety" do
200
- threads = []
201
- skip = User.new(email: "skip@example.com")
202
- nope = User.new(email: "nope@example.com")
164
+ threads << Thread.new do
165
+ sleep 0.5
166
+ nope.semiactivate!
167
+ end
203
168
 
204
- threads << Thread.new do
205
- sleep 0.5
206
- nope.semiactivate!
207
- end
208
- threads << Thread.new do
209
- skip.without_state_transition_tracking do
210
- sleep 1
211
- skip.semiactivate!
169
+ threads << Thread.new do
170
+ skip.without_state_transition_tracking do
171
+ sleep 1
172
+ skip.semiactivate!
173
+ end
212
174
  end
213
- end
214
175
 
215
- threads.each(&:join)
176
+ threads.each(&:join)
216
177
 
217
- nope.semiactivated_state_at.should_not be_nil
218
- skip.semiactivated_state_at.should be_nil
219
- end
178
+ nope.semiactivated_state_at.should_not be_nil
179
+ skip.semiactivated_state_at.should be_nil
180
+ end
220
181
 
221
- it "should not inherit _integration cache on dup" do
222
- u = User.new(email: "user@example.com")
223
- u.save!
182
+ it 'should not inherit _integration cache on dup' do
183
+ u.email = 'user@example.com'
184
+ u.save!
224
185
 
225
- u_duped = u.dup
186
+ u_duped = u.dup
226
187
 
227
- u.semiactivate!
188
+ u.semiactivate!
228
189
 
229
- u_duped_integration = u_duped.send(:_integration)
190
+ u_duped_integration = u_duped.send(:_stator_integration)
230
191
 
231
- u_duped_integration.state.should_not eql(u.state)
232
- u_duped_integration.instance_values["record"].should eq(u_duped)
192
+ u_duped_integration.state.should_not eql(u.state)
193
+ u_duped_integration.instance_values['record'].should eq(u_duped)
194
+ end
233
195
  end
234
196
 
235
- describe "helper methods" do
236
- it "should answer the question of whether the state is currently the one invoked" do
197
+ describe 'helper methods' do
198
+ it 'should answer the question of whether the state is currently the one invoked' do
237
199
  a = Animal.new
238
200
  a.should be_unborn
239
201
  a.should_not be_born
@@ -244,7 +206,7 @@ describe Stator::Model do
244
206
  a.should_not be_unborn
245
207
  end
246
208
 
247
- it "should determine if it can validly execute a transition" do
209
+ it 'should determine if it can validly execute a transition' do
248
210
  a = Animal.new
249
211
  a.can_birth?.should eql(true)
250
212
 
@@ -254,87 +216,18 @@ describe Stator::Model do
254
216
  end
255
217
  end
256
218
 
257
- it "should validate state transitions using the db state after a transaction rollback" do
258
- is_active_record_6_or_higher = Gem::Requirement.new(">= 6.0").satisfied_by?(ActiveRecord.version)
259
-
260
- u = User.create!(email: 'doug@example.com')
261
- u.state.should eql('pending')
262
-
263
- lambda {
264
- ActiveRecord::Base.transaction do
265
- # The state change will be applied to the model object in memory.
266
- # An UPDATE query will be sent to the db, but it will be rolled back
267
- # when the error is raised below.
268
- u.activate!
269
- raise "Some error"
270
- end
271
- }.should raise_error("Some error")
272
-
273
- u.state.should eql("activated")
274
-
275
- # Rails 6.0 fixed a bug where a model's dirty state would be incorrect
276
- # in a scenario like this one, where a model is updated within a transaction,
277
- # and the transaction is then rolled back:
278
- #
279
- # https://github.com/rails/rails/pull/35987
280
- #
281
- # We show this dirty behavior change in Rails 6.0 below to clarify why stator itself
282
- # behaves differently starting in Rails 6.0.
283
- if is_active_record_6_or_higher
284
- # On Rails 6.0 or higher, attribute_in_database is "pending" — which is correct,
285
- # because the db transaction was rolled back.
286
- u.attribute_in_database("state").should eql("pending")
287
-
288
- # Attempting a state change to "hyperactivated" fails, which is correct,
289
- # because the previous state change to "activated" did not succeed.
290
- lambda {
291
- u.hyperactivate!
292
- }.should raise_error(ActiveRecord::RecordInvalid, 'Validation failed: State cannot transition to "hyperactivated" from "pending"')
293
- else
294
- # On Rails < 6.0, attribute_in_database is "activated" — which is incorrect,
295
- # because the db transaction was rolled back.
296
- u.attribute_in_database("state").should eql("activated")
297
-
298
- # On Rails < 6.0, stator incorrectly allows the state change to "hyperactivated"
299
- # because it incorrectly thinks the state has been successfully updated to "activated".
300
- lambda {
301
- u.hyperactivate!
302
- }.should_not raise_error
303
- end
304
- end
305
-
306
- it "should not support multiple state changes made between saves" do
307
- u = User.create!(email: "doug@example.com")
308
- u.state.should eql("pending")
309
-
310
- u.activate(false) # change state, but do not save to db
311
- u.state.should eql("activated")
312
-
313
- lambda {
314
- # Fails because the db state is still "pending", and
315
- # the db state is what stator uses for the "previous" state
316
- # to check that the state transition is valid.
317
- u.hyperactivate!
318
- }.should raise_error(ActiveRecord::RecordInvalid, 'Validation failed: State cannot transition to "hyperactivated" from "pending"')
319
-
320
- # The model is updated in-memory with the new state value,
321
- # but remains invalid.
322
- u.state.should eql("hyperactivated")
323
- u.valid?.should be false
324
- end
325
-
326
- describe "tracker methods" do
219
+ describe 'tracker methods' do
327
220
  before do
328
- Time.zone = "Eastern Time (US & Canada)"
221
+ Time.zone = 'Eastern Time (US & Canada)'
329
222
  end
330
223
 
331
- it "should store the initial state timestamp when the record is created" do
224
+ it 'should store the initial state timestamp when the record is created' do
332
225
  a = Animal.new
333
226
  a.save
334
227
  a.unborn_status_at.should be_within(1).of(Time.zone.now)
335
228
  end
336
229
 
337
- it "should store when a record changed state for the first time" do
230
+ it 'should store when a record changed state for the first time' do
338
231
  a = Animal.new
339
232
  a.unborn_status_at.should be_nil
340
233
  a.born_status_at.should be_nil
@@ -343,7 +236,7 @@ describe Stator::Model do
343
236
  a.born_status_at.should be_within(1).of(Time.zone.now)
344
237
  end
345
238
 
346
- it "should store when a record change states" do
239
+ it 'should store when a record change states' do
347
240
  a = Animal.new
348
241
  a.status_changed_at.should be_nil
349
242
 
@@ -353,15 +246,14 @@ describe Stator::Model do
353
246
 
354
247
  previous_status_changed_at = a.status_changed_at
355
248
 
356
- a.name = "new name"
249
+ a.name = 'new name'
357
250
  a.save
358
251
 
359
252
  a.status_changed_at.should eql(previous_status_changed_at)
360
253
  end
361
254
 
362
- it "should prepend the setting of the timestamp so other callbacks can use it" do
363
- u = User.new
364
- u.email = "doug@example.com"
255
+ it 'should prepend the setting of the timestamp so other callbacks can use it' do
256
+ u.email = 'doug@example.com'
365
257
 
366
258
  u.tagged_at.should be_nil
367
259
  u.semiactivate!
@@ -370,35 +262,34 @@ describe Stator::Model do
370
262
  u.tagged_at.should_not be_nil
371
263
  end
372
264
 
373
- it "should respect the timestamp if explicitly provided" do
374
- t = Time.at(Time.now.to_i - 3600)
265
+ it 'should respect the timestamp if explicitly provided' do
266
+ t = Time.zone.at(Time.now.to_i - 3600)
375
267
 
376
- u = User.new
377
- u.email = "doug@example.com"
378
- u.state = "semiactivated"
268
+ u.email = 'doug@example.com'
269
+ u.state = 'semiactivated'
379
270
  u.semiactivated_state_at = t
380
271
  u.save!
381
272
 
382
- u.state.should eql("semiactivated")
273
+ u.state.should eql('semiactivated')
383
274
  u.semiactivated_state_at.should eql(t)
384
275
  end
385
276
 
386
- it "should respect the timestamp if explicitly provided via create" do
387
- t = Time.at(Time.now.to_i - 3600)
277
+ it 'should respect the timestamp if explicitly provided via create' do
278
+ t = Time.zone.at(Time.now.to_i - 3600)
388
279
 
389
280
  u = User.create!(
390
- email: "doug@example.com",
391
- state: "semiactivated",
281
+ email: 'doug@example.com',
282
+ state: 'semiactivated',
392
283
  semiactivated_state_at: t
393
284
  )
394
285
 
395
- u.state.should eql("semiactivated")
286
+ u.state.should eql('semiactivated')
396
287
  u.semiactivated_state_at.should eql(t)
397
288
  end
398
289
 
399
- it "should allow opting into track by namespace" do
400
- z = ZooKeeper.new(name: "Doug")
401
- z.employment_state.should eql("hired")
290
+ it 'should allow opting into track by namespace' do
291
+ z = ZooKeeper.new(name: 'Doug')
292
+ z.employment_state.should eql('hired')
402
293
  z.employment_fire!
403
294
  z.fired_employment_state_at.should_not be_nil
404
295
 
@@ -411,52 +302,53 @@ describe Stator::Model do
411
302
  z.ended_working_state_at.should be_nil
412
303
  end
413
304
 
414
- describe "#state_by?" do
415
- it "should be true when the transition is earlier" do
416
- t = Time.now
417
- u = User.create!( email: "doug@example.com", activated_state_at: t)
418
- u.state_by?(:activated, Time.at(t.to_i + 1)).should be true
419
- u.activated_state_by?(Time.at(t.to_i + 1)).should be true
305
+ describe '#state_by?' do
306
+ it 'should be true when the transition is earlier' do
307
+ t = Time.zone.now
308
+ u = User.create!(email: 'doug@example.com', activated_state_at: t)
309
+ u.state_by?(:activated, Time.zone.at(t.to_i + 1)).should be true
310
+ u.activated_state_by?(Time.zone.at(t.to_i + 1)).should be true
420
311
  end
421
312
 
422
- it "should be true when the transition is at the same time" do
423
- t = Time.now
424
- u = User.create!( email: "doug@example.com", activated_state_at: t)
313
+ it 'should be true when the transition is at the same time' do
314
+ t = Time.zone.now
315
+ u = User.create!(email: 'doug@example.com', activated_state_at: t)
425
316
  u.state_by?(:activated, t).should be true
426
317
  u.activated_state_by?(t).should be true
427
318
  end
428
319
 
429
- it "should be false when the transition is later" do
430
- t = Time.now
431
- u = User.create!( email: "doug@example.com", activated_state_at: t)
432
- u.state_by?(:activated, Time.at(t.to_i - 1)).should be false
433
- u.activated_state_by?(Time.at(t.to_i - 1)).should be false
320
+ it 'should be false when the transition is later' do
321
+ t = Time.zone.now
322
+ u = User.create!(email: 'doug@example.com', activated_state_at: t)
323
+ u.state_by?(:activated, Time.zone.at(t.to_i - 1)).should be false
324
+ u.activated_state_by?(Time.zone.at(t.to_i - 1)).should be false
434
325
  end
435
326
 
436
- it "should be false when the transition is nil" do
437
- t = Time.now
438
- u = User.create!( email: "doug@example.com", activated_state_at: nil)
327
+ it 'should be false when the transition is nil' do
328
+ t = Time.zone.now
329
+ u = User.create!(email: 'doug@example.com', activated_state_at: nil)
439
330
  u.state_by?(:activated, t).should be false
440
331
  u.activated_state_by?(t).should be false
441
332
  end
442
333
 
443
- it "should be true when the transition is not nil and the time is nil" do
444
- u = User.create!( email: "doug@example.com", activated_state_at: Time.now)
334
+ it 'should be true when the transition is not nil and the time is nil' do
335
+ u = User.create!(email: 'doug@example.com', activated_state_at: Time.zone.now)
445
336
  u.state_by?(:activated, nil).should be true
446
337
  u.activated_state_by?(nil).should be true
447
338
  end
448
339
 
449
- it "should be false when both are nil" do
450
- u = User.create!(email: "doug@example.com", activated_state_at: nil)
340
+ it 'should be false when both are nil' do
341
+ u = User.create!(email: 'doug@example.com', activated_state_at: nil)
451
342
  u.state_by?(:activated, nil).should be false
452
343
  u.activated_state_by?(nil).should be false
453
344
  end
454
345
  end
455
346
  end
456
347
 
457
- describe "aliasing" do
458
- it "should allow aliasing within the dsl" do
459
- u = User.new(email: "doug@example.com")
348
+ describe 'aliasing' do
349
+ it 'should allow aliasing within the dsl' do
350
+ u = User.new(email: 'doug@example.com')
351
+
460
352
  u.should respond_to(:active?)
461
353
  u.should respond_to(:inactive?)
462
354
 
@@ -473,34 +365,28 @@ describe Stator::Model do
473
365
  u.should be_active
474
366
  u.should_not be_inactive
475
367
 
476
- User::ACTIVE_STATES.should eql(%w[activated hyperactivated])
477
- User::INACTIVE_STATES.should eql(%w[pending deactivated semiactivated])
478
-
479
- is_active_record_72_or_higher = Gem::Requirement.new(">= 7.2").satisfied_by?(ActiveRecord.version)
480
-
481
- if (is_active_record_72_or_higher)
482
- User.active.to_sql.gsub(" ", " ").should eq("SELECT 'users'.* FROM 'users' WHERE 'users'.'state' IN ('activated', 'hyperactivated')")
483
- User.inactive.to_sql.gsub(" ", " ").should eq("SELECT 'users'.* FROM 'users' WHERE 'users'.'state' IN ('pending', 'deactivated', 'semiactivated')")
484
- else
485
- User.active.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
486
- User.inactive.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
487
- end
368
+ User::ACTIVE_STATES.should eql(%i[activated hyperactivated])
369
+ User::INACTIVE_STATES.should eql(%i[pending deactivated semiactivated])
488
370
 
371
+ User.active.to_sql.gsub(' ',
372
+ ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
373
+ User.inactive.to_sql.gsub(' ',
374
+ ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
489
375
  end
490
376
 
491
- it "should evaluate inverses correctly" do
377
+ it 'should evaluate inverses correctly' do
492
378
  f = Farm.new
493
- f.house_state = "dirty"
379
+ f.house_state = 'dirty'
494
380
  f.should_not be_house_cleaned
495
381
 
496
- f.house_state = "disgusting"
382
+ f.house_state = 'disgusting'
497
383
  f.should_not be_house_cleaned
498
384
 
499
- f.house_state = "clean"
385
+ f.house_state = 'clean'
500
386
  f.should be_house_cleaned
501
387
  end
502
388
 
503
- it "should namespace aliases just like everything else" do
389
+ it 'should namespace aliases just like everything else' do
504
390
  f = Farm.new
505
391
  f.should respond_to(:house_cleaned?)
506
392
 
@@ -510,24 +396,23 @@ describe Stator::Model do
510
396
  f.should be_house_cleaned
511
397
  end
512
398
 
513
- it "should allow for explicit constant and scope names to be provided" do
399
+ it 'should allow for explicit constant and scope names to be provided' do
514
400
  User.should respond_to(:luke_warmers)
515
- (!!defined?(User::LUKE_WARMERS)).should eql(true)
401
+ (!defined?(User::LUKE_WARMERS).nil?).should eql(true)
516
402
  u = User.new
517
403
  u.should respond_to(:luke_warm?)
518
404
  end
519
405
 
520
- it "should not create constants or scopes by default" do
406
+ it 'should not create constants or scopes by default' do
521
407
  u = User.new
522
408
  u.should respond_to(:iced_tea?)
523
- (!!defined?(User::ICED_TEA_STATES)).should eql(false)
409
+ (!defined?(User::ICED_TEA_STATES).nil?).should eql(false)
524
410
  User.should_not respond_to(:iced_tea)
525
411
  end
526
412
 
527
- it "should determine the full list of states correctly" do
528
- states = User._stator("").states
529
- states.should eql(%w[pending activated deactivated semiactivated hyperactivated])
413
+ it 'should determine the full list of states correctly' do
414
+ states = User._stator('').states
415
+ states.should eql(%i[pending activated deactivated semiactivated hyperactivated])
530
416
  end
531
417
  end
532
-
533
418
  end