enum_fields 0.3.2 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 711e9c8ec5416674480e0d3abf02ac97e53fe5ab3a02ede7c8f70838a05461eb
4
- data.tar.gz: 9fc0c1811f467705a7f6f0d6be1c957b26095f23514d953d4240e7ee721c3a4c
3
+ metadata.gz: b8cef70b80a3d7295656083f0f02fa89ecf8c5909159e8f3739083b6628adecb
4
+ data.tar.gz: 52b5ef83feac0853df498cf0e2249ba05e59cf986ffa08b56ac3145a41b559f1
5
5
  SHA512:
6
- metadata.gz: dfd868cdc669171dda053b068d84719a78758f1b3a01dac77e3c084efe9f87b190054bcec517c51dafe5143bfbd35ecdd4fe06da90a6c829cc586182ba59881c
7
- data.tar.gz: 7b2c111b3a8c779e8f46073a8cb244fd2a385cfbc50fcd018eae254d4dda617a57224bf844826028a2987d0a3ab49a890c98cbd67687c6cfbfadae1b520848a4
6
+ metadata.gz: b302a85589635931d64c7e44d8cff16833b6b6c2041d22886e410a929e092b3ca8de55f43c22b72079a87565b9bc1e5f1c1aacbf8d4a26254665578930302079
7
+ data.tar.gz: '0477991e1b705e53dd5283e581dd43f38fa4ff7dc82d3428c48190ea8ddb918c0865dee701be939823aff23c22b3c535b55e574ed9dbffa00e87634fe88deeb3'
data/CHANGELOG.md CHANGED
@@ -5,89 +5,74 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
- ## [0.3.2] - 2026-03-08
8
+ ## [X.X.X] - YYYY-MM-DD
9
+
10
+ ## [0.4.0] - 2026-03-08
9
11
 
10
- ### Added
12
+ - Extract out Configuration to define global configuration for all enum fields
13
+ - Rename `validate` option to `validatable` to better reflect its purpose
14
+ - Rename `scope` option to `scopeable` to better reflect its purpose
15
+ - Rename `allow_nil` option to `nullable` to better reflect its purpose
16
+ - Add `inquirable` option to control the generation of inquiry methods
17
+ - Polymorphic validation now respects `nullable` option and falls back to the association's `optional` setting
18
+ - Update release script to keep CHANGELOG.md up to date
19
+ - Add Continuous Integration suite to run tests and style checks
20
+ - Update rake release to run release script
21
+
22
+ ## [0.3.2] - 2026-03-08
11
23
 
12
24
  - Restored CHANGELOG.md file
13
25
 
14
26
  ## [0.3.1] - 2026-03-08
15
27
 
16
- ### Added
17
-
18
28
  - Release script to simplify gem deployment
19
29
 
20
30
  ## [0.3.0] - 2026-03-08
21
31
 
22
- ### Added
23
-
24
32
  - Virtual attribute support — enum metadata, property, and inquiry methods now work against user-defined methods that aren't backed by a database column
25
33
  - `scope: false` option to skip scope generation (required for virtual attributes, but useful independently)
26
34
 
27
35
  ## [0.2.1] - 2026-02-25
28
36
 
29
- ### Added
30
-
31
37
  - Flexibility to array definitions, supporting more input formats
32
38
 
33
39
  ## [0.2.0] - 2026-02-24
34
40
 
35
- ### Added
36
-
37
41
  - Namespace support for standalone enum field registration via `EnumFields.namespace(:name) { enum_field ... }`, decoupling definitions from ActiveRecord models
38
42
  - `EnumFields.catalog` method for a sorted, serialization-friendly view of all registered definitions across model and standalone namespaces
39
43
 
40
44
  ## [0.1.2] - 2026-02-20
41
45
 
42
- ### Added
43
-
44
46
  - Global `EnumFields::Registry` for cross-model enum field lookup and introspection
45
47
 
46
48
  ## [0.1.1] - 2026-02-02
47
49
 
48
- ### Fixed
49
-
50
50
  - Polymorphic association resolution now falls back to finding by value when key lookup fails
51
51
 
52
52
  ## [0.1.0] - 2026-01-27
53
53
 
54
- ### Added
55
-
56
54
  - `validate: false` option to disable validations on an enum field
57
55
  - Validation support for columns used in polymorphic associations
58
56
 
59
57
  ## [0.0.5] - 2026-01-03
60
58
 
61
- ### Added
62
-
63
59
  - Class-level value accessors for enum field definitions
64
60
 
65
61
  ## [0.0.4] - 2025-11-19
66
62
 
67
- ### Changed
68
-
69
63
  - `enum_fields_metadata` now returns `HashWithIndifferentAccess` instead of a plain hash
70
64
 
71
65
  ## [0.0.3] - 2025-11-19
72
66
 
73
- ### Added
74
-
75
67
  - `enum_fields_metadata` instance method for accessing field metadata on model instances
76
-
77
- ### Changed
78
-
79
68
  - Extracted core interface functionality into separate `Base` module
80
69
 
81
70
  ## [0.0.2] - 2025-11-19
82
71
 
83
- ### Added
84
-
85
72
  - `enum_field?` class method to check whether a given attribute is a registered enum field
86
73
 
87
74
  ## [0.0.1] - 2025-11-17
88
75
 
89
- ### Added
90
-
91
76
  - Initial release with core `enum_field` DSL
92
77
  - Hash and array definition formats
93
78
  - Column override support
data/README.md CHANGED
@@ -21,6 +21,45 @@ And then execute:
21
21
  bundle install
22
22
  ```
23
23
 
24
+ ## Configuration
25
+
26
+ ### Global Configuration
27
+
28
+ Configure default behavior for all `enum_field` declarations:
29
+
30
+ ```ruby
31
+ # config/initializers/enum_fields.rb
32
+ EnumFields.configure do |config|
33
+ config.scopeable = true # default: true
34
+ config.validatable = true # default: true
35
+ config.nullable = true # default: true
36
+ config.inquirable = true # default: true
37
+ end
38
+ ```
39
+
40
+ | Option | Default | Description |
41
+ | --- | --- | --- |
42
+ | `scopeable` | `true` | Generate query scopes for each enum value |
43
+ | `validatable` | `true` | Add inclusion validation for enum values |
44
+ | `nullable` | `true` | Allow `nil` values in validation (polymorphic columns derive this from the association's `optional` flag instead) |
45
+ | `inquirable` | `true` | Generate `?` inquiry methods for each enum value |
46
+
47
+ Individual `enum_field` options override global configuration:
48
+
49
+ ```ruby
50
+ EnumFields.configure do |config|
51
+ config.scopeable = false
52
+ end
53
+
54
+ class Campaign < ApplicationRecord
55
+ # Uses global scopeable: false
56
+ enum_field :stage, definitions
57
+
58
+ # Overrides global — scopes are generated for this field
59
+ enum_field :priority, definitions, scopeable: true
60
+ end
61
+ ```
62
+
24
63
  ## Usage
25
64
 
26
65
  ### Basic Setup
@@ -215,7 +254,7 @@ Campaign.completed_stage
215
254
 
216
255
  #### Validation
217
256
 
218
- Automatically validates that the column value is included in the defined values (with `allow_nil: true`).
257
+ Automatically validates that the column value is included in the defined values. By default, `nil` values are allowed (see [`nullable`](#nullable) option).
219
258
 
220
259
  ### Options
221
260
 
@@ -227,25 +266,62 @@ Map the accessor to a different database column name:
227
266
  enum_field :role, definitions, column: :user_role
228
267
  ```
229
268
 
230
- #### `scope`
269
+ #### `scopeable`
231
270
 
232
271
  Controls whether query scopes are generated. Defaults to `true`. Set to `false` to skip scope generation:
233
272
 
234
273
  ```ruby
235
- enum_field :speed, definitions, scope: false
274
+ enum_field :speed, definitions, scopeable: false
236
275
  ```
237
276
 
238
- #### `validate`
277
+ #### `validatable`
239
278
 
240
279
  Controls whether inclusion validation is added. Defaults to `true`. Set to `false` to skip validation:
241
280
 
242
281
  ```ruby
243
- enum_field :speed, definitions, validate: false
282
+ enum_field :speed, definitions, validatable: false
283
+ ```
284
+
285
+ #### `nullable`
286
+
287
+ Controls whether `nil` values pass validation. Defaults to `true`. Set to `false` to require a value:
288
+
289
+ ```ruby
290
+ enum_field :speed, definitions, nullable: false
291
+ ```
292
+
293
+ For polymorphic columns, nullability is derived from the association's `optional` flag rather than the global default. A `belongs_to` with `optional: true` allows nil; without it, nil is rejected. An explicit `nullable` option on the field still takes precedence:
294
+
295
+ ```ruby
296
+ class Comment < ApplicationRecord
297
+ belongs_to :commentable, polymorphic: true, optional: true
298
+
299
+ # nil allowed — derived from optional: true
300
+ enum_field :commentable_type, definitions
301
+ end
302
+
303
+ class Attachment < ApplicationRecord
304
+ belongs_to :attachable, polymorphic: true
305
+
306
+ # nil rejected — association is required by default
307
+ enum_field :attachable_type, definitions
308
+
309
+ # Override: allow nil despite required association
310
+ enum_field :attachable_type, definitions, nullable: true
311
+ end
312
+ ```
313
+
314
+ #### `inquirable`
315
+
316
+ Controls whether `?` inquiry methods are generated. Defaults to `true`. Set to `false` to skip:
317
+
318
+ ```ruby
319
+ enum_field :speed, definitions, inquirable: false
244
320
  ```
245
321
 
246
322
  ### Virtual Attributes
247
323
 
248
- `enum_field` works with computed/virtual attributes that aren't backed by a database column. Define a method on the model and use `scope: false` and `validate: false` since those features require a real column:
324
+ `enum_field` works with computed/virtual attributes that aren't backed by a database column. Define a method on the model and use `scopeable: false` and `validatable: false` since those features require a real column:
249
325
 
250
326
  ```ruby
251
327
  class Segment < ApplicationRecord
@@ -262,7 +338,7 @@ class Segment < ApplicationRecord
262
338
  value: "large",
263
339
  label: "Large (< 10K)",
264
340
  },
265
- }, scope: false, validate: false
341
+ }, scopeable: false, validatable: false
266
342
 
267
343
  def size_category
268
344
  case profiles_count
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module EnumFields
4
+ class Configuration
5
+ DEFAULTS = {
6
+ scopeable: true,
7
+ validatable: true,
8
+ nullable: true,
9
+ inquirable: true,
10
+ }.freeze
11
+
12
+ attr_accessor :scopeable, :validatable, :nullable, :inquirable
13
+
14
+ def initialize
15
+ reset!
16
+ end
17
+
18
+ def reset!
19
+ DEFAULTS.each { |key, value| public_send("#{key}=", value) }
20
+ end
21
+ end
22
+ end
@@ -133,6 +133,8 @@ module EnumFields
133
133
  end
134
134
 
135
135
  def define_inquiry_methods!
136
+ return unless column_inquirable?
137
+
136
138
  accessor = @accessor
137
139
  column_name = @column_name
138
140
 
@@ -158,8 +160,9 @@ module EnumFields
158
160
  def define_validation!
159
161
  return unless column_validatable?
160
162
 
161
- if column_polymorphic_association_name.present?
162
- define_polymorphic_validation!
163
+ reflection = polymorphic_reflection
164
+ if reflection
165
+ define_polymorphic_validation!(reflection)
163
166
  else
164
167
  define_standard_validation!
165
168
  end
@@ -167,15 +170,17 @@ module EnumFields
167
170
 
168
171
  def define_standard_validation!
169
172
  valid_values = @definition.values.pluck(:value)
173
+ allow_nil = resolve_option(:nullable)
170
174
 
171
175
  @model_class.validates(@column_name, inclusion: {
172
176
  in: valid_values,
173
- allow_nil: true,
177
+ allow_nil: allow_nil,
174
178
  })
175
179
  end
176
180
 
177
- def define_polymorphic_validation!
178
- association_name = column_polymorphic_association_name
181
+ def define_polymorphic_validation!(reflection)
182
+ association_name = reflection.name
183
+ allow_nil = resolve_polymorphic_nullable(reflection)
179
184
  column_name = @column_name
180
185
  accessor = @accessor
181
186
 
@@ -187,29 +192,43 @@ module EnumFields
187
192
  errors.add(association_name, "must be one of: #{valid_values.join(', ')}") unless valid_values.include?(association_obj.class.name)
188
193
  else
189
194
  column_value = attributes[column_name.to_s]
190
- next if column_value.nil?
195
+ next if column_value.nil? && allow_nil
191
196
 
192
197
  errors.add(column_name, "must be one of: #{valid_values.join(', ')}") unless valid_values.include?(column_value)
193
198
  end
194
199
  end
195
200
  end
196
201
 
197
- def column_polymorphic_association_name
202
+ def polymorphic_reflection
198
203
  return nil unless @model_class.respond_to?(:reflect_on_all_associations)
199
204
 
200
- reflection = @model_class.reflect_on_all_associations(:belongs_to).find do |r|
205
+ @model_class.reflect_on_all_associations(:belongs_to).find do |r|
201
206
  r.options[:polymorphic] && "#{r.name}_type" == @column_name.to_s
202
207
  end
208
+ end
203
209
 
204
- reflection&.name
210
+ def resolve_polymorphic_nullable(reflection)
211
+ return @options[:nullable] if @options.key?(:nullable)
212
+
213
+ reflection.options.fetch(:optional, false)
205
214
  end
206
215
 
207
216
  def column_scopeable?
208
- @definition.present? && @options.fetch(:scope, true)
217
+ @definition.present? && resolve_option(:scopeable)
209
218
  end
210
219
 
211
220
  def column_validatable?
212
- @definition.present? && @options.fetch(:validate, true)
221
+ @definition.present? && resolve_option(:validatable)
222
+ end
223
+
224
+ def column_inquirable?
225
+ @definition.present? && resolve_option(:inquirable)
226
+ end
227
+
228
+ def resolve_option(key)
229
+ return @options[key] if @options.key?(key)
230
+
231
+ EnumFields.configuration.public_send(key)
213
232
  end
214
233
  end
215
234
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module EnumFields
4
- VERSION = "0.3.2"
4
+ VERSION = "0.4.0"
5
5
  end
data/lib/enum_fields.rb CHANGED
@@ -8,6 +8,7 @@ require "active_support/core_ext/array/extract_options"
8
8
  require "active_support/inflector"
9
9
  require "active_record"
10
10
 
11
+ require_relative "enum_fields/configuration"
11
12
  require_relative "enum_fields/errors"
12
13
  require_relative "enum_fields/version"
13
14
  require_relative "enum_fields/base"
@@ -21,6 +22,18 @@ module EnumFields
21
22
  autoload :Namespace
22
23
  autoload :Registry
23
24
 
25
+ def self.configuration
26
+ @configuration ||= Configuration.new
27
+ end
28
+
29
+ def self.configure
30
+ yield(configuration)
31
+ end
32
+
33
+ def self.reset_configuration!
34
+ @configuration = Configuration.new
35
+ end
36
+
24
37
  def self.registry
25
38
  @registry ||= Registry.new
26
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enum_fields
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kinnell Shah
@@ -65,6 +65,7 @@ files:
65
65
  - README.md
66
66
  - lib/enum_fields.rb
67
67
  - lib/enum_fields/base.rb
68
+ - lib/enum_fields/configuration.rb
68
69
  - lib/enum_fields/definition.rb
69
70
  - lib/enum_fields/enum_field.rb
70
71
  - lib/enum_fields/errors.rb