class RuboCop::Cop::Performance::Detect
This cop is used to identify usages of `select.first`, `select.last`, `find_all.first`, and `find_all.last` and change them to use `detect` instead.
@example
# bad [].select { |item| true }.first [].select { |item| true }.last [].find_all { |item| true }.first [].find_all { |item| true }.last # good [].detect { |item| true } [].reverse.detect { |item| true }
`ActiveRecord` compatibility: `ActiveRecord` does not implement a `detect` method and `find` has its own meaning. Correcting ActiveRecord methods with this cop should be considered unsafe.
Constants
- DANGEROUS_METHODS
- MSG
- REVERSE_MSG
- SELECT_METHODS
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 43 def autocorrect(node) receiver, first_method = *node replacement = if first_method == :last "reverse.#{preferred_method}" else preferred_method end first_range = receiver.source_range.end.join(node.loc.selector) receiver, _args, _body = *receiver if receiver.block_type? lambda do |corrector| corrector.remove(first_range) corrector.replace(receiver.loc.selector, replacement) end end
on_send(node)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 32 def on_send(node) return unless should_run? receiver, second_method, *args = *node return if accept_second_call?(receiver, second_method, args) receiver, _args, body = *receiver if receiver.block_type? return if accept_first_call?(receiver, body) offense(node, receiver, second_method) end
Private Instance Methods
accept_first_call?(receiver, body)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 76 def accept_first_call?(receiver, body) caller, first_method, args = *receiver # check that we have usual block or block pass return true if body.nil? && (args.nil? || !args.block_pass_type?) return true unless SELECT_METHODS.include?(first_method) lazy?(caller) end
accept_second_call?(receiver, method, args)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 70 def accept_second_call?(receiver, method, args) !receiver || !DANGEROUS_METHODS.include?(method) || !args.empty? end
lazy?(node)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 102 def lazy?(node) return false if node.nil? receiver, method, _args = *node method == :lazy && !receiver.nil? end
offense(node, receiver, second_method)
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 86 def offense(node, receiver, second_method) _caller, first_method, _args = *receiver range = receiver.loc.selector.join(node.loc.selector) message = second_method == :last ? REVERSE_MSG : MSG add_offense(node, range, format(message, preferred_method, first_method, second_method)) end
preferred_method()
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 97 def preferred_method config.for_cop('Style/CollectionMethods') ['PreferredMethods']['detect'] || 'detect' end
should_run?()
click to toggle source
# File lib/rubocop/cop/performance/detect.rb, line 64 def should_run? !(cop_config['SafeMode'.freeze] || config['Rails'.freeze] && config['Rails'.freeze]['Enabled'.freeze]) end