statusable 0.3.0.pre → 0.4.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 +21 -1
- data/lib/statusable/has_statuses.rb +263 -75
- 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: b529e80d12f7c2f085b89f9ed98fc9abd70e47f2a823c814005bad5243c0bed6
|
4
|
+
data.tar.gz: 503ce3bedca223203c854a936ff4b98ca04a2efe60a8a61d58b530dbe66c56d9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aebb2e90c390cc59bde1e77de2c4468d35bc5acfe339092ac598b5f4f547dca04d04d6b8d5dd7f78ad7828baabc24d8e3842349c8e94a7fc11e4b417beb54cf3
|
7
|
+
data.tar.gz: 4d7f1525ffc1ff3a80be61fac81095649aaf9eecd2b43c48f11edd96034be506c2c39cf801117f3a82b1ea2f348b68f4d845e28f40fbedbcb10b8ef47d4ff957
|
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`
|
@@ -28,126 +28,289 @@ module Statusable::HasStatuses
|
|
28
28
|
last_word_connector: ", or ").
|
29
29
|
freeze
|
30
30
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
# VALIDATIONS
|
32
|
+
|
33
|
+
# Define a presence validation on the given `col_name`, if requested.
|
34
|
+
if validate_presence # rubocop:disable Style/IfUnlessModifier
|
35
|
+
validates(col_name, presence: true)
|
35
36
|
end
|
36
37
|
|
38
|
+
# Define an inclusion validation on the given `col_name` based on the
|
39
|
+
# givien list of `statuses`, if requested.
|
37
40
|
if validate_inclusion
|
41
|
+
message = "must be one of #{humanized_statuses_list}"
|
38
42
|
validates(
|
39
43
|
col_name,
|
40
|
-
inclusion: {
|
41
|
-
in: statuses,
|
42
|
-
allow_blank: true,
|
43
|
-
message: "must be one of #{humanized_statuses_list}",
|
44
|
-
})
|
44
|
+
inclusion: { in: statuses, allow_blank: true, message: message })
|
45
45
|
end
|
46
46
|
|
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
|
47
|
+
# NAMED SCOPES
|
86
48
|
|
87
|
-
#
|
88
|
-
#
|
89
|
-
|
90
|
-
|
91
|
-
|
49
|
+
# Define a named scope that filters on `col_name` records.
|
50
|
+
#
|
51
|
+
# @attr status [String, Array[String]]
|
52
|
+
#
|
53
|
+
# @example Default `col_name`
|
54
|
+
# .for_status(<a_status_name>)
|
55
|
+
#
|
56
|
+
# @example Custom `col_name`
|
57
|
+
# .for_custom_col_name(<a_status_name>)
|
58
|
+
scope :"for_#{col_name}", ->(status) {
|
59
|
+
method_name = status.is_a?(Array) ? :in : :eq
|
60
|
+
where(arel_column.public_send(method_name, status))
|
61
|
+
}
|
62
|
+
|
63
|
+
# Define a named scope that filters out `col_name` records.
|
64
|
+
#
|
65
|
+
# @attr status [String, Array[String]]
|
66
|
+
#
|
67
|
+
# @example Default `col_name`
|
68
|
+
# .not_for_status(<a_status_name>)
|
69
|
+
#
|
70
|
+
# @example Custom `col_name`
|
71
|
+
# .not_for_custom_col_name(<a_status_name>)
|
72
|
+
scope :"not_for_#{col_name}", ->(status) {
|
73
|
+
method_name = status.is_a?(Array) ? :not_in : :not_eq
|
74
|
+
where(arel_column.public_send(method_name, status))
|
75
|
+
}
|
76
|
+
|
77
|
+
# Define a named scope that orders by `col_name`, ascending.
|
78
|
+
#
|
79
|
+
# @example Default `col_name`
|
80
|
+
# .by_status_asc
|
81
|
+
#
|
82
|
+
# @example Custom `col_name`
|
83
|
+
# .by_custom_col_name_asc
|
84
|
+
scope :"by_#{col_name}_asc", -> { order(arel_column) }
|
85
|
+
|
86
|
+
# Define a named scope that orders by `col_name`, descending.
|
87
|
+
#
|
88
|
+
# @example Default `col_name`
|
89
|
+
# .by_status_desc
|
90
|
+
#
|
91
|
+
# @example Custom `col_name`
|
92
|
+
# .by_custom_col_name_desc
|
93
|
+
scope :"by_#{col_name}_desc", -> { order(arel_column.desc) }
|
94
|
+
|
95
|
+
# Define a named scope that groups by `col_name`, ascending.
|
96
|
+
#
|
97
|
+
# @example Default `col_name`
|
98
|
+
# .group_by_status
|
99
|
+
#
|
100
|
+
# @example Custom `col_name`
|
101
|
+
# .group_by_custom_col_name
|
102
|
+
scope :"group_by_#{col_name}", -> { group(arel_column) }
|
103
|
+
|
104
|
+
# CLASS METHODS
|
92
105
|
|
93
|
-
#
|
94
|
-
#
|
106
|
+
# Define a class method that returns the `statuses` Array.
|
107
|
+
#
|
108
|
+
# @return [Array[String]]
|
109
|
+
#
|
110
|
+
# @example Default `col_name`
|
111
|
+
# .status_options # => ["Status 1", "Status 2"]
|
112
|
+
#
|
113
|
+
# @example Custom `col_name`
|
114
|
+
# .custom_col_name_options # => ["Custom 1", "Custom 2"]
|
95
115
|
define_singleton_method(:"#{col_name}_options") do
|
96
116
|
statuses
|
97
117
|
end
|
98
118
|
|
99
|
-
#
|
100
|
-
#
|
119
|
+
# Define a class method that returns a humanized list of `statuses`.
|
120
|
+
#
|
121
|
+
# @return [String]
|
122
|
+
#
|
123
|
+
# @example Default `col_name`
|
124
|
+
# .humanized_statuses_list # => "Status 1, Status 2, or Status 3"
|
125
|
+
#
|
126
|
+
# @example Custom `col_name`
|
127
|
+
# .humanized_custom_col_name_list # => "Custom 1, Custom 2, or Custom 3"
|
128
|
+
define_singleton_method(:"humanized_#{pluralized_column_name}_list") do
|
129
|
+
humanized_statuses_list
|
130
|
+
end
|
131
|
+
|
132
|
+
# INSTANCE METHODS
|
133
|
+
|
134
|
+
# Define an instance method that returns the `statuses` Array.
|
135
|
+
#
|
136
|
+
# @return [Array[String]]
|
137
|
+
#
|
138
|
+
# @example Default `col_name`
|
139
|
+
# #status_options # => ["Status 1", "Status 2"]
|
140
|
+
#
|
141
|
+
# @example Custom `col_name`
|
142
|
+
# #custom_col_name_options # => ["Custom 1", "Custom 2"]
|
101
143
|
define_method(:"#{col_name}_options") do
|
102
144
|
statuses
|
103
145
|
end
|
104
146
|
|
105
|
-
#
|
106
|
-
#
|
147
|
+
# Define an instance method that returns a humanized list of `statuses`.
|
148
|
+
#
|
149
|
+
# @return [String]
|
150
|
+
#
|
151
|
+
# @example Default `col_name`
|
152
|
+
# #humanized_statuses_list # => "Status 1, Status 2, or Status 3"
|
153
|
+
#
|
154
|
+
# @example Custom `col_name`
|
155
|
+
# #humanized_custom_col_name_list # => "Custom 1, Custom 2, or Custom 3"
|
156
|
+
define_method(:"humanized_#{pluralized_column_name}_list") do
|
157
|
+
humanized_statuses_list
|
158
|
+
end
|
159
|
+
|
160
|
+
# Define an instance method that checks whether:
|
161
|
+
# - The current `status` is the same as the given status
|
162
|
+
# - The current `status` is the same as any of the given statuses
|
163
|
+
#
|
164
|
+
# @return [Boolean]
|
165
|
+
#
|
166
|
+
# @example Default `col_name`
|
167
|
+
# #status?("Known Status") # => true
|
168
|
+
# #status?("Unknown Status") # => false
|
169
|
+
# #status?(["Known Status 1", "Unknown Status 1"]) # => true
|
170
|
+
# #status?(["Unknown Status 1", "Unknown Status 2"]) # => false
|
171
|
+
#
|
172
|
+
# @example Custom `col_name`
|
173
|
+
# #custom_col_name?("Known Custom") # => true
|
174
|
+
# #custom_col_name?("Unknown Custom") # => false
|
175
|
+
# #custom_col_name?(["Known Custom 1", "Unknown Custom 1"]) # => true
|
176
|
+
# #custom_col_name?(["Unknown Custom 1", "Unknown Custom 2"]) # => false
|
107
177
|
define_method(:"#{col_name}?") do |a_status|
|
108
178
|
Array(a_status).any?(public_send(col_name))
|
109
179
|
end
|
110
180
|
|
111
|
-
#
|
181
|
+
# rubocop:disable Layout/LineLength
|
182
|
+
|
183
|
+
# Define an instance method that checks whether:
|
184
|
+
# - The current `status` is not the same as given status
|
185
|
+
# - The current `status` is not the same as any of the given statuses
|
186
|
+
#
|
187
|
+
# @return [Boolean]
|
188
|
+
#
|
189
|
+
# @example Default `col_name`
|
190
|
+
# #not_status?("Known Status") # => false
|
191
|
+
# #not_status?("Unknown Status") # => true
|
192
|
+
# #not_status?(["Known Status 1", "Unknown Status 1"]) # => false
|
193
|
+
# #not_status?(["Unknown Status 1", "Unknown Status 2"]) # => true
|
194
|
+
#
|
195
|
+
# @example Custom `col_name`
|
196
|
+
# #not_custom_col_name?("Known Custom") # => false
|
197
|
+
# #not_custom_col_name?("Unknown Custom") # => true
|
198
|
+
# #not_custom_col_name?(["Known Custom 1", "Unknown Custom 1"]) # => false
|
199
|
+
# #not_custom_col_name?(["Unknown Custom 1", "Unknown Custom 2"]) # => true
|
112
200
|
define_method(:"not_#{col_name}?") do |a_status|
|
113
|
-
public_send(col_name)
|
201
|
+
Array(a_status).none?(public_send(col_name))
|
114
202
|
end
|
115
203
|
|
204
|
+
# rubocop:enable Layout/LineLength
|
205
|
+
|
206
|
+
# INDIVIDUAL STATUS-SPECIFIC SCOPES/METHODS
|
207
|
+
|
116
208
|
statuses.each do |status| # rubocop:disable Metrics/BlockLength
|
117
209
|
status_name = status.parameterize.underscore
|
118
210
|
|
119
|
-
#
|
120
|
-
|
211
|
+
# NAMED SCOPES
|
212
|
+
|
213
|
+
# Define a named scope that filters on `col_name` records that match
|
214
|
+
# this `status`.
|
215
|
+
#
|
216
|
+
# @example Default `col_name`
|
217
|
+
# .for_status_ready
|
218
|
+
# .for_status_not_ready
|
219
|
+
#
|
220
|
+
# @example Custom `col_name`
|
221
|
+
# .for_custom_col_name_custom_1
|
222
|
+
# .for_custom_col_name_custom_2
|
223
|
+
scope :"for_#{col_name}_#{status_name}",
|
121
224
|
-> { where(arel_column.eq(status)) }
|
122
225
|
|
123
|
-
#
|
124
|
-
|
226
|
+
# Define a named scope that filters on `col_name` records that do not
|
227
|
+
# match this `status`.
|
228
|
+
#
|
229
|
+
# @example Default `col_name`
|
230
|
+
# .not_for_status_ready
|
231
|
+
# .not_for_status_not_ready
|
232
|
+
#
|
233
|
+
# @example Custom `col_name`
|
234
|
+
# .not_for_custom_col_name_custom_1
|
235
|
+
# .not_for_custom_col_name_custom_2
|
236
|
+
scope :"not_for_#{col_name}_#{status_name}",
|
125
237
|
-> { where(arel_column.not_eq(status)) }
|
126
238
|
|
127
|
-
#
|
128
|
-
|
129
|
-
# .
|
239
|
+
# CLASS METHODS
|
240
|
+
|
241
|
+
# Define a class method that returns this `status`'s value. This
|
242
|
+
# obviates the need to define a constant on the including Class.
|
243
|
+
#
|
244
|
+
# @return [String]
|
245
|
+
#
|
246
|
+
# @example Default `col_name`
|
247
|
+
# .status_ready # => "Ready"
|
248
|
+
# .status_not_ready # => "Not Ready"
|
249
|
+
#
|
250
|
+
# @example Custom `col_name`
|
251
|
+
# .custom_col_name_custom_1 # => "Custom 1"
|
252
|
+
# .custom_col_name_custom_2 # => "Custom 2"
|
130
253
|
define_singleton_method(:"#{col_name}_#{status_name}") do
|
131
254
|
status
|
132
255
|
end
|
133
256
|
|
134
|
-
#
|
135
|
-
#
|
136
|
-
#
|
257
|
+
# Define an instance method that returns this `status`'s value. This
|
258
|
+
# obviates the need to call e.g.
|
259
|
+
# - `self.class::STATUS_READY`
|
260
|
+
# - `self.class.status_ready`
|
261
|
+
# on the including Object.
|
262
|
+
#
|
263
|
+
# @return [String]
|
264
|
+
#
|
265
|
+
# @example Default `col_name`
|
266
|
+
# #status_ready # => "Ready"
|
267
|
+
# #status_not_ready # => "Not Ready"
|
268
|
+
#
|
269
|
+
# @example Custom `col_name`
|
270
|
+
# #custom_col_name_custom_1 # => "Custom 1"
|
271
|
+
# #custom_col_name_custom_2 # => "Custom 2"
|
137
272
|
define_method(:"#{col_name}_#{status_name}") do
|
138
273
|
status
|
139
274
|
end
|
140
275
|
|
276
|
+
# Define an instance method that sets this `status`'s value. This
|
277
|
+
# obviates the need to call e.g. `self.status = status_not_ready` on the
|
278
|
+
# including Object.
|
279
|
+
#
|
141
280
|
# @return [self]
|
142
|
-
#
|
281
|
+
#
|
282
|
+
# @example Default `col_name`
|
283
|
+
# #set_status_ready.status # => "Ready"
|
284
|
+
# #set_status_not_ready.status # => "Not Ready"
|
285
|
+
#
|
286
|
+
# @example Custom `col_name`
|
287
|
+
# #set_custom_col_name_custom_1.custom_col_name # => "Custom 1"
|
288
|
+
# #set_custom_col_name_custom_2.custom_col_name # => "Custom 2"
|
143
289
|
define_method(:"set_#{col_name}_#{status_name}") do
|
144
290
|
public_send(:"#{col_name}=", status)
|
145
291
|
|
146
292
|
self
|
147
293
|
end
|
148
294
|
|
149
|
-
#
|
295
|
+
# Define an instance method that sets this `status`'s value, and then
|
296
|
+
# calls ActiveRecord::Persistence#save!. This obviates the need to call
|
297
|
+
# e.g. `self.status = status_not_ready; save!` on the including Object.
|
298
|
+
#
|
150
299
|
# @return [self]
|
300
|
+
#
|
301
|
+
# @example Default `col_name`
|
302
|
+
# #set_status_ready!.status # => "Ready"
|
303
|
+
# #changes # => {}
|
304
|
+
#
|
305
|
+
# #set_status_not_ready!.status # => "Not Ready"
|
306
|
+
# #changes # => {}
|
307
|
+
#
|
308
|
+
# @example Custom `col_name`
|
309
|
+
# #set_custom_col_name_custom_1!.custom_col_name # => "Custom 1"
|
310
|
+
# #changes # => {}
|
311
|
+
#
|
312
|
+
# #set_custom_col_name_custom_2!.custom_col_name # => "Custom 2"
|
313
|
+
# #changes # => {}
|
151
314
|
define_method(:"set_#{col_name}_#{status_name}!") do
|
152
315
|
public_send(:"set_#{col_name}_#{status_name}")
|
153
316
|
save!
|
@@ -155,12 +318,37 @@ module Statusable::HasStatuses
|
|
155
318
|
self
|
156
319
|
end
|
157
320
|
|
158
|
-
#
|
321
|
+
# Define an instance method that checks whether the current `status` is
|
322
|
+
# the same as the status named by this method name. This obviates the
|
323
|
+
# need to call e.g. `status == status_ready` on the including Object.
|
324
|
+
#
|
325
|
+
# @return [Boolean]
|
326
|
+
#
|
327
|
+
# @example Default `col_name`
|
328
|
+
# #status_ready? # => true
|
329
|
+
# #status_not_ready? # => false
|
330
|
+
#
|
331
|
+
# @example Custom `col_name`
|
332
|
+
# #custom_col_name_custom_1? # => true
|
333
|
+
# #custom_col_name_custom_2? # => false
|
159
334
|
define_method(:"#{col_name}_#{status_name}?") do
|
160
335
|
public_send(col_name) == status
|
161
336
|
end
|
162
337
|
|
163
|
-
#
|
338
|
+
# Define an instance method that checks whether the current `status` is
|
339
|
+
# not the same as the status named by this method name. This obviates
|
340
|
+
# the need to call e.g. `status != status_ready` on the including
|
341
|
+
# Object.
|
342
|
+
#
|
343
|
+
# @return [Boolean]
|
344
|
+
#
|
345
|
+
# @example Default `col_name`
|
346
|
+
# #not_status_ready? # => false
|
347
|
+
# #not_status_not_ready? # => true
|
348
|
+
#
|
349
|
+
# @example Custom `col_name`
|
350
|
+
# #not_custom_col_name_custom_1? # => false
|
351
|
+
# #not_custom_col_name_custom_2? # => true
|
164
352
|
define_method(:"not_#{col_name}_#{status_name}?") do
|
165
353
|
public_send(col_name) != status
|
166
354
|
end
|
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.0
|
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-21 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
|