Skip to content

Commit 1464219

Browse files
Bruno Vezolisantib
authored andcommitted
[Fix #78] Create EnumHash Cop
1 parent cdb7330 commit 1464219

File tree

7 files changed

+147
-1
lines changed

7 files changed

+147
-1
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## master (unreleased)
44

5+
### New features
6+
7+
* [#78](https://github.com/rubocop-hq/rubocop-rails/issues/78): Add new `Rails/EnumHash` cop. ([@fedeagripa][], [@brunvez][], [@santib][])
8+
59
### Bug fixes
610

711
* [#53](https://github.com/rubocop-hq/rubocop-rails/issues/53): Fix a false positive for `Rails/SaveBang` when implicitly return using finder method and creation method connected by `||`. ([@koic][])
@@ -47,3 +51,6 @@
4751
[@buehmann]: https://github.com/buehmann
4852
[@anthony-robin]: https://github.com/anthony-robin
4953
[@rmm5t]: https://github.com/rmm5t
54+
[@fedeagripa]: https://github.com/fedeagripa
55+
[@brunvez]: https://github.com/brunvez
56+
[@santib]: https://github.com/santib

config/default.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,14 @@ Rails/DynamicFindBy:
145145
Whitelist:
146146
- find_by_sql
147147

148+
Rails/EnumHash:
149+
Description: 'Prefer hash syntax over array syntax when defining enums.'
150+
StyleGuide: '#enums'
151+
Enabled: true
152+
VersionAdded: '2.3'
153+
Include:
154+
- app/models/**/*.rb
155+
148156
Rails/EnumUniqueness:
149157
Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.'
150158
Enabled: true

lib/rubocop/cop/rails/enum_hash.rb

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Rails
6+
# This cop looks for enums written with array syntax.
7+
#
8+
# When using array syntax, adding an element in a
9+
# position other than the last causes all previous
10+
# definitions to shift. Explicitly specifying the
11+
# value for each key prevents this from happening.
12+
#
13+
# @example
14+
# # bad
15+
# enum status: [:active, :archived]
16+
#
17+
# # good
18+
# enum status: { active: 0, archived: 1 }
19+
#
20+
class EnumHash < Cop
21+
MSG = 'Enum defined as an array found in `%<enum>s` enum declaration. '\
22+
'Use hash syntax instead.'
23+
24+
def_node_matcher :enum_with_array?, <<~PATTERN
25+
(send nil? :enum (hash (pair (_ $_) array)))
26+
PATTERN
27+
28+
def on_send(node)
29+
enum_with_array?(node) do |name|
30+
add_offense(node, message: format(MSG, enum: name))
31+
end
32+
end
33+
end
34+
end
35+
end
36+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
require_relative 'rails/delegate'
1818
require_relative 'rails/delegate_allow_blank'
1919
require_relative 'rails/dynamic_find_by'
20+
require_relative 'rails/enum_hash'
2021
require_relative 'rails/enum_uniqueness'
2122
require_relative 'rails/environment_comparison'
2223
require_relative 'rails/exit'

manual/cops.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
* [Rails/Delegate](cops_rails.md#railsdelegate)
1717
* [Rails/DelegateAllowBlank](cops_rails.md#railsdelegateallowblank)
1818
* [Rails/DynamicFindBy](cops_rails.md#railsdynamicfindby)
19+
* [Rails/EnumHash](cops_rails.md#railsenumhash)
1920
* [Rails/EnumUniqueness](cops_rails.md#railsenumuniqueness)
2021
* [Rails/EnvironmentComparison](cops_rails.md#railsenvironmentcomparison)
2122
* [Rails/Exit](cops_rails.md#railsexit)
@@ -54,4 +55,4 @@
5455
* [Rails/UnknownEnv](cops_rails.md#railsunknownenv)
5556
* [Rails/Validation](cops_rails.md#railsvalidation)
5657

57-
<!-- END_COP_LIST -->
58+
<!-- END_COP_LIST -->

manual/cops_rails.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,39 @@ Whitelist | `find_by_sql` | Array
642642

643643
* [https://rails.rubystyle.guide#find_by](https://rails.rubystyle.guide#find_by)
644644

645+
## Rails/EnumHash
646+
647+
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
648+
--- | --- | --- | --- | ---
649+
Enabled | Yes | No | 2.3 | -
650+
651+
This cop looks for enums written with array syntax.
652+
653+
When using array syntax, adding an element in a
654+
position other than the last causes all previous
655+
definitions to shift. Explicitly specifying the
656+
value for each key prevents this from happening.
657+
658+
### Examples
659+
660+
```ruby
661+
# bad
662+
enum status: [:active, :archived]
663+
664+
# good
665+
enum status: { active: 0, archived: 1 }
666+
```
667+
668+
### Configurable attributes
669+
670+
Name | Default value | Configurable values
671+
--- | --- | ---
672+
Include | `app/models/**/*.rb` | Array
673+
674+
### References
675+
676+
* [https://rails.rubystyle.guide#enums](https://rails.rubystyle.guide#enums)
677+
645678
## Rails/EnumUniqueness
646679

647680
Enabled by default | Safe | Supports autocorrection | VersionAdded | VersionChanged
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::EnumHash do
4+
subject(:cop) { described_class.new(config) }
5+
6+
let(:config) { RuboCop::Config.new }
7+
8+
context 'when array syntax is used' do
9+
context 'with %i[] syntax' do
10+
it 'registers an offense' do
11+
expect_offense(<<~RUBY)
12+
enum status: %i[active archived]
13+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead.
14+
RUBY
15+
end
16+
end
17+
18+
context 'with %w[] syntax' do
19+
it 'registers an offense' do
20+
expect_offense(<<~RUBY)
21+
enum status: %w[active archived]
22+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead.
23+
RUBY
24+
end
25+
end
26+
27+
context 'with %i() syntax' do
28+
it 'registers an offense' do
29+
expect_offense(<<~RUBY)
30+
enum status: %i(active archived)
31+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead.
32+
RUBY
33+
end
34+
end
35+
36+
context 'with %w() syntax' do
37+
it 'registers an offense' do
38+
expect_offense(<<~RUBY)
39+
enum status: %w(active archived)
40+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead.
41+
RUBY
42+
end
43+
end
44+
45+
context 'with [] syntax' do
46+
it 'registers an offense' do
47+
expect_offense(<<~RUBY)
48+
enum status: [:active, :archived]
49+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead.
50+
RUBY
51+
end
52+
end
53+
end
54+
55+
context 'when hash syntax is used' do
56+
it 'does not register an offense' do
57+
expect_no_offenses('enum status: { active: 0, archived: 1 }')
58+
end
59+
end
60+
end

0 commit comments

Comments
 (0)