Reputation: 967
I am learning some metaprogramming and I was stuck trying to find a method. Let's say I have the following class:
class MyClass
def self.my_method
end
def your_method
end
end
With the following code I can search for each method in the object space:
type = Class
name = /^my_method$/
result = ObjectSpace.each_object(type).select do |o|
o.instance_methods(false).grep(name).size > 0 || o.methods.grep(name).size > 0
end
p result
And it finds it showing the following output:
[MyClass]
As the searcher code also searches for instance methods, it shows the same output when looking for your_method.
Even with if I add a singleton method to an object:
mc = MyClass.new
def mc.our_method
end
Just changing the searcher like this:
type = Object
name = /^our_method$/
result = ObjectSpace.each_object(type).select do |o|
o.methods.grep(name).size > 0
end
p result
It also finds it:
[#<MyClass:0x8f86760>]
The question is, how do I find a method defined in the top level object? This method:
def hidden
end
Besides, which is the current class when defining a method like this?
Upvotes: 4
Views: 81
Reputation: 110725
If you had this:
def my_method() end
class A
def self.my_method() end
end
class B < A
def my_method() end
end
class C
def my_method() end
end
and wanted to find methods named 'my_method'
that you've created, you could do this:
ObjectSpace.each_object(Class).select do |o|
o.instance_methods(false).include?(:my_method)
end
#=> [C, B]
ObjectSpace.each_object(Class).select do |o|
o.methods(false).include?(:my_method)
end
#=> [A]
ObjectSpace.each_object(Class).select do |o|
o.private_instance_methods(false).include?(:my_method)
end
#=> [Object]
Upvotes: 0
Reputation: 96994
Which is the current class when defining a method like this?
We can easily figure out what object we’re in by inspecting self
in this top level scope:
self #=> main
self.class #=> Object
So we’re not in a Class, but an instance of Object which is dubbed “main”.
How do I find a method defined in the top level object?
This is where it gets interesting. The top-level scope object in Ruby behaves specially, but it’s relatively easy to discover where a method here defined lives:
def foo; :bar; end
method(:foo).owner #=> Object
Object.new.foo #=> NoMethodError: private method `foo' called
Object.new.send(:foo) #=> :bar
So methods defined at the top-level are made (private*) instance methods of Object. The reason your ”searcher” cannot find it is because these methods are private, and neither methods
nor instance_methods
include private methods, instead you need private_methods
and private_instance_methods
:
Object.instance_methods.include?(:foo) #=> false
Object.private_instance_methods.include?(:foo) #=> true
* Note that Pry (at least v0.10.1) alters this to make methods defined at top-level in its REPL public.
Upvotes: 5