stator 0.3.1 → 0.3.3

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
2
  SHA256:
3
- metadata.gz: 3ea9ce5a04f3d128aecd8f78788c7a06a49d2785dc3669a7c54a2c973fb01f2b
4
- data.tar.gz: c638206a0fb9dedf3e53403d160425054be95b1f08223e6436239f500afb9eb7
3
+ metadata.gz: c4db54f443ba466ae3fc6f79857816b8719e0cbacf0615f8c014ae0c71c32e81
4
+ data.tar.gz: 53d72d27aafa1a340c02d2d5459235488bf5e12df9198312ffe1d5121fc24912
5
5
  SHA512:
6
- metadata.gz: e32e3867650801979aefd648ebc2184e0a9cf9357c0fa08146a963308c35ec610b3c5ac4a9439149acfa086b98957dd1006484310b60ab0fb18fad56a26bfe51
7
- data.tar.gz: b8fa99e1f0e0bdf6a3832395d9de0730ee3a990994509c2dc8b30aa6f5ee06ca1af3114b4f9c00899cb83b15515cca142841a521ee4f0532bc863ba4d03532fe
6
+ metadata.gz: a2e76eb8e8bbe0e1dab6d8fbdbb6516f12cff56c26c3d10d974d4aadce08fbcabdcd49dbba710d0f904a1a04ea4c489125b18475a119de5e625a9cbb6e9406a4
7
+ data.tar.gz: 0fef985f07d95f3d8801f4e3534f478feb516fea223532e1e562cc85bebdc54c09222ee0087517d4c3f396f4d094ad80a9404f7e0cb69829ffa6c5ddc40bb297
data/Gemfile CHANGED
@@ -5,6 +5,6 @@ gem 'activerecord', '5.2.3'
5
5
 
6
6
  gemspec
7
7
 
8
+ gem 'activerecord-nulldb-adapter', '~> 0.4.0', require: false
8
9
  gem 'rake'
9
- gem 'activerecord-nulldb-adapter', '~> 0.4.0', :require => false, :git => 'git@github.com:nulldb/nulldb.git'
10
10
  gem 'rspec'
@@ -7,6 +7,9 @@ module Stator
7
7
  delegate :transitions, to: :@machine
8
8
  delegate :namespace, to: :@machine
9
9
 
10
+ attr_reader :skip_validations
11
+ attr_reader :skip_transition_tracking
12
+
10
13
  def initialize(machine, record)
11
14
  @machine = machine
12
15
  @record = record
@@ -38,7 +41,7 @@ module Stator
38
41
 
39
42
  def validate_transition
40
43
  return unless state_changed?
41
- return if @machine.skip_validations
44
+ return if skip_validations
42
45
 
43
46
  was = state_was
44
47
  is = state
@@ -60,7 +63,7 @@ module Stator
60
63
  end
61
64
 
62
65
  def track_transition
63
- return if @machine.skip_transition_tracking
66
+ return if skip_transition_tracking
64
67
 
65
68
  attempt_to_track_state(state)
66
69
  attempt_to_track_state_changed_timestamp
@@ -115,6 +118,22 @@ module Stator
115
118
  @machine.states.reverse.detect { |s| in_state_at?(s, t) }
116
119
  end
117
120
 
121
+ def without_validation
122
+ was = @skip_validations
123
+ @skip_validations = true
124
+ yield @record
125
+ ensure
126
+ @skip_validations = was
127
+ end
128
+
129
+ def without_transition_tracking
130
+ was = @skip_transition_tracking
131
+ @skip_transition_tracking = true
132
+ yield @record
133
+ ensure
134
+ @skip_transition_tracking = was
135
+ end
136
+
118
137
  protected
119
138
 
120
139
  def attempt_to_track_state(state_to_track)
@@ -7,16 +7,14 @@ module Stator
7
7
  attr_reader :transitions
8
8
  attr_reader :states
9
9
  attr_reader :namespace
10
- attr_reader :skip_validations
11
- attr_reader :skip_transition_tracking
12
-
13
10
 
14
11
  def initialize(klass, options = {})
15
- @class_name = klass.name
16
- @field = options[:field] || :state
17
- @namespace = options[:namespace] || nil
12
+ @class_name = klass.name
13
+ @field = options[:field] || :state
14
+ @namespace = options[:namespace]
18
15
 
19
- @initial_state = options[:initial] && options[:initial].to_s
16
+ @initial_state = options[:initial] && options[:initial].to_s
17
+ @tracking_enabled = options[:track] || false
20
18
 
21
19
  @transitions = []
22
20
  @aliases = []
@@ -26,7 +24,6 @@ module Stator
26
24
  @states = [@initial_state].compact
27
25
 
28
26
  @options = options
29
-
30
27
  end
31
28
 
32
29
  def integration(record)
@@ -38,7 +35,6 @@ module Stator
38
35
  end
39
36
 
40
37
  def transition(name, &block)
41
-
42
38
  t = ::Stator::Transition.new(@class_name, name, @namespace)
43
39
  t.instance_eval(&block) if block_given?
44
40
 
@@ -66,6 +62,10 @@ module Stator
66
62
  end
67
63
  end
68
64
 
65
+ def tracking_enabled?
66
+ @tracking_enabled
67
+ end
68
+
69
69
  def conditional(*states, &block)
70
70
  _namespace = @namespace
71
71
 
@@ -88,22 +88,6 @@ module Stator
88
88
  @class_name.constantize
89
89
  end
90
90
 
91
- def without_validation
92
- was = @skip_validations
93
- @skip_validations = true
94
- yield
95
- ensure
96
- @skip_validations = was
97
- end
98
-
99
- def without_transition_tracking
100
- was = @skip_transition_tracking
101
- @skip_transition_tracking = true
102
- yield
103
- ensure
104
- @skip_transition_tracking = was
105
- end
106
-
107
91
  protected
108
92
 
109
93
  def verify_transition_validity(transition)
data/lib/stator/model.rb CHANGED
@@ -35,26 +35,25 @@ module Stator
35
35
 
36
36
  def self.included(base)
37
37
  base.class_eval do
38
- before_save :_stator_track_transition, prepend: true
38
+ before_save :_stator_maybe_track_transition, prepend: true
39
39
  end
40
40
  end
41
41
 
42
42
  def in_state_at?(state, t, namespace = '')
43
- machine = self._stator(namespace)
44
- machine.integration(self).in_state_at?(state, t)
43
+ _integration(namespace).in_state_at?(state, t)
45
44
  end
46
45
 
47
46
  def likely_state_at(t, namespace = '')
48
- machine = self._stator(namespace)
49
- machine.integration(self).likely_state_at(t)
47
+ _integration(namespace).likely_state_at(t)
50
48
  end
51
49
 
52
50
  protected
53
51
 
54
-
55
- def _stator_track_transition
52
+ def _stator_maybe_track_transition
56
53
  self._stators.each do |namespace, machine|
57
- machine.integration(self).track_transition
54
+ next unless machine.tracking_enabled?
55
+
56
+ _integration(namespace).track_transition
58
57
  end
59
58
 
60
59
  true
@@ -70,23 +69,28 @@ module Stator
70
69
  end
71
70
  end
72
71
 
72
+ def initialize_dup(other)
73
+ @_integrations = {}
74
+ super
75
+ end
76
+
73
77
  def without_state_transition_validations(namespace = '')
74
- self._stator(namespace).without_validation do
75
- yield
78
+ _integration(namespace).without_validation do
79
+ yield self
76
80
  end
77
81
  end
78
82
 
79
83
  def without_state_transition_tracking(namespace = '')
80
- self._stator(namespace).without_transition_tracking do
81
- yield
84
+ _integration(namespace).without_transition_tracking do
85
+ yield self
82
86
  end
83
87
  end
84
88
 
85
89
  protected
86
90
 
87
91
  def _stator_validate_transition
88
- self._stators.each do |namespace, machine|
89
- machine.integration(self).validate_transition
92
+ self._stators.each_key do |namespace|
93
+ _integration(namespace).validate_transition
90
94
  end
91
95
  end
92
96
 
@@ -94,6 +98,12 @@ module Stator
94
98
  self.class._stator(namespace)
95
99
  end
96
100
 
101
+ def _integration(namespace = '')
102
+ @_integrations ||= {}
103
+ @_integrations[namespace] ||= _stator(namespace).integration(self)
104
+ @_integrations[namespace]
105
+ end
106
+
97
107
  end
98
108
  end
99
109
  end
@@ -86,7 +86,7 @@ module Stator
86
86
  def generate_methods
87
87
  klass.class_eval <<-EV, __FILE__, __LINE__ + 1
88
88
  def #{@full_name}(should_save = true)
89
- integration = self._stator(#{@namespace.inspect}).integration(self)
89
+ integration = _integration(#{@namespace.to_s.inspect})
90
90
 
91
91
  unless can_#{@full_name}?
92
92
  integration.invalid_transition!(integration.state, #{@to.inspect}) if should_save
@@ -98,7 +98,7 @@ module Stator
98
98
  end
99
99
 
100
100
  def #{@full_name}!
101
- integration = self._stator(#{@namespace.inspect}).integration(self)
101
+ integration = _integration(#{@namespace.to_s.inspect})
102
102
 
103
103
  unless can_#{@full_name}?
104
104
  integration.invalid_transition!(integration.state, #{@to.inspect})
@@ -110,10 +110,10 @@ module Stator
110
110
  end
111
111
 
112
112
  def can_#{@full_name}?
113
- machine = self._stator(#{@namespace.inspect})
114
- return true if machine.skip_validations
113
+ integration = _integration(#{@namespace.to_s.inspect})
114
+ return true if integration.skip_validations
115
115
 
116
- integration = machine.integration(self)
116
+ machine = self._stator(#{@namespace.to_s.inspect})
117
117
  transition = machine.transitions.detect{|t| t.full_name.to_s == #{@full_name.inspect}.to_s }
118
118
  transition.can?(integration.state)
119
119
  end
@@ -4,7 +4,7 @@ module Stator
4
4
 
5
5
  MAJOR = 0
6
6
  MINOR = 3
7
- PATCH = 1
7
+ PATCH = 3
8
8
  PRERELEASE = nil
9
9
 
10
10
  VERSION = [MAJOR, MINOR, PATCH, PRERELEASE].compact.join(".")
data/spec/model_spec.rb CHANGED
@@ -160,6 +160,42 @@ describe Stator::Model do
160
160
  u.activated_state_at.should_not be_nil
161
161
  end
162
162
 
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")
167
+
168
+ threads << Thread.new do
169
+ sleep 0.5
170
+ nope.semiactivate!
171
+ end
172
+ threads << Thread.new do
173
+ skip.without_state_transition_tracking do
174
+ sleep 1
175
+ skip.semiactivate!
176
+ end
177
+ end
178
+
179
+ threads.each(&:join)
180
+
181
+ nope.semiactivated_state_at.should_not be_nil
182
+ skip.semiactivated_state_at.should be_nil
183
+ end
184
+
185
+ it "should not inherit _integration cache on dup" do
186
+ u = User.new(email: "user@example.com")
187
+ u.save!
188
+
189
+ u_duped = u.dup
190
+
191
+ u.semiactivate!
192
+
193
+ u_duped_integration = u_duped.send(:_integration)
194
+
195
+ u_duped_integration.state.should_not eql(u.state)
196
+ u_duped_integration.instance_values["record"].should eq(u_duped)
197
+ end
198
+
163
199
  describe "helper methods" do
164
200
  it "should answer the question of whether the state is currently the one invoked" do
165
201
  a = Animal.new
@@ -254,6 +290,21 @@ describe Stator::Model do
254
290
  u.state.should eql("semiactivated")
255
291
  u.semiactivated_state_at.should eql(t)
256
292
  end
293
+
294
+ it "should allow opting into track by namespace" do
295
+ z = ZooKeeper.new(name: "Doug")
296
+ z.employment_state.should eql("hired")
297
+ z.employment_fire!
298
+ z.fired_employment_state_at.should_not be_nil
299
+
300
+ z.employment_hire!
301
+ z.hired_employment_state_at.should_not be_nil
302
+
303
+ z.working_start!
304
+ z.started_working_state_at.should be_nil
305
+ z.working_end!
306
+ z.ended_working_state_at.should be_nil
307
+ end
257
308
  end
258
309
 
259
310
  describe "aliasing" do
@@ -134,6 +134,33 @@ class Zoo < ActiveRecord::Base
134
134
  end
135
135
  end
136
136
 
137
+ class ZooKeeper < ActiveRecord::Base
138
+ extend Stator::Model
139
+
140
+ stator namespace: 'employment', field: 'employment_state', track: true do
141
+ transition :hire do
142
+ from nil, :fired
143
+ to :hired
144
+ end
145
+
146
+ transition :fire do
147
+ from :hired
148
+ to :fired
149
+ end
150
+ end
151
+
152
+ stator namespace: 'working', field: 'working_state', track: false do
153
+ transition :start do
154
+ from nil, :ended
155
+ to :started
156
+ end
157
+
158
+ transition :end do
159
+ from :started
160
+ to :ended
161
+ end
162
+ end
163
+ end
137
164
 
138
165
  class Farm < ActiveRecord::Base
139
166
  extend Stator::Model
@@ -22,6 +22,16 @@ ActiveRecord::Schema.define(:version => 20130628161227) do
22
22
  t.datetime "born_status_at"
23
23
  end
24
24
 
25
+ create_table "zoo_keepers", :force => true do |t|
26
+ t.string "name"
27
+ t.string "employment_state", :default => 'hired'
28
+ t.datetime "hired_employment_state_at"
29
+ t.datetime "fired_employment_state_at"
30
+ t.string "working_state"
31
+ t.datetime "started_working_state_at"
32
+ t.datetime "ended_working_state_at"
33
+ end
34
+
25
35
  create_table "zoos", :force => true do |t|
26
36
  t.string "name"
27
37
  t.string "state", :default => 'closed'
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.1
4
+ version: 0.3.3
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-10-22 00:00:00.000000000 Z
11
+ date: 2021-03-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -75,8 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
75
  - !ruby/object:Gem::Version
76
76
  version: '0'
77
77
  requirements: []
78
- rubyforge_project:
79
- rubygems_version: 2.7.7
78
+ rubygems_version: 3.0.6
80
79
  signing_key:
81
80
  specification_version: 4
82
81
  summary: The simplest of ActiveRecord state machines