statusable 0.3.0.pre → 0.4.1
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 +21 -1
- data/lib/statusable/has_statuses.rb +270 -75
- data/lib/statusable/railtie.rb +2 -0
- data/lib/statusable/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 47b494f50bfb5227bdc81b7b94b6401aacfbca8b9feb76a9ab05778aee68eccd
|
4
|
+
data.tar.gz: 53dad8c7f78793022eeeb65319178bf77214ad681cb10db7fcdb92ca34ac1a13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 514eaadc11e7e6556f1baab28a92fff17b060c701d61f83d82bdab267f4dec27d1038b8620d1fdcf488bbe80daf7641dfd96a4d0a44988c656e2721a7fcebb4d
|
7
|
+
data.tar.gz: f20b7697fe30031dfb688d08f0a2c7b1031c03be687d5183d593013b7ba49099d165d5b15e912834afeeb9815842ddb984ed91e7e6611270fccc74c6ce99bd24
|
data/README.md
CHANGED
@@ -142,6 +142,7 @@ job.validate; job.errors[:status]
|
|
142
142
|
The column name is customizable, as is whether or not to validate on presence or inclusion. Validating on inclusion means: ensuring that the current status value is included in the list of possible status values.
|
143
143
|
|
144
144
|
Defaults:
|
145
|
+
|
145
146
|
- `col_name = "status"`
|
146
147
|
- `validate_presence = false`
|
147
148
|
- `validate_inclusion = true`
|
@@ -245,9 +246,28 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
245
246
|
|
246
247
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
247
248
|
|
249
|
+
### Testing
|
250
|
+
|
251
|
+
To test this gem:
|
252
|
+
|
253
|
+
```bash
|
254
|
+
rake
|
255
|
+
```
|
256
|
+
|
257
|
+
#### Linters
|
258
|
+
|
259
|
+
```bash
|
260
|
+
rubocop
|
261
|
+
|
262
|
+
reek
|
263
|
+
|
264
|
+
npx prettier . --check
|
265
|
+
npx prettier . --write
|
266
|
+
```
|
267
|
+
|
248
268
|
### Releases
|
249
269
|
|
250
|
-
To release a new version of
|
270
|
+
To release a new version of this gem to RubyGems:
|
251
271
|
|
252
272
|
1. Update the version number in `version.rb`
|
253
273
|
2. Update the release date, etc. in `CHANGELOG.md`
|
@@ -10,9 +10,15 @@ module Statusable::HasStatuses
|
|
10
10
|
extend ActiveSupport::Concern
|
11
11
|
|
12
12
|
class_methods do # rubocop:disable Metrics/BlockLength
|
13
|
+
# :reek:TooManyStatements
|
14
|
+
# :reek:LongParameterList
|
15
|
+
# :reek:BooleanParameter
|
16
|
+
# :reek:ControlParameter
|
17
|
+
# :reek:DuplicateMethodCall
|
13
18
|
# rubocop:disable Metrics/AbcSize
|
14
19
|
# rubocop:disable Metrics/MethodLength
|
15
20
|
# rubocop:disable Naming/PredicateName
|
21
|
+
|
16
22
|
def has_statuses(
|
17
23
|
*args,
|
18
24
|
col_name: "status",
|
@@ -28,126 +34,289 @@ module Statusable::HasStatuses
|
|
28
34
|
last_word_connector: ", or ").
|
29
35
|
freeze
|
30
36
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
37
|
+
# VALIDATIONS
|
38
|
+
|
39
|
+
# Define a presence validation on the given `col_name`, if requested.
|
40
|
+
if validate_presence # rubocop:disable Style/IfUnlessModifier
|
41
|
+
validates(col_name, presence: true)
|
35
42
|
end
|
36
43
|
|
44
|
+
# Define an inclusion validation on the given `col_name` based on the
|
45
|
+
# givien list of `statuses`, if requested.
|
37
46
|
if validate_inclusion
|
47
|
+
message = "must be one of #{humanized_statuses_list}"
|
38
48
|
validates(
|
39
49
|
col_name,
|
40
|
-
inclusion: {
|
41
|
-
in: statuses,
|
42
|
-
allow_blank: true,
|
43
|
-
message: "must be one of #{humanized_statuses_list}",
|
44
|
-
})
|
50
|
+
inclusion: { in: statuses, allow_blank: true, message: message })
|
45
51
|
end
|
46
52
|
|
47
|
-
#
|
48
|
-
scope "for_#{col_name}",
|
49
|
-
->(status) {
|
50
|
-
where(
|
51
|
-
if status.is_a?(Array)
|
52
|
-
arel_column.in(status)
|
53
|
-
else
|
54
|
-
arel_column.eq(status)
|
55
|
-
end)
|
56
|
-
}
|
57
|
-
|
58
|
-
# .not_for_status(<status>)
|
59
|
-
scope "not_for_#{col_name}",
|
60
|
-
->(status) {
|
61
|
-
where(
|
62
|
-
if status.is_a?(Array)
|
63
|
-
arel_column.not_in(status)
|
64
|
-
else
|
65
|
-
arel_column.not_eq(status)
|
66
|
-
end)
|
67
|
-
}
|
68
|
-
|
69
|
-
# .by_status_asc
|
70
|
-
scope "by_#{col_name}_asc",
|
71
|
-
-> { order(arel_column) }
|
72
|
-
|
73
|
-
# .by_status_desc
|
74
|
-
scope "by_#{col_name}_desc",
|
75
|
-
-> { order(arel_column.desc) }
|
76
|
-
|
77
|
-
# .group_by_status
|
78
|
-
scope "group_by_#{col_name}",
|
79
|
-
-> { group(arel_column) }
|
80
|
-
|
81
|
-
# Class method to get a humanized list of statuses.
|
82
|
-
# .humanized_statuses_list
|
83
|
-
define_singleton_method(:"humanized_#{pluralized_column_name}_list") do
|
84
|
-
humanized_statuses_list
|
85
|
-
end
|
53
|
+
# NAMED SCOPES
|
86
54
|
|
87
|
-
#
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
55
|
+
# Define a named scope that filters on `col_name` records.
|
56
|
+
#
|
57
|
+
# @attr status [String, Array[String]]
|
58
|
+
#
|
59
|
+
# @example Default `col_name`
|
60
|
+
# .for_status(<a_status_name>)
|
61
|
+
#
|
62
|
+
# @example Custom `col_name`
|
63
|
+
# .for_custom_col_name(<a_status_name>)
|
64
|
+
scope :"for_#{col_name}", ->(status) {
|
65
|
+
method_name = status.is_a?(Array) ? :in : :eq
|
66
|
+
where(arel_column.public_send(method_name, status))
|
67
|
+
}
|
68
|
+
|
69
|
+
# Define a named scope that filters out `col_name` records.
|
70
|
+
#
|
71
|
+
# @attr status [String, Array[String]]
|
72
|
+
#
|
73
|
+
# @example Default `col_name`
|
74
|
+
# .not_for_status(<a_status_name>)
|
75
|
+
#
|
76
|
+
# @example Custom `col_name`
|
77
|
+
# .not_for_custom_col_name(<a_status_name>)
|
78
|
+
scope :"not_for_#{col_name}", ->(status) {
|
79
|
+
method_name = status.is_a?(Array) ? :not_in : :not_eq
|
80
|
+
where(arel_column.public_send(method_name, status))
|
81
|
+
}
|
82
|
+
|
83
|
+
# Define a named scope that orders by `col_name`, ascending.
|
84
|
+
#
|
85
|
+
# @example Default `col_name`
|
86
|
+
# .by_status_asc
|
87
|
+
#
|
88
|
+
# @example Custom `col_name`
|
89
|
+
# .by_custom_col_name_asc
|
90
|
+
scope :"by_#{col_name}_asc", -> { order(arel_column) }
|
91
|
+
|
92
|
+
# Define a named scope that orders by `col_name`, descending.
|
93
|
+
#
|
94
|
+
# @example Default `col_name`
|
95
|
+
# .by_status_desc
|
96
|
+
#
|
97
|
+
# @example Custom `col_name`
|
98
|
+
# .by_custom_col_name_desc
|
99
|
+
scope :"by_#{col_name}_desc", -> { order(arel_column.desc) }
|
100
|
+
|
101
|
+
# Define a named scope that groups by `col_name`, ascending.
|
102
|
+
#
|
103
|
+
# @example Default `col_name`
|
104
|
+
# .group_by_status
|
105
|
+
#
|
106
|
+
# @example Custom `col_name`
|
107
|
+
# .group_by_custom_col_name
|
108
|
+
scope :"group_by_#{col_name}", -> { group(arel_column) }
|
109
|
+
|
110
|
+
# CLASS METHODS
|
92
111
|
|
93
|
-
#
|
94
|
-
#
|
112
|
+
# Define a class method that returns the `statuses` Array.
|
113
|
+
#
|
114
|
+
# @return [Array[String]]
|
115
|
+
#
|
116
|
+
# @example Default `col_name`
|
117
|
+
# .status_options # => ["Status 1", "Status 2"]
|
118
|
+
#
|
119
|
+
# @example Custom `col_name`
|
120
|
+
# .custom_col_name_options # => ["Custom 1", "Custom 2"]
|
95
121
|
define_singleton_method(:"#{col_name}_options") do
|
96
122
|
statuses
|
97
123
|
end
|
98
124
|
|
99
|
-
#
|
100
|
-
#
|
125
|
+
# Define a class method that returns a humanized list of `statuses`.
|
126
|
+
#
|
127
|
+
# @return [String]
|
128
|
+
#
|
129
|
+
# @example Default `col_name`
|
130
|
+
# .humanized_statuses_list # => "Status 1, Status 2, or Status 3"
|
131
|
+
#
|
132
|
+
# @example Custom `col_name`
|
133
|
+
# .humanized_custom_col_name_list # => "Custom 1, Custom 2, or Custom 3"
|
134
|
+
define_singleton_method(:"humanized_#{pluralized_column_name}_list") do
|
135
|
+
humanized_statuses_list
|
136
|
+
end
|
137
|
+
|
138
|
+
# INSTANCE METHODS
|
139
|
+
|
140
|
+
# Define an instance method that returns the `statuses` Array.
|
141
|
+
#
|
142
|
+
# @return [Array[String]]
|
143
|
+
#
|
144
|
+
# @example Default `col_name`
|
145
|
+
# #status_options # => ["Status 1", "Status 2"]
|
146
|
+
#
|
147
|
+
# @example Custom `col_name`
|
148
|
+
# #custom_col_name_options # => ["Custom 1", "Custom 2"]
|
101
149
|
define_method(:"#{col_name}_options") do
|
102
150
|
statuses
|
103
151
|
end
|
104
152
|
|
105
|
-
#
|
106
|
-
#
|
153
|
+
# Define an instance method that returns a humanized list of `statuses`.
|
154
|
+
#
|
155
|
+
# @return [String]
|
156
|
+
#
|
157
|
+
# @example Default `col_name`
|
158
|
+
# #humanized_statuses_list # => "Status 1, Status 2, or Status 3"
|
159
|
+
#
|
160
|
+
# @example Custom `col_name`
|
161
|
+
# #humanized_custom_col_name_list # => "Custom 1, Custom 2, or Custom 3"
|
162
|
+
define_method(:"humanized_#{pluralized_column_name}_list") do
|
163
|
+
humanized_statuses_list
|
164
|
+
end
|
165
|
+
|
166
|
+
# Define an instance method that checks whether:
|
167
|
+
# - The current `status` is the same as the given status
|
168
|
+
# - The current `status` is the same as any of the given statuses
|
169
|
+
#
|
170
|
+
# @return [Boolean]
|
171
|
+
#
|
172
|
+
# @example Default `col_name`
|
173
|
+
# #status?("Known Status") # => true
|
174
|
+
# #status?("Unknown Status") # => false
|
175
|
+
# #status?(["Known Status 1", "Unknown Status 1"]) # => true
|
176
|
+
# #status?(["Unknown Status 1", "Unknown Status 2"]) # => false
|
177
|
+
#
|
178
|
+
# @example Custom `col_name`
|
179
|
+
# #custom_col_name?("Known Custom") # => true
|
180
|
+
# #custom_col_name?("Unknown Custom") # => false
|
181
|
+
# #custom_col_name?(["Known Custom 1", "Unknown Custom 1"]) # => true
|
182
|
+
# #custom_col_name?(["Unknown Custom 1", "Unknown Custom 2"]) # => false
|
107
183
|
define_method(:"#{col_name}?") do |a_status|
|
108
184
|
Array(a_status).any?(public_send(col_name))
|
109
185
|
end
|
110
186
|
|
111
|
-
#
|
187
|
+
# rubocop:disable Layout/LineLength
|
188
|
+
|
189
|
+
# Define an instance method that checks whether:
|
190
|
+
# - The current `status` is not the same as given status
|
191
|
+
# - The current `status` is not the same as any of the given statuses
|
192
|
+
#
|
193
|
+
# @return [Boolean]
|
194
|
+
#
|
195
|
+
# @example Default `col_name`
|
196
|
+
# #not_status?("Known Status") # => false
|
197
|
+
# #not_status?("Unknown Status") # => true
|
198
|
+
# #not_status?(["Known Status 1", "Unknown Status 1"]) # => false
|
199
|
+
# #not_status?(["Unknown Status 1", "Unknown Status 2"]) # => true
|
200
|
+
#
|
201
|
+
# @example Custom `col_name`
|
202
|
+
# #not_custom_col_name?("Known Custom") # => false
|
203
|
+
# #not_custom_col_name?("Unknown Custom") # => true
|
204
|
+
# #not_custom_col_name?(["Known Custom 1", "Unknown Custom 1"]) # => false
|
205
|
+
# #not_custom_col_name?(["Unknown Custom 1", "Unknown Custom 2"]) # => true
|
112
206
|
define_method(:"not_#{col_name}?") do |a_status|
|
113
|
-
public_send(col_name)
|
207
|
+
Array(a_status).none?(public_send(col_name))
|
114
208
|
end
|
115
209
|
|
210
|
+
# rubocop:enable Layout/LineLength
|
211
|
+
|
212
|
+
# INDIVIDUAL STATUS-SPECIFIC SCOPES/METHODS
|
213
|
+
|
116
214
|
statuses.each do |status| # rubocop:disable Metrics/BlockLength
|
117
215
|
status_name = status.parameterize.underscore
|
118
216
|
|
119
|
-
#
|
120
|
-
|
217
|
+
# NAMED SCOPES
|
218
|
+
|
219
|
+
# Define a named scope that filters on `col_name` records that match
|
220
|
+
# this `status`.
|
221
|
+
#
|
222
|
+
# @example Default `col_name`
|
223
|
+
# .for_status_ready
|
224
|
+
# .for_status_not_ready
|
225
|
+
#
|
226
|
+
# @example Custom `col_name`
|
227
|
+
# .for_custom_col_name_custom_1
|
228
|
+
# .for_custom_col_name_custom_2
|
229
|
+
scope :"for_#{col_name}_#{status_name}",
|
121
230
|
-> { where(arel_column.eq(status)) }
|
122
231
|
|
123
|
-
#
|
124
|
-
|
232
|
+
# Define a named scope that filters on `col_name` records that do not
|
233
|
+
# match this `status`.
|
234
|
+
#
|
235
|
+
# @example Default `col_name`
|
236
|
+
# .not_for_status_ready
|
237
|
+
# .not_for_status_not_ready
|
238
|
+
#
|
239
|
+
# @example Custom `col_name`
|
240
|
+
# .not_for_custom_col_name_custom_1
|
241
|
+
# .not_for_custom_col_name_custom_2
|
242
|
+
scope :"not_for_#{col_name}_#{status_name}",
|
125
243
|
-> { where(arel_column.not_eq(status)) }
|
126
244
|
|
127
|
-
#
|
128
|
-
|
129
|
-
# .
|
245
|
+
# CLASS METHODS
|
246
|
+
|
247
|
+
# Define a class method that returns this `status`'s value. This
|
248
|
+
# obviates the need to define a constant on the including Class.
|
249
|
+
#
|
250
|
+
# @return [String]
|
251
|
+
#
|
252
|
+
# @example Default `col_name`
|
253
|
+
# .status_ready # => "Ready"
|
254
|
+
# .status_not_ready # => "Not Ready"
|
255
|
+
#
|
256
|
+
# @example Custom `col_name`
|
257
|
+
# .custom_col_name_custom_1 # => "Custom 1"
|
258
|
+
# .custom_col_name_custom_2 # => "Custom 2"
|
130
259
|
define_singleton_method(:"#{col_name}_#{status_name}") do
|
131
260
|
status
|
132
261
|
end
|
133
262
|
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
263
|
+
# Define an instance method that returns this `status`'s value. This
|
264
|
+
# obviates the need to call e.g.
|
265
|
+
# - `self.class::STATUS_READY`
|
266
|
+
# - `self.class.status_ready`
|
267
|
+
# on the including Object.
|
268
|
+
#
|
269
|
+
# @return [String]
|
270
|
+
#
|
271
|
+
# @example Default `col_name`
|
272
|
+
# #status_ready # => "Ready"
|
273
|
+
# #status_not_ready # => "Not Ready"
|
274
|
+
#
|
275
|
+
# @example Custom `col_name`
|
276
|
+
# #custom_col_name_custom_1 # => "Custom 1"
|
277
|
+
# #custom_col_name_custom_2 # => "Custom 2"
|
137
278
|
define_method(:"#{col_name}_#{status_name}") do
|
138
279
|
status
|
139
280
|
end
|
140
281
|
|
282
|
+
# Define an instance method that sets this `status`'s value. This
|
283
|
+
# obviates the need to call e.g. `self.status = status_not_ready` on the
|
284
|
+
# including Object.
|
285
|
+
#
|
141
286
|
# @return [self]
|
142
|
-
#
|
287
|
+
#
|
288
|
+
# @example Default `col_name`
|
289
|
+
# #set_status_ready.status # => "Ready"
|
290
|
+
# #set_status_not_ready.status # => "Not Ready"
|
291
|
+
#
|
292
|
+
# @example Custom `col_name`
|
293
|
+
# #set_custom_col_name_custom_1.custom_col_name # => "Custom 1"
|
294
|
+
# #set_custom_col_name_custom_2.custom_col_name # => "Custom 2"
|
143
295
|
define_method(:"set_#{col_name}_#{status_name}") do
|
144
296
|
public_send(:"#{col_name}=", status)
|
145
297
|
|
146
298
|
self
|
147
299
|
end
|
148
300
|
|
149
|
-
#
|
301
|
+
# Define an instance method that sets this `status`'s value, and then
|
302
|
+
# calls ActiveRecord::Persistence#save!. This obviates the need to call
|
303
|
+
# e.g. `self.status = status_not_ready; save!` on the including Object.
|
304
|
+
#
|
150
305
|
# @return [self]
|
306
|
+
#
|
307
|
+
# @example Default `col_name`
|
308
|
+
# #set_status_ready!.status # => "Ready"
|
309
|
+
# #changes # => {}
|
310
|
+
#
|
311
|
+
# #set_status_not_ready!.status # => "Not Ready"
|
312
|
+
# #changes # => {}
|
313
|
+
#
|
314
|
+
# @example Custom `col_name`
|
315
|
+
# #set_custom_col_name_custom_1!.custom_col_name # => "Custom 1"
|
316
|
+
# #changes # => {}
|
317
|
+
#
|
318
|
+
# #set_custom_col_name_custom_2!.custom_col_name # => "Custom 2"
|
319
|
+
# #changes # => {}
|
151
320
|
define_method(:"set_#{col_name}_#{status_name}!") do
|
152
321
|
public_send(:"set_#{col_name}_#{status_name}")
|
153
322
|
save!
|
@@ -155,17 +324,43 @@ module Statusable::HasStatuses
|
|
155
324
|
self
|
156
325
|
end
|
157
326
|
|
158
|
-
#
|
327
|
+
# Define an instance method that checks whether the current `status` is
|
328
|
+
# the same as the status named by this method name. This obviates the
|
329
|
+
# need to call e.g. `status == status_ready` on the including Object.
|
330
|
+
#
|
331
|
+
# @return [Boolean]
|
332
|
+
#
|
333
|
+
# @example Default `col_name`
|
334
|
+
# #status_ready? # => true
|
335
|
+
# #status_not_ready? # => false
|
336
|
+
#
|
337
|
+
# @example Custom `col_name`
|
338
|
+
# #custom_col_name_custom_1? # => true
|
339
|
+
# #custom_col_name_custom_2? # => false
|
159
340
|
define_method(:"#{col_name}_#{status_name}?") do
|
160
341
|
public_send(col_name) == status
|
161
342
|
end
|
162
343
|
|
163
|
-
#
|
344
|
+
# Define an instance method that checks whether the current `status` is
|
345
|
+
# not the same as the status named by this method name. This obviates
|
346
|
+
# the need to call e.g. `status != status_ready` on the including
|
347
|
+
# Object.
|
348
|
+
#
|
349
|
+
# @return [Boolean]
|
350
|
+
#
|
351
|
+
# @example Default `col_name`
|
352
|
+
# #not_status_ready? # => false
|
353
|
+
# #not_status_not_ready? # => true
|
354
|
+
#
|
355
|
+
# @example Custom `col_name`
|
356
|
+
# #not_custom_col_name_custom_1? # => false
|
357
|
+
# #not_custom_col_name_custom_2? # => true
|
164
358
|
define_method(:"not_#{col_name}_#{status_name}?") do
|
165
359
|
public_send(col_name) != status
|
166
360
|
end
|
167
361
|
end
|
168
362
|
end
|
363
|
+
|
169
364
|
# rubocop:enable Naming/PredicateName
|
170
365
|
# rubocop:enable Metrics/MethodLength
|
171
366
|
# rubocop:enable Metrics/AbcSize
|
data/lib/statusable/railtie.rb
CHANGED
data/lib/statusable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: statusable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul DobbinSchmaltz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-11-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -98,14 +98,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
98
98
|
requirements:
|
99
99
|
- - ">="
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: '
|
101
|
+
version: '3.1'
|
102
102
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
103
|
requirements:
|
104
104
|
- - ">="
|
105
105
|
- !ruby/object:Gem::Version
|
106
106
|
version: '0'
|
107
107
|
requirements: []
|
108
|
-
rubygems_version: 3.
|
108
|
+
rubygems_version: 3.3.27
|
109
109
|
signing_key:
|
110
110
|
specification_version: 4
|
111
111
|
summary: Adds a `has_statuses` macro for defining common status-related ActiveRecord
|