diff --git a/changelog/fix_false_negative_for_rails_expanded_date_range.md b/changelog/fix_false_negative_for_rails_expanded_date_range.md new file mode 100644 index 0000000000..2cf8caaa27 --- /dev/null +++ b/changelog/fix_false_negative_for_rails_expanded_date_range.md @@ -0,0 +1 @@ +* [#737](https://github.com/rubocop/rubocop-rails/pull/737): Make `Rails/ExpandedDateRange` aware `beginning_of_week` with an argument. ([@koic][]) diff --git a/lib/rubocop/cop/rails/expanded_date_range.rb b/lib/rubocop/cop/rails/expanded_date_range.rb index 35f583da1c..073d41abe9 100644 --- a/lib/rubocop/cop/rails/expanded_date_range.rb +++ b/lib/rubocop/cop/rails/expanded_date_range.rb @@ -29,14 +29,6 @@ class ExpandedDateRange < Base minimum_target_rails_version 5.1 - def_node_matcher :expanded_date_range, <<~PATTERN - (irange - (send - $_ {:beginning_of_day :beginning_of_week :beginning_of_month :beginning_of_quarter :beginning_of_year}) - (send - $_ {:end_of_day :end_of_week :end_of_month :end_of_quarter :end_of_year})) - PATTERN - PREFERRED_METHODS = { beginning_of_day: 'all_day', beginning_of_week: 'all_week', @@ -54,31 +46,55 @@ class ExpandedDateRange < Base }.freeze def on_irange(node) - return unless expanded_date_range(node) - begin_node = node.begin end_node = node.end - return unless same_receiver?(begin_node, end_node) - - beginning_method = begin_node.method_name - end_method = end_node.method_name - return unless use_mapped_methods?(beginning_method, end_method) + return if allow?(begin_node, end_node) - preferred_method = "#{begin_node.receiver.source}.#{PREFERRED_METHODS[beginning_method]}" + preferred_method = preferred_method(begin_node) + if begin_node.method?(:beginning_of_week) && begin_node.arguments.one? + return unless same_argument?(begin_node, end_node) - add_offense(node, message: format(MSG, preferred_method: preferred_method)) do |corrector| - corrector.replace(node, preferred_method) + preferred_method << "(#{begin_node.first_argument.source})" + elsif any_arguments?(begin_node, end_node) + return end + + register_offense(node, preferred_method) end private - def same_receiver?(begin_node, end_node) - begin_node.receiver.source == end_node.receiver.source + def allow?(begin_node, end_node) + return true unless (begin_source = receiver_source(begin_node)) + return true unless (end_source = receiver_source(end_node)) + + begin_source != end_source || MAPPED_DATE_RANGE_METHODS[begin_node.method_name] != end_node.method_name + end + + def receiver_source(node) + return if !node&.send_type? || node.receiver.nil? + + node.receiver.source end - def use_mapped_methods?(beginning_method, end_method) - MAPPED_DATE_RANGE_METHODS[beginning_method] == end_method + def same_argument?(begin_node, end_node) + begin_node.first_argument.source == end_node.first_argument.source + end + + def preferred_method(begin_node) + +"#{begin_node.receiver.source}.#{PREFERRED_METHODS[begin_node.method_name]}" + end + + def any_arguments?(begin_node, end_node) + begin_node.arguments.any? || end_node.arguments.any? + end + + def register_offense(node, preferred_method) + message = format(MSG, preferred_method: preferred_method) + + add_offense(node, message: message) do |corrector| + corrector.replace(node, preferred_method) + end end end end diff --git a/spec/rubocop/cop/rails/expanded_date_range_spec.rb b/spec/rubocop/cop/rails/expanded_date_range_spec.rb index 42faa1ab54..039a713c2c 100644 --- a/spec/rubocop/cop/rails/expanded_date_range_spec.rb +++ b/spec/rubocop/cop/rails/expanded_date_range_spec.rb @@ -46,6 +46,17 @@ RUBY end + it 'registers and corrects an offense when using `date.beginning_of_week(:sunday)..date.end_of_week(:sunday)`' do + expect_offense(<<~RUBY) + date.beginning_of_week(:sunday)..date.end_of_week(:sunday) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `date.all_week(:sunday)` instead. + RUBY + + expect_correction(<<~RUBY) + date.all_week(:sunday) + RUBY + end + it 'registers and corrects an offense when using `date.beginning_of_year..date.end_of_year`' do expect_offense(<<~RUBY) date.beginning_of_year..date.end_of_year @@ -110,6 +121,36 @@ date.beginning_of_day..date.end_of_year RUBY end + + it 'does not register an offense when `date.beginning_of_week(:sunday)..date.end_of_week(:saturday)`' do + expect_no_offenses(<<~RUBY) + date.beginning_of_week(:sunday)..date.end_of_week(:saturday) + RUBY + end + + it 'does not register an offense when `date.beginning_of_day..date.end_of_day` with any argument' do + expect_no_offenses(<<~RUBY) + date.beginning_of_day(arg)..date.end_of_day(arg) + RUBY + end + + it 'does not register an offense when `beginning_of_day..end_of_day`' do + expect_no_offenses(<<~RUBY) + beginning_of_day..end_of_day + RUBY + end + + it 'does not register an offense when `beginning_of_day..date.end_of_day`' do + expect_no_offenses(<<~RUBY) + beginning_of_day..date.end_of_day + RUBY + end + + it 'does not register an offense when `date.beginning_of_day..end_of_day`' do + expect_no_offenses(<<~RUBY) + date.beginning_of_day..end_of_day + RUBY + end end context 'Rails <= 5.0', :rails50 do