statusable 0.1.0.pre → 0.2.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: 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