lib/rubocop/cop/performance/hash_each_methods.rb in rubocop-0.49.1 vs lib/rubocop/cop/performance/hash_each_methods.rb in rubocop-0.50.0
- old
+ new
@@ -18,64 +18,105 @@
class HashEachMethods < Cop
include Lint::UnusedArgument
MSG = 'Use `%s` instead of `%s`.'.freeze
- def_node_matcher :plain_each, <<-END
- (block $(send (send _ :hash) :each) (args (arg $_k) (arg $_v)) ...)
- END
+ def_node_matcher :plain_each, <<-PATTERN
+ (block $(send _ :each) (args (arg $_k) (arg $_v)) ...)
+ PATTERN
- def_node_matcher :kv_each, <<-END
- (block $(send (send (send _ :hash) ${:keys :values}) :each) ...)
- END
+ def_node_matcher :kv_each, <<-PATTERN
+ (block $(send (send _ ${:keys :values}) :each) ...)
+ PATTERN
def on_block(node)
+ register_each_offense(node)
+ register_kv_offense(node)
+ end
+
+ private
+
+ def register_each_offense(node)
plain_each(node) do |target, k, v|
return if @args[k] && @args[v]
used = @args[k] ? :key : :value
- add_offense(target, range(target), format(message,
- "each_#{used}",
- :each))
+ add_offense(
+ target, plain_range(target), format(message,
+ "each_#{used}",
+ :each)
+ )
end
+ end
+
+ def register_kv_offense(node)
kv_each(node) do |target, method|
- add_offense(target, range(target), format(message,
- "each_#{method[0..-2]}",
- "#{method}.each"))
+ add_offense(
+ target, kv_range(target), format(message,
+ "each_#{method[0..-2]}",
+ "#{method}.each")
+ )
end
end
def check_argument(variable)
return unless variable.block_argument?
(@args ||= {})[variable.name] = variable.used?
end
def autocorrect(node)
receiver, _second_method = *node
- caller, first_method = *receiver
+ _caller, first_method = *receiver
+
lambda do |corrector|
- if first_method == :hash
- method = @args.values.first ? :key : :value
- new_source = receiver.source + ".each_#{method}"
- corrector.replace(node.loc.expression, new_source)
- correct_args(node, corrector)
+ case first_method
+ when :keys, :values
+ return correct_implicit(node, corrector) if receiver.receiver.nil?
+
+ correct_key_value_each(node, corrector)
else
- new_source = caller.source + ".each_#{first_method[0..-2]}"
- corrector.replace(node.loc.expression, new_source)
+ return correct_implicit(node, corrector) if receiver.nil?
+
+ correct_plain_each(node, corrector)
end
end
end
- private
+ def correct_implicit(node, corrector)
+ method = @args.include?(:k) ? :key : :value
+ new_source = "each_#{method}"
+ corrector.replace(node.loc.expression, new_source)
+ correct_args(node, corrector)
+ end
+
+ def correct_key_value_each(node, corrector)
+ receiver = node.receiver
+
+ new_source = receiver.receiver.source +
+ ".each_#{receiver.method_name[0..-2]}"
+ corrector.replace(node.loc.expression, new_source)
+ end
+
+ def correct_plain_each(node, corrector)
+ method = @args.include?(:k) ? :key : :value
+ new_source = node.receiver.source + ".each_#{method}"
+
+ corrector.replace(node.loc.expression, new_source)
+ correct_args(node, corrector)
+ end
+
def correct_args(node, corrector)
args = node.parent.children[1]
used_arg = "|#{@args.detect { |_k, v| v }.first}|"
- args_range = range_between(args.loc.begin.begin_pos,
- args.loc.end.end_pos)
- corrector.replace(args_range, used_arg)
+
+ corrector.replace(args.source_range, used_arg)
end
- def range(outer_node)
+ def plain_range(outer_node)
+ outer_node.loc.selector
+ end
+
+ def kv_range(outer_node)
inner_node = outer_node.children.first
inner_node.loc.selector.join(outer_node.loc.selector)
end
end
end