Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style/ExplicitBlockArgument: do not assume the block parameter name #10064

Merged
merged 1 commit into from Sep 8, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/fix_hardcoded_block_parameter_name.md
@@ -0,0 +1 @@
* [#10064](https://github.com/rubocop/rubocop/pull/10064): Fix `Style/ExplicitBlockArgument` corrector assuming any existing block argument was named `block`. ([@byroot][])
32 changes: 21 additions & 11 deletions lib/rubocop/cop/style/explicit_block_argument.rb
Expand Up @@ -67,17 +67,27 @@ def on_yield(node)
# 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)
add_block_argument(def_node, corrector) if @def_nodes.add?(def_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

def extract_block_name(def_node)
if def_node.block_argument?
def_node.arguments.last.name
else
'block'
end
end

def yielding_arguments?(block_args, yield_args)
yield_args = yield_args.dup.fill(
nil,
Expand All @@ -91,15 +101,15 @@ def yielding_arguments?(block_args, yield_args)
end
end

def add_block_argument(node, corrector)
def add_block_argument(node, corrector, block_name)
if node.arguments?
insert_argument(node, corrector)
insert_argument(node, corrector, block_name)
elsif empty_arguments?(node)
corrector.replace(node.arguments, '(&block)')
corrector.replace(node.arguments, "(&#{block_name})")
elsif call_like?(node)
correct_call_node(node, corrector)
correct_call_node(node, corrector, block_name)
else
corrector.insert_after(node.loc.name, '(&block)')
corrector.insert_after(node.loc.name, "(&#{block_name})")
end
end

Expand All @@ -112,16 +122,16 @@ def call_like?(node)
node.call_type? || node.zsuper_type? || node.super_type?
end

def insert_argument(node, corrector)
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'
replacement = " &#{block_name}"
replacement = ",#{replacement}" unless arg_range.source.end_with?(',')
corrector.insert_after(arg_range, replacement) unless last_arg.blockarg_type?
end

def correct_call_node(node, corrector)
corrector.insert_after(node, '(&block)')
def correct_call_node(node, corrector, block_name)
corrector.insert_after(node, "(&#{block_name})")
return unless node.parenthesized?

args_begin = Util.args_begin(node)
Expand Down
6 changes: 3 additions & 3 deletions spec/rubocop/cop/style/explicit_block_argument_spec.rb
Expand Up @@ -41,15 +41,15 @@ def m

it 'correctly corrects when method already has an explicit block argument' do
expect_offense(<<~RUBY)
def m(&block)
def m(&blk)
items.something { |i| yield i }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Consider using explicit block argument in the surrounding method's signature over `yield`.
end
RUBY

expect_correction(<<~RUBY)
def m(&block)
items.something(&block)
def m(&blk)
items.something(&blk)
end
RUBY
end
Expand Down