statusable 0.1.0.pre → 0.3.0.pre

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c9dd86e72394b2b8e82391af2c925c3b2ab2bab6db1fc2c6620c2d8d51f502
4
- data.tar.gz: f04aa28c9f999d8594f632d5892bb1ed8aa11c7db6dfb89f064930dcca17ba93
3
+ metadata.gz: '08042127a22da0aacac6b596858eadf3dbbcbf4e0afdd3ff8713807a579f0960'
4
+ data.tar.gz: cca9c44afb9772931d2a8b3e6b1c06ce9b765674762d0c47423e61b87ac1a634
5
5
  SHA512:
6
- metadata.gz: 5a45c11415d8f4122f3a11da376c2ec68b8f502d255386efe96b957fbb1535e52bdc4a16a199c548c0ee8145969894b3be1712094d564742f6897b653e65e004
7
- data.tar.gz: 516c253ee89fd0251e3b4cf9ccb4af45c2447ffbebf97abc4b5beddf58d0fe6066301360172c18f822e889445556dea0def970a70eb24d39df5e8aee082aa24c
6
+ metadata.gz: df801462f17e8287a0885a001d97c71906a579c296851e113698f0c6ae3c2df02d7d249cb7dd8ef74906ea07c2e451d51c186580cce9af954e5846358d79629e
7
+ data.tar.gz: 0e7b0fcaaf55e968d4d97bdcaadf4f3d8ca820498d737146f4b08fb739657cde63033567a336d1342dab38b50f56d731ed653b5b7d5134e442a897472aa6d742
data/README.md CHANGED
@@ -1,11 +1,58 @@
1
1
  # Statusable
2
2
 
3
+ [![Gem Version](https://img.shields.io/github/v/release/pdobb/statusable)](https://img.shields.io/github/v/release/pdobb/statusable)
4
+
3
5
  Statusable adds a `has_statuses` macro for defining common status-related methods for use with ActiveRecord objects / Relations.
4
6
 
5
- ## Usage
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "statusable"
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```bash
18
+ $ bundle
19
+ ```
20
+
21
+ Or install it yourself:
22
+
23
+ ```bash
24
+ $ gem install statusable
25
+ ```
26
+
27
+ ## Configuration
28
+
29
+ First, add a `status` column to your model. Or pick any other name you may want instead of `status`... the column name is configurable. (See [Advanced Usage](#advanced-usage).)
30
+
31
+ ```ruby
32
+ # db/migrate/<version>_add_status_to_jobs.rb
33
+
34
+ def change
35
+ add_column :jobs, :status, :string, null: false, default: "Initializing"
36
+ add_index :jobs, :status
37
+ end
38
+ ```
39
+
40
+ Next, include `Statusable::HasStatuses` either into your model or into ApplicationRecord, per your preference.
6
41
 
7
42
  ```ruby
8
- class MyModel < ApplicationRecord
43
+ class Job < ApplicationRecord
44
+ include Statusable::HasStatuses
45
+ end
46
+ ```
47
+
48
+ Finally, call the `has_statuses` macro in your model, along with an array of your desired status names. See below for [Basic Usage](#basic-usage) and [Advanced Usage](#advanced-usage).
49
+
50
+ ## Basic Usage
51
+
52
+ ```ruby
53
+ class Job < ApplicationRecord
54
+ include Statusable::HasStatuses
55
+
9
56
  has_statuses(%w[
10
57
  Pending
11
58
  Running
@@ -14,22 +61,178 @@ class MyModel < ApplicationRecord
14
61
  end
15
62
  ```
16
63
 
17
- ## Installation
18
-
19
- Add this line to your application's Gemfile:
64
+ This adds a number of methods, named_scopes, and even ActiveModel validations to the model.
20
65
 
21
66
  ```ruby
22
- gem "statusable"
67
+ # The following are equivalent:
68
+
69
+ job = Job.new(status: "Pending")
70
+ job = Job.new(status: Job.status_pending)
71
+ job = Job.new; job.set_status_pending
72
+
73
+ # Check current status:
74
+
75
+ job.status_pending? # => true
76
+ job.status?("Pending") # => true
77
+
78
+ job.not_status_running? # => true
79
+ job.not_status?("Running") # => true
80
+
81
+ # Set status without saving:
82
+
83
+ job.set_status_running
84
+ # => #<Job:0x000000012fc3b060 id: nil, status: "Running", created_at: nil, updated_at: nil>
85
+ job.status_running? # => true
86
+
87
+ # Set status and save:
88
+
89
+ job.set_status_running!
90
+ # => #<Job:0x000000012fc3b560 id: 1, status: "Running", created_at: "...", updated_at: "...">
91
+
92
+ # Get status names/lists:
93
+
94
+ Job.status_pending # => "Pending"
95
+ job.status_pending # => "Pending"
96
+
97
+ Job.status_options # => ["Pending", "Running", "Completed"]
98
+ job.status_options # => ["Pending", "Running", "Completed"]
99
+
100
+ Job.humanized_statuses_list # => "Pending, Running, or Completed"
101
+ job.humanized_statuses_list # => "Pending, Running, or Completed"
102
+
103
+ # Named scopes:
104
+
105
+ Job.for_status("Pending").to_sql
106
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" = 'Pending'
107
+ Job.for_status(%w[Pending Running]).to_sql
108
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" IN ('Pending', 'Running')
109
+
110
+ Job.not_for_status("Pending").to_sql
111
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" != 'Pending'
112
+ Job.not_for_status(%w[Pending Running]).to_sql
113
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" NOT IN ('Pending', 'Running')
114
+
115
+ Job.for_status_pending.to_sql
116
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" = 'Pending'
117
+ Job.not_for_status_pending.to_sql
118
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."status" != 'Pending'
119
+
120
+ Job.by_status_asc.to_sql
121
+ # => SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."status"
122
+ Job.by_status_desc.to_sql
123
+ # => SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."status" DESC
124
+
125
+ Job.group_by_status.to_sql
126
+ # => SELECT "jobs".* FROM "jobs" GROUP BY "jobs"."status"
127
+
128
+ # Validation:
129
+
130
+ # By default, we don't validate on presence, but this can be changed.
131
+ # See the Advanced Usage section.
132
+ job.status = nil
133
+ job.validate; job.errors[:status] # => []
134
+
135
+ job.status = "Invalid Status"
136
+ job.validate; job.errors[:status]
137
+ # => ["must be one of Pending, Running, or Completed"]
23
138
  ```
24
139
 
25
- And then execute:
26
- ```bash
27
- $ bundle
140
+ ## Advanced Usage
141
+
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
+
144
+ Defaults:
145
+ - `col_name = "status"`
146
+ - `validate_presence = false`
147
+ - `validate_inclusion = true`
148
+
149
+ _Note: Be sure that the column name in your migration matches whatever you choose for `col_name`, below._
150
+
151
+ ```ruby
152
+ class Job < ApplicationRecord
153
+ include Statusable::HasStatuses
154
+
155
+ has_statuses(%w[
156
+ Pending
157
+ Running
158
+ Completed
159
+ ],
160
+ col_name: "lifecycle_state",
161
+ validate_presence: true,
162
+ validate_inclusion: true)
163
+ end
28
164
  ```
29
165
 
30
- Or install it yourself as:
31
- ```bash
32
- $ gem install statusable
166
+ This adds a number of methods, named_scopes, and even ActiveModel validations to the model--the same ones shown in Basic Usage. However, the "status" name varies, and this time we include a presence validation:
167
+
168
+ ```ruby
169
+ # The following are equivalent:
170
+
171
+ job = Job.new; job.set_lifecycle_state_pending
172
+
173
+ # Check current status:
174
+
175
+ job.lifecycle_state_pending? # => true
176
+ job.lifecycle_state?("Pending") # => true
177
+
178
+ job.not_lifecycle_state_running? # => true
179
+ job.not_lifecycle_state?("Running") # => true
180
+
181
+ # Set status without saving:
182
+
183
+ job.set_lifecycle_state_running
184
+ # => #<Job:0x000000012fc3b060 id: nil, lifecycle_state: "Running", created_at: nil, updated_at: nil>
185
+ job.lifecycle_state_running? # => true
186
+
187
+ # Set status and save:
188
+
189
+ job.set_lifecycle_state_running!
190
+ # => #<Job:0x000000012fc3b560 id: 1, lifecycle_state: "Running", created_at: "...", updated_at: "...">
191
+
192
+ # Get status names/lists:
193
+
194
+ Job.lifecycle_state_pending # => "Pending"
195
+ job.lifecycle_state_pending # => "Pending"
196
+
197
+ Job.lifecycle_state_options # => ["Pending", "Running", "Completed"]
198
+ job.lifecycle_state_options # => ["Pending", "Running", "Completed"]
199
+
200
+ Job.humanized_lifecycle_states_list # => "Pending, Running, or Completed"
201
+ job.humanized_lifecycle_states_list # => "Pending, Running, or Completed"
202
+
203
+ # Named scopes:
204
+
205
+ Job.for_lifecycle_state("Pending").to_sql
206
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" = 'Pending'
207
+ Job.for_lifecycle_state(%w[Pending Running]).to_sql
208
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" IN ('Pending', 'Running')
209
+
210
+ Job.not_for_lifecycle_state("Pending").to_sql
211
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" != 'Pending'
212
+ Job.not_for_lifecycle_state(%w[Pending Running]).to_sql
213
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" NOT IN ('Pending', 'Running')
214
+
215
+ Job.for_lifecycle_state_pending.to_sql
216
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" = 'Pending'
217
+ Job.not_for_lifecycle_state_pending.to_sql
218
+ # => SELECT "jobs".* FROM "jobs" WHERE "jobs"."lifecycle_state" != 'Pending'
219
+
220
+ Job.by_lifecycle_state_asc.to_sql
221
+ # => SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."lifecycle_state"
222
+ Job.by_lifecycle_state_desc.to_sql
223
+ # => SELECT "jobs".* FROM "jobs" ORDER BY "jobs"."lifecycle_state" DESC
224
+
225
+ Job.group_by_lifecycle_state.to_sql
226
+ # => SELECT "jobs".* FROM "jobs" GROUP BY "jobs"."lifecycle_state"
227
+
228
+ # Validation:
229
+
230
+ job.lifecycle_state = nil
231
+ job.validate; job.errors[:lifecycle_state] # => ["can't be blank"]
232
+
233
+ job.lifecycle_state = "Invalid lifecycle_state"
234
+ job.validate; job.errors[:lifecycle_state]
235
+ # => ["must be one of Pending, Running, or Completed"]
33
236
  ```
34
237
 
35
238
  ## Contributing
@@ -42,7 +245,15 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
42
245
 
43
246
  To install this gem onto your local machine, run `bundle exec rake install`.
44
247
 
45
- To release a new version, update the version number in `version.rb` and then run `bundle exec 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).
248
+ ### Releases
249
+
250
+ To release a new version of Statusable to RubyGems:
251
+
252
+ 1. Update the version number in `version.rb`
253
+ 2. Update the release date, etc. in `CHANGELOG.md`
254
+ 3. Run `bundle` to update Gemfile.lock with the latest version info
255
+ 4. Commit the changes. e.g. `Bump to vX.Y.Z`
256
+ 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).
46
257
 
47
258
  ## License
48
259
 
@@ -12,18 +12,15 @@ module Statusable::HasStatuses
12
12
  class_methods do # rubocop:disable Metrics/BlockLength
13
13
  # rubocop:disable Metrics/AbcSize
14
14
  # rubocop:disable Metrics/MethodLength
15
- # rubocop:disable Metrics/PerceivedComplexity
16
15
  # rubocop:disable Naming/PredicateName
17
16
  def has_statuses(
18
17
  *args,
19
18
  col_name: "status",
20
- arel_column: nil,
21
- validate_inclusion: true,
22
- validate_presence: false)
19
+ validate_presence: false,
20
+ validate_inclusion: true)
23
21
  statuses = args.flatten.freeze
24
-
25
- arel_column ||= arel_table[col_name]
26
22
  pluralized_column_name = col_name.to_s.pluralize
23
+ arel_column = arel_table[col_name]
27
24
 
28
25
  humanized_statuses_list =
29
26
  statuses.to_sentence(
@@ -31,18 +28,20 @@ module Statusable::HasStatuses
31
28
  last_word_connector: ", or ").
32
29
  freeze
33
30
 
34
- if validate_inclusion
35
- validates col_name,
36
- inclusion: {
37
- in: statuses,
38
- allow_blank: true,
39
- message: "must be one of #{humanized_statuses_list}",
40
- }
31
+ if validate_presence
32
+ validates(
33
+ col_name,
34
+ presence: true)
41
35
  end
42
36
 
43
- if validate_presence
44
- validates col_name,
45
- presence: true
37
+ if validate_inclusion
38
+ validates(
39
+ col_name,
40
+ inclusion: {
41
+ in: statuses,
42
+ allow_blank: true,
43
+ message: "must be one of #{humanized_statuses_list}",
44
+ })
46
45
  end
47
46
 
48
47
  # .for_status(<status>)
@@ -103,6 +102,17 @@ module Statusable::HasStatuses
103
102
  statuses
104
103
  end
105
104
 
105
+ # #status?("Ready")
106
+ # #status?(["Ready", "Not Ready"])
107
+ define_method(:"#{col_name}?") do |a_status|
108
+ Array(a_status).any?(public_send(col_name))
109
+ end
110
+
111
+ # #not_status?("Ready")
112
+ define_method(:"not_#{col_name}?") do |a_status|
113
+ public_send(col_name) != a_status
114
+ end
115
+
106
116
  statuses.each do |status| # rubocop:disable Metrics/BlockLength
107
117
  status_name = status.parameterize.underscore
108
118
 
@@ -154,15 +164,9 @@ module Statusable::HasStatuses
154
164
  define_method(:"not_#{col_name}_#{status_name}?") do
155
165
  public_send(col_name) != status
156
166
  end
157
-
158
- # #status?(<a_status>)
159
- define_method(:"#{col_name}?") do |a_status|
160
- public_send(col_name) == a_status
161
- end
162
167
  end
163
168
  end
164
169
  # rubocop:enable Naming/PredicateName
165
- # rubocop:enable Metrics/PerceivedComplexity
166
170
  # rubocop:enable Metrics/MethodLength
167
171
  # rubocop:enable Metrics/AbcSize
168
172
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Statusable
4
- VERSION = "0.1.0.pre"
4
+ VERSION = "0.3.0.pre"
5
5
  end
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.1.0.pre
4
+ version: 0.3.0.pre
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-08-15 00:00:00.000000000 Z
11
+ date: 2024-08-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails