123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Performance::RedundantMerge

Relationships & Source Files
Namespace Children
Classes:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, AutoCorrector, Base
Instance Chain:
self, Alignment, Base
Inherits: Base
  • Object
Defined in: lib/rubocop/cop/performance/redundant_merge.rb

Overview

Identifies places where Hash#merge! can be replaced by Hash#[]=. You can set the maximum number of key-value pairs to consider an offense with MaxKeyValuePairs.

Examples:

# bad
hash.merge!(a: 1)
hash.merge!({'key' => 'value'})

# good
hash[:a] = 1
hash['key'] = 'value'

MaxKeyValuePairs: 2 (default)

# bad
hash.merge!(a: 1, b: 2)

# good
hash[:a] = 1
hash[:b] = 2

Cop Safety Information:

  • This cop is unsafe because RuboCop cannot determine if the receiver of merge! is actually a hash or not.

Constant Summary

Instance Method Summary

Instance Method Details

#correct_multiple_elements(corrector, node, parent, new_source) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 106

def correct_multiple_elements(corrector, node, parent, new_source)
  if modifier_flow_control?(parent)
    new_source = rewrite_with_modifier(node, parent, new_source)
    node = parent
  else
    padding = "\n#{leading_spaces(node)}"
    new_source.gsub!("\n", padding)
  end

  corrector.replace(node, new_source)
end

#correct_single_element(corrector, node, new_source) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 118

def correct_single_element(corrector, node, new_source)
  corrector.replace(node, new_source)
end

#each_redundant_merge(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 79

def each_redundant_merge(node)
  redundant_merge_candidate(node) do |receiver, pairs|
    next if non_redundant_merge?(node, receiver, pairs)

    yield node
  end
end

#kwsplat_used?(pairs) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 98

def kwsplat_used?(pairs)
  pairs.any?(&:kwsplat_type?)
end

#leading_spaces(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 146

def leading_spaces(node)
  node.source_range.source_line[/\A\s*/]
end

#max_key_value_pairs (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 150

def max_key_value_pairs
  Integer(cop_config['MaxKeyValuePairs'] || 2)
end

#message(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 71

def message(node)
  redundant_merge_candidate(node) do |receiver, pairs|
    assignments = to_assignments(receiver, pairs).join('; ')

    format(MSG, prefer: assignments, current: node.source)
  end
end

#non_redundant_merge?(node, receiver, pairs) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 87

def non_redundant_merge?(node, receiver, pairs)
  pairs.empty? ||
    non_redundant_pairs?(receiver, pairs) ||
    kwsplat_used?(pairs) ||
    non_redundant_value_used?(receiver, node)
end

#non_redundant_pairs?(receiver, pairs) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 94

def non_redundant_pairs?(receiver, pairs)
  (pairs.size > 1 && !receiver.pure?) || pairs.size > max_key_value_pairs
end

#non_redundant_value_used?(receiver, node) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 102

def non_redundant_value_used?(receiver, node)
  node.value_used? && !EachWithObjectInspector.new(node, receiver).value_used?
end

#on_send(node)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 52

def on_send(node)
  each_redundant_merge(node) do |redundant_merge_node|
    message = message(node)
    add_offense(redundant_merge_node, message: message) do |corrector|
      redundant_merge_candidate(node) do |receiver, pairs|
        new_source = to_assignments(receiver, pairs).join("\n")

        if node.parent && pairs.size > 1
          correct_multiple_elements(corrector, node, node.parent, new_source)
        else
          correct_single_element(corrector, node, new_source)
        end
      end
    end
  end
end

#rewrite_with_modifier(node, parent, new_source) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 132

def rewrite_with_modifier(node, parent, new_source)
  # FIXME: `|| 2` can be removed when support is limited to RuboCop 1.44 or higher.
  # https://github.com/rubocop/rubocop/commit/02d1e5b
  indent = ' ' * (configured_indentation_width || 2)
  padding = "\n#{indent + leading_spaces(node)}"
  new_source.gsub!("\n", padding)

  format(WITH_MODIFIER_CORRECTION, keyword: parent.loc.keyword.source,
                                   condition: parent.condition.source,
                                   leading_space: leading_spaces(node),
                                   indent: indent,
                                   body: new_source).chomp
end

#to_assignments(receiver, pairs) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/redundant_merge.rb', line 122

def to_assignments(receiver, pairs)
  pairs.map do |pair|
    key, value = *pair

    key = key.sym_type? && pair.colon? ? ":#{key.source}" : key.source

    format(AREF_ASGN, receiver: receiver.source, key: key, value: value.source)
  end
end