Class: RuboCop::Cop::Style::PreferNumberedParameter

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Defined in:
lib/rubocop/cop/style/prefer_numbered_parameter.rb,
sig/rubocop/cop/style/prefer_numbered_parameter.rbs

Overview

Recommends using numbered parameters (_1, _2) instead of named block arguments in single-line blocks with few arguments.

Examples:

# bad
users.map { |user| user.name }
items.select { |item| item.active? }

# good
users.map { _1.name }
items.select { _1.active? }

# good - multi-line block (not targeted)
users.map do |user|
  user.name
end

MaxArguments: 2

# bad
hash.each { |key, value| "#{key}: #{value}" }

# good
hash.each { "#{_1}: #{_2}" }

Constant Summary collapse

MSG =

Returns:

  • (::String)
"Use numbered parameters (`_1`, `_2`, ...) instead of named block arguments " \
"for single-line blocks."

Instance Method Summary collapse

Instance Method Details

#autocorrect(corrector, node) ⇒ void

This method returns an undefined value.

Parameters:

  • corrector (RuboCop::Cop::Corrector)
  • node (RuboCop::AST::BlockNode)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 55

def autocorrect(corrector, node) #: void # rubocop:disable Metrics/AbcSize
  lvar_nodes = collect_lvar_nodes(node.body)

  argument_list = node.arguments.argument_list #: Array[RuboCop::AST::ArgNode]
  argument_list.each.with_index(1) do |arg, index|
    numbered = "_#{index}"
    lvar_nodes.select { _1.children.first == arg.name }.each do |lvar|
      corrector.replace(lvar.source_range, numbered)
    end
  end

  args_range = node.arguments.source_range
  corrector.remove(args_range.resize(args_range.size + 1))
end

#collect_lvar_nodes(node) ⇒ Array[RuboCop::AST::Node]

Parameters:

  • node (RuboCop::AST::Node, nil)

Returns:

  • (Array[RuboCop::AST::Node])


71
72
73
74
75
76
77
78
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 71

def collect_lvar_nodes(node) #: Array[RuboCop::AST::Node]
  return [] unless node

  result = [] #: Array[RuboCop::AST::Node]
  result << node if node.lvar_type?
  node.each_descendant(:lvar) { result << _1 }
  result
end

#contains_inner_block?(node) ⇒ Boolean

Parameters:

  • node (RuboCop::AST::Node, nil)

Returns:

  • (Boolean)


92
93
94
95
96
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 92

def contains_inner_block?(node) #: bool
  return false unless node

  node.block_type? || node.numblock_type? || node.each_descendant(:block, :numblock).any?
end

#max_argumentsInteger

: Integer

Returns:

  • (Integer)


80
81
82
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 80

def max_arguments #: Integer
  cop_config.fetch("MaxArguments", 1)
end

#on_block(node) ⇒ void

This method returns an undefined value.

Parameters:

  • node (RuboCop::AST::BlockNode)


37
38
39
40
41
42
43
44
45
46
47
48
49
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 37

def on_block(node) #: void # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity
  return unless node.single_line?
  return if node.lambda?
  return if node.arguments.argument_list.empty?
  return if node.arguments.argument_list.count > max_arguments
  return if node.body.nil?
  return if special_arguments?(node)
  return if contains_inner_block?(node.body)

  add_offense(node) do |corrector|
    autocorrect(corrector, node)
  end
end

#special_arguments?(node) ⇒ Boolean

Parameters:

  • node (RuboCop::AST::BlockNode)

Returns:

  • (Boolean)


85
86
87
88
89
# File 'lib/rubocop/cop/style/prefer_numbered_parameter.rb', line 85

def special_arguments?(node) #: bool
  node.arguments.argument_list.any? do |arg|
    arg.mlhs_type? || arg.restarg_type? || arg.blockarg_type? || arg.shadowarg_type?
  end
end