statusable 0.1.0.pre → 0.2.0.pre

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 25c9dd86e72394b2b8e82391af2c925c3b2ab2bab6db1fc2c6620c2d8d51f502
4
- data.tar.gz: f04aa28c9f999d8594f632d5892bb1ed8aa11c7db6dfb89f064930dcca17ba93
3
+ metadata.gz: 6abf9f62c9ce28ec0003fe73731760adc77dd2e6fad64f05165279d2cb575684
4
+ data.tar.gz: db4e4a6a8dd888ee50dc489defe0e44c6b225a68a07ec1c41e02b4194eb6d4f8
5
5
  SHA512:
6
- metadata.gz: 5a45c11415d8f4122f3a11da376c2ec68b8f502d255386efe96b957fbb1535e52bdc4a16a199c548c0ee8145969894b3be1712094d564742f6897b653e65e004
7
- data.tar.gz: 516c253ee89fd0251e3b4cf9ccb4af45c2447ffbebf97abc4b5beddf58d0fe6066301360172c18f822e889445556dea0def970a70eb24d39df5e8aee082aa24c
6
+ metadata.gz: db814ddca7cffb1c14facd97dadc88d341616a4357e32822f254a9b0d6196103bc17022549955f58cd4db71544295a409381fcc08e022a5a366586d8110cd793
7
+ data.tar.gz: aa2482d72ee291e07f8b40f3e5e4c9d26b518508c0214974695b51687d8735f3d92a7d991372219dd88c1b87bc9be4432eb4bc8c17c0a504ad16734d58f7ffbd
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:
6
10
 
7
11
  ```ruby
8
- class MyModel < ApplicationRecord
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.
41
+
42
+ ```ruby
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
@@ -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,16 @@ module Statusable::HasStatuses
103
102
  statuses
104
103
  end
105
104
 
105
+ # #status?("Ready")
106
+ define_method(:"#{col_name}?") do |a_status|
107
+ public_send(col_name) == a_status
108
+ end
109
+
110
+ # #not_status?("Ready")
111
+ define_method(:"not_#{col_name}?") do |a_status|
112
+ public_send(col_name) != a_status
113
+ end
114
+
106
115
  statuses.each do |status| # rubocop:disable Metrics/BlockLength
107
116
  status_name = status.parameterize.underscore
108
117
 
@@ -154,15 +163,9 @@ module Statusable::HasStatuses
154
163
  define_method(:"not_#{col_name}_#{status_name}?") do
155
164
  public_send(col_name) != status
156
165
  end
157
-
158
- # #status?(<a_status>)
159
- define_method(:"#{col_name}?") do |a_status|
160
- public_send(col_name) == a_status
161
- end
162
166
  end
163
167
  end
164
168
  # rubocop:enable Naming/PredicateName
165
- # rubocop:enable Metrics/PerceivedComplexity
166
169
  # rubocop:enable Metrics/MethodLength
167
170
  # rubocop:enable Metrics/AbcSize
168
171
  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.2.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.2.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-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails