class RuboCop::Cop::Style::ExplicitBlockArgument
Enforces the use of explicit block argument to avoid writing block literal that just passes its arguments to another block.
NOTE: This cop only registers an offense if the block args match the yield args exactly.
@example
# bad def with_tmp_dir Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir) { |dir| yield dir } # block just passes arguments end end # bad def nine_times 9.times { yield } end # good def with_tmp_dir(&block) Dir.mktmpdir do |tmp_dir| Dir.chdir(tmp_dir, &block) end end with_tmp_dir do |dir| puts "dir is accessible as a parameter and pwd is set: #{dir}" end # good def nine_times(&block) 9.times(&block) end
Constants
- MSG
Public Class Methods
autocorrect_incompatible_with()
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 53 def self.autocorrect_incompatible_with [Lint::UnusedMethodArgument] end
new(config = nil, options = nil)
click to toggle source
Calls superclass method
RuboCop::Cop::Base::new
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 57 def initialize(config = nil, options = nil) super @def_nodes = Set.new end
Public Instance Methods
on_yield(node)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 62 def on_yield(node) block_node = node.parent yielding_block?(block_node) do |send_node, block_args, yield_args| return unless yielding_arguments?(block_args, yield_args) def_node = block_node.each_ancestor(:def, :defs).first # if `yield` is being called outside of a method context, ignore # this is not a valid ruby pattern, but can happen in haml or erb, # so this can cause crashes in haml_lint return unless def_node block_name = extract_block_name(def_node) add_offense(block_node) do |corrector| corrector.remove(block_body_range(block_node, send_node)) add_block_argument(send_node, corrector, block_name) add_block_argument(def_node, corrector, block_name) if @def_nodes.add?(def_node) end end end
Private Instance Methods
add_block_argument(node, corrector, block_name)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 108 def add_block_argument(node, corrector, block_name) if node.arguments? insert_argument(node, corrector, block_name) elsif empty_arguments?(node) corrector.replace(node.arguments, "(&#{block_name})") elsif call_like?(node) correct_call_node(node, corrector, block_name) else corrector.insert_after(node.loc.name, "(&#{block_name})") end end
block_body_range(block_node, send_node)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 147 def block_body_range(block_node, send_node) range_between(send_node.loc.expression.end_pos, block_node.loc.end.end_pos) end
call_like?(node)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 125 def call_like?(node) node.call_type? || node.zsuper_type? || node.super_type? end
correct_call_node(node, corrector, block_name)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 137 def correct_call_node(node, corrector, block_name) corrector.insert_after(node, "(&#{block_name})") return unless node.parenthesized? args_begin = Util.args_begin(node) args_end = Util.args_end(node) range = range_between(args_begin.begin_pos, args_end.end_pos) corrector.remove(range) end
empty_arguments?(node)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 120 def empty_arguments?(node) # Is there an arguments node with only parentheses? node.arguments.is_a?(RuboCop::AST::Node) && node.arguments.loc.begin end
extract_block_name(def_node)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 87 def extract_block_name(def_node) if def_node.block_argument? def_node.arguments.last.name else 'block' end end
insert_argument(node, corrector, block_name)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 129 def insert_argument(node, corrector, block_name) last_arg = node.arguments.last arg_range = range_with_surrounding_comma(last_arg.source_range, :right) replacement = " &#{block_name}" replacement = ",#{replacement}" unless arg_range.source.end_with?(',') corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type? end
yielding_arguments?(block_args, yield_args)
click to toggle source
# File lib/rubocop/cop/style/explicit_block_argument.rb, line 95 def yielding_arguments?(block_args, yield_args) yield_args = yield_args.dup.fill( nil, yield_args.length, block_args.length - yield_args.length ) yield_args.zip(block_args).all? do |yield_arg, block_arg| next false unless yield_arg && block_arg block_arg && yield_arg.children.first == block_arg.children.first end end