statusable 0.2.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 +29 -1
- data/lib/statusable/has_statuses.rb +264 -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,7 +246,34 @@ 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
|
|
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
|
+
|
268
|
+
### Releases
|
269
|
+
|
270
|
+
To release a new version of this gem to RubyGems:
|
271
|
+
|
272
|
+
1. Update the version number in `version.rb`
|
273
|
+
2. Update the release date, etc. in `CHANGELOG.md`
|
274
|
+
3. Run `bundle` to update Gemfile.lock with the latest version info
|
275
|
+
4. Commit the changes. e.g. `Bump to vX.Y.Z`
|
276
|
+
5. Run `rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
249
277
|
|
250
278
|
## License
|
251
279
|
|
@@ -28,125 +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
|
-
#
|
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
|
106
177
|
define_method(:"#{col_name}?") do |a_status|
|
107
|
-
public_send(col_name)
|
178
|
+
Array(a_status).any?(public_send(col_name))
|
108
179
|
end
|
109
180
|
|
110
|
-
#
|
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
|
111
200
|
define_method(:"not_#{col_name}?") do |a_status|
|
112
|
-
public_send(col_name)
|
201
|
+
Array(a_status).none?(public_send(col_name))
|
113
202
|
end
|
114
203
|
|
204
|
+
# rubocop:enable Layout/LineLength
|
205
|
+
|
206
|
+
# INDIVIDUAL STATUS-SPECIFIC SCOPES/METHODS
|
207
|
+
|
115
208
|
statuses.each do |status| # rubocop:disable Metrics/BlockLength
|
116
209
|
status_name = status.parameterize.underscore
|
117
210
|
|
118
|
-
#
|
119
|
-
|
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}",
|
120
224
|
-> { where(arel_column.eq(status)) }
|
121
225
|
|
122
|
-
#
|
123
|
-
|
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}",
|
124
237
|
-> { where(arel_column.not_eq(status)) }
|
125
238
|
|
126
|
-
#
|
127
|
-
|
128
|
-
# .
|
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"
|
129
253
|
define_singleton_method(:"#{col_name}_#{status_name}") do
|
130
254
|
status
|
131
255
|
end
|
132
256
|
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
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"
|
136
272
|
define_method(:"#{col_name}_#{status_name}") do
|
137
273
|
status
|
138
274
|
end
|
139
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
|
+
#
|
140
280
|
# @return [self]
|
141
|
-
#
|
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"
|
142
289
|
define_method(:"set_#{col_name}_#{status_name}") do
|
143
290
|
public_send(:"#{col_name}=", status)
|
144
291
|
|
145
292
|
self
|
146
293
|
end
|
147
294
|
|
148
|
-
#
|
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
|
+
#
|
149
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 # => {}
|
150
314
|
define_method(:"set_#{col_name}_#{status_name}!") do
|
151
315
|
public_send(:"set_#{col_name}_#{status_name}")
|
152
316
|
save!
|
@@ -154,12 +318,37 @@ module Statusable::HasStatuses
|
|
154
318
|
self
|
155
319
|
end
|
156
320
|
|
157
|
-
#
|
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
|
158
334
|
define_method(:"#{col_name}_#{status_name}?") do
|
159
335
|
public_send(col_name) == status
|
160
336
|
end
|
161
337
|
|
162
|
-
#
|
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
|
163
352
|
define_method(:"not_#{col_name}_#{status_name}?") do
|
164
353
|
public_send(col_name) != status
|
165
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
|