Skip to content

Commit

Permalink
[Fix #9025] Add AllowedMethods to Lint/ConstantDefinitionInBlock
Browse files Browse the repository at this point in the history
Fixes #9025.

This PR adds `AllowedMethods` option to `Lint/ConstantDefinitionInBlock`.

The following example can be allowed by configuring `AllowedMethods`.

```ruby
class TestEnum < T::Enum
  enums do
    Foo = new("foo")
  end
end
```

Example configuration:

```yaml
# .rubocop.yml
Lint/ConstantDefinitionInBlock:
  AllowedMethods:
    - enums
```
  • Loading branch information
koic authored and bbatsov committed Nov 11, 2020
1 parent 28649d7 commit 406243e
Show file tree
Hide file tree
Showing 5 changed files with 117 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9025](https://github.com/rubocop-hq/rubocop/issues/9025): Add `AllowedMethods` option to `Lint/ConstantDefinitionInBlock`. ([@koic][])
2 changes: 2 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1400,6 +1400,8 @@ Lint/ConstantDefinitionInBlock:
StyleGuide: '#no-constant-definition-in-block'
Enabled: true
VersionAdded: '0.91'
VersionChanged: '1.3'
AllowedMethods: []

Lint/ConstantResolution:
Description: 'Check that constants are fully qualified with `::`.'
Expand Down
24 changes: 23 additions & 1 deletion docs/modules/ROOT/pages/cops_lint.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ end
| Yes
| No
| 0.91
| -
| 1.3
|===

Do not define constants within a block, since the block's scope does not
Expand Down Expand Up @@ -415,6 +415,28 @@ module M
end
----

==== AllowedMethods: ['enums']

[source,ruby]
----
# good
class TestEnum < T::Enum
enums do
Foo = new("foo")
end
end
----

=== Configurable attributes

|===
| Name | Default value | Configurable values

| AllowedMethods
| `[]`
| Array
|===

=== References

* https://rubystyle.guide#no-constant-definition-in-block
Expand Down
25 changes: 23 additions & 2 deletions lib/rubocop/cop/lint/constant_definition_in_block.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,18 @@ module Lint
# const_set(:LIST, [])
# end
# end
#
# @example AllowedMethods: ['enums']
# # good
# class TestEnum < T::Enum
# enums do
# Foo = new("foo")
# end
# end
#
class ConstantDefinitionInBlock < Base
include AllowedMethods

MSG = 'Do not define constants this way within a block.'

def_node_matcher :constant_assigned_in_block?, <<~PATTERN
Expand All @@ -61,13 +72,23 @@ class ConstantDefinitionInBlock < Base
PATTERN

def on_casgn(node)
add_offense(node) if constant_assigned_in_block?(node)
return if !constant_assigned_in_block?(node) || allowed_method?(method_name(node))

add_offense(node)
end

def on_class(node)
add_offense(node) if module_defined_in_block?(node)
return if !module_defined_in_block?(node) || allowed_method?(method_name(node))

add_offense(node)
end
alias on_module on_class

private

def method_name(node)
node.ancestors.find(&:block_type?).send_node.method_name
end
end
end
end
Expand Down
71 changes: 68 additions & 3 deletions spec/rubocop/cop/lint/constant_definition_in_block_spec.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
# frozen_string_literal: true

RSpec.describe RuboCop::Cop::Lint::ConstantDefinitionInBlock do
RSpec.describe RuboCop::Cop::Lint::ConstantDefinitionInBlock, :config do
subject(:cop) { described_class.new(config) }

let(:config) { RuboCop::Config.new }

it 'does not register an offense for a top-level constant' do
expect_no_offenses(<<~RUBY)
FOO = 1
Expand Down Expand Up @@ -134,4 +132,71 @@ module Foo; end
end
RUBY
end

context 'when `AllowedMethods: [enums]`' do
let(:cop_config) { { 'AllowedMethods' => ['enums'] } }

it 'does not register an offense for a casign used within a block of `enums` method' do
expect_no_offenses(<<~RUBY)
class TestEnum < T::Enum
enums do
Foo = new("foo")
end
end
RUBY
end

it 'does not register an offense for a class defined within a block of `enums` method' do
expect_no_offenses(<<~RUBY)
enums do
class Foo
end
end
RUBY
end

it 'does not register an offense for a module defined within a block of `enums` method' do
expect_no_offenses(<<~RUBY)
enums do
module Foo
end
end
RUBY
end
end

context 'when `AllowedMethods: []`' do
let(:cop_config) { { 'AllowedMethods' => [] } }

it 'registers an offense for a casign used within a block of `enums` method' do
expect_offense(<<~RUBY)
class TestEnum < T::Enum
enums do
Foo = new("foo")
^^^^^^^^^^^^^^^^ Do not define constants this way within a block.
end
end
RUBY
end

it 'registers an offense for a class defined within a block of `enums` method' do
expect_offense(<<~RUBY)
enums do
class Foo
^^^^^^^^^ Do not define constants this way within a block.
end
end
RUBY
end

it 'registers an offense for a module defined within a block of `enums` method' do
expect_offense(<<~RUBY)
enums do
module Foo
^^^^^^^^^^ Do not define constants this way within a block.
end
end
RUBY
end
end
end

0 comments on commit 406243e

Please sign in to comment.