I'm trying to understand ruby metaprogramming a bit better and while I have workarounds for what I want to do, I would like to make it as clean as possible.
Simply put I would like to check if the class that includes a module has defined a given method:
irb(main):058:1* module A
irb(main):059:2* def self.included(base)
irb(main):060:2* puts base.singleton_method(:singleton_test)
irb(main):061:1* end
irb(main):062:0> end
:included
irb(main):063:1* class B
irb(main):064:1* include A
irb(main):065:2* def self.singleton_test
irb(main):066:2* puts "hi"
irb(main):067:1* end
irb(main):068:0> end
I would expect this to output something like the following:
#<Method: B.singleton_test() (irb):95>
However, it does not:
(irb):60:in `singleton_method': undefined singleton method `singleton_test' for `B' (NameError)
puts base.singleton_method(:singleton_test)
^^^^^^^^^^^^^^^^^
I suspect it's because the singleton methods are not bound to base
yet when the included
hook is called.
How would I go about checking for singleton_test
being defined in this pattern?
PS Maybe also worth noting this seems to happen with any method definitions on base
at the time Module A
is included, singleton or instance.
It's a simple ordering issue.
Ruby is (mostly) evaluated left-to-right top-to-bottom.
class B
include A
def self.singleton_test
puts('hi')
end
end
As you can see, the include
comes before the method definition. You need to swap the two around:
class B
def self.singleton_test
puts('hi')
end
include A
# #<Method: B.singleton_test() ./test.rb:2>
end