Class: RuboCop::Cop::Lint::SymbolConversion

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector
Includes:
ConfigurableEnforcedStyle, SymbolHelp
Defined in:
lib/rubocop/cop/lint/symbol_conversion.rb

Overview

Checks for uses of literal strings converted to a symbol where a literal symbol could be used instead.

There are two possible styles for this cop. strict (default) will register an offense for any incorrect usage. consistent additionally requires hashes to use the same style for every symbol key (ie. if any symbol key needs to be quoted it requires all keys to be quoted).

Examples:

# bad
'string'.to_sym
:symbol.to_sym
'underscored_string'.to_sym
:'underscored_symbol'
'hyphenated-string'.to_sym
"string_#{interpolation}".to_sym

# good
:string
:symbol
:underscored_string
:underscored_symbol
:'hyphenated-string'
:"string_#{interpolation}"

EnforcedStyle: strict (default)


# bad
{
  'a': 1,
  "b": 2,
  'c-d': 3
}

# good (don't quote keys that don't require quoting)
{
  a: 1,
  b: 2,
  'c-d': 3
}

EnforcedStyle: consistent


# bad
{
  a: 1,
  'b-c': 2
}

# good (quote all keys if any need quoting)
{
  'a': 1,
  'b-c': 2
}

# good (no quoting required)
{
  a: 1,
  b: 2
}

Constant Summary collapse

MSG =
'Unnecessary symbol conversion; use `%<correction>s` instead.'
MSG_CONSISTENCY =
'Symbol hash key should be quoted for consistency; ' \
'use `%<correction>s` instead.'
RESTRICT_ON_SEND =
%i[to_sym intern].freeze

Instance Attribute Summary

Attributes inherited from Base

#config, #processed_source, #project_index

Instance Method Summary collapse

Methods included from AutoCorrector

support_autocorrect?

Methods included from SymbolHelp

#hash_key?

Methods included from ConfigurableEnforcedStyle

#alternative_style, #alternative_styles, #ambiguous_style_detected, #correct_style_detected, #detected_style, #detected_style=, #no_acceptable_style!, #no_acceptable_style?, #opposite_style_detected, #style, #style_configured?, #style_detected, #style_parameter_name, #supported_styles, #unexpected_style_detected

Methods inherited from Base

#active_support_extensions_enabled?, #add_global_offense, #add_offense, #always_autocorrect?, autocorrect_incompatible_with, badge, #begin_investigation, #callbacks_needed, callbacks_needed, #config_to_allow_offenses, #config_to_allow_offenses=, #contextual_autocorrect?, #cop_config, cop_name, #cop_name, department, documentation_url, exclude_from_registry, #excluded_file?, #external_dependency_checksum, inherited, #initialize, #inspect, joining_forces, lint?, match?, #message, #offenses, #on_investigation_end, #on_new_investigation, #on_other_file, #parse, #parser_engine, #ready, #relevant_file?, requires_gem, #string_literals_frozen_by_default?, support_autocorrect?, support_multiple_source?, #target_gem_version, #target_rails_version, #target_ruby_version

Methods included from ExcludeLimit

cop_dir_for, #exclude_limit, read_limits

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #autocorrect_with_disable_uncorrectable?, #correctable?, #disable_uncorrectable?, #safe_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

silence_warnings

Constructor Details

This class inherits a constructor from RuboCop::Cop::Base

Instance Method Details

#dstr_correction(receiver) ⇒ Object

Reuse the already-escaped inner source for a plain "..." string so embedded quotes stay escaped. Percent literals (%{}, %Q{}, ...) and adjacent string concatenation have multi-character or no delimiters, so slicing the source would corrupt them; fall back to the node's value there.



97
98
99
100
101
102
103
# File 'lib/rubocop/cop/lint/symbol_conversion.rb', line 97

def dstr_correction(receiver)
  if receiver.loc.begin&.source == '"'
    ":\"#{receiver.source[1..-2]}\""
  else
    ":\"#{receiver.value.to_sym}\""
  end
end

#on_hash(node) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rubocop/cop/lint/symbol_conversion.rb', line 122

def on_hash(node)
  # For `EnforcedStyle: strict`, hash keys are evaluated in `on_sym`
  return unless style == :consistent

  keys = node.keys.select(&:sym_type?)

  if keys.any? { |key| requires_quotes?(key) }
    correct_inconsistent_hash_keys(keys)
  else
    # If there are no symbol keys requiring quoting,
    # treat the hash like `EnforcedStyle: strict`.
    keys.each { |key| correct_hash_key(key) }
  end
end

#on_send(node) ⇒ Object



78
79
80
81
82
83
# File 'lib/rubocop/cop/lint/symbol_conversion.rb', line 78

def on_send(node)
  return unless node.receiver
  return unless (correction = symbol_conversion_correction(node.receiver))

  register_offense(node, correction: correction)
end

#on_sym(node) ⇒ Object



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
# File 'lib/rubocop/cop/lint/symbol_conversion.rb', line 105

def on_sym(node)
  return if ignored_node?(node) || properly_quoted?(node.source, node.value.inspect)

  # `alias` arguments are symbols but since a symbol that requires
  # being quoted is not a valid method identifier, it can be ignored
  return if in_alias?(node)

  # The `%I[]` and `%i[]` macros are parsed as normal arrays of symbols
  # so they need to be ignored.
  return if in_percent_literal_array?(node)

  # Symbol hash keys have a different format and need to be handled separately
  return correct_hash_key(node) if hash_key?(node)

  register_offense(node, correction: node.value.inspect)
end

#symbol_conversion_correction(receiver) ⇒ Object



85
86
87
88
89
90
91
# File 'lib/rubocop/cop/lint/symbol_conversion.rb', line 85

def symbol_conversion_correction(receiver)
  if receiver.type?(:str, :sym)
    receiver.value.to_sym.inspect
  elsif receiver.dstr_type? && !receiver.heredoc?
    dstr_correction(receiver)
  end
end