state_gate 1.2.3 → 1.3.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/lib/state_gate/builder/conflict_detection_methods.rb +59 -18
- data/lib/state_gate/builder/dynamic_module_creation_methods.rb +36 -22
- data/lib/state_gate/builder/scope_methods.rb +30 -20
- data/lib/state_gate/builder/state_methods.rb +108 -72
- data/lib/state_gate/builder/transition_methods.rb +54 -34
- data/lib/state_gate/builder/transition_validation_methods.rb +76 -66
- data/lib/state_gate/builder.rb +53 -43
- data/lib/state_gate/engine/configurator.rb +77 -63
- data/lib/state_gate/engine/errator.rb +42 -9
- data/lib/state_gate/engine/fixer.rb +21 -12
- data/lib/state_gate/engine/scoper.rb +12 -4
- data/lib/state_gate/engine/sequencer.rb +18 -5
- data/lib/state_gate/engine/stator.rb +98 -53
- data/lib/state_gate/engine/transitioner.rb +28 -14
- data/lib/state_gate/engine.rb +19 -6
- data/lib/state_gate/type.rb +22 -2
- data/lib/state_gate.rb +88 -61
- metadata +3 -3
@@ -8,37 +8,37 @@ module StateGate
|
|
8
8
|
# Multiple private methods enabling StateGate::Builder to generate
|
9
9
|
# state functionality.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# Klass.statuses
|
11
|
+
# - query the class for all state:
|
12
|
+
# Klass.statuses #=> [:pending, :active, :archived]
|
13
13
|
#
|
14
|
-
#
|
15
|
-
# Klass.human_statuses
|
14
|
+
# - query the class for the human names of all state:
|
15
|
+
# Klass.human_statuses #=> ['Pending Activation', 'Active', 'Archived']
|
16
16
|
#
|
17
|
-
#
|
17
|
+
# - query the class for an Array of human names/state names for use in a select form:
|
18
18
|
# Klass.statuses_for_select
|
19
|
-
#
|
19
|
+
# #=> [['Pending Activation', 'pending'],["Active', 'active'], ['Archived','archived']]
|
20
20
|
#
|
21
|
-
#
|
22
|
-
# .status_states
|
21
|
+
# - list all attribute states:
|
22
|
+
# .status_states #=> [:pending, :active, :archived]
|
23
23
|
#
|
24
|
-
#
|
25
|
-
# .status_human_names
|
24
|
+
# - list all human names for the attribute states:
|
25
|
+
# .status_human_names #=> ['Pending Activation', 'Active', 'Archived']
|
26
26
|
#
|
27
|
-
#
|
28
|
-
# .human_status
|
27
|
+
# - list the human name for the attribute state:
|
28
|
+
# .human_status #=> 'Pending Activation'
|
29
29
|
#
|
30
|
-
#
|
31
|
-
# .pending?
|
32
|
-
# .active?
|
33
|
-
# .archived?
|
30
|
+
# - is a particular state set:
|
31
|
+
# .pending? #=> false
|
32
|
+
# .active? #=> true
|
33
|
+
# .archived? #=> false
|
34
34
|
#
|
35
|
-
#
|
36
|
-
# .not_pending?
|
37
|
-
# .not_active?
|
38
|
-
# .not_archived?
|
35
|
+
# - is a particular state not set:
|
36
|
+
# .not_pending? #=> true
|
37
|
+
# .not_active? #=> false
|
38
|
+
# .not_archived? #=> true
|
39
39
|
#
|
40
|
-
#
|
41
|
-
# .status_transitions
|
40
|
+
# - list the allowed transitions for the current state.
|
41
|
+
# .status_transitions #=> [:suspended, :archived]
|
42
42
|
#
|
43
43
|
module StateMethods
|
44
44
|
|
@@ -46,25 +46,27 @@ module StateGate
|
|
46
46
|
# ======================================================================
|
47
47
|
private
|
48
48
|
|
49
|
+
##
|
49
50
|
# Add Class and instance methods that allow querying states
|
50
51
|
#
|
51
|
-
def
|
52
|
-
|
53
|
-
|
52
|
+
def _generate_state_methods
|
53
|
+
_add_state_attribute_methods
|
54
|
+
_add_state_alias_methods
|
54
55
|
end
|
55
56
|
|
56
57
|
|
57
58
|
|
59
|
+
##
|
58
60
|
# add attribute methods
|
59
61
|
#
|
60
|
-
def
|
62
|
+
def _add_state_attribute_methods
|
61
63
|
_add__klass__attrs
|
62
64
|
_add__klass__human_attrs
|
63
65
|
_add__klass__attrs_for_select
|
64
66
|
|
65
67
|
_add__instance__attrs
|
66
68
|
_add__instance__human_attrs
|
67
|
-
_add__instance__human_attr
|
69
|
+
_add__instance__human_attr
|
68
70
|
_add__instance__state?
|
69
71
|
_add__instance__not_state?
|
70
72
|
_add__instance__attrs_for_select
|
@@ -72,9 +74,10 @@ module StateGate
|
|
72
74
|
|
73
75
|
|
74
76
|
|
77
|
+
##
|
75
78
|
# add alias methods
|
76
79
|
#
|
77
|
-
def
|
80
|
+
def _add_state_alias_methods
|
78
81
|
return unless @alias
|
79
82
|
|
80
83
|
_add__klass__attrs(@alias)
|
@@ -92,14 +95,19 @@ module StateGate
|
|
92
95
|
# Class Merthods
|
93
96
|
# ======================================================================
|
94
97
|
|
98
|
+
##
|
95
99
|
# Adds a Class method to return an Array of the defined states for the attribute
|
96
|
-
#
|
97
|
-
#
|
100
|
+
#
|
101
|
+
# @param [Symbol] method_name
|
102
|
+
# the name for the new method
|
103
|
+
#
|
104
|
+
# @example
|
105
|
+
# Klass.statuses #=> [:pending, :active, :suspended, :archived]
|
98
106
|
#
|
99
107
|
def _add__klass__attrs(method_name = @attribute)
|
100
108
|
method_name = method_name.to_s.pluralize
|
101
109
|
|
102
|
-
|
110
|
+
_add__klass__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
103
111
|
def #{method_name}
|
104
112
|
stateables[:#{@attribute}].states
|
105
113
|
end
|
@@ -108,16 +116,21 @@ module StateGate
|
|
108
116
|
|
109
117
|
|
110
118
|
|
119
|
+
##
|
111
120
|
# Adds a Class method to return an Array of the human names of the defined states
|
112
121
|
# for the attribute
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
122
|
+
#
|
123
|
+
# @param [Symbol] method_name
|
124
|
+
# the name for the new method
|
125
|
+
#
|
126
|
+
# @example
|
127
|
+
# Klass.human_statuses #=> ['Pending Activation', 'Active',
|
128
|
+
# 'Suspended by Admin', 'Archived']
|
116
129
|
#
|
117
130
|
def _add__klass__human_attrs(method_name = @attribute)
|
118
131
|
method_name = "human_#{method_name.to_s.pluralize}"
|
119
132
|
|
120
|
-
|
133
|
+
_add__klass__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
121
134
|
def #{method_name}
|
122
135
|
stateables[:#{@attribute}].human_states
|
123
136
|
end
|
@@ -126,30 +139,36 @@ module StateGate
|
|
126
139
|
|
127
140
|
|
128
141
|
|
142
|
+
##
|
129
143
|
# Adds a Class method to return an Array of the human and state names for the
|
130
144
|
# attribute, suitable for using in a form select statement.
|
131
145
|
#
|
132
|
-
#
|
133
|
-
#
|
146
|
+
# @param [Symbol] method_name
|
147
|
+
# the name for the new method
|
148
|
+
#
|
149
|
+
# @option method_name sorted
|
150
|
+
# if TRUE, the array is sorted in alphabetical order by human name
|
151
|
+
# otherwise it is in the order specified
|
134
152
|
#
|
135
|
-
#
|
153
|
+
# @example
|
154
|
+
# Klass.statuses_for_select #=> [ ['Pending Activation', 'pending'],
|
136
155
|
# ['Active', 'active'],
|
137
156
|
# ['Suspended by Admin', 'suspended',
|
138
157
|
# ['Archived', 'archived'] ]
|
139
158
|
#
|
140
|
-
# Klass.statuses_for_select(true)
|
159
|
+
# Klass.statuses_for_select(true) #=> [ ['Active', 'active'],
|
141
160
|
# ['Pending Activation', 'pending'],
|
142
161
|
# ['Suspended by Admin', 'suspended',
|
143
162
|
# ['Archived', 'archived'] ]
|
144
163
|
#
|
145
|
-
#
|
146
|
-
#
|
147
|
-
#
|
164
|
+
# @note
|
165
|
+
# States should NEVER be set from direct user selection. This method is
|
166
|
+
# intended for use within search forms, where the user may filter by state.
|
148
167
|
#
|
149
168
|
def _add__klass__attrs_for_select(method_name = @attribute)
|
150
169
|
method_name = "#{method_name.to_s.pluralize}_for_select"
|
151
170
|
|
152
|
-
|
171
|
+
_add__klass__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
153
172
|
def #{method_name}(sorted = false)
|
154
173
|
stateables[:#{@attribute}].states_for_select(sorted)
|
155
174
|
end
|
@@ -162,14 +181,19 @@ module StateGate
|
|
162
181
|
# Instance Methods
|
163
182
|
# ======================================================================
|
164
183
|
|
184
|
+
##
|
165
185
|
# Adds an Instance method to return Array of the defined states for the attribute
|
166
|
-
#
|
167
|
-
#
|
186
|
+
#
|
187
|
+
# @param [Symbol] method_name
|
188
|
+
# the name for the new method
|
189
|
+
#
|
190
|
+
# @example
|
191
|
+
# .statuses #=> [:pending, :active, :suspended, :archived]
|
168
192
|
#
|
169
193
|
def _add__instance__attrs(method_name = @attribute)
|
170
194
|
method_name = method_name.to_s.pluralize
|
171
195
|
|
172
|
-
|
196
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
173
197
|
def #{method_name}
|
174
198
|
stateables[:#{@attribute}].states
|
175
199
|
end
|
@@ -178,15 +202,20 @@ module StateGate
|
|
178
202
|
|
179
203
|
|
180
204
|
|
205
|
+
##
|
181
206
|
# Adds an Instance method to return an Array of the human names for the attribute
|
182
|
-
#
|
183
|
-
#
|
184
|
-
#
|
207
|
+
#
|
208
|
+
# @param [Symbol] method_name
|
209
|
+
# the name for the new method
|
210
|
+
#
|
211
|
+
# @example
|
212
|
+
# .status_human_states #=> ['Pending Activation', 'Active',
|
213
|
+
# 'Suspended by Admin', 'Archived']
|
185
214
|
#
|
186
215
|
def _add__instance__human_attrs(method_name = @attribute)
|
187
216
|
method_name = "human_#{method_name.to_s.pluralize}"
|
188
217
|
|
189
|
-
|
218
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
190
219
|
def #{method_name}
|
191
220
|
stateables[:#{@attribute}].human_states
|
192
221
|
end
|
@@ -197,12 +226,12 @@ module StateGate
|
|
197
226
|
|
198
227
|
# Adds an Instance method to return the human name for the attribute's state
|
199
228
|
# eg:
|
200
|
-
# .human_status
|
229
|
+
# .human_status #=> 'Suspended by Admin'
|
201
230
|
#
|
202
231
|
def _add__instance__human_attr(method_name = @attribute)
|
203
232
|
method_name = "human_#{method_name.to_s}"
|
204
233
|
|
205
|
-
|
234
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
206
235
|
def #{method_name}
|
207
236
|
stateables[:#{@attribute}].human_state_for(#{@attribute})
|
208
237
|
end
|
@@ -211,17 +240,19 @@ module StateGate
|
|
211
240
|
|
212
241
|
|
213
242
|
|
243
|
+
##
|
214
244
|
# Adds an Instance method for each state, returning TRUE if the state is set
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
245
|
+
#
|
246
|
+
# @example
|
247
|
+
# --> when :active
|
248
|
+
# .active? #=> true
|
249
|
+
# .archived? #=> false
|
219
250
|
#
|
220
251
|
def _add__instance__state?
|
221
252
|
@engine.states.each do |state|
|
222
253
|
method_name = "#{@engine.scope_name_for_state(state)}?"
|
223
254
|
|
224
|
-
|
255
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 3, %(
|
225
256
|
def #{method_name}
|
226
257
|
self[:#{@attribute}] == :#{state}.to_s
|
227
258
|
end
|
@@ -231,20 +262,19 @@ module StateGate
|
|
231
262
|
|
232
263
|
|
233
264
|
|
265
|
+
##
|
234
266
|
# Adds an Instance method for each state, returning TRUE if the state is not set.
|
235
|
-
# eg:
|
236
|
-
# --> when :active
|
237
|
-
# .not_active? # => false
|
238
|
-
# .not_archived? # => true
|
239
267
|
#
|
240
|
-
#
|
241
|
-
#
|
268
|
+
# @example
|
269
|
+
# --> when :active
|
270
|
+
# .not_active? #=> false
|
271
|
+
# .not_archived? #=> true
|
242
272
|
#
|
243
273
|
def _add__instance__not_state?
|
244
274
|
@engine.states.each do |state|
|
245
275
|
method_name = "not_#{@engine.scope_name_for_state(state)}?"
|
246
276
|
|
247
|
-
|
277
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 3, %(
|
248
278
|
def #{method_name}
|
249
279
|
self[:#{@attribute}] != :#{state}.to_s
|
250
280
|
end
|
@@ -254,30 +284,36 @@ module StateGate
|
|
254
284
|
|
255
285
|
|
256
286
|
|
287
|
+
##
|
257
288
|
# Adds a, Instance method to return an Array of the human and state names for the
|
258
289
|
# attribute, suitable for using in a form select statement.
|
259
290
|
#
|
260
|
-
#
|
261
|
-
#
|
291
|
+
# @param [Symbol] method_name
|
292
|
+
# the name for the new method
|
293
|
+
#
|
294
|
+
# @option method_name sorted
|
295
|
+
# if TRUE, the array is sorted in alphabetical order by human name
|
296
|
+
# otherwise it is in the order specified
|
262
297
|
#
|
263
|
-
#
|
298
|
+
# @example
|
299
|
+
# .statuses_for_select #=> [ ['Pending Activation', 'pending'],
|
264
300
|
# ['Active', 'active'],
|
265
301
|
# ['Suspended by Admin', 'suspended',
|
266
302
|
# ['Archived', 'archived'] ]
|
267
303
|
#
|
268
|
-
# .statuses_for_select(true)
|
304
|
+
# .statuses_for_select(true) #=> [ ['Active', 'active'],
|
269
305
|
# ['Pending Activation', 'pending'],
|
270
306
|
# ['Suspended by Admin', 'suspended',
|
271
307
|
# ['Archived', 'archived'] ]
|
272
308
|
#
|
273
|
-
#
|
274
|
-
#
|
275
|
-
#
|
309
|
+
# @note
|
310
|
+
# States should NEVER be set from direct user selection. This method is
|
311
|
+
# intended for use within search forms, where the user may filter by state.
|
276
312
|
#
|
277
313
|
def _add__instance__attrs_for_select(method_name = @attribute)
|
278
314
|
method_name = "#{method_name.to_s.pluralize}_for_select"
|
279
315
|
|
280
|
-
|
316
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
281
317
|
def #{method_name}(sorted = false)
|
282
318
|
stateables[:#{@attribute}].states_for_select(sorted)
|
283
319
|
end
|
@@ -8,21 +8,21 @@ module StateGate
|
|
8
8
|
# Multiple private methods allowing StateGate::Builder to generate
|
9
9
|
# transition methods.
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# Klass.status_transitions
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
11
|
+
# - query the class for all allowed transitions:
|
12
|
+
# Klass.status_transitions #=> { pending: [:active],
|
13
|
+
# active: [:suspended, :archived],
|
14
|
+
# suspended: [:active, :archived],
|
15
|
+
# archived: [] }
|
16
16
|
#
|
17
|
-
#
|
18
|
-
# Klass.status_transitions_for(:pending)
|
19
|
-
# Klass.status_transitions_for(:active)
|
17
|
+
# - query the class for the allowed transitions for the given state:
|
18
|
+
# Klass.status_transitions_for(:pending) #=> [:active]
|
19
|
+
# Klass.status_transitions_for(:active) #=> [:suspended, :archived]
|
20
20
|
#
|
21
|
-
#
|
22
|
-
# .status_transitions
|
21
|
+
# - list the allowed transitions from the current state:
|
22
|
+
# .status_transitions #=> [:suspended, :archived]
|
23
23
|
#
|
24
|
-
#
|
25
|
-
# .status_transitions_to?(:active)
|
24
|
+
# - query if a given transition is allowed from the current state:
|
25
|
+
# .status_transitions_to?(:active) #=> true
|
26
26
|
#
|
27
27
|
module TransitionMethods
|
28
28
|
|
@@ -32,9 +32,10 @@ module StateGate
|
|
32
32
|
|
33
33
|
|
34
34
|
|
35
|
+
##
|
35
36
|
# Add instance methods to the klass that query the allowed transitions
|
36
37
|
#
|
37
|
-
def
|
38
|
+
def _generate_transition_methods
|
38
39
|
_add__klass__attr_transitions
|
39
40
|
_add__klass__attr_transitions_for
|
40
41
|
|
@@ -56,17 +57,22 @@ module StateGate
|
|
56
57
|
# Class methods
|
57
58
|
# ======================================================================
|
58
59
|
|
60
|
+
##
|
59
61
|
# Adds a Class method to return a Hash of the allowed transitions for the attribte
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
62
|
+
#
|
63
|
+
# @param [Symbol] method_name
|
64
|
+
# the name for the new method
|
65
|
+
#
|
66
|
+
# @example
|
67
|
+
# Klass.status_transitions #=> { pending: [:active],
|
68
|
+
# active: [:suspended, :archived],
|
69
|
+
# suspended: [:active, :archived],
|
70
|
+
# archived: [] }
|
65
71
|
#
|
66
72
|
def _add__klass__attr_transitions(method_name = @attribute)
|
67
73
|
method_name = "#{method_name}_transitions"
|
68
74
|
|
69
|
-
|
75
|
+
_add__klass__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
70
76
|
def #{method_name}
|
71
77
|
stateables[:#{@attribute}].transitions
|
72
78
|
end
|
@@ -75,17 +81,22 @@ module StateGate
|
|
75
81
|
|
76
82
|
|
77
83
|
|
84
|
+
##
|
78
85
|
# Adds a Class method to return an Array of the allowed attribute transitions for
|
79
86
|
# the provided state.
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
87
|
+
#
|
88
|
+
# @param [Symbol] method_name
|
89
|
+
# the name for the new method
|
90
|
+
#
|
91
|
+
# @example
|
92
|
+
# Klass.status_transitions_for(:pending) #=> [:active]
|
93
|
+
# Klass.status_transitions_for(:active) #=> [:suspended, :archived]
|
94
|
+
# Klass.status_transitions_for(:dummy) #=> ArgumentError
|
84
95
|
#
|
85
96
|
def _add__klass__attr_transitions_for(method_name = @attribute)
|
86
97
|
method_name = "#{method_name}_transitions_for"
|
87
98
|
|
88
|
-
|
99
|
+
_add__klass__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
89
100
|
def #{method_name}(state)
|
90
101
|
stateables[:#{@attribute}].transitions_for_state(state)
|
91
102
|
end
|
@@ -99,17 +110,22 @@ module StateGate
|
|
99
110
|
# ======================================================================
|
100
111
|
|
101
112
|
|
113
|
+
##
|
102
114
|
# Adds an instance method to return an Array of the allowed transitions from
|
103
115
|
# the current attribute state.
|
104
|
-
#
|
105
|
-
#
|
106
|
-
#
|
107
|
-
#
|
116
|
+
#
|
117
|
+
# @param [Symbol] method_name
|
118
|
+
# the name for the new method
|
119
|
+
#
|
120
|
+
# @example
|
121
|
+
# .status_transitions #=> [:active]
|
122
|
+
# .status_transitions #=> [:suspended, :archived]
|
123
|
+
# .status_transitions #=> []
|
108
124
|
#
|
109
125
|
def _add__instance__attr_transitions(method_name = @attribute)
|
110
126
|
method_name = "#{method_name}_transitions"
|
111
127
|
|
112
|
-
|
128
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
113
129
|
def #{method_name}
|
114
130
|
stateables[:#{@attribute}].transitions_for_state(self[:#{@attribute}])
|
115
131
|
end
|
@@ -118,17 +134,21 @@ module StateGate
|
|
118
134
|
|
119
135
|
|
120
136
|
|
121
|
-
|
137
|
+
##
|
122
138
|
# Adds an instance method to return TRUE if the current attribute state can
|
123
139
|
# transition to the queries status.
|
124
|
-
#
|
125
|
-
#
|
126
|
-
#
|
140
|
+
#
|
141
|
+
# @param [Symbol] method_name
|
142
|
+
# the name for the new method
|
143
|
+
#
|
144
|
+
# @example
|
145
|
+
# .status_transitions_to?(:active) #=> true
|
146
|
+
# .status_transitions_to?(:archived) #=> false
|
127
147
|
#
|
128
148
|
def _add__instance__attr_transitions_to(method_name = @attribute)
|
129
149
|
method_name = "#{method_name}_transitions_to?"
|
130
150
|
|
131
|
-
|
151
|
+
_add__instance__helper_method(method_name, __FILE__, __LINE__ - 2, %(
|
132
152
|
def #{method_name}(query_state)
|
133
153
|
test_state = StateGate.symbolize(query_state)
|
134
154
|
stateables[:#{@attribute}].transitions_for_state(self[:#{@attribute}])
|