123456789_123456789_123456789_123456789_123456789_

Class: RuboCop::Cop::Performance::StringReplacement

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

Overview

Identifies places where gsub can be replaced by tr or delete.

Examples:

# bad
'abc'.gsub('b', 'd')
'abc'.gsub('a', '')
'abc'.gsub(/a/, 'd')
'abc'.gsub!('a', 'd')

# good
'abc'.gsub(/.*/, 'a')
'abc'.gsub(/a+/, 'd')
'abc'.tr('b', 'd')
'a b c'.delete(' ')

Constant Summary

Instance Method Summary

Instance Method Details

#accept_first_param?(first_param) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 84

def accept_first_param?(first_param)
  first_source, options = first_source(first_param)
  return true if first_source.nil?

  unless first_param.str_type?
    return true if options
    return true unless first_source.is_a?(String) && first_source =~ DETERMINISTIC_REGEX

    # This must be done after checking DETERMINISTIC_REGEX
    # Otherwise things like \s will trip us up
    first_source = interpret_string_escapes(first_source)
  end

  first_source.length != 1
end

#accept_second_param?(second_param) ⇒ Boolean (private)

[ GitHub ]

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

def accept_second_param?(second_param)
  second_source, = *second_param
  second_source.length > 1
end

#autocorrect(corrector, node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 60

def autocorrect(corrector, node)
  _string, _method, first_param, second_param = *node
  first_source, = first_source(first_param)
  second_source, = *second_param

  first_source = interpret_string_escapes(first_source) unless first_param.str_type?

  replace_method(corrector, node, first_source, second_source, first_param)
end

#first_source(first_param) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 100

def first_source(first_param)
  case first_param.type
  when :regexp
    source_from_regex_literal(first_param)
  when :send
    source_from_regex_constructor(first_param)
  when :str
    first_param.children.first
  end
end

#message(node, first_source, second_source) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 143

def message(node, first_source, second_source)
  replacement_method = replacement_method(node, first_source, second_source)

  format(MSG, prefer: replacement_method, current: node.method_name)
end

#method_suffix(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 149

def method_suffix(node)
  node.loc.end ? node.loc.end.source : ''
end

#offense(node, first_param, second_param) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 49

def offense(node, first_param, second_param)
  first_source, = first_source(first_param)
  first_source = interpret_string_escapes(first_source) unless first_param.str_type?
  second_source, = *second_param
  message = message(node, first_source, second_source)

  add_offense(range(node), message: message) do |corrector|
    autocorrect(corrector, node)
  end
end

#on_csend(node)

Alias for #on_send.

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 45

alias on_csend on_send

#on_send(node) Also known as: #on_csend

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 37

def on_send(node)
  string_replacement?(node) do |first_param, second_param|
    return if accept_second_param?(second_param)
    return if accept_first_param?(first_param)

    offense(node, first_param, second_param)
  end
end

#range(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 129

def range(node)
  range_between(node.loc.selector.begin_pos, node.source_range.end_pos)
end

#remove_second_param(corrector, node, first_param) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 153

def remove_second_param(corrector, node, first_param)
  end_range = range_between(first_param.source_range.end_pos, node.source_range.end_pos)

  corrector.replace(end_range, method_suffix(node))
end

#replace_method(corrector, node, first_source, second_source, first_param) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 70

def replace_method(corrector, node, first_source, second_source, first_param)
  replacement_method = replacement_method(node, first_source, second_source)

  corrector.replace(node.loc.selector, replacement_method)
  corrector.replace(first_param, to_string_literal(first_source)) unless first_param.str_type?

  remove_second_param(corrector, node, first_param) if second_source.empty? && first_source.length == 1
end

#replacement_method(node, first_source, second_source) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 133

def replacement_method(node, first_source, second_source)
  replacement = if second_source.empty? && first_source.length == 1
                  DELETE
                else
                  TR
                end

  "#{replacement}#{BANG if node.bang_method?}"
end

#source_from_regex_constructor(node) (private)

[ GitHub ]

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

def source_from_regex_constructor(node)
  _const, _init, regex = *node
  case regex.type
  when :regexp
    source_from_regex_literal(regex)
  when :str
    source, = *regex
    source
  end
end

#source_from_regex_literal(node) (private)

[ GitHub ]

  
# File 'lib/rubocop/cop/performance/string_replacement.rb', line 111

def source_from_regex_literal(node)
  regex, options = *node
  source, = *regex
  options, = *options
  [source, options]
end