Class: RuboCop::Cop::Style::SelectByRange

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
RangeHelp
Defined in:
lib/rubocop/cop/style/select_by_range.rb

Overview

Looks for places where a subset of an Enumerable (array, range, set, etc.; see note below) is calculated based on a range check, and suggests grep or grep_v instead.

NOTE: Hashes do not behave as you may expect with grep, which means that hash.grep is not equivalent to hash.select. Although RuboCop is limited by static analysis, this cop attempts to avoid registering an offense when the receiver is a hash (hash literal, Hash.new, ‘Hash#[]`, or to_h/to_hash).

Examples:

# bad (select or find_all)
array.select { |x| x.between?(1, 10) }
array.select { |x| (1..10).cover?(x) }
array.select { |x| (1..10).include?(x) }

# bad (reject)
array.reject { |x| x.between?(1, 10) }

# bad (find or detect)
array.find { |x| x.between?(1, 10) }
array.detect { |x| (1..10).cover?(x) }

# bad (negative form)
array.reject { |x| !x.between?(1, 10) }
array.find { |x| !(1..10).cover?(x) }

# good
array.grep(1..10)
array.grep_v(1..10)
array.grep(1..10).first
array.grep_v(1..10).first

Constant Summary collapse

MSG =
'Prefer `%<replacement>s` to `%<original_method>s` with a range check.'
RESTRICT_ON_SEND =
i[select filter find_all reject find detect].freeze
SELECT_METHODS =
i[select filter find_all].freeze
FIND_METHODS =
i[find detect].freeze

Constants included from RangeHelp

RangeHelp::BYTE_ORDER_MARK, RangeHelp::NOT_GIVEN

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, #cop_name, cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

#exclude_limit

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#between_call?(node, name) ⇒ Object



93
94
95
# File 'lib/rubocop/cop/style/select_by_range.rb', line 93

def_node_matcher :between_call?, "(send (lvar %1) :between? _ _)\n"

#creates_hash?(node) ⇒ Object

Returns true if a node appears to return a hash



79
80
81
82
83
84
85
# File 'lib/rubocop/cop/style/select_by_range.rb', line 79

def_node_matcher :creates_hash?, "{\n  (call (const _ :Hash) {:new :[]} ...)\n  (block (call (const _ :Hash) :new ...) ...)\n  (call _ { :to_h :to_hash } ...)\n}\n"

#env_const?(node) ⇒ Object



88
89
90
# File 'lib/rubocop/cop/style/select_by_range.rb', line 88

def_node_matcher :env_const?, "(const {nil? cbase} :ENV)\n"

#on_send(node) ⇒ Object Also known as: on_csend



102
103
104
105
106
107
108
109
110
111
112
# File 'lib/rubocop/cop/style/select_by_range.rb', line 102

def on_send(node)
  return unless (block_node = node.block_node)
  return if block_node.body&.begin_type?
  return if receiver_allowed?(block_node.receiver)
  return unless (range_check_send_node = extract_send_node(block_node))

  replacement = replacement(range_check_send_node, node)
  range_literal = find_range(range_check_send_node)

  register_offense(node, block_node, range_literal, replacement)
end

#range_check?(node) ⇒ Object

Matches: x.between?(min, max) or (min..max).cover?(x) or (min..max).include?(x)



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/rubocop/cop/style/select_by_range.rb', line 54

def_node_matcher :range_check?, "{\n  (block call (args (arg $_)) ${(send (lvar _) :between? _ _)})\n  (block call (args (arg $_)) ${(send {range (begin range)} {:cover? :include?} (lvar _))})\n  (block call (args (arg $_)) ${(send (send (lvar _) :between? _ _) :!)})\n  (block call (args (arg $_)) ${(send (send {range (begin range)} {:cover? :include?} (lvar _)) :!)})\n  (block call (args (arg $_)) ${(send (begin (send (lvar _) :between? _ _)) :!)})\n  (block call (args (arg $_)) ${(send (begin (send {range (begin range)} {:cover? :include?} (lvar _))) :!)})\n  (numblock call $1 ${(send (lvar _) :between? _ _)})\n  (numblock call $1 ${(send {range (begin range)} {:cover? :include?} (lvar _))})\n  (numblock call $1 ${(send (send (lvar _) :between? _ _) :!)})\n  (numblock call $1 ${(send (send {range (begin range)} {:cover? :include?} (lvar _)) :!)})\n  (numblock call $1 ${(send (begin (send (lvar _) :between? _ _)) :!)})\n  (numblock call $1 ${(send (begin (send {range (begin range)} {:cover? :include?} (lvar _))) :!)})\n  (itblock call $_ ${(send (lvar _) :between? _ _)})\n  (itblock call $_ ${(send {range (begin range)} {:cover? :include?} (lvar _))})\n  (itblock call $_ ${(send (send (lvar _) :between? _ _) :!)})\n  (itblock call $_ ${(send (send {range (begin range)} {:cover? :include?} (lvar _)) :!)})\n  (itblock call $_ ${(send (begin (send (lvar _) :between? _ _)) :!)})\n  (itblock call $_ ${(send (begin (send {range (begin range)} {:cover? :include?} (lvar _))) :!)})\n}\n"

#range_cover_call?(node, name) ⇒ Object



98
99
100
# File 'lib/rubocop/cop/style/select_by_range.rb', line 98

def_node_matcher :range_cover_call?, "(send {range (begin range)} {:cover? :include?} (lvar %1))\n"