Sha256: a6c82ad55ab2c0d61e05c528fd36d886bfe9d0b70c47d5b1c3b6b9ac45f99ba2

Contents?: true

Size: 1.44 KB

Versions: 1

Compression:

Stored size: 1.44 KB

Contents

require "method_locator/version"

# MethodLocator finds all method definitions in an object instance, class, or
# module ancestor chain. This code will make more sense if you understand Ruby's
# object model and method lookup path. A great explanation of this can be found in:
# "Ruby's Eigenclasses Demystified" - http://blog.madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html

module MethodLocator
  def methods_for(meth)
    method_lookup_path.each_with_object([]) do |clazz, matches|
      matches << clazz.instance_method(meth) if instance_methods_for(clazz).include?(meth)
    end
  end

  def method_lookup_path
    lookup_path = is_a?(Class) ? class_lookup_path : nonclass_lookup_path
    insert_modules_into(lookup_path)
  end

  def class_only_ancestors
    ancestors.grep(Class)
  end

  private

  def instance_methods_for(clazz)
    clazz.instance_methods(false) + clazz.private_instance_methods(false)
  end

  def nonclass_lookup_path
    self.class.class_only_ancestors.unshift(singleton_class)
  end

  def class_lookup_path
    class_only_ancestors.map(&:singleton_class) + Class.class_only_ancestors
  end

  def insert_modules_into(lookup_path)
    # reverse is used here since included_modules contains all modules defined in
    # the current class as well as in its ancestors.
    lookup_path.reverse.map do |clazz|
      [clazz.included_modules.reverse, clazz]
    end.flatten.uniq.reverse
  end
end

Object.send(:include, MethodLocator)

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
method_locator-0.0.3 lib/method_locator.rb