stator 0.3.0 → 0.3.1

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
- SHA1:
3
- metadata.gz: bd69f892293770471063f818138639b932e78120
4
- data.tar.gz: 8f0f90685de79f5fd2d29e9170dc25a8c82bc6bb
2
+ SHA256:
3
+ metadata.gz: 3ea9ce5a04f3d128aecd8f78788c7a06a49d2785dc3669a7c54a2c973fb01f2b
4
+ data.tar.gz: c638206a0fb9dedf3e53403d160425054be95b1f08223e6436239f500afb9eb7
5
5
  SHA512:
6
- metadata.gz: e167050e139b82a6d1004739881e42a90dc711f0465d23823475876bf05254ecb0157e41b4038ae82e2779dcb102df5d334750d86da6da367ca78e237b4a0b40
7
- data.tar.gz: 8e5346d2586207932a1bdddff88d828953c2ffaebca9a98861845a2fde0b95a7b0a7b2d0c0f2a534c4b85db960534cd3cea14139ff10a1a41323056e6d3ecb3b
6
+ metadata.gz: e32e3867650801979aefd648ebc2184e0a9cf9357c0fa08146a963308c35ec610b3c5ac4a9439149acfa086b98957dd1006484310b60ab0fb18fad56a26bfe51
7
+ data.tar.gz: b8fa99e1f0e0bdf6a3832395d9de0730ee3a990994509c2dc8b30aa6f5ee06ca1af3114b4f9c00899cb83b15515cca142841a521ee4f0532bc863ba4d03532fe
@@ -1 +1 @@
1
- 2.2.3
1
+ 2.5.1
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stator
2
4
  class Integration
3
5
 
4
- delegate :states, :to => :@machine
5
- delegate :transitions, :to => :@machine
6
- delegate :namespace, :to => :@machine
6
+ delegate :states, to: :@machine
7
+ delegate :transitions, to: :@machine
8
+ delegate :namespace, to: :@machine
7
9
 
8
10
  def initialize(machine, record)
9
11
  @machine = machine
@@ -11,7 +13,7 @@ module Stator
11
13
  end
12
14
 
13
15
  def state=(new_value)
14
- @record.send("#{@machine.field}=", new_value)
16
+ @record.send("#{@machine.field}=", new_value)
15
17
  end
16
18
 
17
19
  def state
@@ -35,11 +37,11 @@ module Stator
35
37
  end
36
38
 
37
39
  def validate_transition
38
- return unless self.state_changed?
40
+ return unless state_changed?
39
41
  return if @machine.skip_validations
40
42
 
41
- was = self.state_was
42
- is = self.state
43
+ was = state_was
44
+ is = state
43
45
 
44
46
  if @record.new_record?
45
47
  invalid_state! unless @machine.matching_transition(::Stator::Transition::ANY, is)
@@ -48,7 +50,7 @@ module Stator
48
50
  end
49
51
  end
50
52
 
51
- # todo: i18n
53
+ # TODO: i18n
52
54
  def invalid_state!
53
55
  @record.errors.add(@machine.field, "is not a valid state")
54
56
  end
@@ -60,8 +62,8 @@ module Stator
60
62
  def track_transition
61
63
  return if @machine.skip_transition_tracking
62
64
 
63
- self.attempt_to_track_state(self.state)
64
- self.attempt_to_track_state_changed_timestamp
65
+ attempt_to_track_state(state)
66
+ attempt_to_track_state_changed_timestamp
65
67
 
66
68
  true
67
69
  end
@@ -82,7 +84,6 @@ module Stator
82
84
 
83
85
  # grab all the states and their timestamps that occur on or after state_at and on or before the time in question
84
86
  later_states = all_states.map do |s|
85
-
86
87
  next if state == s
87
88
 
88
89
  at = @record.send("#{s}_#{@machine.field}_at")
@@ -98,8 +99,8 @@ module Stator
98
99
  return true if later_states.empty?
99
100
 
100
101
  # grab the states that were present at the lowest timestamp
101
- later_groups = later_states.group_by{|s| s[:at] }
102
- later_group_key = later_groups.keys.sort[0]
102
+ later_groups = later_states.group_by { |s| s[:at] }
103
+ later_group_key = later_groups.keys.min
103
104
  later_states = later_groups[later_group_key]
104
105
 
105
106
  # if the lowest timestamp is the same as the state's timestamp, evaluate based on state index
@@ -111,13 +112,14 @@ module Stator
111
112
  end
112
113
 
113
114
  def likely_state_at(t)
114
- @machine.states.reverse.detect{|s| in_state_at?(s,t) }
115
+ @machine.states.reverse.detect { |s| in_state_at?(s, t) }
115
116
  end
116
117
 
117
118
  protected
118
119
 
119
120
  def attempt_to_track_state(state_to_track)
120
121
  return unless state_to_track
122
+
121
123
  _attempt_to_track_change("#{state_to_track}_#{@machine.field}_at")
122
124
  end
123
125
 
@@ -128,7 +130,8 @@ module Stator
128
130
  def _attempt_to_track_change(field_name)
129
131
  return unless @record.respond_to?(field_name)
130
132
  return unless @record.respond_to?("#{field_name}=")
131
- return unless @record.send("#{field_name}").nil? || self.state_changed?
133
+ return unless @record.send(field_name.to_s).nil? || state_changed?
134
+ return if @record.send("#{field_name}_changed?")
132
135
 
133
136
  @record.send("#{field_name}=", (Time.zone || Time).now)
134
137
  end
@@ -1,8 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Stator
4
+
2
5
  MAJOR = 0
3
6
  MINOR = 3
4
- PATCH = 0
7
+ PATCH = 1
5
8
  PRERELEASE = nil
6
9
 
7
- VERSION = [MAJOR, MINOR, PATCH, PRERELEASE].compact.join('.')
10
+ VERSION = [MAJOR, MINOR, PATCH, PRERELEASE].compact.join(".")
11
+
8
12
  end
@@ -1,103 +1,104 @@
1
- require 'spec_helper'
1
+ # frozen_string_literal: true
2
2
 
3
- describe Stator::Model do
3
+ require "spec_helper"
4
4
 
5
- it 'should set the default state after initialization' do
5
+ describe Stator::Model do
6
+ it "should set the default state after initialization" do
6
7
  u = User.new
7
- u.state.should eql('pending')
8
+ u.state.should eql("pending")
8
9
  end
9
10
 
10
- it 'should see the initial setting of the state as a change with the initial state as the previous value' do
11
+ it "should see the initial setting of the state as a change with the initial state as the previous value" do
11
12
  u = User.new
12
- u.state = 'activated'
13
- u.state_was.should eql('pending')
13
+ u.state = "activated"
14
+ u.state_was.should eql("pending")
14
15
  end
15
16
 
16
- it 'should not obstruct normal validations' do
17
+ it "should not obstruct normal validations" do
17
18
  u = User.new
18
19
  u.should_not be_valid
19
20
  u.errors[:email].grep(/length/).should_not be_empty
20
21
  end
21
22
 
22
- it 'should ensure a valid state transition when given a bogus state' do
23
+ it "should ensure a valid state transition when given a bogus state" do
23
24
  u = User.new
24
- u.state = 'anythingelse'
25
+ u.state = "anythingelse"
25
26
 
26
27
  u.should_not be_valid
27
- u.errors[:state].should eql(['is not a valid state'])
28
+ u.errors[:state].should eql(["is not a valid state"])
28
29
  end
29
30
 
30
- it 'should allow creation at any state' do
31
- u = User.new(:email => 'doug@example.com')
32
- u.state = 'hyperactivated'
31
+ it "should allow creation at any state" do
32
+ u = User.new(email: "doug@example.com")
33
+ u.state = "hyperactivated"
33
34
 
34
35
  u.should be_valid
35
36
  end
36
37
 
37
- it 'should ensure a valid state transition when given an illegal state based on the current state' do
38
+ it "should ensure a valid state transition when given an illegal state based on the current state" do
38
39
  u = User.new
39
40
 
40
41
  allow(u).to receive(:new_record?).and_return(false)
41
42
 
42
- u.state = 'hyperactivated'
43
+ u.state = "hyperactivated"
43
44
 
44
45
  u.should_not be_valid
45
46
  u.errors[:state].should_not be_empty
46
47
  end
47
48
 
48
- it 'should not allow a transition that is currently in a `to` state' do
49
- u = User.new(:email => 'fred@example.com')
49
+ it "should not allow a transition that is currently in a `to` state" do
50
+ u = User.new(email: "fred@example.com")
50
51
  u.activate!
51
52
  u.hyperactivate!
52
53
 
53
- lambda{
54
+ lambda {
54
55
  u.hyperactivate!
55
56
  }.should raise_error(/cannot transition to \"hyperactivated\" from \"hyperactivated\"/)
56
57
  end
57
58
 
58
- it 'should run conditional validations' do
59
+ it "should run conditional validations" do
59
60
  u = User.new
60
- u.state = 'semiactivated'
61
+ u.state = "semiactivated"
61
62
  u.should_not be_valid
62
63
 
63
64
  u.errors[:state].should be_empty
64
65
  u.errors[:email].grep(/format/).should_not be_empty
65
66
  end
66
67
 
67
- it 'should invoke callbacks' do
68
- u = User.new(:activated => true, :email => 'doug@example.com', :name => 'doug')
68
+ it "should invoke callbacks" do
69
+ u = User.new(activated: true, email: "doug@example.com", name: "doug")
69
70
  u.activated.should == true
70
71
 
71
72
  u.deactivate
72
73
 
73
74
  u.activated.should == false
74
- u.state.should eql('deactivated')
75
+ u.state.should eql("deactivated")
75
76
  u.activated_state_at.should be_nil
76
77
  u.should be_persisted
77
78
  end
78
79
 
79
- it 'should blow up if the record is invalid and a bang method is used' do
80
- u = User.new(:email => 'doug@other.com', :name => 'doug')
81
- lambda{
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 {
82
83
  u.activate!
83
84
  }.should raise_error(ActiveRecord::RecordInvalid)
84
85
  end
85
86
 
86
- it 'should allow for other fields to be used other than state' do
87
+ it "should allow for other fields to be used other than state" do
87
88
  a = Animal.new
88
89
  a.should be_valid
89
90
 
90
91
  a.birth!
91
92
  end
92
93
 
93
- it 'should create implicit transitions for state declarations' do
94
+ it "should create implicit transitions for state declarations" do
94
95
  a = Animal.new
95
96
  a.should_not be_grown_up
96
- a.status = 'grown_up'
97
+ a.status = "grown_up"
97
98
  a.save
98
99
  end
99
100
 
100
- it 'should allow multiple machines in the same model' do
101
+ it "should allow multiple machines in the same model" do
101
102
  f = Farm.new
102
103
  f.should be_dirty
103
104
  f.should be_house_dirty
@@ -112,30 +113,30 @@ describe Stator::Model do
112
113
  f.should_not be_house_dirty
113
114
  end
114
115
 
115
- it 'should allow saving to be skipped' do
116
+ it "should allow saving to be skipped" do
116
117
  f = Farm.new
117
118
  f.cleanup(false)
118
119
 
119
120
  f.should_not be_persisted
120
121
  end
121
122
 
122
- it 'should allow no initial state' do
123
+ it "should allow no initial state" do
123
124
  f = Factory.new
124
125
  f.state.should be_nil
125
126
 
126
127
  f.construct.should eql(true)
127
128
 
128
- f.state.should eql('constructed')
129
+ f.state.should eql("constructed")
129
130
  end
130
131
 
131
- it 'should allow any transition if validations are opted out of' do
132
+ it "should allow any transition if validations are opted out of" do
132
133
  u = User.new
133
- u.email = 'doug@example.com'
134
+ u.email = "doug@example.com"
134
135
 
135
136
  u.can_hyperactivate?.should eql(false)
136
137
  u.hyperactivate.should eql(false)
137
138
 
138
- u.state.should eql('pending')
139
+ u.state.should eql("pending")
139
140
 
140
141
  u.without_state_transition_validations do
141
142
  u.can_hyperactivate?.should eql(true)
@@ -143,13 +144,13 @@ describe Stator::Model do
143
144
  end
144
145
  end
145
146
 
146
- it 'should skip tracking timestamps if opted out of' do
147
+ it "should skip tracking timestamps if opted out of" do
147
148
  u = User.new
148
- u.email = 'doug@example.com'
149
+ u.email = "doug@example.com"
149
150
 
150
151
  u.without_state_transition_tracking do
151
152
  u.semiactivate!
152
- u.state.should eql('semiactivated')
153
+ u.state.should eql("semiactivated")
153
154
  u.semiactivated_state_at.should be_nil
154
155
  end
155
156
 
@@ -159,9 +160,8 @@ describe Stator::Model do
159
160
  u.activated_state_at.should_not be_nil
160
161
  end
161
162
 
162
- describe 'helper methods' do
163
-
164
- it 'should answer the question of whether the state is currently the one invoked' do
163
+ describe "helper methods" do
164
+ it "should answer the question of whether the state is currently the one invoked" do
165
165
  a = Animal.new
166
166
  a.should be_unborn
167
167
  a.should_not be_born
@@ -172,7 +172,7 @@ describe Stator::Model do
172
172
  a.should_not be_unborn
173
173
  end
174
174
 
175
- it 'should determine if it can validly execute a transition' do
175
+ it "should determine if it can validly execute a transition" do
176
176
  a = Animal.new
177
177
  a.can_birth?.should eql(true)
178
178
 
@@ -180,22 +180,20 @@ describe Stator::Model do
180
180
 
181
181
  a.can_birth?.should eql(false)
182
182
  end
183
-
184
183
  end
185
184
 
186
- describe 'tracker methods' do
187
-
185
+ describe "tracker methods" do
188
186
  before do
189
- Time.zone = 'Eastern Time (US & Canada)'
187
+ Time.zone = "Eastern Time (US & Canada)"
190
188
  end
191
189
 
192
- it 'should store the initial state timestamp when the record is created' do
190
+ it "should store the initial state timestamp when the record is created" do
193
191
  a = Animal.new
194
192
  a.save
195
193
  a.unborn_status_at.should be_within(1).of(Time.zone.now)
196
194
  end
197
195
 
198
- it 'should store when a record changed state for the first time' do
196
+ it "should store when a record changed state for the first time" do
199
197
  a = Animal.new
200
198
  a.unborn_status_at.should be_nil
201
199
  a.born_status_at.should be_nil
@@ -204,7 +202,7 @@ describe Stator::Model do
204
202
  a.born_status_at.should be_within(1).of(Time.zone.now)
205
203
  end
206
204
 
207
- it 'should store when a record change states' do
205
+ it "should store when a record change states" do
208
206
  a = Animal.new
209
207
  a.status_changed_at.should be_nil
210
208
 
@@ -218,12 +216,11 @@ describe Stator::Model do
218
216
  a.save
219
217
 
220
218
  a.status_changed_at.should eql(previous_status_changed_at)
221
-
222
219
  end
223
220
 
224
- it 'should prepend the setting of the timestamp so other callbacks can use it' do
221
+ it "should prepend the setting of the timestamp so other callbacks can use it" do
225
222
  u = User.new
226
- u.email = 'doug@example.com'
223
+ u.email = "doug@example.com"
227
224
 
228
225
  u.tagged_at.should be_nil
229
226
  u.semiactivate!
@@ -232,11 +229,36 @@ describe Stator::Model do
232
229
  u.tagged_at.should_not be_nil
233
230
  end
234
231
 
232
+ it "should respect the timestamp if explicitly provided" do
233
+ t = Time.at(Time.now.to_i - 3600)
234
+
235
+ u = User.new
236
+ u.email = "doug@example.com"
237
+ u.state = "semiactivated"
238
+ u.semiactivated_state_at = t
239
+ u.save!
240
+
241
+ u.state.should eql("semiactivated")
242
+ u.semiactivated_state_at.should eql(t)
243
+ end
244
+
245
+ it "should respect the timestamp if explicitly provided via create" do
246
+ t = Time.at(Time.now.to_i - 3600)
247
+
248
+ u = User.create!(
249
+ email: "doug@example.com",
250
+ state: "semiactivated",
251
+ semiactivated_state_at: t
252
+ )
253
+
254
+ u.state.should eql("semiactivated")
255
+ u.semiactivated_state_at.should eql(t)
256
+ end
235
257
  end
236
258
 
237
- describe 'aliasing' do
238
- it 'should allow aliasing within the dsl' do
239
- u = User.new(:email => 'doug@example.com')
259
+ describe "aliasing" do
260
+ it "should allow aliasing within the dsl" do
261
+ u = User.new(email: "doug@example.com")
240
262
  u.should respond_to(:active?)
241
263
  u.should respond_to(:inactive?)
242
264
 
@@ -253,11 +275,11 @@ describe Stator::Model do
253
275
  u.should be_active
254
276
  u.should_not be_inactive
255
277
 
256
- User::ACTIVE_STATES.should eql(['activated', 'hyperactivated'])
257
- User::INACTIVE_STATES.should eql(['pending', 'deactivated', 'semiactivated'])
278
+ User::ACTIVE_STATES.should eql(%w[activated hyperactivated])
279
+ User::INACTIVE_STATES.should eql(%w[pending deactivated semiactivated])
258
280
 
259
- User.active.to_sql.gsub(' ', ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
260
- User.inactive.to_sql.gsub(' ', ' ').should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
281
+ User.active.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('activated', 'hyperactivated')")
282
+ User.inactive.to_sql.gsub(" ", " ").should eq("SELECT users.* FROM users WHERE users.state IN ('pending', 'deactivated', 'semiactivated')")
261
283
  end
262
284
 
263
285
  it "should evaluate inverses correctly" do
@@ -272,7 +294,7 @@ describe Stator::Model do
272
294
  f.should be_house_cleaned
273
295
  end
274
296
 
275
- it 'should namespace aliases just like everything else' do
297
+ it "should namespace aliases just like everything else" do
276
298
  f = Farm.new
277
299
  f.should respond_to(:house_cleaned?)
278
300
 
@@ -282,24 +304,23 @@ describe Stator::Model do
282
304
  f.should be_house_cleaned
283
305
  end
284
306
 
285
- it 'should allow for explicit constant and scope names to be provided' do
307
+ it "should allow for explicit constant and scope names to be provided" do
286
308
  User.should respond_to(:luke_warmers)
287
309
  (!!defined?(User::LUKE_WARMERS)).should eql(true)
288
310
  u = User.new
289
311
  u.should respond_to(:luke_warm?)
290
312
  end
291
313
 
292
- it 'should not create constants or scopes by default' do
314
+ it "should not create constants or scopes by default" do
293
315
  u = User.new
294
316
  u.should respond_to(:iced_tea?)
295
317
  (!!defined?(User::ICED_TEA_STATES)).should eql(false)
296
318
  User.should_not respond_to(:iced_tea)
297
319
  end
298
320
 
299
- it 'should determine the full list of states correctly' do
321
+ it "should determine the full list of states correctly" do
300
322
  states = User._stator("").states
301
- states.should eql(["pending", "activated", "deactivated", "semiactivated", "hyperactivated"])
323
+ states.should eql(%w[pending activated deactivated semiactivated hyperactivated])
302
324
  end
303
325
  end
304
-
305
326
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stator
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mike Nelson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-07-31 00:00:00.000000000 Z
11
+ date: 2019-10-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -76,7 +76,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
76
76
  version: '0'
77
77
  requirements: []
78
78
  rubyforge_project:
79
- rubygems_version: 2.4.5.1
79
+ rubygems_version: 2.7.7
80
80
  signing_key:
81
81
  specification_version: 4
82
82
  summary: The simplest of ActiveRecord state machines