stator 0.9.0.beta → 0.9.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.
@@ -1,73 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- stator (0.9.0.beta)
5
- activerecord
6
- activesupport
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- activemodel (6.1.6.1)
12
- activesupport (= 6.1.6.1)
13
- activerecord (6.1.6.1)
14
- activemodel (= 6.1.6.1)
15
- activesupport (= 6.1.6.1)
16
- activerecord-nulldb-adapter (0.8.0)
17
- activerecord (>= 5.2.0, < 7.1)
18
- activesupport (6.1.6.1)
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
20
- i18n (>= 1.6, < 2)
21
- minitest (>= 5.1)
22
- tzinfo (~> 2.0)
23
- zeitwerk (~> 2.3)
24
- appraisal (2.4.1)
25
- bundler
26
- rake
27
- thor (>= 0.14.0)
28
- concurrent-ruby (1.1.10)
29
- debug (1.6.1)
30
- irb (>= 1.3.6)
31
- reline (>= 0.3.1)
32
- diff-lcs (1.5.0)
33
- i18n (1.12.0)
34
- concurrent-ruby (~> 1.0)
35
- io-console (0.5.11)
36
- irb (1.4.1)
37
- reline (>= 0.3.0)
38
- minitest (5.16.2)
39
- rake (13.0.6)
40
- reline (0.3.1)
41
- io-console (~> 0.5)
42
- rspec (3.11.0)
43
- rspec-core (~> 3.11.0)
44
- rspec-expectations (~> 3.11.0)
45
- rspec-mocks (~> 3.11.0)
46
- rspec-core (3.11.0)
47
- rspec-support (~> 3.11.0)
48
- rspec-expectations (3.11.0)
49
- diff-lcs (>= 1.2.0, < 2.0)
50
- rspec-support (~> 3.11.0)
51
- rspec-mocks (3.11.1)
52
- diff-lcs (>= 1.2.0, < 2.0)
53
- rspec-support (~> 3.11.0)
54
- rspec-support (3.11.0)
55
- thor (1.2.1)
56
- tzinfo (2.0.5)
57
- concurrent-ruby (~> 1.0)
58
- zeitwerk (2.6.0)
59
-
60
- PLATFORMS
61
- ruby
62
-
63
- DEPENDENCIES
64
- activerecord (~> 6.1.0)
65
- activerecord-nulldb-adapter
66
- appraisal
67
- debug
68
- rake
69
- rspec
70
- stator!
71
-
72
- BUNDLED WITH
73
- 2.3.16
@@ -1,12 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 7.0.0"
6
- gem "appraisal"
7
- gem "debug"
8
- gem "activerecord-nulldb-adapter"
9
- gem "rake"
10
- gem "rspec"
11
-
12
- gemspec path: "../"
@@ -1,71 +0,0 @@
1
- PATH
2
- remote: ..
3
- specs:
4
- stator (0.9.0.beta)
5
- activerecord
6
- activesupport
7
-
8
- GEM
9
- remote: https://rubygems.org/
10
- specs:
11
- activemodel (7.0.3.1)
12
- activesupport (= 7.0.3.1)
13
- activerecord (7.0.3.1)
14
- activemodel (= 7.0.3.1)
15
- activesupport (= 7.0.3.1)
16
- activerecord-nulldb-adapter (0.8.0)
17
- activerecord (>= 5.2.0, < 7.1)
18
- activesupport (7.0.3.1)
19
- concurrent-ruby (~> 1.0, >= 1.0.2)
20
- i18n (>= 1.6, < 2)
21
- minitest (>= 5.1)
22
- tzinfo (~> 2.0)
23
- appraisal (2.4.1)
24
- bundler
25
- rake
26
- thor (>= 0.14.0)
27
- concurrent-ruby (1.1.10)
28
- debug (1.6.1)
29
- irb (>= 1.3.6)
30
- reline (>= 0.3.1)
31
- diff-lcs (1.5.0)
32
- i18n (1.12.0)
33
- concurrent-ruby (~> 1.0)
34
- io-console (0.5.11)
35
- irb (1.4.1)
36
- reline (>= 0.3.0)
37
- minitest (5.16.2)
38
- rake (13.0.6)
39
- reline (0.3.1)
40
- io-console (~> 0.5)
41
- rspec (3.11.0)
42
- rspec-core (~> 3.11.0)
43
- rspec-expectations (~> 3.11.0)
44
- rspec-mocks (~> 3.11.0)
45
- rspec-core (3.11.0)
46
- rspec-support (~> 3.11.0)
47
- rspec-expectations (3.11.0)
48
- diff-lcs (>= 1.2.0, < 2.0)
49
- rspec-support (~> 3.11.0)
50
- rspec-mocks (3.11.1)
51
- diff-lcs (>= 1.2.0, < 2.0)
52
- rspec-support (~> 3.11.0)
53
- rspec-support (3.11.0)
54
- thor (1.2.1)
55
- tzinfo (2.0.5)
56
- concurrent-ruby (~> 1.0)
57
-
58
- PLATFORMS
59
- ruby
60
-
61
- DEPENDENCIES
62
- activerecord (~> 7.0.0)
63
- activerecord-nulldb-adapter
64
- appraisal
65
- debug
66
- rake
67
- rspec
68
- stator!
69
-
70
- BUNDLED WITH
71
- 2.3.16
data/spec/model_spec.rb DELETED
@@ -1,418 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Stator::Model do
6
-
7
- let(:u) { User.new }
8
-
9
- describe "basic operations" do
10
-
11
- it 'should set the default state after initialization' do
12
- u.state.to_sym.should eql(:pending)
13
- end
14
-
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
24
-
25
- it 'should ensure a valid state transition when given a bogus state' do
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.email = 'doug@example.com'
34
- u.state = :hyperactivated
35
-
36
- u.should be_valid
37
- end
38
-
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)
41
-
42
- u.state = 'hyperactivated'
43
-
44
- u.should_not be_valid
45
- u.errors[:state].should_not be_empty
46
- end
47
-
48
- it 'should not allow a transition that is currently in a `to` state' do
49
- u.email = 'fred@example.com'
50
- u.activate!
51
- u.hyperactivate!
52
-
53
- lambda {
54
- u.hyperactivate!
55
- }.should raise_error(/cannot transition to hyperactivated from hyperactivated/)
56
- end
57
-
58
- it 'should run conditional validations' do
59
- u.state = 'semiactivated'
60
- u.should_not be_valid
61
-
62
- u.errors[:state].should be_empty
63
- u.errors[:email].should_not be_empty
64
- end
65
-
66
- it 'should invoke callbacks' do
67
- u.assign_attributes(activated: true, email: 'doug@example.com', name: 'doug')
68
- u.activated.should == true
69
-
70
- u.deactivate
71
-
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
77
-
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
82
-
83
- it 'should allow for other fields to be used other than state' do
84
- a = Animal.new
85
- a.should be_valid
86
-
87
- a.birth!
88
- end
89
-
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
96
-
97
- it 'should allow multiple machines in the same model' do
98
- f = Farm.new
99
-
100
- f.should be_dirty
101
- f.should be_house_dirty
102
-
103
- f.cleanup
104
-
105
- f.should_not be_dirty
106
- f.should be_house_dirty
107
-
108
- f.house_cleanup # the house namespace
109
-
110
- f.should_not be_dirty
111
- f.should_not be_house_dirty
112
- end
113
-
114
- it 'should allow saving to be skipped' do
115
- f = Farm.new
116
- f.cleanup(false)
117
-
118
- f.should_not be_persisted
119
- end
120
-
121
- it 'should allow no initial state' do
122
- f = Factory.new
123
- f.state.should be_nil
124
-
125
- f.construct.should eql(true)
126
-
127
- f.state.should eql(:constructed)
128
- end
129
-
130
- it 'should allow any transition if validations are opted out of' do
131
- u.email = 'doug@example.com'
132
-
133
- u.can_hyperactivate?.should eql(false)
134
- u.hyperactivate.should eql(false)
135
-
136
- u.current_state.should eql :pending
137
-
138
- u.without_state_transition_validations do
139
- u.can_hyperactivate?.should eql(true)
140
- u.hyperactivate.should eql(true)
141
- end
142
- end
143
-
144
- it 'should skip tracking timestamps if opted out of' do
145
- u.email = 'doug@example.com'
146
-
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
157
- end
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!
167
- end
168
-
169
- threads << Thread.new do
170
- skip.without_state_transition_tracking do
171
- sleep 1
172
- skip.semiactivate!
173
- end
174
- end
175
-
176
- threads.each(&:join)
177
-
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!
185
-
186
- u_duped = u.dup
187
-
188
- u.semiactivate!
189
-
190
- u_duped_integration = u_duped.send(:_stator_integration)
191
-
192
- u_duped_integration.state.should_not eql(u.state)
193
- u_duped_integration.instance_values['record'].should eq(u_duped)
194
- end
195
- end
196
-
197
- describe 'helper methods' do
198
- it 'should answer the question of whether the state is currently the one invoked' do
199
- a = Animal.new
200
- a.should be_unborn
201
- a.should_not be_born
202
-
203
- a.birth
204
-
205
- a.should be_born
206
- a.should_not be_unborn
207
- end
208
-
209
- it 'should determine if it can validly execute a transition' do
210
- a = Animal.new
211
- a.can_birth?.should eql(true)
212
-
213
- a.birth
214
-
215
- a.can_birth?.should eql(false)
216
- end
217
- end
218
-
219
- describe 'tracker methods' do
220
- before do
221
- Time.zone = 'Eastern Time (US & Canada)'
222
- end
223
-
224
- it 'should store the initial state timestamp when the record is created' do
225
- a = Animal.new
226
- a.save
227
- a.unborn_status_at.should be_within(1).of(Time.zone.now)
228
- end
229
-
230
- it 'should store when a record changed state for the first time' do
231
- a = Animal.new
232
- a.unborn_status_at.should be_nil
233
- a.born_status_at.should be_nil
234
- a.birth
235
- a.unborn_status_at.should be_nil
236
- a.born_status_at.should be_within(1).of(Time.zone.now)
237
- end
238
-
239
- it 'should store when a record change states' do
240
- a = Animal.new
241
- a.status_changed_at.should be_nil
242
-
243
- a.birth
244
-
245
- a.status_changed_at.should be_within(1).of(Time.zone.now)
246
-
247
- previous_status_changed_at = a.status_changed_at
248
-
249
- a.name = 'new name'
250
- a.save
251
-
252
- a.status_changed_at.should eql(previous_status_changed_at)
253
- end
254
-
255
- it 'should prepend the setting of the timestamp so other callbacks can use it' do
256
- u.email = 'doug@example.com'
257
-
258
- u.tagged_at.should be_nil
259
- u.semiactivate!
260
-
261
- u.semiactivated_state_at.should_not be_nil
262
- u.tagged_at.should_not be_nil
263
- end
264
-
265
- it 'should respect the timestamp if explicitly provided' do
266
- t = Time.zone.at(Time.now.to_i - 3600)
267
-
268
- u.email = 'doug@example.com'
269
- u.state = 'semiactivated'
270
- u.semiactivated_state_at = t
271
- u.save!
272
-
273
- u.state.should eql('semiactivated')
274
- u.semiactivated_state_at.should eql(t)
275
- end
276
-
277
- it 'should respect the timestamp if explicitly provided via create' do
278
- t = Time.zone.at(Time.now.to_i - 3600)
279
-
280
- u = User.create!(
281
- email: 'doug@example.com',
282
- state: 'semiactivated',
283
- semiactivated_state_at: t
284
- )
285
-
286
- u.state.should eql('semiactivated')
287
- u.semiactivated_state_at.should eql(t)
288
- end
289
-
290
- it 'should allow opting into track by namespace' do
291
- z = ZooKeeper.new(name: 'Doug')
292
- z.employment_state.should eql('hired')
293
- z.employment_fire!
294
- z.fired_employment_state_at.should_not be_nil
295
-
296
- z.employment_hire!
297
- z.hired_employment_state_at.should_not be_nil
298
-
299
- z.working_start!
300
- z.started_working_state_at.should be_nil
301
- z.working_end!
302
- z.ended_working_state_at.should be_nil
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
346
- end
347
-
348
- describe 'aliasing' do
349
- it 'should allow aliasing within the dsl' do
350
- u = User.new(email: 'doug@example.com')
351
-
352
- u.should respond_to(:active?)
353
- u.should respond_to(:inactive?)
354
-
355
- u.should_not be_active
356
-
357
- u.inactive?
358
- u.should be_inactive
359
-
360
- u.activate!
361
- u.should be_active
362
- u.should_not be_inactive
363
-
364
- u.hyperactivate!
365
- u.should be_active
366
- u.should_not be_inactive
367
-
368
- User::ACTIVE_STATES.should eql(%i[activated hyperactivated])
369
- User::INACTIVE_STATES.should eql(%i[pending deactivated semiactivated])
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')")
375
- end
376
-
377
- it 'should evaluate inverses correctly' do
378
- f = Farm.new
379
- f.house_state = 'dirty'
380
- f.should_not be_house_cleaned
381
-
382
- f.house_state = 'disgusting'
383
- f.should_not be_house_cleaned
384
-
385
- f.house_state = 'clean'
386
- f.should be_house_cleaned
387
- end
388
-
389
- it 'should namespace aliases just like everything else' do
390
- f = Farm.new
391
- f.should respond_to(:house_cleaned?)
392
-
393
- f.should_not be_house_cleaned
394
- f.house_cleanup!
395
-
396
- f.should be_house_cleaned
397
- end
398
-
399
- it 'should allow for explicit constant and scope names to be provided' do
400
- User.should respond_to(:luke_warmers)
401
- (!defined?(User::LUKE_WARMERS).nil?).should eql(true)
402
- u = User.new
403
- u.should respond_to(:luke_warm?)
404
- end
405
-
406
- it 'should not create constants or scopes by default' do
407
- u = User.new
408
- u.should respond_to(:iced_tea?)
409
- (!defined?(User::ICED_TEA_STATES).nil?).should eql(false)
410
- User.should_not respond_to(:iced_tea)
411
- end
412
-
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])
416
- end
417
- end
418
- end
data/spec/spec_helper.rb DELETED
@@ -1,38 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This file was generated by the `rspec --init` command. Conventionally, all
4
- # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
5
- # Require this file using `require "spec_helper"` to ensure that it is only
6
- # loaded once.
7
- #
8
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
9
-
10
- require 'active_record'
11
- require 'nulldb/core'
12
- require 'active_support/core_ext'
13
- require 'stator'
14
-
15
- RSpec.configure do |config|
16
- config.expect_with(:rspec) { |c| c.syntax = :should }
17
- config.run_all_when_everything_filtered = true
18
- config.filter_run :focus
19
-
20
- config.raise_errors_for_deprecations!
21
-
22
- NullDB.configure do |c|
23
- c.project_root = File.dirname(__FILE__)
24
- end
25
-
26
- ActiveRecord::Base.establish_connection(
27
- adapter: :nulldb,
28
- schema: 'support/schema.rb'
29
- )
30
-
31
- require 'support/models'
32
-
33
- # Run specs in random order to surface order dependencies. If you find an
34
- # order dependency and want to debug it, you can fix the order by providing
35
- # the seed, which is printed after each run.
36
- # --seed 1234
37
- config.order = 'random'
38
- end