I'm trying to use reflective methods in Ruby, and running into a behavior that I find really surpising.
The following examples seems to work differently in IRB and when called a ruby script:
Example 1:
def myfun; end
p respond_to?(:myfun)
In IRb, this says 'true', In script: 'false'.
Example 2:
ml = methods
def myfun; end
p methods - ml
In IRb, this says [:myfun]. In script: [].
I found this under 1.8, 1.9 MRI, JRuby 1.5.6, etc - so I assume this is normal.
Why is the difference?
I was pretty sure 'respond_to?' is the way to see if a method is available - why is that not working in the above case?
This function - method on "main" object - is defined as private in ruby script. You can check this easily:
ml = private_methods
def myfun; end
p private_methods - ml #=> [:myfun]
p respond_to?(:myfun, true) #=> true
If you call it explicitly on self you will get an error:
self.myfun
# NoMethodError: private method ‘myfun’ called for main:Object
On the other hand, in IRB your method is defined as public. Under the hood it looks something like this:
class Object
def irb_binding
# this is where your entered code is evaluated
def myfun; :ok; end # you can define methods in other methods
self.myfun # and they are public by default
end
end
p irb_binding # :ok
IRB could easily evaluate at the top level but instead it creates a separate environment with the method so that local variables are not shared:
require "irb"
foo = :ok
IRB.start
#>> foo
# NameError: undefined local variable or method `foo' for main:Object
I think methods being public is just a coincidence due to the implementation and it doesn't matter much. These methods are temporary anyway.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With