module Ivar

def self.check_all(&block)

Returns:
  • (void) -

Parameters:
  • block (Proc) -- Optional block. If provided, auto-checking is only active
def self.check_all(&block)
  root = project_root
  CHECK_ALL_MANAGER.enable(root, &block)
end

def self.check_policy

Returns:
  • (Symbol) - The default check policy
def self.check_policy
  @default_check_policy
end

def self.check_policy=(policy)

Parameters:
  • policy (Symbol, Policy) -- The default check policy
def self.check_policy=(policy)
  MUTEX.synchronize { @default_check_policy = policy }
end

def self.class_checked?(klass)

Returns:
  • (Boolean) - Whether the class has been validated

Parameters:
  • klass (Class) -- The class to check
def self.class_checked?(klass)
  MUTEX.synchronize { @checked_classes.key?(klass) }
end

def self.clear_analysis_cache

Thread-safe: Write operation protected by mutex
For testing purposes - allows clearing the cache
def self.clear_analysis_cache
  MUTEX.synchronize do
    @analysis_cache.clear
    @checked_classes.clear
    @manifest_registry.clear
  end
  PROJECT_ROOT_FINDER.clear_cache
end

def self.disable_check_all

Returns:
  • (void) -
def self.disable_check_all
  CHECK_ALL_MANAGER.disable
end

def self.get_analysis(klass)

Thread-safe: Multiple readers are allowed, but writers block all other access
Creates a new analysis if one doesn't exist in the cache
Returns a cached analysis for the given class or module
def self.get_analysis(klass)
  return @analysis_cache[klass] if @analysis_cache.key?(klass)
  MUTEX.synchronize do
    @analysis_cache[klass] ||= TargetedPrismAnalysis.new(klass)
  end
end

def self.get_ancestral_analyses(klass)

def self.get_ancestral_analyses(klass)
  klass
    .ancestors.filter_map { |ancestor| maybe_get_analysis(ancestor) }
    .reverse
end

def self.get_manifest(klass, create: true)

Returns:
  • (Manifest, nil) - The manifest for the class or module, or nil if not found and create_if_missing is false

Parameters:
  • create (Boolean) -- Whether to create a new manifest if one doesn't exist
  • klass (Class, Module) -- The class or module to get a manifest for
def self.get_manifest(klass, create: true)
  return @manifest_registry[klass] if @manifest_registry.key?(klass)
  return nil unless create
  MUTEX.synchronize do
    @manifest_registry[klass] ||= Manifest.new(klass)
  end
end

def self.get_or_create_manifest(klass)

Returns:
  • (Manifest) - The manifest for the class or module

Parameters:
  • klass (Class, Module) -- The class or module to get a manifest for
def self.get_or_create_manifest(klass)
  get_manifest(klass, create: true)
end

def self.get_policy(policy, **options)

Returns:
  • (Policy) - The policy instance

Parameters:
  • options (Hash) -- Options to pass to the policy constructor
  • policy (Symbol, Policy, Array) -- The policy to get
def self.get_policy(policy, **options)
  return policy if policy.is_a?(Policy)
  # Handle the case where policy is an array with [policy_name, options]
  if policy.is_a?(Array) && policy.size == 2 && policy[1].is_a?(Hash)
    policy_name, policy_options = policy
    policy_class = POLICY_CLASSES[policy_name]
    raise ArgumentError, "Unknown policy: #{policy_name}" unless policy_class
    return policy_class.new(**policy_options)
  end
  policy_class = POLICY_CLASSES[policy]
  raise ArgumentError, "Unknown policy: #{policy}" unless policy_class
  policy_class.new(**options)
end

def self.get_stashed_method(klass, method_name)

Returns:
  • (UnboundMethod, nil) - The stashed method or nil if not found

Parameters:
  • method_name (Symbol) -- The name of the method to retrieve
  • klass (Class) -- The class that owns the method
def self.get_stashed_method(klass, method_name)
  (klass.instance_variable_get(:@__ivar_method_impl_stash) || {})[method_name]
end

def self.internal_ivar?(ivar_name)

Returns:
  • (Boolean) - Whether the variable is an internal variable

Parameters:
  • ivar_name (Symbol, String) -- The instance variable name to check
def self.internal_ivar?(ivar_name)
  ivar_name.to_s.start_with?(INTERNAL_IVAR_PREFIX)
end

def self.known_internal_ivars

Returns:
  • (Array) - List of known internal instance variables
def self.known_internal_ivars
  [
    :@__ivar_check_policy,
    :@__ivar_initialized_vars,
    :@__ivar_method_impl_stash,
    :@__ivar_skip_init
  ]
end

def self.manifest_exists?(klass)

Returns:
  • (Boolean) - Whether a manifest exists for the class or module

Parameters:
  • klass (Class, Module) -- The class or module to check
def self.manifest_exists?(klass)
  @manifest_registry.key?(klass)
end

def self.mark_class_checked(klass)

Parameters:
  • klass (Class) -- The class to mark as checked
def self.mark_class_checked(klass)
  MUTEX.synchronize { @checked_classes[klass] = true }
end

def self.maybe_get_analysis(klass)

def self.maybe_get_analysis(klass)
  if klass.include?(Validation)
    get_analysis(klass)
  end
end

def self.project_root(caller_location = nil)

Returns:
  • (String) - The absolute path to the project root directory

Parameters:
  • caller_location (String, nil) -- Optional file path to start from (defaults to caller's location)
def self.project_root(caller_location = nil)
  @project_root ||= PROJECT_ROOT_FINDER.find(caller_location)
end

def self.project_root=(explicit_root)

def self.project_root=(explicit_root)
  @project_root = explicit_root
end

def self.stash_method(klass, method_name)

Returns:
  • (UnboundMethod, nil) - The stashed method or nil if the method doesn't exist

Parameters:
  • method_name (Symbol) -- The name of the method to stash
  • klass (Class) -- The class that owns the method
def self.stash_method(klass, method_name)
  return nil unless klass.method_defined?(method_name) || klass.private_method_defined?(method_name)
  method_impl = klass.instance_method(method_name)
  stash = klass.instance_variable_get(:@__ivar_method_impl_stash) ||
    klass.instance_variable_set(:@__ivar_method_impl_stash, {})
  stash[method_name] = method_impl
end