I have been looking at the process ruby utilizes for method lookup,
and wrote the code below. It has proven very enlightening to me. I am
sharing. It allows obj#method_table to be called where one normally
uses obj#methods. It inserts markers (conspicuous method names) into
the method array that delimit the source for the listed methods up to
that point so that it is clear how the method array is composed. See
the test case at the bottom for clarification.
The most thrilling thing I have done this entire year is to monkey-
patch methods and see them hop to the appropriate section of the
method_table and disappear from the previous position.
I’d be interested to hear any feedback interested rubyists have about
the approach or if anyone has suggestions to refactor the code.
Thanks,
Tim
module Kernel
def method_table
#for completness sake, include the self in inh_chain, that way we
can see the singleton_methods if any exist
inh_chain = self.class.ancestors.unshift(self)
inh_chain.each do |anc|
meth_name = anc.to_s.center(20,'_')
#define bookmark method to mark the position of that portion of
the lookup path
if anc.respond_to? :class_eval
begin
anc.class_eval(“def #{meth_name}; end” )
rescue
end
end
if anc.respond_to?(:define_singleton_method)
begin
anc.define_singleton_method(“singleton_to_left”.to_s.center(25,’_’).to_sym)
{}
#uncommnet the following line to see how subsequent
singleton methods stack on
#anc.define_singleton_method(“Bsingleton”.to_s.center(20,’’).to_sym){}
meth_name = "extension_to_right".to_s.center(25,'_').to_sym
anc.extend(Module.new{eval("def #{meth_name};end")})
#uncommnet the following lines to see how subsequent
extended methods stack on
#meth_name = “extension”.to_s.center(20,‘→’).to_sym
#anc.extend(Module.new{eval “def B#{meth_name};end;def
C#{meth_name};end”})
rescue
end
end
end
self.methods
end
end
#######TEST CASE###########
module First
def added_in_first
end
end
module Second
def added_in_second
end
end
class NewObject
include First
end
no = NewObject.new
no.extend(Second)
def no.singleton_method
end
p no.method_table
=>[:singleton_method, :singleton_to_left,
:extension_to_right_, :added_in_second, :NewObject_,
:added_in_first, :First_, :Object, :nil?,
:===, :=~, :!
~, :eql?, :class, :clone, :dup, :taint, :tainted?, :untaint, :untrust,
:untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods,
:singleton_methods, :protected_methods, :private_methods,
:public_methods, :instance_variables, :instance_variable_get,
:instance_variable_set, :instance_variable_defined?, :instance_of?,
:kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :extend,
:display, :method, :public_method, :define_singleton_method, :hash,
:id, :object_id, :to_enum, :enum_for, :gem, :method_table,
:Kernel, :==, :equal?, :!, :!
=, :instance_eval, :instance_exec, :send, :BasicObject_]