stator 0.3.3 → 0.9.0.beta

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