Skip to content

Commit

Permalink
[Fix rubocop#451] Fix a false negative for Rails/RelativeDateConstant
Browse files Browse the repository at this point in the history
Fixes rubocop#451.

This commit fixes a false negative for `Rails/RelativeDateConstant` when
a method is chained after a relative date method.
  • Loading branch information
koic committed Mar 25, 2021
1 parent f3a0097 commit 2ec8ce4
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 14 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
* [#421](https://github.com/rubocop/rubocop-rails/issues/421): Fix incorrect auto-correct for `Rails/LinkToBlank` when using `target: '_blank'` with hash brackets for the option. ([@koic][])
* [#436](https://github.com/rubocop/rubocop-rails/issues/436): Fix a false positive for `Rails/ContentTag` when the first argument is a splat argument. ([@koic][])
* [#435](https://github.com/rubocop/rubocop-rails/issues/435): Fix a false negative for `Rails/BelongsTo` when using `belongs_to` lambda block with `required` option. ([@koic][])
* [#451](https://github.com/rubocop/rubocop-rails/issues/451): Fix a false negative for `Rails/RelativeDateConstant` when a method is chained after a relative date method. ([@koic][])

### Changes

Expand Down
29 changes: 15 additions & 14 deletions lib/rubocop/cop/rails/relative_date_constant.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,16 @@ class RelativeDateConstant < Base

MSG = 'Do not assign %<method_name>s to constants as it ' \
'will be evaluated only once.'
RELATIVE_DATE_METHODS = %i[since from_now after ago until before].freeze

def on_casgn(node)
relative_date_assignment?(node) do |method_name|
add_offense(node, message: message(method_name)) do |corrector|
autocorrect(corrector, node)
return if node.children[2]&.block_type?

node.each_descendant(:send) do |send_node|
relative_date?(send_node) do |method_name|
add_offense(node, message: message(method_name)) do |corrector|
autocorrect(corrector, node)
end
end
end
end
Expand Down Expand Up @@ -88,23 +93,19 @@ def offense_range(name, value)
range_between(name.loc.expression.begin_pos, value.loc.expression.end_pos)
end

def_node_matcher :relative_date_assignment?, <<~PATTERN
{
(casgn _ _ (send _ ${:since :from_now :after :ago :until :before}))
(casgn _ _ ({erange irange} _ (send _ ${:since :from_now :after :ago :until :before})))
(casgn _ _ ({erange irange} (send _ ${:since :from_now :after :ago :until :before}) _))
}
PATTERN
def relative_date_method?(method_name)
RELATIVE_DATE_METHODS.include?(method_name)
end

def_node_matcher :relative_date_or_assignment?, <<~PATTERN
(:or_asgn (casgn _ _) (send _ ${:since :from_now :after :ago :until :before}))
(:or_asgn (casgn _ _) (send _ $#relative_date_method?))
PATTERN

def_node_matcher :relative_date?, <<~PATTERN
{
({erange irange} _ (send _ ${:since :from_now :after :ago :until :before}))
({erange irange} (send _ ${:since :from_now :after :ago :until :before}) _)
(send _ ${:since :from_now :after :ago :until :before})
({erange irange} _ (send _ $#relative_date_method?))
({erange irange} (send _ $#relative_date_method?) _)
(send _ $#relative_date_method?)
}
PATTERN
end
Expand Down
17 changes: 17 additions & 0 deletions spec/rubocop/cop/rails/relative_date_constant_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ def self.expired_at
RUBY
end

it 'registers and corrects an offense when a method is chained after a relative date method' do
expect_offense(<<~RUBY)
class SomeClass
START_DATE = 2.weeks.ago.to_date
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Do not assign ago to constants as it will be evaluated only once.
end
RUBY

expect_correction(<<~RUBY)
class SomeClass
def self.start_date
2.weeks.ago.to_date
end
end
RUBY
end

it 'registers an offense for exclusive end range' do
expect_offense(<<~RUBY)
class SomeClass
Expand Down

0 comments on commit 2ec8ce4

Please sign in to comment.