enumerate_it 4.1.0 → 4.2.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: 0e0e2aa1d31c14c5e310f50feb06824c19e7bffa49d08ab1f29d8f3a9b45e32d
4
- data.tar.gz: a6e1642362885b5e306c713dd54c859452c2392bb17c012e039c84bd8878f9e9
3
+ metadata.gz: 9bfa9b8d0d7c06bf9c2d19dd7a41824a27a5e8e4ed6c8ba5cdc8a32b4ea1fb79
4
+ data.tar.gz: 1b34d10ee5220f0e123cfb3479bca25e319f78fd6d98a39edb35d73385d3d11d
5
5
  SHA512:
6
- metadata.gz: ea12eb1fe75185a0525f0580906391e37d5b540bcc09f273a2cac96c7e168994b184f549c54cd04af9940452355fd159d449c199db5855cdf0b0b03c209dd8f6
7
- data.tar.gz: f2793a073ffb559e162970e069bc5136d08b03e74dd77f885c1f27d041c48c7d25fb83de9c982bcfb4e1105149635272db5ef8ee4d86c228666c87318baae765
6
+ metadata.gz: c2021954323a6cb5b9c16534998bf240036dad2ba1af4c78936af9048f6ee1dd105d99340300684e72a6182e9fe75134fe2df88a3da1fddf86564d078cfcb3f3
7
+ data.tar.gz: 339d92259a7fa059dd10e5a4531a76005524e0ce34fe921c6f11a4de0108efa3f94aa827ef30ebb4b1c75fbdbc07b7735195f0aae81fd7c569817ee85ddd937c
@@ -14,6 +14,7 @@ jobs:
14
14
  - 3.2
15
15
  - 3.3
16
16
  - 3.4
17
+ - 4.0
17
18
  gemfile:
18
19
  - gemfiles/rails_6.0.gemfile
19
20
  - gemfiles/rails_6.1.gemfile
@@ -21,12 +22,24 @@ jobs:
21
22
  - gemfiles/rails_7.1.gemfile
22
23
  - gemfiles/rails_7.2.gemfile
23
24
  - gemfiles/rails_8.0.gemfile
25
+ - gemfiles/rails_8.1.gemfile
24
26
  exclude:
25
- # Rails 8 requires Ruby 3.2 or newer
27
+ # Rails 8+ requires Ruby 3.2 or newer
26
28
  - ruby: 3.0
27
29
  gemfile: gemfiles/rails_8.0.gemfile
30
+ - ruby: 3.0
31
+ gemfile: gemfiles/rails_8.1.gemfile
28
32
  - ruby: 3.1
29
33
  gemfile: gemfiles/rails_8.0.gemfile
34
+ - ruby: 3.1
35
+ gemfile: gemfiles/rails_8.1.gemfile
36
+ # Rails 6.x and 7.0 are EOL and don't support Ruby 4+
37
+ - ruby: 4.0
38
+ gemfile: gemfiles/rails_6.0.gemfile
39
+ - ruby: 4.0
40
+ gemfile: gemfiles/rails_6.1.gemfile
41
+ - ruby: 4.0
42
+ gemfile: gemfiles/rails_7.0.gemfile
30
43
 
31
44
  env:
32
45
  BUNDLE_GEMFILE: "${{ matrix.gemfile }}"
@@ -35,7 +48,7 @@ jobs:
35
48
 
36
49
  steps:
37
50
  - name: Checkout
38
- uses: actions/checkout@v4
51
+ uses: actions/checkout@v6
39
52
  - name: Set up Ruby
40
53
  uses: ruby/setup-ruby@v1
41
54
  with:
@@ -43,7 +56,7 @@ jobs:
43
56
  bundler-cache: true
44
57
 
45
58
  - name: Rubocop
46
- if: ${{ matrix.ruby == '3.4' }}
59
+ if: ${{ matrix.ruby == '4.0' }}
47
60
  run: "bundle exec rubocop"
48
61
 
49
62
  - name: Tests
data/.prettierrc.json ADDED
@@ -0,0 +1,4 @@
1
+ {
2
+ "printWidth": 80,
3
+ "proseWrap": "always"
4
+ }
data/.rubocop.yml CHANGED
@@ -8,7 +8,7 @@ inherit_mode:
8
8
 
9
9
  AllCops:
10
10
  NewCops: enable
11
- TargetRubyVersion: 3.4
11
+ TargetRubyVersion: 3.0 # Keep in sync with `required_ruby_version` in the gemspec.
12
12
 
13
13
  Exclude:
14
14
  - 'lib/generators/enumerate_it/enum/templates/**/*'
@@ -67,7 +67,11 @@ Style/HashTransformKeys:
67
67
  Style/HashTransformValues:
68
68
  Enabled: true
69
69
 
70
- Naming/PredicateName:
70
+ Style/OneClassPerFile:
71
+ Exclude:
72
+ - 'spec/support//**/*'
73
+
74
+ Naming/PredicatePrefix:
71
75
  Exclude:
72
76
  - 'lib/enumerate_it/class_methods.rb'
73
77
 
data/Appraisals CHANGED
@@ -4,7 +4,7 @@ require 'json'
4
4
  rails_versions = JSON.parse(Net::HTTP.get(URI('https://rubygems.org/api/v1/versions/rails.json')))
5
5
  .group_by { |version| version['number'] }.keys.grep_v(/rc|racecar|alpha|beta|pre/)
6
6
 
7
- %w[6.0 6.1 7.0 7.1 7.2 8.0].each do |rails_version|
7
+ %w[6.0 6.1 7.0 7.1 7.2 8.0 8.1].each do |rails_version|
8
8
  appraise "rails_#{rails_version}" do
9
9
  current_version = rails_versions
10
10
  .select { |key| key.match(/\A#{rails_version}/) }
data/Gemfile.lock CHANGED
@@ -1,26 +1,26 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- enumerate_it (4.1.0)
4
+ enumerate_it (4.2.0)
5
5
  activesupport (>= 6.0.0)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
9
9
  specs:
10
- activemodel (8.0.2)
11
- activesupport (= 8.0.2)
12
- activerecord (8.0.2)
13
- activemodel (= 8.0.2)
14
- activesupport (= 8.0.2)
10
+ activemodel (8.1.3)
11
+ activesupport (= 8.1.3)
12
+ activerecord (8.1.3)
13
+ activemodel (= 8.1.3)
14
+ activesupport (= 8.1.3)
15
15
  timeout (>= 0.4.0)
16
- activesupport (8.0.2)
16
+ activesupport (8.1.3)
17
17
  base64
18
- benchmark (>= 0.3)
19
18
  bigdecimal
20
19
  concurrent-ruby (~> 1.0, >= 1.3.1)
21
20
  connection_pool (>= 2.2.5)
22
21
  drb
23
22
  i18n (>= 1.6, < 2)
23
+ json
24
24
  logger (>= 1.4.2)
25
25
  minitest (>= 5.1)
26
26
  securerandom (>= 0.3)
@@ -31,80 +31,86 @@ GEM
31
31
  rake
32
32
  thor (>= 0.14.0)
33
33
  ast (2.4.3)
34
- base64 (0.2.0)
35
- benchmark (0.4.0)
36
- bigdecimal (3.1.9)
34
+ base64 (0.3.0)
35
+ bigdecimal (4.1.2)
37
36
  coderay (1.1.3)
38
- concurrent-ruby (1.3.5)
39
- connection_pool (2.5.3)
40
- diff-lcs (1.6.1)
41
- drb (2.2.1)
42
- i18n (1.14.7)
37
+ concurrent-ruby (1.3.6)
38
+ connection_pool (3.0.2)
39
+ diff-lcs (1.6.2)
40
+ drb (2.2.3)
41
+ i18n (1.14.8)
43
42
  concurrent-ruby (~> 1.0)
44
- json (2.11.3)
45
- language_server-protocol (3.17.0.4)
43
+ io-console (0.8.2)
44
+ json (2.19.8)
45
+ language_server-protocol (3.17.0.5)
46
46
  lint_roller (1.1.0)
47
47
  logger (1.7.0)
48
48
  method_source (1.1.0)
49
- mini_portile2 (2.8.8)
50
- minitest (5.25.5)
51
- parallel (1.27.0)
52
- parser (3.3.8.0)
49
+ mini_portile2 (2.8.9)
50
+ minitest (6.0.6)
51
+ drb (~> 2.0)
52
+ prism (~> 1.5)
53
+ parallel (2.1.0)
54
+ parser (3.3.11.1)
53
55
  ast (~> 2.4.1)
54
56
  racc
55
- prism (1.4.0)
56
- pry (0.15.2)
57
+ prism (1.9.0)
58
+ pry (0.16.0)
57
59
  coderay (~> 1.1)
58
60
  method_source (~> 1.0)
61
+ reline (>= 0.6.0)
59
62
  racc (1.8.1)
60
63
  rainbow (3.1.1)
61
- rake (13.2.1)
62
- regexp_parser (2.10.0)
63
- rspec (3.13.0)
64
+ rake (13.4.2)
65
+ regexp_parser (2.12.0)
66
+ reline (0.6.3)
67
+ io-console (~> 0.5)
68
+ rspec (3.13.2)
64
69
  rspec-core (~> 3.13.0)
65
70
  rspec-expectations (~> 3.13.0)
66
71
  rspec-mocks (~> 3.13.0)
67
- rspec-core (3.13.3)
72
+ rspec-core (3.13.6)
68
73
  rspec-support (~> 3.13.0)
69
- rspec-expectations (3.13.3)
74
+ rspec-expectations (3.13.5)
70
75
  diff-lcs (>= 1.2.0, < 2.0)
71
76
  rspec-support (~> 3.13.0)
72
- rspec-mocks (3.13.2)
77
+ rspec-mocks (3.13.8)
73
78
  diff-lcs (>= 1.2.0, < 2.0)
74
79
  rspec-support (~> 3.13.0)
75
- rspec-support (3.13.2)
76
- rubocop (1.75.4)
80
+ rspec-support (3.13.7)
81
+ rubocop (1.87.0)
77
82
  json (~> 2.3)
78
83
  language_server-protocol (~> 3.17.0.2)
79
84
  lint_roller (~> 1.1.0)
80
- parallel (~> 1.10)
85
+ parallel (>= 1.10)
81
86
  parser (>= 3.3.0.2)
82
87
  rainbow (>= 2.2.2, < 4.0)
83
88
  regexp_parser (>= 2.9.3, < 3.0)
84
- rubocop-ast (>= 1.44.0, < 2.0)
89
+ rubocop-ast (>= 1.49.0, < 2.0)
85
90
  ruby-progressbar (~> 1.7)
86
91
  unicode-display_width (>= 2.4.0, < 4.0)
87
- rubocop-ast (1.44.1)
92
+ rubocop-ast (1.49.1)
88
93
  parser (>= 3.3.7.2)
89
- prism (~> 1.4)
94
+ prism (~> 1.7)
90
95
  rubocop-rake (0.7.1)
91
96
  lint_roller (~> 1.1)
92
97
  rubocop (>= 1.72.1)
93
- rubocop-rspec (3.6.0)
98
+ rubocop-rspec (3.10.2)
94
99
  lint_roller (~> 1.1)
95
- rubocop (~> 1.72, >= 1.72.1)
100
+ regexp_parser (>= 2.0)
101
+ rubocop (~> 1.86, >= 1.86.2)
96
102
  ruby-progressbar (1.13.0)
97
103
  securerandom (0.4.1)
98
- sqlite3 (1.7.3)
104
+ sqlite3 (2.9.5)
99
105
  mini_portile2 (~> 2.8.0)
100
- thor (1.3.2)
101
- timeout (0.4.3)
106
+ thor (1.5.0)
107
+ timeout (0.6.1)
102
108
  tzinfo (2.0.6)
103
109
  concurrent-ruby (~> 1.0)
104
- unicode-display_width (3.1.4)
105
- unicode-emoji (~> 4.0, >= 4.0.4)
106
- unicode-emoji (4.0.4)
107
- uri (1.0.3)
110
+ unicode-display_width (3.2.0)
111
+ unicode-emoji (~> 4.1)
112
+ unicode-emoji (4.2.0)
113
+ uri (1.1.1)
108
114
 
109
115
  PLATFORMS
110
116
  ruby
@@ -120,7 +126,7 @@ DEPENDENCIES
120
126
  rubocop
121
127
  rubocop-rake
122
128
  rubocop-rspec
123
- sqlite3 (< 2)
129
+ sqlite3
124
130
 
125
131
  BUNDLED WITH
126
- 2.6.6
132
+ 4.0.3
data/README.md CHANGED
@@ -17,6 +17,32 @@ This means you can add it to any **Ruby** project! Secondly, you can
17
17
  [define your enumerations in classes](#creating-enumerations), allowing you to
18
18
  **add behavior** and **reuse** them! 😀
19
19
 
20
+ At a glance:
21
+
22
+ ```ruby
23
+ class RelationshipStatus < EnumerateIt::Base
24
+ associate_values :single, :married, :divorced
25
+
26
+ custom_helpers do
27
+ def ever_married?(value)
28
+ [MARRIED, DIVORCED].include?(value)
29
+ end
30
+ end
31
+ end
32
+
33
+ class Person < ApplicationRecord
34
+ has_enumeration_for :relationship_status, create_helpers: true, create_scopes: true
35
+ end
36
+
37
+ person = Person.new(relationship_status: RelationshipStatus::MARRIED)
38
+
39
+ person.married? #=> true
40
+ person.ever_married? #=> true
41
+ person.relationship_status_humanize #=> 'Married'
42
+ Person.married.to_sql #=> SELECT "people".* FROM "people" WHERE "people"."relationship_status" = "married"
43
+ RelationshipStatus.to_a #=> [['Divorced', 'divorced'], ['Married', 'married'], ['Single', 'single']]
44
+ ```
45
+
20
46
  ---
21
47
 
22
48
  <!-- Tocer[start]: Auto-generated, don't remove. -->
@@ -206,10 +232,13 @@ class Person
206
232
  end
207
233
  ```
208
234
 
209
- > **Note:** If the enumeration class name differs from the attribute name, use
210
- > the `with` option:
235
+ <!-- prettier-ignore -->
236
+ > [!NOTE]
237
+ > If the enumeration class name differs from the attribute name, use the `with` option:
211
238
  >
212
- > `has_enumeration_for :relationship_status, with: RelationshipStatus`
239
+ > ```ruby
240
+ > has_enumeration_for :relationship_status, with: RelationshipStatus
241
+ > ```
213
242
 
214
243
  This will create:
215
244
 
@@ -229,7 +258,7 @@ This will create:
229
258
  p = Person.new
230
259
  p.relationship_status = RelationshipStatus::DIVORCED
231
260
  p.relationship_status_humanize
232
- #=> 'Divorciado'
261
+ #=> 'Divorciado' # with a pt-BR locale loaded
233
262
  ```
234
263
 
235
264
  - The associated enumerations, which can be retrieved with the `enumerations`
@@ -335,6 +364,63 @@ This will create:
335
364
  #=> true
336
365
  ```
337
366
 
367
+ <!-- prettier-ignore -->
368
+ > [!IMPORTANT]
369
+ > On ActiveRecord objects, mutator methods like `married!` call `save!`
370
+ > immediately, running callbacks and raising on validation failure. They are
371
+ > not pure setters.
372
+
373
+ You can also define custom helper methods on the enumeration class using
374
+ a `custom_helpers` block:
375
+
376
+ ```ruby
377
+ class RelationshipStatus < EnumerateIt::Base
378
+ associate_values :single, :married, :divorced
379
+
380
+ custom_helpers do
381
+ def ever_married?(value)
382
+ [MARRIED, DIVORCED].include?(value)
383
+ end
384
+ end
385
+ end
386
+ ```
387
+
388
+ These become class methods on the enumeration:
389
+
390
+ ```ruby
391
+ RelationshipStatus.ever_married?(RelationshipStatus::MARRIED) #=> true
392
+ RelationshipStatus.ever_married?(RelationshipStatus::DIVORCED) #=> true
393
+ RelationshipStatus.ever_married?(RelationshipStatus::SINGLE) #=> false
394
+ ```
395
+
396
+ When `create_helpers: true` is used, they also become instance methods on the
397
+ model:
398
+
399
+ ```ruby
400
+ class Person < ApplicationRecord
401
+ has_enumeration_for :relationship_status, with: RelationshipStatus, create_helpers: true
402
+ end
403
+
404
+ person = Person.new(relationship_status: RelationshipStatus::DIVORCED)
405
+ person.ever_married? #=> true
406
+ ```
407
+
408
+ The `prefix` option also applies to custom helpers:
409
+
410
+ ```ruby
411
+ class Person < ApplicationRecord
412
+ has_enumeration_for :relationship_status,
413
+ with: RelationshipStatus, create_helpers: { prefix: true }
414
+ end
415
+
416
+ person = Person.new(relationship_status: RelationshipStatus::DIVORCED)
417
+ person.relationship_status_ever_married? #=> true
418
+ ```
419
+
420
+ Custom helper methods return `nil` when the attribute is `nil`. If a method
421
+ name collides with an already-defined class method on the enumeration, an
422
+ `ArgumentError` is raised at load time.
423
+
338
424
  - A scope method for each enumeration option if you pass the `create_scopes`
339
425
  option as `true`:
340
426
 
@@ -344,7 +430,7 @@ This will create:
344
430
  end
345
431
 
346
432
  Person.married.to_sql
347
- #=> SELECT "users".* FROM "users" WHERE "users"."relationship_status" = "married"
433
+ #=> SELECT "people".* FROM "people" WHERE "people"."relationship_status" = "married"
348
434
  ```
349
435
 
350
436
  The `:create_scopes` also accepts `prefix` option.
@@ -401,6 +487,12 @@ This will create:
401
487
  #=> true
402
488
  ```
403
489
 
490
+ <!-- prettier-ignore -->
491
+ > [!NOTE]
492
+ > `skip_validation: true` disables all validations added by EnumerateIt,
493
+ > including the presence validation from `required: true`. If both are
494
+ > passed, `skip_validation` wins and `required` is silently ignored.
495
+
404
496
  Remember that you can add validations to any kind of class and not only
405
497
  `ActiveRecord` ones.
406
498
 
@@ -431,7 +523,7 @@ Yes,
431
523
 
432
524
  ## I18n
433
525
 
434
- I18n lookup is provided for both `_humanized` and `Enumeration#to_a` methods,
526
+ I18n lookup is provided for both `_humanize` and `Enumeration#to_a` methods,
435
527
  given the hash key is a Symbol. The I18n strings are located on
436
528
  `enumerations.<enumeration_name>.<key>`:
437
529
 
@@ -453,11 +545,11 @@ end
453
545
 
454
546
  p = Person.new
455
547
  p.relationship_status = RelationshipStatus::MARRIED
456
- p.relationship_status_humanize # Existent key
548
+ p.relationship_status_humanize # Key found in the locale file
457
549
  #=> 'Casado'
458
550
 
459
551
  p.relationship_status = RelationshipStatus::SINGLE
460
- p.relationship_status_humanize # Non-existent key
552
+ p.relationship_status_humanize # Key missing, falls back to the humanized name
461
553
  #=> 'Single'
462
554
  ```
463
555
 
@@ -550,12 +642,12 @@ you can see them on the [releases page](../../releases).
550
642
  - Add tests for it. This is important so we don't break it in a future version
551
643
  unintentionally.
552
644
  - [Optional] Run the tests against a specific Gemfile:
553
- `bundle exec appraisal rails_8.0 rake spec`.
645
+ `bundle exec appraisal rails_8.1 rake spec`.
554
646
  - Run the tests against all supported versions: `bundle exec rake`
555
647
  - Commit, but please do not mess with `Rakefile`, version, or history.
556
648
  - Send a Pull Request. Bonus points for topic branches.
557
649
 
558
650
  ## Copyright
559
651
 
560
- Copyright (c) 2010-2025 Cássio Marques and Lucas Caton. See `LICENSE` file for
652
+ Copyright (c) 2010-2026 Cássio Marques and Lucas Caton. See `LICENSE` file for
561
653
  details.
data/enumerate_it.gemspec CHANGED
@@ -31,5 +31,5 @@ Gem::Specification.new do |gem|
31
31
  gem.add_development_dependency 'rubocop'
32
32
  gem.add_development_dependency 'rubocop-rake'
33
33
  gem.add_development_dependency 'rubocop-rspec'
34
- gem.add_development_dependency 'sqlite3', '< 2'
34
+ gem.add_development_dependency 'sqlite3'
35
35
  end
@@ -2,8 +2,8 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'activerecord', '~> 7.0.8.7'
6
- gem 'activesupport', '~> 7.0.8.7'
5
+ gem 'activerecord', '~> 7.0.10'
6
+ gem 'activesupport', '~> 7.0.10'
7
7
  gem 'base64'
8
8
  gem 'bigdecimal'
9
9
  gem 'mutex_m'
@@ -2,8 +2,8 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'activerecord', '~> 7.1.5.1'
6
- gem 'activesupport', '~> 7.1.5.1'
5
+ gem 'activerecord', '~> 7.1.6'
6
+ gem 'activesupport', '~> 7.1.6'
7
7
  gem 'sqlite3'
8
8
 
9
9
  gemspec path: '../'
@@ -2,8 +2,8 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'activerecord', '~> 7.2.2.1'
6
- gem 'activesupport', '~> 7.2.2.1'
5
+ gem 'activerecord', '~> 7.2.3.1'
6
+ gem 'activesupport', '~> 7.2.3.1'
7
7
  gem 'sqlite3'
8
8
 
9
9
  gemspec path: '../'
@@ -2,8 +2,8 @@
2
2
 
3
3
  source 'https://rubygems.org'
4
4
 
5
- gem 'activerecord', '~> 8.0.2'
6
- gem 'activesupport', '~> 8.0.2'
5
+ gem 'activerecord', '~> 8.0.5'
6
+ gem 'activesupport', '~> 8.0.5'
7
7
  gem 'sqlite3'
8
8
 
9
9
  gemspec path: '../'
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gem 'activerecord', '~> 8.1.3'
6
+ gem 'activesupport', '~> 8.1.3'
7
+ gem 'sqlite3'
8
+
9
+ gemspec path: '../'
@@ -51,8 +51,8 @@ module EnumerateIt
51
51
  list.map { |value| t(value) }
52
52
  end
53
53
 
54
- def each_value(&)
55
- list.each(&)
54
+ def each_value(&block)
55
+ list.each(&block)
56
56
  end
57
57
 
58
58
  def to_json(options = nil)
@@ -95,6 +95,25 @@ module EnumerateIt
95
95
  I18n.t("enumerations.#{name.underscore}.#{value.to_s.underscore}", default: default)
96
96
  end
97
97
 
98
+ def custom_helpers(&block)
99
+ @custom_helper_methods ||= []
100
+
101
+ mod = Module.new(&block)
102
+ methods = mod.instance_methods(false)
103
+ collisions = methods & singleton_class.instance_methods
104
+
105
+ raise ArgumentError, <<~MESSAGE.chomp if collisions.any?
106
+ Custom helper(s) '#{collisions.join(', ')}' would override existing EnumerateIt::Base methods
107
+ MESSAGE
108
+
109
+ @custom_helper_methods.concat(methods)
110
+ extend mod
111
+ end
112
+
113
+ def custom_helper_methods
114
+ @custom_helper_methods || []
115
+ end
116
+
98
117
  private
99
118
 
100
119
  def sorted_map
@@ -134,9 +153,7 @@ module EnumerateIt
134
153
  def values_hash(args)
135
154
  return args.first if args.first.is_a?(Hash)
136
155
 
137
- args.each_with_object({}) do |value, hash|
138
- hash[value] = value.to_s
139
- end
156
+ args.to_h { |value| [value, value.to_s] }
140
157
  end
141
158
  end
142
159
  end
@@ -1,5 +1,5 @@
1
1
  module EnumerateIt
2
- module ClassMethods
2
+ module ClassMethods # rubocop:disable Metrics/ModuleLength
3
3
  def has_enumeration_for(attribute, options = {})
4
4
  self.enumerations = enumerations.dup
5
5
 
@@ -17,7 +17,8 @@ module EnumerateIt
17
17
  set_validations(attribute, options) unless options[:skip_validation]
18
18
 
19
19
  if options[:create_helpers]
20
- %w[create_helper_methods create_mutator_methods create_polymorphic_methods].each do |method|
20
+ %w[create_helper_methods create_mutator_methods create_polymorphic_methods
21
+ create_custom_helper_methods].each do |method|
21
22
  send(method, options[:with], attribute, options[:create_helpers])
22
23
  end
23
24
  end
@@ -100,12 +101,27 @@ module EnumerateIt
100
101
  end
101
102
  end
102
103
 
104
+ def create_custom_helper_methods(klass, attribute_name, helpers)
105
+ return unless klass.custom_helper_methods.any?
106
+
107
+ prefix_name = "#{attribute_name}_" if helpers.is_a?(Hash) && helpers[:prefix]
108
+
109
+ class_eval do
110
+ klass.custom_helper_methods.each do |method_name|
111
+ define_method "#{prefix_name}#{method_name}" do
112
+ value = send(attribute_name)
113
+ klass.public_send(method_name, value) unless value.nil?
114
+ end
115
+ end
116
+ end
117
+ end
118
+
103
119
  def define_enumeration_class(attribute, options)
104
120
  return if options[:with]
105
121
 
106
122
  inner_enum_class_name = attribute.to_s.camelize.to_sym
107
123
 
108
- options[:with] = if constants.include?(inner_enum_class_name)
124
+ options[:with] = if const_defined?(inner_enum_class_name)
109
125
  const_get(inner_enum_class_name)
110
126
  else
111
127
  attribute.to_s.camelize.constantize
@@ -1,3 +1,3 @@
1
1
  module EnumerateIt
2
- VERSION = '4.1.0'.freeze
2
+ VERSION = '4.2.0'.freeze
3
3
  end
@@ -228,6 +228,55 @@ describe EnumerateIt::Base do
228
228
  end
229
229
  end
230
230
 
231
+ describe '.custom_helpers' do
232
+ context 'when methods are defined inside the block' do
233
+ it 'become class methods on the enum' do
234
+ expect(TestEnumerationWithCustomHelpers.lookup('1')).to eq(:one)
235
+ expect(TestEnumerationWithCustomHelpers.lookup('2')).to eq(:two)
236
+ expect(TestEnumerationWithCustomHelpers.boolean?('1')).to be(true)
237
+ expect(TestEnumerationWithCustomHelpers.boolean?('2')).to be(false)
238
+ end
239
+ end
240
+
241
+ context 'when a custom helper name collides with a built-in method' do
242
+ let(:build_colliding_enum) do
243
+ proc do
244
+ Class.new(EnumerateIt::Base) do
245
+ associate_values :collision
246
+
247
+ custom_helpers do
248
+ def list
249
+ '...'
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+
256
+ it 'raises an ArgumentError' do
257
+ expect(&build_colliding_enum).to raise_error(
258
+ ArgumentError,
259
+ "Custom helper(s) 'list' would override existing EnumerateIt::Base methods"
260
+ )
261
+ end
262
+ end
263
+ end
264
+
265
+ describe '.custom_helper_methods' do
266
+ context 'when methods are defined inside custom_helpers block' do
267
+ it 'returns the registered names' do
268
+ expect(TestEnumerationWithCustomHelpers.custom_helper_methods)
269
+ .to eq(%i[lookup boolean?])
270
+ end
271
+ end
272
+
273
+ context 'when there is no .custom_helpers block on an enum' do
274
+ it 'returns an empty array' do
275
+ expect(TestEnumeration.custom_helper_methods).to eq([])
276
+ end
277
+ end
278
+ end
279
+
231
280
  context 'associate values with a list' do
232
281
  it 'creates constants for each enumeration value' do
233
282
  expect(TestEnumerationWithList::FIRST).to eq('first')
@@ -289,11 +338,11 @@ describe EnumerateIt::Base do
289
338
  attr_accessor :bla
290
339
 
291
340
  class << self
292
- def validates_inclusion_of(_attribute, _options)
341
+ def validates_inclusion_of(_attribute, _options) # rubocop:disable Naming/PredicateMethod
293
342
  true
294
343
  end
295
344
 
296
- def validates_presence_of
345
+ def validates_presence_of # rubocop:disable Naming/PredicateMethod
297
346
  true
298
347
  end
299
348
  end
@@ -4,6 +4,7 @@ describe EnumerateIt do
4
4
  let :test_class do
5
5
  Class.new do
6
6
  extend EnumerateIt
7
+
7
8
  attr_accessor :foobar
8
9
 
9
10
  has_enumeration_for :foobar, with: TestEnumeration
@@ -41,6 +42,15 @@ describe EnumerateIt do
41
42
  expect(target).not_to respond_to(:value_1?)
42
43
  end
43
44
 
45
+ it 'defaults to not creating custom helper methods' do
46
+ klass = Class.new do
47
+ extend EnumerateIt
48
+
49
+ has_enumeration_for :foobar, with: TestEnumerationWithCustomHelpers
50
+ end
51
+ expect(klass.new).not_to respond_to(:lookup)
52
+ end
53
+
44
54
  it 'stores the enumeration class in a class-level hash' do
45
55
  expect(test_class.enumerations[:foobar]).to eq(TestEnumeration)
46
56
  end
@@ -71,6 +81,7 @@ describe EnumerateIt do
71
81
  let :test_class_for_enumeration_without_array do
72
82
  Class.new do
73
83
  extend EnumerateIt
84
+
74
85
  attr_accessor :foobar
75
86
 
76
87
  has_enumeration_for :foobar, with: TestEnumerationWithoutArray
@@ -102,6 +113,7 @@ describe EnumerateIt do
102
113
  let :foo_bar_class do
103
114
  Class.new do
104
115
  extend EnumerateIt
116
+
105
117
  attr_accessor :test_enumeration
106
118
 
107
119
  has_enumeration_for :test_enumeration
@@ -124,12 +136,13 @@ describe EnumerateIt do
124
136
  # rubocop:disable Lint/ConstantDefinitionInBlock
125
137
  # rubocop:disable RSpec/LeakyConstantDeclaration
126
138
  class NestedEnum < EnumerateIt::Base
127
- associate_values foo: %w[1 Blerrgh], bar: ['2' => 'Blarghhh']
139
+ associate_values foo: %w[1 Blerrgh], bar: [{ '2' => 'Blarghhh' }]
128
140
  end
129
141
  # rubocop:enable RSpec/LeakyConstantDeclaration
130
142
  # rubocop:enable Lint/ConstantDefinitionInBlock
131
143
 
132
144
  extend EnumerateIt
145
+
133
146
  attr_accessor :nested_enum
134
147
 
135
148
  has_enumeration_for :nested_enum
@@ -151,6 +164,7 @@ describe EnumerateIt do
151
164
  let :test_class_with_helper do
152
165
  Class.new do
153
166
  extend EnumerateIt
167
+
154
168
  attr_accessor :foobar
155
169
 
156
170
  has_enumeration_for :foobar, with: TestEnumeration, create_helpers: true
@@ -192,6 +206,7 @@ describe EnumerateIt do
192
206
  let :test_class_with_prefixed_helper do
193
207
  Class.new do
194
208
  extend EnumerateIt
209
+
195
210
  attr_accessor :foobar
196
211
 
197
212
  has_enumeration_for :foobar, with: TestEnumeration, create_helpers: { prefix: true }
@@ -234,6 +249,7 @@ describe EnumerateIt do
234
249
  let :polymorphic_class do
235
250
  Class.new do
236
251
  extend EnumerateIt
252
+
237
253
  attr_accessor :foo
238
254
 
239
255
  has_enumeration_for :foo, with: PolymorphicEnum, create_helpers: { polymorphic: true }
@@ -260,6 +276,7 @@ describe EnumerateIt do
260
276
  let :polymorphic_class_with_suffix do
261
277
  Class.new do
262
278
  extend EnumerateIt
279
+
263
280
  attr_accessor :foo
264
281
 
265
282
  has_enumeration_for :foo, with: PolymorphicEnum,
@@ -280,6 +297,62 @@ describe EnumerateIt do
280
297
  end
281
298
  end
282
299
  end
300
+
301
+ context 'with custom_helpers defined on the enumeration' do
302
+ context 'creates methods that delegates to the enum' do
303
+ let :test_class_with_custom_helpers do
304
+ Class.new do
305
+ extend EnumerateIt
306
+
307
+ attr_accessor :foobar
308
+
309
+ has_enumeration_for :foobar, with: TestEnumerationWithCustomHelpers,
310
+ create_helpers: true
311
+
312
+ def initialize(foobar)
313
+ @foobar = foobar
314
+ end
315
+ end
316
+ end
317
+
318
+ it 'returns value respective to attribute value' do
319
+ target = test_class_with_custom_helpers.new(TestEnumerationWithCustomHelpers::VALUE_ONE)
320
+ expect(target.lookup).to eq(:one)
321
+ expect(target.boolean?).to be(true)
322
+ end
323
+
324
+ it 'returns nil when attribute is nil' do
325
+ target = test_class_with_custom_helpers.new(nil)
326
+ expect(target.lookup).to be_nil
327
+ expect(target.boolean?).to be_nil
328
+ end
329
+ end
330
+
331
+ context 'create methods with prefix that delegates to the enum' do
332
+ let :test_class_with_prefixed_custom_helpers do
333
+ Class.new do
334
+ extend EnumerateIt
335
+
336
+ attr_accessor :foobar
337
+
338
+ has_enumeration_for :foobar, with: TestEnumerationWithCustomHelpers,
339
+ create_helpers: { prefix: true }
340
+
341
+ def initialize(foobar)
342
+ @foobar = foobar
343
+ end
344
+ end
345
+ end
346
+
347
+ it 'method is prefixed with the attribute name' do
348
+ target = test_class_with_prefixed_custom_helpers.new(TestEnumerationWithCustomHelpers::VALUE_ONE)
349
+ expect(target.foobar_lookup).to eq(:one)
350
+ expect(target.foobar_boolean?).to be(true)
351
+ expect(target).not_to respond_to(:lookup)
352
+ expect(target).not_to respond_to(:boolean?)
353
+ end
354
+ end
355
+ end
283
356
  end
284
357
 
285
358
  describe 'using the :create_scopes option' do
@@ -78,3 +78,17 @@ def create_enumeration_class_with_sort_mode(sort_mode)
78
78
  )
79
79
  end
80
80
  end
81
+
82
+ class TestEnumerationWithCustomHelpers < EnumerateIt::Base
83
+ associate_values value_one: '1', value_two: '2'
84
+
85
+ custom_helpers do
86
+ def lookup(value)
87
+ { '1' => :one, '2' => :two }[value]
88
+ end
89
+
90
+ def boolean?(value)
91
+ value == '1'
92
+ end
93
+ end
94
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: enumerate_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.0
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cássio Marques
@@ -154,16 +154,16 @@ dependencies:
154
154
  name: sqlite3
155
155
  requirement: !ruby/object:Gem::Requirement
156
156
  requirements:
157
- - - "<"
157
+ - - ">="
158
158
  - !ruby/object:Gem::Version
159
- version: '2'
159
+ version: '0'
160
160
  type: :development
161
161
  prerelease: false
162
162
  version_requirements: !ruby/object:Gem::Requirement
163
163
  requirements:
164
- - - "<"
164
+ - - ">="
165
165
  - !ruby/object:Gem::Version
166
- version: '2'
166
+ version: '0'
167
167
  description: Enumerations for Ruby with some magic powers!
168
168
  executables: []
169
169
  extensions: []
@@ -172,6 +172,7 @@ files:
172
172
  - ".github/dependabot.yml"
173
173
  - ".github/workflows/ci.yml"
174
174
  - ".gitignore"
175
+ - ".prettierrc.json"
175
176
  - ".rspec"
176
177
  - ".rubocop.yml"
177
178
  - Appraisals
@@ -188,6 +189,7 @@ files:
188
189
  - gemfiles/rails_7.1.gemfile
189
190
  - gemfiles/rails_7.2.gemfile
190
191
  - gemfiles/rails_8.0.gemfile
192
+ - gemfiles/rails_8.1.gemfile
191
193
  - lib/enumerate_it.rb
192
194
  - lib/enumerate_it/base.rb
193
195
  - lib/enumerate_it/class_methods.rb
@@ -223,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
223
225
  - !ruby/object:Gem::Version
224
226
  version: '0'
225
227
  requirements: []
226
- rubygems_version: 3.6.8
228
+ rubygems_version: 4.0.3
227
229
  specification_version: 4
228
230
  summary: Ruby Enumerations
229
231
  test_files: []