rubocop-ast icon indicating copy to clipboard operation
rubocop-ast copied to clipboard

Handle numblock in each cops

Open pocke opened this issue 5 years ago • 2 comments

Numbered Parameters feature has been introduced since 2.7. The new node type, numblock, will be supported by rubocop-hq/rubocop#7665, but we still need to modify cops that use on_block or block_type? methods.

For example, Style/BlockDelimiters cop does not work for numblock even if the pull request is merged.

# with TargetRubyVersion: 2.7, and the PR.

# The cop adds an offense to the following code.
items.each do |item| item / 5 end 

# The cop does not add an offense but it should.
items.each do _1 / 5 end

In this case, I guess we can add alias on_numblock on_block to the cop. And we can probably add the same code to the similar cops.

And I guess we also need to modify Node#block_type? method call. I guess we can extend numblock node with BlockNode extension.


Expected behavior

Cops that work for block should work for numblock also.

Actual behavior

It does not work well even with rubocop-hq/rubocop#7665

Steps to reproduce the problem

For Stlye/BlockDelimiters example, we can reproduce the problem with the following commands.

  • Install RuboCop with rubocop-hq/rubocop#7665
  • Put .rubocop.yml with TargetRubyVersion: 2.7
  • Put the example as a Ruby file
  • Execute RuboCop

And we can find the potential target cops with git grep.

$ git grep on_block
lib/rubocop/ast/traversal.rb:      def on_block(node)
lib/rubocop/cop/layout/access_modifier_indentation.rb:        alias on_block  on_class
lib/rubocop/cop/layout/block_alignment.rb:        def on_block(node)
lib/rubocop/cop/layout/block_end_newline.rb:        def on_block(node)
lib/rubocop/cop/layout/empty_lines_around_access_modifier.rb:        def on_block(node)
lib/rubocop/cop/layout/empty_lines_around_block_body.rb:        def on_block(node)
lib/rubocop/cop/layout/indentation_width.rb:        def on_block(node)
lib/rubocop/cop/layout/multiline_block_layout.rb:        def on_block(node)
lib/rubocop/cop/layout/space_around_block_parameters.rb:        def on_block(node)
lib/rubocop/cop/layout/space_around_keyword.rb:        def on_block(node)
lib/rubocop/cop/layout/space_before_block_braces.rb:        def on_block(node)
lib/rubocop/cop/layout/space_inside_block_braces.rb:        def on_block(node)
lib/rubocop/cop/lint/next_without_accumulator.rb:        def on_block(node)
lib/rubocop/cop/lint/non_deterministic_require_order.rb:        def on_block(node)
lib/rubocop/cop/lint/redundant_with_index.rb:        def on_block(node)
lib/rubocop/cop/lint/redundant_with_object.rb:        def on_block(node)
lib/rubocop/cop/lint/useless_access_modifier.rb:        def on_block(node)
lib/rubocop/cop/lint/void.rb:        def on_block(node)
lib/rubocop/cop/metrics/block_length.rb:        def on_block(node)
lib/rubocop/cop/metrics/method_length.rb:        def on_block(node)
lib/rubocop/cop/mixin/method_complexity.rb:      def on_block(node)
lib/rubocop/cop/naming/block_parameter_name.rb:        def on_block(node)
lib/rubocop/cop/naming/variable_name.rb:        alias on_blockarg  on_lvasgn
lib/rubocop/cop/style/block_delimiters.rb:        def on_block(node)
lib/rubocop/cop/style/collection_methods.rb:        def on_block(node)
lib/rubocop/cop/style/each_for_simple_loop.rb:        def on_block(node)
lib/rubocop/cop/style/each_with_object.rb:        def on_block(node)
lib/rubocop/cop/style/empty_block_parameter.rb:        def on_block(node)
lib/rubocop/cop/style/empty_lambda_parameter.rb:        def on_block(node)
lib/rubocop/cop/style/for.rb:        def on_block(node)
lib/rubocop/cop/style/inverse_methods.rb:        def on_block(node)
lib/rubocop/cop/style/lambda.rb:        def on_block(node)
lib/rubocop/cop/style/method_called_on_do_end_block.rb:        def on_block(node)
lib/rubocop/cop/style/multiline_block_chain.rb:        def on_block(node)
lib/rubocop/cop/style/multiline_block_chain.rb:            # found by subsequent calls to on_block.
lib/rubocop/cop/style/next.rb:        def on_block(node)
lib/rubocop/cop/style/proc.rb:        def on_block(node)
lib/rubocop/cop/style/redundant_begin.rb:        def on_block(node)
lib/rubocop/cop/style/redundant_self.rb:        def on_blockarg(node)
lib/rubocop/cop/style/redundant_self.rb:        def on_block(node)
lib/rubocop/cop/style/redundant_sort_by.rb:        def on_block(node)
lib/rubocop/cop/style/single_line_block_params.rb:        def on_block(node)
lib/rubocop/cop/style/symbol_proc.rb:        def on_block(node)

$ git grep -F block_type?
lib/rubocop/ast/node/mixin/method_dispatch_node.rb:        parent&.block_type? && eql?(parent.send_node)
lib/rubocop/cop/lint/ambiguous_block_association.rb:          send_node.last_argument.block_type? &&
lib/rubocop/cop/lint/assignment_in_condition.rb:          return if node.condition.block_type?
lib/rubocop/cop/lint/shadowed_argument.rb:          node.conditional? || node.block_type? ||
lib/rubocop/cop/metrics/block_nesting.rb:          count_blocks? && node.block_type?
lib/rubocop/cop/mixin/multiline_expression_indentation.rb:          break false if a.block_type?
lib/rubocop/cop/mixin/multiline_expression_indentation.rb:          ancestor.block_type? && part_of_block_body?(candidate, ancestor)
lib/rubocop/cop/style/auto_resource_cleanup.rb:            (parent && (parent.block_type? || !parent.lvasgn_type?))
lib/rubocop/cop/style/inverse_methods.rb:          if node.block_type?
lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb:            parent = node.parent&.block_type? ? node.parent.parent : node.parent
lib/rubocop/cop/style/method_called_on_do_end_block.rb:          return unless receiver&.block_type? &&
lib/rubocop/cop/style/multiline_block_chain.rb:            next unless receiver&.block_type? && receiver&.multiline?
lib/rubocop/cop/style/parallel_assignment.rb:          node.block_type? || node.send_type?
lib/rubocop/cop/style/redundant_parentheses.rb:          !ancestor.begin_type? && !ancestor.def_type? && !ancestor.block_type?
lib/rubocop/cop/style/safe_navigation.rb:          receiver = if method_chain.block_type?
lib/rubocop/cop/variable_force/variable.rb:          argument? && @scope.node.block_type?
lib/rubocop/cop/variable_force/variable_table.rb:            return nil unless scope.node.block_type?
lib/rubocop/cop/variable_force/variable_table.rb:            break variables unless scope.node.block_type?
lib/rubocop/cop/variable_force/variable_table.rb:          return unless current_scope.node.block_type?
spec/rubocop/ast/send_node_spec.rb:      it { expect(send_node.block_node.block_type?).to be(true) }
spec/rubocop/ast/super_node_spec.rb:      it { expect(super_node.block_node.block_type?).to be(true) }

RuboCop version

master (with rubocop-hq/rubocop#7665 )

pocke avatar Jan 24 '20 12:01 pocke

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contribution and understanding!

stale[bot] avatar Jul 23 '20 12:07 stale[bot]

I'll see what I can do.

I agree with you that it should work out of the box as much as possible. I would alias on_numblock to on_block; cops that want to do something different can override it but by default it would work. What do you think of Block#arguments returning an array of Nodes like (arg :_1) instead of [] as currently, to make it even more similar?

I'd be tempted for block_type? to be true even for type == :numblock, but maybe it's best to define a common genblock_type?

Transferring to rubocop-ast

marcandre avatar Jul 23 '20 14:07 marcandre

I haven't seen any issues with using alias on_numblock on_block, and there's even an InternalAffairs/NumblockHandler cop now. At least in rubocop-rspec we often disable the cop and skip aliasing, as certain DSL methods don't yield arguments to their blocks, and numblock handling is redundant, like in let(:foo) { "bar" }.

Is there anything actionable left here?

pirj avatar May 23 '23 16:05 pirj

Thanks for the feedback. Let's close then

marcandre avatar May 23 '23 20:05 marcandre