state_machines-activemodel 0.200.0 → 0.300.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 +27 -1
- data/lib/state_machines/integrations/active_model/version.rb +1 -1
- data/test/machine_with_refusal_reasons_test.rb +146 -0
- metadata +13 -11
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e9bcbb7b130697e27194b008c66a4726b5bd9023fd81b74b36eacbe863c7863d
|
|
4
|
+
data.tar.gz: a6417bddb1b03bc3e93c1ac5e060ac05f0f8a4439cd0feb5cdb7585b473f34a4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 366e48ee43687f70332bad18f99e4366b261c03fdfda013455ff01f1b4f986289877782aef9379dc952695568273867e9e9a2c371a266da0fab3277112e6e77c
|
|
7
|
+
data.tar.gz: 165ffdfc7019e95ae43182c67967c78beadbf9512054c0da4205de99e67efd1d14bd0e33d78b64121998bbfc444c0edbbf108762945b54c23de3f8ec504bed8b
|
data/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Or install it yourself as:
|
|
|
22
22
|
|
|
23
23
|
## Dependencies
|
|
24
24
|
|
|
25
|
-
Active Model
|
|
25
|
+
Active Model 8.0+
|
|
26
26
|
|
|
27
27
|
## Usage
|
|
28
28
|
|
|
@@ -63,6 +63,32 @@ class Vehicle
|
|
|
63
63
|
end
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
### Why an event was refused
|
|
67
|
+
|
|
68
|
+
An event method still returns `false` when it is refused, and `errors` is filled
|
|
69
|
+
as before. The `<event>_refusal` reader from state_machines tells the reasons
|
|
70
|
+
apart (`nil` after a success):
|
|
71
|
+
|
|
72
|
+
```ruby
|
|
73
|
+
vehicle.park # => false
|
|
74
|
+
vehicle.park_refusal # => :no_transition (errors: State cannot transition via "park")
|
|
75
|
+
|
|
76
|
+
vehicle.ignite # => false, a before_transition returned false
|
|
77
|
+
vehicle.ignite_refusal # => :halted
|
|
78
|
+
|
|
79
|
+
# With `action: :save`, a save that returns false (e.g. failed validations)
|
|
80
|
+
vehicle.shift_up # => false
|
|
81
|
+
vehicle.shift_up_refusal # => :action_failed
|
|
82
|
+
vehicle.errors.full_messages # => ["Seatbelt on can't be blank"]
|
|
83
|
+
|
|
84
|
+
vehicle.shift_up! # => StateMachines::InvalidTransition, #reason => :action_failed
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The reasons are `:no_transition`, `:guard`, `:halted`, `:action_failed` (and
|
|
88
|
+
`:contended` in async mode). They are also recorded for event attributes
|
|
89
|
+
(`vehicle.state_event = 'park'; vehicle.save`). See the state_machines README
|
|
90
|
+
for parallel events.
|
|
91
|
+
|
|
66
92
|
## Contributing
|
|
67
93
|
|
|
68
94
|
1. Fork it ( https://github.com/state-machines/state_machines-activemodel/fork )
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test_helper'
|
|
4
|
+
|
|
5
|
+
class MachineWithRefusalReasonsTest < BaseTestCase
|
|
6
|
+
def setup
|
|
7
|
+
@model = new_model do
|
|
8
|
+
include ActiveModel::Validations
|
|
9
|
+
|
|
10
|
+
attribute :alarm_state, :string
|
|
11
|
+
attr_accessor :fuelled, :abort_ignite, :jam_alarm, :saved
|
|
12
|
+
|
|
13
|
+
validates :state, exclusion: { in: %w[blocked] }
|
|
14
|
+
|
|
15
|
+
# Defined on an ancestor so the machine hooks it for event attributes
|
|
16
|
+
include(Module.new do
|
|
17
|
+
def save
|
|
18
|
+
valid? && (self.saved = true)
|
|
19
|
+
end
|
|
20
|
+
end)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
@machine = StateMachines::Machine.new(@model, action: :save, initial: :parked)
|
|
24
|
+
@machine.state :blocked
|
|
25
|
+
@machine.before_transition(on: :ignite) { |record| !record.abort_ignite }
|
|
26
|
+
@machine.event(:ignite) { transition parked: :idling, if: ->(record) { record.fuelled != false } }
|
|
27
|
+
@machine.event(:park) { transition idling: :parked }
|
|
28
|
+
@machine.event(:block) { transition parked: :blocked }
|
|
29
|
+
|
|
30
|
+
@alarm = StateMachines::Machine.new(@model, :alarm_state, action: :save, initial: :active, namespace: :alarm)
|
|
31
|
+
@alarm.around_transition(on: :disable) do |record, _transition, block|
|
|
32
|
+
block.call unless record.jam_alarm
|
|
33
|
+
end
|
|
34
|
+
@alarm.event(:disable) { transition active: :off }
|
|
35
|
+
|
|
36
|
+
@record = @model.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_should_report_no_transition
|
|
40
|
+
assert_same false, @record.park
|
|
41
|
+
assert_equal :no_transition, @record.park_refusal
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def test_should_keep_the_invalid_transition_error
|
|
45
|
+
@record.park
|
|
46
|
+
|
|
47
|
+
assert_equal ['State cannot transition via "park"'], @record.errors.full_messages
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def test_should_report_guard
|
|
51
|
+
@record.fuelled = false
|
|
52
|
+
|
|
53
|
+
refute @record.ignite
|
|
54
|
+
assert_equal :guard, @record.ignite_refusal
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def test_should_report_halted_by_a_before_transition_returning_false
|
|
58
|
+
@record.abort_ignite = true
|
|
59
|
+
|
|
60
|
+
refute @record.ignite
|
|
61
|
+
assert_equal :halted, @record.ignite_refusal
|
|
62
|
+
assert_equal 'parked', @record.state
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_should_report_halted_by_an_around_transition_that_does_not_yield
|
|
66
|
+
@record.jam_alarm = true
|
|
67
|
+
|
|
68
|
+
refute @record.disable_alarm
|
|
69
|
+
assert_equal :halted, @record.disable_alarm_refusal
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def test_should_report_action_failed_when_validation_fails
|
|
73
|
+
refute @record.block
|
|
74
|
+
assert_equal :action_failed, @record.block_refusal
|
|
75
|
+
assert_equal 'parked', @record.state
|
|
76
|
+
refute @record.saved
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_should_keep_validation_errors_when_the_action_fails
|
|
80
|
+
@record.block
|
|
81
|
+
|
|
82
|
+
assert_equal ['State is reserved'], @record.errors.full_messages
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_should_clear_the_refusal_after_success
|
|
86
|
+
@record.abort_ignite = true
|
|
87
|
+
@record.ignite
|
|
88
|
+
@record.abort_ignite = false
|
|
89
|
+
|
|
90
|
+
assert @record.ignite
|
|
91
|
+
assert_nil @record.ignite_refusal
|
|
92
|
+
assert @record.saved
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def test_should_carry_the_reason_on_bang
|
|
96
|
+
error = assert_raises(StateMachines::InvalidTransition) { @record.block! }
|
|
97
|
+
|
|
98
|
+
assert_equal :action_failed, error.reason
|
|
99
|
+
assert_includes error.message, 'State is reserved'
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def test_should_carry_halted_on_bang
|
|
103
|
+
@record.abort_ignite = true
|
|
104
|
+
error = assert_raises(StateMachines::InvalidTransition) { @record.ignite! }
|
|
105
|
+
|
|
106
|
+
assert_equal :halted, error.reason
|
|
107
|
+
assert_includes error.message, 'Transition halted'
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def test_should_report_no_transition_for_an_event_attribute
|
|
111
|
+
@record.state_event = 'park'
|
|
112
|
+
|
|
113
|
+
refute @record.save
|
|
114
|
+
assert_equal :no_transition, @record.park_refusal
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_should_report_action_failed_for_an_event_attribute
|
|
118
|
+
@record.state_event = 'block'
|
|
119
|
+
|
|
120
|
+
refute @record.save
|
|
121
|
+
assert_equal :action_failed, @record.block_refusal
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_should_report_action_failed_for_every_event_in_parallel
|
|
125
|
+
@record.fuelled = true
|
|
126
|
+
@record.define_singleton_method(:save) { false }
|
|
127
|
+
|
|
128
|
+
refute @record.fire_events(:ignite, :disable_alarm)
|
|
129
|
+
assert_equal :action_failed, @record.ignite_refusal
|
|
130
|
+
assert_equal :action_failed, @record.disable_alarm_refusal
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def test_should_report_only_the_halting_event_in_parallel
|
|
134
|
+
@record.jam_alarm = true
|
|
135
|
+
|
|
136
|
+
refute @record.fire_events(:ignite, :disable_alarm)
|
|
137
|
+
assert_nil @record.ignite_refusal
|
|
138
|
+
assert_equal :halted, @record.disable_alarm_refusal
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_should_carry_parallel_reasons_on_bang
|
|
142
|
+
error = assert_raises(StateMachines::InvalidParallelTransition) { @record.fire_events!(:park, :disable_alarm) }
|
|
143
|
+
|
|
144
|
+
assert_equal({ park: :no_transition }, error.reasons)
|
|
145
|
+
end
|
|
146
|
+
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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.300.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Abdelkader Boudih
|
|
@@ -16,28 +16,28 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: 0.
|
|
19
|
+
version: 0.300.0
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: 0.
|
|
26
|
+
version: 0.300.0
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: activemodel
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '8.1'
|
|
34
34
|
type: :runtime
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '8.1'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: bundler
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -84,16 +84,16 @@ dependencies:
|
|
|
84
84
|
name: minitest
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
|
-
- -
|
|
87
|
+
- - "~>"
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version:
|
|
89
|
+
version: '6.0'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
|
-
- -
|
|
94
|
+
- - "~>"
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version:
|
|
96
|
+
version: '6.0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
98
|
name: minitest-reporters
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -144,6 +144,7 @@ files:
|
|
|
144
144
|
- test/machine_with_internationalization_test.rb
|
|
145
145
|
- test/machine_with_model_state_attribute_test.rb
|
|
146
146
|
- test/machine_with_non_model_state_attribute_undefined_test.rb
|
|
147
|
+
- test/machine_with_refusal_reasons_test.rb
|
|
147
148
|
- test/machine_with_state_driven_validations_test.rb
|
|
148
149
|
- test/machine_with_states_test.rb
|
|
149
150
|
- test/machine_with_static_initial_state_test.rb
|
|
@@ -162,14 +163,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
162
163
|
requirements:
|
|
163
164
|
- - ">="
|
|
164
165
|
- !ruby/object:Gem::Version
|
|
165
|
-
version:
|
|
166
|
+
version: '4.0'
|
|
166
167
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
167
168
|
requirements:
|
|
168
169
|
- - ">="
|
|
169
170
|
- !ruby/object:Gem::Version
|
|
170
171
|
version: '0'
|
|
171
172
|
requirements: []
|
|
172
|
-
rubygems_version: 4.0.
|
|
173
|
+
rubygems_version: 4.0.20
|
|
173
174
|
specification_version: 4
|
|
174
175
|
summary: ActiveModel integration for State Machines
|
|
175
176
|
test_files:
|
|
@@ -195,6 +196,7 @@ test_files:
|
|
|
195
196
|
- test/machine_with_internationalization_test.rb
|
|
196
197
|
- test/machine_with_model_state_attribute_test.rb
|
|
197
198
|
- test/machine_with_non_model_state_attribute_undefined_test.rb
|
|
199
|
+
- test/machine_with_refusal_reasons_test.rb
|
|
198
200
|
- test/machine_with_state_driven_validations_test.rb
|
|
199
201
|
- test/machine_with_states_test.rb
|
|
200
202
|
- test/machine_with_static_initial_state_test.rb
|