class RuboCop::Cop::ThreadSafety::MutableClassInstanceVariable
end
end.freeze
end
puts 1
def foo
@var = Struct.new do
class Model
# good
end
@var = Something.new.freeze
class Model
# good
end
end
end
puts 1
def foo
@var = Struct.new do
class Model
# bad
end
@var = Something.new
class Model
# bad
@example EnforcedStyle: strict
end
@var = Something.new
class Model
# good
end
TESTING
This is a heredoc
@var = <<~TESTING.freeze
class Model
# good
end
@list = [1, 2, 3].freeze
class Model
# good
end
@list = [1, 2, 3]
class Model
# bad
@example EnforcedStyle: literals (default)
Luckily, there is no harm in freezing an already frozen object.
objects so there is a decent chance of getting some false positives.
updated with an exhaustive list of all methods that will produce frozen
Strict mode is considered an experimental feature. It has not been
than just literals.
Strict mode can be used to freeze all class instance variables, rather
ThreadSafety/ClassAndModuleAttributes cop.
updated via an attr_reader so would not be detected by the
between threads. A mutable object such as an array or hash may be
Class instance variables are a risk to threaded code as they are shared
See github.com/rubocop/rubocop/blob/master/lib/rubocop/cop/style/mutable_constant.rb<br>It is based on Style/MutableConstant from RuboCop.
mutable literal (e.g. array or hash).
Checks whether some class instance variable isn’t a
def autocorrect(corrector, node)
def autocorrect(corrector, node) expr = node.source_range 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
def check(value)
def check(value) return unless mutable_literal?(value) || range_enclosed_in_parentheses?(value) return if frozen_string_literal?(value) add_offense(value) do |corrector| autocorrect(corrector, value) end end
def container?(node)
def container?(node) return true if define_singleton_method?(node) return true if define_method?(node) %i[def defs class module].include?(node.type) end
def correct_splat_expansion(corrector, expr, splat_value)
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
def frozen_string_literal?(node)
def frozen_string_literal?(node) literal_types = if target_ruby_version >= 3.0 FROZEN_STRING_LITERAL_TYPES_RUBY30 else FROZEN_STRING_LITERAL_TYPES_RUBY27 end literal_types.include?(node.type) && frozen_string_literals_enabled? end
def immutable_literal?(node)
def immutable_literal?(node) node.nil? || node.immutable_literal? end
def in_class?(node)
def in_class?(node) container = node.ancestors.find do |ancestor| container?(ancestor) end return false if container.nil? %i[class module].include?(container.type) end
def mutable_literal?(node)
def mutable_literal?(node) return false if node.nil? node.mutable_literal? || range_type?(node) end
def on_assignment(value)
def on_assignment(value) if style == :strict strict_check(value) else check(value) end end
def on_ivasgn(node)
def on_ivasgn(node) return unless in_class?(node) on_assignment(node.expression) end
def on_masgn(node)
def on_masgn(node) return unless in_class?(node) mlhs, values = *node # rubocop:disable InternalAffairs/NodeDestructuring return unless values.array_type? mlhs.to_a.zip(values.to_a).each do |lhs, value| next unless lhs.ivasgn_type? on_assignment(value) end end
def on_or_asgn(node)
def on_or_asgn(node) return unless node.assignment_node.ivasgn_type? return unless in_class?(node) on_assignment(node.expression) end
def range_type?(node)
def range_type?(node) node.type?(:range) end
def requires_parentheses?(node)
def requires_parentheses?(node) range_type?(node) || (node.send_type? && node.loc.dot.nil?) end
def strict_check(value)
def strict_check(value) return if immutable_literal?(value) return if operation_produces_immutable_object?(value) return if operation_produces_threadsafe_object?(value) return if frozen_string_literal?(value) add_offense(value) do |corrector| autocorrect(corrector, value) end end