module Fidgit::RedirectorMethods

Redirects methods to an object, but does not mask methods and ivars from the calling context.

Public Instance Methods

instance_methods_eval() { |context| ... } click to toggle source

Evaluate a block accessing methods and ivars from the calling context, but calling public methods (not ivars or non-public methods) on this object in preference.

# File lib/fidgit/redirector.rb, line 6
def instance_methods_eval(&block)
  raise ArgumentError, "block required" unless block_given?

  context = eval('self', block.binding)

  context.send :push_redirection_target, self

  begin
    yield context
  ensure
    context.send :pop_redirection_target
  end

  self
end

Protected Instance Methods

pop_redirection_target() click to toggle source
# File lib/fidgit/redirector.rb, line 54
def pop_redirection_target
  meta_class = class << self; self; end

  target, methods_to_recreate, methods_to_remove = redirection_stack.pop

  # Remove the redirection methods
  methods_to_remove.reverse_each do |meth|
    meta_class.send :remove_method, meth
  end

  # Replace with the previous versions of the methods.
  methods_to_recreate.reverse_each do |meth, reference, access|
    meta_class.send :define_method, meth, reference
    meta_class.send access, meth unless access == :public
  end

  target
end
push_redirection_target(target) click to toggle source
# File lib/fidgit/redirector.rb, line 23
def push_redirection_target(target)
  meta_class = class << self; self; end
  base_methods = Object.public_instance_methods

  # Redirect just the public methods of the target, less those that are on Object.
  methods_to_redirect = target.public_methods - base_methods

  # Only hide those public/private/protected methods that are being redirected.
  methods_overridden = []
  [:public, :protected, :private].each do |access|
    methods_to_hide = meta_class.send("#{access}_instance_methods", false) & methods_to_redirect
    methods_to_hide.each do |meth|
      # Take a reference to the method we are about to override.
      methods_overridden.push [meth, method(meth), access]
      meta_class.send :remove_method, meth
    end
  end

  # Add a method, to redirect calls to the target.
  methods_to_redirect.each do |meth|
    meta_class.send :define_method, meth do |*args, &block|
      target.send meth, *args, &block
    end
  end

  redirection_stack.push [target, methods_overridden, methods_to_redirect]

  target
end

Private Instance Methods

redirection_stack() click to toggle source

Direct access to the redirection stack.

# File lib/fidgit/redirector.rb, line 75
def redirection_stack
  @_redirection_stack ||= []
end