module Console1984::Freezeable
Prevents adding new methods to classes, changing class-state or accessing/overridden instance variables via reflection. This is meant to prevent manipulating certain Console1984
classes during a console session.
Notice this won't prevent every state-modification command. You should handle special cases by overriding #freeze
(if necessary) and invoking freezing on the instance when it makes sense.
For example: check Console1984::Config#freeze
and Console1984::Shield#freeze_all.
The “freezing” doesn't materialize when the mixin is included. When mixed in, it will store the host class or module in a list. Then a call to Console1984::Freezeable.freeze_all
will look through all the modules/classes freezing them. This way, we can control the moment where we stop classes from being modifiable at setup time.
Public Class Methods
# File lib/console1984/freezeable.rb, line 48 def freeze_all class_and_modules_to_freeze.each do |class_or_module| freeze_class_or_module(class_or_module) end end
Not using ActiveSupport::Concern because a bunch of classes skip its .invoked
hook which is terrible for our purposes. This happened because it was being included in parent classes (such as Object), so it was skipping the include block.
# File lib/console1984/freezeable.rb, line 21 def self.included(base) Console1984::Freezeable.to_freeze << base base.extend ClassMethods # Flag to control manipulating instance data via instance_variable_get and instance_variable_set. # true by default. base.thread_mattr_accessor :prevent_instance_data_manipulation_after_freezing, default: true end
Private Class Methods
# File lib/console1984/freezeable.rb, line 55 def class_and_modules_to_freeze with_descendants(to_freeze) end
# File lib/console1984/freezeable.rb, line 59 def freeze_class_or_module(class_or_module) class_or_module.prevent_instance_data_manipulation if class_or_module.prevent_instance_data_manipulation_after_freezing class_or_module.freeze end
# File lib/console1984/freezeable.rb, line 64 def with_descendants(classes_and_modules) classes_and_modules + classes_and_modules.grep(Class).flat_map(&:descendants) end