stator 0.3.3 → 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.
data/spec/model_spec.rb CHANGED
@@ -1,203 +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
- it "should set the default state after initialization" do
7
- u = User.new
8
- u.state.should eql("pending")
9
- end
10
6
 
11
- it "should see the initial setting of the state as a change with the initial state as the previous value" do
12
- u = User.new
13
- u.state = "activated"
14
- u.state_was.should eql("pending")
15
- end
7
+ let(:u) { User.new }
16
8
 
17
- it "should not obstruct normal validations" do
18
- u = User.new
19
- u.should_not be_valid
20
- u.errors[:email].grep(/length/).should_not be_empty
21
- end
9
+ describe "basic operations" do
22
10
 
23
- it "should ensure a valid state transition when given a bogus state" do
24
- u = User.new
25
- u.state = "anythingelse"
11
+ it 'should set the default state after initialization' do
12
+ u.state.to_sym.should eql(:pending)
13
+ end
26
14
 
27
- u.should_not be_valid
28
- u.errors[:state].should eql(["is not a valid state"])
29
- end
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
19
+
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
30
24
 
31
- it "should allow creation at any state" do
32
- u = User.new(email: "doug@example.com")
33
- u.state = "hyperactivated"
25
+ it 'should ensure a valid state transition when given a bogus state' do
26
+ u.state = :anythingelse
34
27
 
35
- u.should be_valid
36
- end
28
+ u.should_not be_valid
29
+ u.errors[:state].should eql(['is not a valid state'])
30
+ end
37
31
 
38
- it "should ensure a valid state transition when given an illegal state based on the current state" do
39
- u = User.new
32
+ it 'should allow creation at any state' do
33
+ u.email = 'doug@example.com'
34
+ u.state = :hyperactivated
40
35
 
41
- allow(u).to receive(:new_record?).and_return(false)
36
+ u.should be_valid
37
+ end
42
38
 
43
- 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)
44
41
 
45
- u.should_not be_valid
46
- u.errors[:state].should_not be_empty
47
- end
42
+ u.state = 'hyperactivated'
48
43
 
49
- it "should not allow a transition that is currently in a `to` state" do
50
- u = User.new(email: "fred@example.com")
51
- u.activate!
52
- u.hyperactivate!
44
+ u.should_not be_valid
45
+ u.errors[:state].should_not be_empty
46
+ end
53
47
 
54
- 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!
55
51
  u.hyperactivate!
56
- }.should raise_error(/cannot transition to \"hyperactivated\" from \"hyperactivated\"/)
57
- end
58
52
 
59
- it "should run conditional validations" do
60
- u = User.new
61
- u.state = "semiactivated"
62
- u.should_not be_valid
53
+ lambda {
54
+ u.hyperactivate!
55
+ }.should raise_error(/cannot transition to hyperactivated from hyperactivated/)
56
+ end
63
57
 
64
- u.errors[:state].should be_empty
65
- u.errors[:email].grep(/format/).should_not be_empty
66
- end
58
+ it 'should run conditional validations' do
59
+ u.state = 'semiactivated'
60
+ u.should_not be_valid
67
61
 
68
- it "should invoke callbacks" do
69
- u = User.new(activated: true, email: "doug@example.com", name: "doug")
70
- u.activated.should == true
62
+ u.errors[:state].should be_empty
63
+ u.errors[:email].should_not be_empty
64
+ end
71
65
 
72
- u.deactivate
66
+ it 'should invoke callbacks' do
67
+ u.assign_attributes(activated: true, email: 'doug@example.com', name: 'doug')
68
+ u.activated.should == true
73
69
 
74
- u.activated.should == false
75
- u.state.should eql("deactivated")
76
- u.activated_state_at.should be_nil
77
- u.should be_persisted
78
- end
70
+ u.deactivate
79
71
 
80
- it "should blow up if the record is invalid and a bang method is used" do
81
- u = User.new(email: "doug@other.com", name: "doug")
82
- lambda {
83
- u.activate!
84
- }.should raise_error(ActiveRecord::RecordInvalid)
85
- end
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
86
77
 
87
- it "should allow for other fields to be used other than state" do
88
- a = Animal.new
89
- a.should be_valid
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
90
82
 
91
- a.birth!
92
- end
83
+ it 'should allow for other fields to be used other than state' do
84
+ a = Animal.new
85
+ a.should be_valid
93
86
 
94
- it "should create implicit transitions for state declarations" do
95
- a = Animal.new
96
- a.should_not be_grown_up
97
- a.status = "grown_up"
98
- a.save
99
- end
87
+ a.birth!
88
+ end
100
89
 
101
- it "should allow multiple machines in the same model" do
102
- f = Farm.new
103
- f.should be_dirty
104
- f.should be_house_dirty
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
105
96
 
106
- f.cleanup
97
+ it 'should allow multiple machines in the same model' do
98
+ f = Farm.new
107
99
 
108
- f.should_not be_dirty
109
- f.should be_house_dirty
100
+ f.should be_dirty
101
+ f.should be_house_dirty
110
102
 
111
- f.house_cleanup
103
+ f.cleanup
112
104
 
113
- f.should_not be_house_dirty
114
- end
105
+ f.should_not be_dirty
106
+ f.should be_house_dirty
115
107
 
116
- it "should allow saving to be skipped" do
117
- f = Farm.new
118
- f.cleanup(false)
108
+ f.house_cleanup # the house namespace
119
109
 
120
- f.should_not be_persisted
121
- end
110
+ f.should_not be_dirty
111
+ f.should_not be_house_dirty
112
+ end
122
113
 
123
- it "should allow no initial state" do
124
- f = Factory.new
125
- f.state.should be_nil
114
+ it 'should allow saving to be skipped' do
115
+ f = Farm.new
116
+ f.cleanup(false)
126
117
 
127
- f.construct.should eql(true)
118
+ f.should_not be_persisted
119
+ end
128
120
 
129
- f.state.should eql("constructed")
130
- end
121
+ it 'should allow no initial state' do
122
+ f = Factory.new
123
+ f.state.should be_nil
131
124
 
132
- it "should allow any transition if validations are opted out of" do
133
- u = User.new
134
- u.email = "doug@example.com"
125
+ f.construct.should eql(true)
135
126
 
136
- u.can_hyperactivate?.should eql(false)
137
- u.hyperactivate.should eql(false)
127
+ f.state.should eql(:constructed)
128
+ end
138
129
 
139
- u.state.should eql("pending")
130
+ it 'should allow any transition if validations are opted out of' do
131
+ u.email = 'doug@example.com'
140
132
 
141
- u.without_state_transition_validations do
142
- u.can_hyperactivate?.should eql(true)
143
- u.hyperactivate.should eql(true)
144
- end
145
- end
133
+ u.can_hyperactivate?.should eql(false)
134
+ u.hyperactivate.should eql(false)
146
135
 
147
- it "should skip tracking timestamps if opted out of" do
148
- u = User.new
149
- u.email = "doug@example.com"
136
+ u.current_state.should eql :pending
150
137
 
151
- u.without_state_transition_tracking do
152
- u.semiactivate!
153
- u.state.should eql("semiactivated")
154
- u.semiactivated_state_at.should be_nil
138
+ u.without_state_transition_validations do
139
+ u.can_hyperactivate?.should eql(true)
140
+ u.hyperactivate.should eql(true)
141
+ end
155
142
  end
156
143
 
157
- # Make sure that tracking is ensured back to
158
- # original value
159
- u.activate!
160
- u.activated_state_at.should_not be_nil
161
- end
144
+ it 'should skip tracking timestamps if opted out of' do
145
+ u.email = 'doug@example.com'
162
146
 
163
- it "should skip tracking timestamps if opted out of with thread safety" do
164
- threads = []
165
- skip = User.new(email: "skip@example.com")
166
- nope = User.new(email: "nope@example.com")
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
167
152
 
168
- threads << Thread.new do
169
- sleep 0.5
170
- nope.semiactivate!
153
+ # Make sure that tracking is ensured back to
154
+ # original value
155
+ u.activate!
156
+ u.activated_state_at.should_not be_nil
171
157
  end
172
- threads << Thread.new do
173
- skip.without_state_transition_tracking do
174
- sleep 1
175
- skip.semiactivate!
158
+
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)
163
+
164
+ threads << Thread.new do
165
+ sleep 0.5
166
+ nope.semiactivate!
176
167
  end
177
- end
178
168
 
179
- threads.each(&:join)
169
+ threads << Thread.new do
170
+ skip.without_state_transition_tracking do
171
+ sleep 1
172
+ skip.semiactivate!
173
+ end
174
+ end
180
175
 
181
- nope.semiactivated_state_at.should_not be_nil
182
- skip.semiactivated_state_at.should be_nil
183
- end
176
+ threads.each(&:join)
184
177
 
185
- it "should not inherit _integration cache on dup" do
186
- u = User.new(email: "user@example.com")
187
- u.save!
178
+ nope.semiactivated_state_at.should_not be_nil
179
+ skip.semiactivated_state_at.should be_nil
180
+ end
181
+
182
+ it 'should not inherit _integration cache on dup' do
183
+ u.email = 'user@example.com'
184
+ u.save!
188
185
 
189
- u_duped = u.dup
186
+ u_duped = u.dup
190
187
 
191
- u.semiactivate!
188
+ u.semiactivate!
192
189
 
193
- u_duped_integration = u_duped.send(:_integration)
190
+ u_duped_integration = u_duped.send(:_stator_integration)
194
191
 
195
- u_duped_integration.state.should_not eql(u.state)
196
- 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
197
195
  end
198
196
 
199
- describe "helper methods" do
200
- 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
201
199
  a = Animal.new
202
200
  a.should be_unborn
203
201
  a.should_not be_born
@@ -208,7 +206,7 @@ describe Stator::Model do
208
206
  a.should_not be_unborn
209
207
  end
210
208
 
211
- it "should determine if it can validly execute a transition" do
209
+ it 'should determine if it can validly execute a transition' do
212
210
  a = Animal.new
213
211
  a.can_birth?.should eql(true)
214
212
 
@@ -218,18 +216,18 @@ describe Stator::Model do
218
216
  end
219
217
  end
220
218
 
221
- describe "tracker methods" do
219
+ describe 'tracker methods' do
222
220
  before do
223
- Time.zone = "Eastern Time (US & Canada)"
221
+ Time.zone = 'Eastern Time (US & Canada)'
224
222
  end
225
223
 
226
- 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
227
225
  a = Animal.new
228
226
  a.save
229
227
  a.unborn_status_at.should be_within(1).of(Time.zone.now)
230
228
  end
231
229
 
232
- 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
233
231
  a = Animal.new
234
232
  a.unborn_status_at.should be_nil
235
233
  a.born_status_at.should be_nil
@@ -238,7 +236,7 @@ describe Stator::Model do
238
236
  a.born_status_at.should be_within(1).of(Time.zone.now)
239
237
  end
240
238
 
241
- it "should store when a record change states" do
239
+ it 'should store when a record change states' do
242
240
  a = Animal.new
243
241
  a.status_changed_at.should be_nil
244
242
 
@@ -248,15 +246,14 @@ describe Stator::Model do
248
246
 
249
247
  previous_status_changed_at = a.status_changed_at
250
248
 
251
- a.name = "new name"
249
+ a.name = 'new name'
252
250
  a.save
253
251
 
254
252
  a.status_changed_at.should eql(previous_status_changed_at)
255
253
  end
256
254
 
257
- it "should prepend the setting of the timestamp so other callbacks can use it" do
258
- u = User.new
259
- 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'
260
257
 
261
258
  u.tagged_at.should be_nil
262
259
  u.semiactivate!
@@ -265,35 +262,34 @@ describe Stator::Model do
265
262
  u.tagged_at.should_not be_nil
266
263
  end
267
264
 
268
- it "should respect the timestamp if explicitly provided" do
269
- 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)
270
267
 
271
- u = User.new
272
- u.email = "doug@example.com"
273
- u.state = "semiactivated"
268
+ u.email = 'doug@example.com'
269
+ u.state = 'semiactivated'
274
270
  u.semiactivated_state_at = t
275
271
  u.save!
276
272
 
277
- u.state.should eql("semiactivated")
273
+ u.state.should eql('semiactivated')
278
274
  u.semiactivated_state_at.should eql(t)
279
275
  end
280
276
 
281
- it "should respect the timestamp if explicitly provided via create" do
282
- 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)
283
279
 
284
280
  u = User.create!(
285
- email: "doug@example.com",
286
- state: "semiactivated",
281
+ email: 'doug@example.com',
282
+ state: 'semiactivated',
287
283
  semiactivated_state_at: t
288
284
  )
289
285
 
290
- u.state.should eql("semiactivated")
286
+ u.state.should eql('semiactivated')
291
287
  u.semiactivated_state_at.should eql(t)
292
288
  end
293
289
 
294
- it "should allow opting into track by namespace" do
295
- z = ZooKeeper.new(name: "Doug")
296
- 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')
297
293
  z.employment_fire!
298
294
  z.fired_employment_state_at.should_not be_nil
299
295
 
@@ -305,11 +301,54 @@ describe Stator::Model do
305
301
  z.working_end!
306
302
  z.ended_working_state_at.should be_nil
307
303
  end
304
+
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
311
+ end
312
+
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)
316
+ u.state_by?(:activated, t).should be true
317
+ u.activated_state_by?(t).should be true
318
+ end
319
+
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
325
+ end
326
+
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)
330
+ u.state_by?(:activated, t).should be false
331
+ u.activated_state_by?(t).should be false
332
+ end
333
+
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)
336
+ u.state_by?(:activated, nil).should be true
337
+ u.activated_state_by?(nil).should be true
338
+ end
339
+
340
+ it 'should be false when both are nil' do
341
+ u = User.create!(email: 'doug@example.com', activated_state_at: nil)
342
+ u.state_by?(:activated, nil).should be false
343
+ u.activated_state_by?(nil).should be false
344
+ end
345
+ end
308
346
  end
309
347
 
310
- describe "aliasing" do
311
- it "should allow aliasing within the dsl" do
312
- 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
+
313
352
  u.should respond_to(:active?)
314
353
  u.should respond_to(:inactive?)
315
354
 
@@ -326,26 +365,28 @@ describe Stator::Model do
326
365
  u.should be_active
327
366
  u.should_not be_inactive
328
367
 
329
- User::ACTIVE_STATES.should eql(%w[activated hyperactivated])
330
- User::INACTIVE_STATES.should eql(%w[pending deactivated semiactivated])
368
+ User::ACTIVE_STATES.should eql(%i[activated hyperactivated])
369
+ User::INACTIVE_STATES.should eql(%i[pending deactivated semiactivated])
331
370
 
332
- User.active.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
333
- User.inactive.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
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')")
334
375
  end
335
376
 
336
- it "should evaluate inverses correctly" do
377
+ it 'should evaluate inverses correctly' do
337
378
  f = Farm.new
338
- f.house_state = "dirty"
379
+ f.house_state = 'dirty'
339
380
  f.should_not be_house_cleaned
340
381
 
341
- f.house_state = "disgusting"
382
+ f.house_state = 'disgusting'
342
383
  f.should_not be_house_cleaned
343
384
 
344
- f.house_state = "clean"
385
+ f.house_state = 'clean'
345
386
  f.should be_house_cleaned
346
387
  end
347
388
 
348
- it "should namespace aliases just like everything else" do
389
+ it 'should namespace aliases just like everything else' do
349
390
  f = Farm.new
350
391
  f.should respond_to(:house_cleaned?)
351
392
 
@@ -355,23 +396,23 @@ describe Stator::Model do
355
396
  f.should be_house_cleaned
356
397
  end
357
398
 
358
- 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
359
400
  User.should respond_to(:luke_warmers)
360
- (!!defined?(User::LUKE_WARMERS)).should eql(true)
401
+ (!defined?(User::LUKE_WARMERS).nil?).should eql(true)
361
402
  u = User.new
362
403
  u.should respond_to(:luke_warm?)
363
404
  end
364
405
 
365
- it "should not create constants or scopes by default" do
406
+ it 'should not create constants or scopes by default' do
366
407
  u = User.new
367
408
  u.should respond_to(:iced_tea?)
368
- (!!defined?(User::ICED_TEA_STATES)).should eql(false)
409
+ (!defined?(User::ICED_TEA_STATES).nil?).should eql(false)
369
410
  User.should_not respond_to(:iced_tea)
370
411
  end
371
412
 
372
- it "should determine the full list of states correctly" do
373
- states = User._stator("").states
374
- 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])
375
416
  end
376
417
  end
377
418
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file was generated by the `rspec --init` command. Conventionally, all
2
4
  # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
5
  # Require this file using `require "spec_helper"` to ensure that it is only
@@ -11,18 +13,19 @@ require 'active_support/core_ext'
11
13
  require 'stator'
12
14
 
13
15
  RSpec.configure do |config|
14
- config.treat_symbols_as_metadata_keys_with_true_values = true
15
16
  config.expect_with(:rspec) { |c| c.syntax = :should }
16
17
  config.run_all_when_everything_filtered = true
17
18
  config.filter_run :focus
18
19
 
20
+ config.raise_errors_for_deprecations!
21
+
19
22
  NullDB.configure do |c|
20
23
  c.project_root = File.dirname(__FILE__)
21
24
  end
22
25
 
23
26
  ActiveRecord::Base.establish_connection(
24
- :adapter => :nulldb,
25
- :schema => 'support/schema.rb'
27
+ adapter: :nulldb,
28
+ schema: 'support/schema.rb'
26
29
  )
27
30
 
28
31
  require 'support/models'