class RuboCop::Cop::Style::MutableConstant

This cop checks whether some constant value isn't a mutable literal (e.g. array or hash).

Strict mode can be used to freeze all constants, rather than just literals. Strict mode is considered an experimental feature. It has not been updated with an exhaustive list of all methods that will produce frozen objects so there is a decent chance of getting some false positives. Luckily, there is no harm in freezing an already frozen object.

@example EnforcedStyle: literals (default)

# bad
CONST = [1, 2, 3]

# good
CONST = [1, 2, 3].freeze

# good
CONST = <<~TESTING.freeze
  This is a heredoc
TESTING

# good
CONST = Something.new

@example EnforcedStyle: strict

# bad
CONST = Something.new

# bad
CONST = Struct.new do
  def foo
    puts 1
  end
end

# good
CONST = Something.new.freeze

# good
CONST = Struct.new do
  def foo
    puts 1
  end
end.freeze

Constants

MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 72
def autocorrect(node)
  expr = node.source_range

  lambda do |corrector|
    splat_value = splat_value(node)
    if splat_value
      correct_splat_expansion(corrector, expr, splat_value)
    elsif node.array_type? && !node.bracketed?
      corrector.insert_before(expr, '[')
      corrector.insert_after(expr, ']')
    elsif requires_parentheses?(node)
      corrector.insert_before(expr, '(')
      corrector.insert_after(expr, ')')
    end

    corrector.insert_after(expr, '.freeze')
  end
end
on_casgn(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 59
def on_casgn(node)
  _scope, _const_name, value = *node
  on_assignment(value)
end
on_or_asgn(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 64
def on_or_asgn(node)
  lhs, value = *node

  return unless lhs&.casgn_type?

  on_assignment(value)
end

Private Instance Methods

check(value) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 109
def check(value)
  range_enclosed_in_parentheses = range_enclosed_in_parentheses?(value)

  return unless mutable_literal?(value) ||
                range_enclosed_in_parentheses
  return if FROZEN_STRING_LITERAL_TYPES.include?(value.type) &&
            frozen_string_literals_enabled?

  add_offense(value)
end
correct_splat_expansion(corrector, expr, splat_value) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 138
def correct_splat_expansion(corrector, expr, splat_value)
  if range_enclosed_in_parentheses?(splat_value)
    corrector.replace(expr, "#{splat_value.source}.to_a")
  else
    corrector.replace(expr, "(#{splat_value.source}).to_a")
  end
end
frozen_string_literal?(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 128
def frozen_string_literal?(node)
  FROZEN_STRING_LITERAL_TYPES.include?(node.type) &&
    frozen_string_literals_enabled?
end
immutable_literal?(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 124
def immutable_literal?(node)
  node.nil? || node.immutable_literal?
end
mutable_literal?(value) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 120
def mutable_literal?(value)
  value&.mutable_literal?
end
on_assignment(value) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 93
def on_assignment(value)
  if style == :strict
    strict_check(value)
  else
    check(value)
  end
end
requires_parentheses?(node) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 133
def requires_parentheses?(node)
  node.range_type? ||
    (node.send_type? && node.loc.dot.nil?)
end
strict_check(value) click to toggle source
# File lib/rubocop/cop/style/mutable_constant.rb, line 101
def strict_check(value)
  return if immutable_literal?(value)
  return if operation_produces_immutable_object?(value)
  return if frozen_string_literal?(value)

  add_offense(value)
end