stator 0.3.0 → 0.3.1

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