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

freeze_all() click to toggle source
# 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
included(base) click to toggle source

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

class_and_modules_to_freeze() click to toggle source
# File lib/console1984/freezeable.rb, line 55
def class_and_modules_to_freeze
  with_descendants(to_freeze)
end
freeze_class_or_module(class_or_module) click to toggle source
# 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
with_descendants(classes_and_modules) click to toggle source
# 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