class RuboCop::Cop::Lint::SymbolConversion
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).
@example
# 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}"
@example 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 }
@example 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 }
Constants
- MSG
- MSG_CONSISTENCY
- RESTRICT_ON_SEND
Public Instance Methods
on_hash(node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 105 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)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 78 def on_send(node) return unless node.receiver if node.receiver.str_type? || node.receiver.sym_type? register_offense(node, correction: node.receiver.value.to_sym.inspect) elsif node.receiver.dstr_type? register_offense(node, correction: ":\"#{node.receiver.value.to_sym}\"") end end
on_sym(node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 88 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
Private Instance Methods
correct_hash_key(node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 147 def correct_hash_key(node) # Although some operators can be converted to symbols normally # (ie. `:==`), these are not accepted as hash keys and will # raise a syntax error (eg. `{ ==: ... }`). Therefore, if the # symbol does not start with an alphanumeric or underscore, it # will be ignored. return unless node.value.to_s.match?(/\A[a-z0-9_]/i) correction = node.value.inspect correction = correction.delete_prefix(':') if node.parent.colon? return if properly_quoted?(node.source, correction) register_offense( node, correction: correction, message: format(MSG, correction: node.parent.colon? ? "#{correction}:" : correction) ) end
correct_inconsistent_hash_keys(keys)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 166 def correct_inconsistent_hash_keys(keys) keys.each do |key| ignore_node(key) next if requires_quotes?(key) next if properly_quoted?(key.source, %("#{key.value}")) correction = %("#{key.value}") register_offense( key, correction: correction, message: format(MSG_CONSISTENCY, correction: "#{correction}:") ) end end
in_alias?(node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 139 def in_alias?(node) node.parent&.alias_type? end
in_percent_literal_array?(node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 143 def in_percent_literal_array?(node) node.parent&.array_type? && node.parent.percent_literal? end
properly_quoted?(source, value)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 126 def properly_quoted?(source, value) return true if style == :strict && (!source.match?(/['"]/) || value.end_with?('=')) source == value || # `Symbol#inspect` uses double quotes, but allow single-quoted # symbols to work as well. source.gsub('"', '\"').tr("'", '"') == value end
register_offense(node, correction:, message: format(MSG, correction: correction))
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 122 def register_offense(node, correction:, message: format(MSG, correction: correction)) add_offense(node, message: message) { |corrector| corrector.replace(node, correction) } end
requires_quotes?(sym_node)
click to toggle source
# File lib/rubocop/cop/lint/symbol_conversion.rb, line 135 def requires_quotes?(sym_node) sym_node.value.inspect.match?(/^:".*?"|=$/) end