Skip to content

Commit

Permalink
Add new cop Lint/OrAssignmentToConstant
Browse files Browse the repository at this point in the history
This cop checks for unintended or-assignment to a constant.

Constants should always be assigned in the same location. And its value
should always be the same. If constants are assigned in multiple
locations, the result may vary depending on the order of `require`.

Also, if you already have such an implementation, auto-correction may
change the result.

```ruby
CONST ||= 1

CONST = 1
```
  • Loading branch information
uplus committed Jan 14, 2021
1 parent 3dc4e62 commit 93a7e0d
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5366,3 +5366,4 @@
[@ohbarye]: https://github.com/ohbarye
[@magneland]: https://github.com/magneland
[@k-karen]: https://github.com/k-karen
[@uplus]: https://github.com/uplus
1 change: 1 addition & 0 deletions changelog/new_add_new_cop_lintorassignmenttoconstant.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9363](https://github.com/rubocop-hq/rubocop/pull/9363): Add new cop `Lint/OrAssignmentToConstant`. ([@uplus][])
6 changes: 6 additions & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1811,6 +1811,12 @@ Lint/NumberedParameterAssignment:
Enabled: pending
VersionAdded: '<<next>>'

Lint/OrAssignmentToConstant:
Description: 'Checks unintended or-assignment to constant.'
Enabled: pending
Safe: false
VersionAdded: '<<next>>'

Lint/OrderedMagicComments:
Description: 'Checks the proper ordering of magic comments and whether a magic comment is not placed before a shebang.'
Enabled: true
Expand Down
1 change: 1 addition & 0 deletions lib/rubocop.rb
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@
require_relative 'rubocop/cop/lint/non_local_exit_from_iterator'
require_relative 'rubocop/cop/lint/number_conversion'
require_relative 'rubocop/cop/lint/numbered_parameter_assignment'
require_relative 'rubocop/cop/lint/or_assignment_to_constant'
require_relative 'rubocop/cop/lint/ordered_magic_comments'
require_relative 'rubocop/cop/lint/out_of_range_regexp_ref'
require_relative 'rubocop/cop/lint/parentheses_as_grouped_expression'
Expand Down
39 changes: 39 additions & 0 deletions lib/rubocop/cop/lint/or_assignment_to_constant.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# frozen_string_literal: true

module RuboCop
module Cop
module Lint
# This cop checks for unintended or-assignment to a constant.
#
# Constants should always be assigned in the same location. And its value
# should always be the same. If constants are assigned in multiple
# locations, the result may vary depending on the order of `require`.
#
# Also, if you already have such an implementation, auto-correction may
# change the result.
#
# @example
#
# # bad
# CONST ||= 1
#
# # good
# CONST = 1
#
class OrAssignmentToConstant < Base
extend AutoCorrector

MSG = 'Avoid using or-assignment with constants.'

def on_or_asgn(node)
lhs, _rhs = *node
return unless lhs&.casgn_type?

add_offense(node.loc.operator) do |corrector|
corrector.replace(node.loc.operator, '=')
end
end
end
end
end
end
36 changes: 36 additions & 0 deletions spec/rubocop/cop/lint/or_assignment_to_constant_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

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

it 'registers an offense with or-assignment to a constant' do
expect_offense(<<~RUBY)
CONST ||= 1
^^^ Avoid using or-assignment with constants.
RUBY

expect_correction(<<~RUBY)
CONST = 1
RUBY
end

it 'does not register an offense with plain assignment to a constant' do
expect_no_offenses(<<~RUBY)
CONST = 1
RUBY
end

[
['a local variable', 'var'],
['an instance variable', '@var'],
['a class variable', '@@var'],
['a global variable', '$var'],
['an attribute', 'self.var']
].each do |type, var|
it "does not register an offense with or-assignment to #{type}" do
expect_no_offenses(<<~RUBY)
#{var} ||= 1
RUBY
end
end
end

0 comments on commit 93a7e0d

Please sign in to comment.