state_machines-activemodel 0.9.0 → 0.10.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.
- checksums.yaml +4 -4
- data/README.md +7 -25
- data/lib/state_machines/integrations/active_model/locale.rb +2 -0
- data/lib/state_machines/integrations/active_model/version.rb +3 -1
- data/lib/state_machines/integrations/active_model.rb +30 -83
- data/lib/state_machines-activemodel.rb +2 -0
- data/test/integration_test.rb +3 -1
- data/test/machine_by_default_test.rb +3 -1
- data/test/machine_errors_test.rb +3 -1
- data/test/machine_multiple_test.rb +3 -1
- data/test/machine_with_callbacks_test.rb +3 -1
- data/test/machine_with_dirty_attribute_and_custom_attributes_during_loopback_test.rb +3 -1
- data/test/machine_with_dirty_attribute_and_state_events_test.rb +3 -1
- data/test/machine_with_dirty_attributes_and_custom_attribute_test.rb +3 -1
- data/test/machine_with_dirty_attributes_during_loopback_test.rb +3 -1
- data/test/machine_with_dirty_attributes_test.rb +3 -1
- data/test/machine_with_dynamic_initial_state_test.rb +3 -1
- data/test/machine_with_events_test.rb +3 -1
- data/test/machine_with_failed_after_callbacks_test.rb +3 -1
- data/test/machine_with_failed_before_callbacks_test.rb +3 -1
- data/test/machine_with_initialized_aliased_attribute_test.rb +3 -1
- data/test/machine_with_initialized_state_test.rb +3 -1
- data/test/machine_with_internationalization_test.rb +3 -1
- data/test/machine_with_model_state_attribute_test.rb +3 -1
- data/test/machine_with_non_model_state_attribute_undefined_test.rb +3 -1
- data/test/machine_with_state_driven_validations_test.rb +4 -2
- data/test/machine_with_states_test.rb +3 -1
- data/test/machine_with_static_initial_state_test.rb +3 -1
- data/test/machine_with_validations_and_custom_attribute_test.rb +3 -1
- data/test/machine_with_validations_test.rb +3 -1
- data/test/test_helper.rb +55 -0
- metadata +10 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a37766e74933c9b284c1bea7acc586937d437222fb51371a12118cb9c28873c
|
4
|
+
data.tar.gz: 05d7748697762082b5cd5c6a388cfbcdb62d7f54bdaf656587c7cdc9158b78f6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 49059888466d7e77da042aa4d3b296d029d3bbaf600ef70cf514322a04c14211460527444d08fd591a8b3e38a3039b1119c3c719d06bdc6363ab03dadf83b7c0
|
7
|
+
data.tar.gz: 787f045227838e8ce24c6b5448d991631ef1a35c90f078582f8f2fff66470760d90d0c05f2bc56c174dcb93f4c4662b137100d06ff27e44aefca98a4d4b7f11e
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ Or install it yourself as:
|
|
23
23
|
|
24
24
|
## Dependencies
|
25
25
|
|
26
|
-
Active Model
|
26
|
+
Active Model 7.1+
|
27
27
|
|
28
28
|
## Usage
|
29
29
|
|
@@ -36,19 +36,19 @@ class Vehicle
|
|
36
36
|
attr_accessor :state
|
37
37
|
define_attribute_methods [:state]
|
38
38
|
|
39
|
-
state_machine :
|
40
|
-
before_transition :
|
41
|
-
after_transition any
|
39
|
+
state_machine initial: :parked do
|
40
|
+
before_transition parked: any - :parked, do: :put_on_seatbelt
|
41
|
+
after_transition any: :parked do |vehicle, transition|
|
42
42
|
vehicle.seatbelt = 'off'
|
43
43
|
end
|
44
44
|
around_transition :benchmark
|
45
45
|
|
46
|
-
event :
|
47
|
-
transition :
|
46
|
+
event ignite: do
|
47
|
+
transition parked: :idling
|
48
48
|
end
|
49
49
|
|
50
50
|
state :first_gear, :second_gear do
|
51
|
-
|
51
|
+
validates :seatbelt_on, presence: true
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -62,24 +62,6 @@ class Vehicle
|
|
62
62
|
...
|
63
63
|
end
|
64
64
|
end
|
65
|
-
|
66
|
-
class VehicleObserver < ActiveModel::Observer
|
67
|
-
# Callback for :ignite event *before* the transition is performed
|
68
|
-
def before_ignite(vehicle, transition)
|
69
|
-
# log message
|
70
|
-
end
|
71
|
-
|
72
|
-
# Generic transition callback *after* the transition is performed
|
73
|
-
def after_transition(vehicle, transition)
|
74
|
-
Audit.log(vehicle, transition)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Generic callback after the transition fails to perform
|
78
|
-
def after_failure_to_transition(vehicle, transition)
|
79
|
-
Audit.error(vehicle, transition)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
65
|
```
|
84
66
|
|
85
67
|
## Contributing
|
@@ -1,6 +1,8 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'active_model'
|
2
4
|
require 'active_support/core_ext/hash/keys'
|
3
|
-
require 'active_support/core_ext/module/attribute_accessors
|
5
|
+
require 'active_support/core_ext/module/attribute_accessors'
|
4
6
|
require 'state_machines'
|
5
7
|
require 'state_machines/integrations/base'
|
6
8
|
require 'state_machines/integrations/active_model/version'
|
@@ -25,9 +27,9 @@ module StateMachines
|
|
25
27
|
# attr_accessor :state
|
26
28
|
# define_attribute_methods [:state]
|
27
29
|
#
|
28
|
-
# state_machine :
|
30
|
+
# state_machine initial: :parked do
|
29
31
|
# event :ignite do
|
30
|
-
# transition :
|
32
|
+
# transition parked: :idling
|
31
33
|
# end
|
32
34
|
# end
|
33
35
|
# end
|
@@ -45,7 +47,7 @@ module StateMachines
|
|
45
47
|
# include ActiveModel::Validations
|
46
48
|
# attr_accessor :state
|
47
49
|
#
|
48
|
-
# state_machine :
|
50
|
+
# state_machine action: :save do
|
49
51
|
# ...
|
50
52
|
# end
|
51
53
|
#
|
@@ -83,7 +85,7 @@ module StateMachines
|
|
83
85
|
# state_machine do
|
84
86
|
# ...
|
85
87
|
# state :first_gear, :second_gear do
|
86
|
-
# validate {|vehicle| vehicle.speed_is_legal}
|
88
|
+
# validate { |vehicle| vehicle.speed_is_legal }
|
87
89
|
# end
|
88
90
|
# end
|
89
91
|
# end
|
@@ -115,38 +117,44 @@ module StateMachines
|
|
115
117
|
# Beware that public event attributes mean that events can be fired
|
116
118
|
# whenever mass-assignment is being used. If you want to prevent malicious
|
117
119
|
# users from tampering with events through URLs / forms, the attribute
|
118
|
-
# should be protected
|
120
|
+
# should be protected using Strong Parameters in your controllers:
|
119
121
|
#
|
120
122
|
# class Vehicle
|
121
|
-
# include ActiveModel::MassAssignmentSecurity
|
122
123
|
# attr_accessor :state
|
123
124
|
#
|
124
|
-
# attr_protected :state_event
|
125
|
-
# # attr_accessible ... # Alternative technique
|
126
|
-
#
|
127
125
|
# state_machine do
|
128
126
|
# ...
|
129
127
|
# end
|
130
128
|
# end
|
131
129
|
#
|
130
|
+
# # In your controller
|
131
|
+
# def vehicle_params
|
132
|
+
# params.require(:vehicle).permit(:attribute1, :attribute2) # Exclude :state_event
|
133
|
+
# end
|
134
|
+
#
|
132
135
|
# If you want to only have *some* events be able to fire via mass-assignment,
|
133
|
-
# you can build two state machines (one
|
136
|
+
# you can build two state machines (one private and one public) like so:
|
134
137
|
#
|
135
138
|
# class Vehicle
|
136
139
|
# attr_accessor :state
|
137
140
|
#
|
138
|
-
# attr_protected :state_event # Prevent access to events in the first machine
|
139
|
-
#
|
140
141
|
# state_machine do
|
141
142
|
# # Define private events here
|
142
143
|
# end
|
143
144
|
#
|
144
145
|
# # Public machine targets the same state as the private machine
|
145
|
-
# state_machine :public_state, :
|
146
|
+
# state_machine :public_state, attribute: :state do
|
146
147
|
# # Define public events here
|
147
148
|
# end
|
148
149
|
# end
|
149
150
|
#
|
151
|
+
# # In your controller
|
152
|
+
# def vehicle_params
|
153
|
+
# # Only permit events from the public state machine
|
154
|
+
# params.require(:vehicle).permit(:attribute1, :attribute2, :public_state_event)
|
155
|
+
# # The private state_event is not permitted
|
156
|
+
# end
|
157
|
+
#
|
150
158
|
# == Callbacks
|
151
159
|
#
|
152
160
|
# All before/after transition callbacks defined for ActiveModel models
|
@@ -159,7 +167,7 @@ module StateMachines
|
|
159
167
|
# include ActiveModel::Validations
|
160
168
|
# attr_accessor :state
|
161
169
|
#
|
162
|
-
# state_machine :
|
170
|
+
# state_machine initial: :parked do
|
163
171
|
# before_transition any => :idling do |vehicle|
|
164
172
|
# vehicle.put_on_seatbelt
|
165
173
|
# end
|
@@ -169,7 +177,7 @@ module StateMachines
|
|
169
177
|
# end
|
170
178
|
#
|
171
179
|
# event :ignite do
|
172
|
-
# transition :
|
180
|
+
# transition parked: :idling
|
173
181
|
# end
|
174
182
|
# end
|
175
183
|
#
|
@@ -181,64 +189,6 @@ module StateMachines
|
|
181
189
|
# Note, also, that the transition can be accessed by simply defining
|
182
190
|
# additional arguments in the callback block.
|
183
191
|
#
|
184
|
-
# == Observers
|
185
|
-
#
|
186
|
-
# In order to hook in observer support for your application, the
|
187
|
-
# ActiveModel::Observing feature must be included. This can be added by including the
|
188
|
-
# https://github.com/state-machines/state_machines-activemodel-observers gem in your
|
189
|
-
# Gemfile. Because of the way
|
190
|
-
# ActiveModel observers are designed, there is less flexibility around the
|
191
|
-
# specific transitions that can be hooked in. However, a large number of
|
192
|
-
# hooks *are* supported. For example, if a transition for a object's
|
193
|
-
# +state+ attribute changes the state from +parked+ to +idling+ via the
|
194
|
-
# +ignite+ event, the following observer methods are supported:
|
195
|
-
# * before/after/after_failure_to-_ignite_from_parked_to_idling
|
196
|
-
# * before/after/after_failure_to-_ignite_from_parked
|
197
|
-
# * before/after/after_failure_to-_ignite_to_idling
|
198
|
-
# * before/after/after_failure_to-_ignite
|
199
|
-
# * before/after/after_failure_to-_transition_state_from_parked_to_idling
|
200
|
-
# * before/after/after_failure_to-_transition_state_from_parked
|
201
|
-
# * before/after/after_failure_to-_transition_state_to_idling
|
202
|
-
# * before/after/after_failure_to-_transition_state
|
203
|
-
# * before/after/after_failure_to-_transition
|
204
|
-
#
|
205
|
-
# The following class shows an example of some of these hooks:
|
206
|
-
#
|
207
|
-
# class VehicleObserver < ActiveModel::Observer
|
208
|
-
# # Callback for :ignite event *before* the transition is performed
|
209
|
-
# def before_ignite(vehicle, transition)
|
210
|
-
# # log message
|
211
|
-
# end
|
212
|
-
#
|
213
|
-
# # Callback for :ignite event *after* the transition has been performed
|
214
|
-
# def after_ignite(vehicle, transition)
|
215
|
-
# # put on seatbelt
|
216
|
-
# end
|
217
|
-
#
|
218
|
-
# # Generic transition callback *before* the transition is performed
|
219
|
-
# def after_transition(vehicle, transition)
|
220
|
-
# Audit.log(vehicle, transition)
|
221
|
-
# end
|
222
|
-
#
|
223
|
-
# def after_failure_to_transition(vehicle, transition)
|
224
|
-
# Audit.error(vehicle, transition)
|
225
|
-
# end
|
226
|
-
# end
|
227
|
-
#
|
228
|
-
# More flexible transition callbacks can be defined directly within the
|
229
|
-
# model as described in StateMachine::Machine#before_transition
|
230
|
-
# and StateMachine::Machine#after_transition.
|
231
|
-
#
|
232
|
-
# To define a single observer for multiple state machines:
|
233
|
-
#
|
234
|
-
# class StateMachineObserver < ActiveModel::Observer
|
235
|
-
# observe Vehicle, Switch, Project
|
236
|
-
#
|
237
|
-
# def after_transition(object, transition)
|
238
|
-
# Audit.log(object, transition)
|
239
|
-
# end
|
240
|
-
# end
|
241
|
-
#
|
242
192
|
# == Internationalization
|
243
193
|
#
|
244
194
|
# Any error message that is generated from performing invalid transitions
|
@@ -308,9 +258,9 @@ module StateMachines
|
|
308
258
|
# include ActiveModel::Dirty
|
309
259
|
# attr_accessor :state
|
310
260
|
#
|
311
|
-
# state_machine :
|
261
|
+
# state_machine initial: :parked do
|
312
262
|
# event :park do
|
313
|
-
# transition :
|
263
|
+
# transition parked: :parked, ...
|
314
264
|
# end
|
315
265
|
# end
|
316
266
|
# end
|
@@ -322,7 +272,7 @@ module StateMachines
|
|
322
272
|
#
|
323
273
|
# class Vehicle
|
324
274
|
# ...
|
325
|
-
# state_machine :
|
275
|
+
# state_machine initial: :parked do
|
326
276
|
# before_transition all => same do |vehicle|
|
327
277
|
# vehicle.state_will_change!
|
328
278
|
#
|
@@ -344,7 +294,7 @@ module StateMachines
|
|
344
294
|
# module StateMachine::Integrations::MyORM
|
345
295
|
# include ActiveModel
|
346
296
|
#
|
347
|
-
# mattr_accessor(:defaults) { :
|
297
|
+
# mattr_accessor(:defaults) { { action: :persist } }
|
348
298
|
#
|
349
299
|
# def self.matches?(klass)
|
350
300
|
# defined?(::MyORM::Base) && klass <= ::MyORM::Base
|
@@ -376,10 +326,7 @@ module StateMachines
|
|
376
326
|
def invalidate(object, attribute, message, values = [])
|
377
327
|
if supports_validations?
|
378
328
|
attribute = self.attribute(attribute)
|
379
|
-
options = values.
|
380
|
-
h[key] = value
|
381
|
-
h
|
382
|
-
end
|
329
|
+
options = values.to_h { |key, value| [key, value] }
|
383
330
|
|
384
331
|
default_options = default_error_message_options(object, attribute, message)
|
385
332
|
object.errors.add(attribute, message, **options, **default_options)
|
@@ -389,7 +336,7 @@ module StateMachines
|
|
389
336
|
# Describes the current validation errors on the given object. If none
|
390
337
|
# are specific, then the default error is interpeted as a "halt".
|
391
338
|
def errors_for(object)
|
392
|
-
object.errors.empty? ? 'Transition halted' : object.errors.full_messages
|
339
|
+
object.errors.empty? ? 'Transition halted' : object.errors.full_messages.join(', ')
|
393
340
|
end
|
394
341
|
|
395
342
|
# Resets any errors previously added when invalidating the given object
|
data/test/integration_test.rb
CHANGED
data/test/machine_errors_test.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'test_helper'
|
2
4
|
|
3
5
|
class MachineWithStateDrivenValidationsTest < BaseTestCase
|
4
6
|
def setup
|
@@ -9,7 +11,7 @@ class MachineWithStateDrivenValidationsTest < BaseTestCase
|
|
9
11
|
|
10
12
|
@machine = StateMachines::Machine.new(@model)
|
11
13
|
@machine.state :first_gear, :second_gear do
|
12
|
-
|
14
|
+
validates :seatbelt, presence: true
|
13
15
|
end
|
14
16
|
@machine.other_states :parked
|
15
17
|
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'debug'
|
4
|
+
|
5
|
+
require 'state_machines-activemodel'
|
6
|
+
require 'minitest/autorun'
|
7
|
+
require 'minitest/reporters'
|
8
|
+
require 'active_support/all'
|
9
|
+
Minitest::Reporters.use! [Minitest::Reporters::ProgressReporter.new]
|
10
|
+
I18n.enforce_available_locales = true
|
11
|
+
|
12
|
+
class BaseTestCase < ActiveSupport::TestCase
|
13
|
+
protected
|
14
|
+
# Creates a new ActiveModel model (and the associated table)
|
15
|
+
def new_model(&block)
|
16
|
+
# Simple ActiveModel superclass
|
17
|
+
parent = Class.new do
|
18
|
+
def self.model_attribute(name)
|
19
|
+
define_method(name) { instance_variable_defined?(:"@#{name}") ? instance_variable_get(:"@#{name}") : nil }
|
20
|
+
define_method("#{name}=") do |value|
|
21
|
+
send(:"#{name}_will_change!") if self.class <= ActiveModel::Dirty && value != send(name)
|
22
|
+
instance_variable_set("@#{name}", value)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create
|
27
|
+
object = new
|
28
|
+
object.save
|
29
|
+
object
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(attrs = {})
|
33
|
+
attrs.each { |attr, value| send("#{attr}=", value) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def attributes
|
37
|
+
@attributes ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def save
|
41
|
+
true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
model = Class.new(parent) do
|
46
|
+
def self.name
|
47
|
+
'Foo'
|
48
|
+
end
|
49
|
+
|
50
|
+
model_attribute :state
|
51
|
+
end
|
52
|
+
model.class_eval(&block) if block_given?
|
53
|
+
model
|
54
|
+
end
|
55
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_machines-activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abdelkader Boudih
|
8
8
|
- Aaron Pfeifer
|
9
|
-
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: state_machines
|
@@ -17,28 +16,28 @@ dependencies:
|
|
17
16
|
requirements:
|
18
17
|
- - ">="
|
19
18
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.
|
19
|
+
version: 0.10.0
|
21
20
|
type: :runtime
|
22
21
|
prerelease: false
|
23
22
|
version_requirements: !ruby/object:Gem::Requirement
|
24
23
|
requirements:
|
25
24
|
- - ">="
|
26
25
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.
|
26
|
+
version: 0.10.0
|
28
27
|
- !ruby/object:Gem::Dependency
|
29
28
|
name: activemodel
|
30
29
|
requirement: !ruby/object:Gem::Requirement
|
31
30
|
requirements:
|
32
31
|
- - ">="
|
33
32
|
- !ruby/object:Gem::Version
|
34
|
-
version: '
|
33
|
+
version: '7.1'
|
35
34
|
type: :runtime
|
36
35
|
prerelease: false
|
37
36
|
version_requirements: !ruby/object:Gem::Requirement
|
38
37
|
requirements:
|
39
38
|
- - ">="
|
40
39
|
- !ruby/object:Gem::Version
|
41
|
-
version: '
|
40
|
+
version: '7.1'
|
42
41
|
- !ruby/object:Gem::Dependency
|
43
42
|
name: bundler
|
44
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -147,11 +146,11 @@ files:
|
|
147
146
|
- test/machine_with_static_initial_state_test.rb
|
148
147
|
- test/machine_with_validations_and_custom_attribute_test.rb
|
149
148
|
- test/machine_with_validations_test.rb
|
149
|
+
- test/test_helper.rb
|
150
150
|
homepage: https://github.com/state-machines/state_machines-activemodel
|
151
151
|
licenses:
|
152
152
|
- MIT
|
153
153
|
metadata: {}
|
154
|
-
post_install_message:
|
155
154
|
rdoc_options: []
|
156
155
|
require_paths:
|
157
156
|
- lib
|
@@ -159,15 +158,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
159
158
|
requirements:
|
160
159
|
- - ">="
|
161
160
|
- !ruby/object:Gem::Version
|
162
|
-
version: 3.
|
161
|
+
version: 3.1.0
|
163
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
164
163
|
requirements:
|
165
164
|
- - ">="
|
166
165
|
- !ruby/object:Gem::Version
|
167
166
|
version: '0'
|
168
167
|
requirements: []
|
169
|
-
rubygems_version: 3.
|
170
|
-
signing_key:
|
168
|
+
rubygems_version: 3.6.7
|
171
169
|
specification_version: 4
|
172
170
|
summary: ActiveModel integration for State Machines
|
173
171
|
test_files:
|
@@ -195,3 +193,4 @@ test_files:
|
|
195
193
|
- test/machine_with_static_initial_state_test.rb
|
196
194
|
- test/machine_with_validations_and_custom_attribute_test.rb
|
197
195
|
- test/machine_with_validations_test.rb
|
196
|
+
- test/test_helper.rb
|