[Q] How can I ask to which module a method belongs to?

M

Markus Gaelli

Hi List,

more questions from a Ruby-Newbie...

Sam Roberts from Ruby-Core answered to my original question:
This is probably best posted to ruby-talk, not ruby-core, folks would
likely be quite interested.

classes are "open" in ruby, you can add methods as you wish.

irb(main):001:0> s = "hi"
=> "hi"
irb(main):002:0> class String; def this(opt) puts(self+opt) end end
=> nil
irb(main):003:0> s.this(" that")
hi that
=> nil
irb(main):004:0> "bye".this(" that")
bye that
=> nil

Cheers,
Sam

That is good news to me. But now I wonder, if and how I can ask e.g.
String#this(opt) in which module it is defined.
Any ideas?

Cheers,

Markus
 
R

Rick DeNatale

Hi List,

more questions from a Ruby-Newbie...

Sam Roberts from Ruby-Core answered to my original question:

That is good news to me. But now I wonder, if and how I can ask e.g.
String#this(opt) in which module it is defined.

First note, that a method can be defined in a module or a class, and
that a class is a kind of module.

I haven't tested this extensively but I think it works. It searches
for a method name in a class the same way that methods are found at
runtime, at each level of the class hierarchy, the class is searched,
then any modules that class includes in the reverse order they were
included. This code depends on Module#included_modules giving it's
result in the right order, which a few quick tests seems to indicate:
module A
end
module B
end
module C
include B
include A
end

C.included_modules => [A, B]
module D
include A
include B
end
D.included_modules => [B, A]

Okay so here's my code:

class Module
def module_defining(method_name)
method_name = method_name.to_s
return self if instance_methods(false).include?(method_name)
included_modules.each do |mixin|
answer = mixin.module_defining(method_name)
return answer if answer
end
nil
end
end

class Class
def module_defining(method_name)
answer = super
return answer if answer
return superclass.module_defining(method_name) if superclass
end
end

irb(main):001:0> load 'moddefining.rb'
=> true
irb(main):002:0> String.module_defining('==')
=> String
irb(main):003:0> String.module_defining('id')
=> Kernel
irb(main):004:0> String.module_defining('map')
=> Enumerable
 
P

Phrogz

irb(main):001:0> load 'moddefining.rb'
=> true
irb(main):002:0> String.module_defining('==')
=> String
irb(main):003:0> String.module_defining('id')
=> Kernel
irb(main):004:0> String.module_defining('map')
=> Enumerable

Sexy! :)

IMO something like this would make a nice addition to the core library.
Jumping through hoops for introspection is no fun. (At least this one
doesn't involve any string parsing.)

Note that the Method#inspect method gives you this same information in
string form:

irb(main):001:0> "".method( :== )
=> #<Method: String#==>
irb(main):002:0> String.instance_method( :== )
=> #<UnboundMethod: String#==>
irb(main):003:0> "".method( :id )
=> #<Method: String(Kernel)#id>
irb(main):004:0> String.instance_method( :id )
=> #<UnboundMethod: String(Kernel)#id>
irb(main):005:0> "".method( :map )
=> #<Method: String(Enumerable)#map>
irb(main):006:0> String.instance_method( :map )
=> #<UnboundMethod: String(Enumerable)#map>

Less or more reliable to use this with string parsing? Perhaps slightly
more, if only to be sure that the method resolution order is properly
followed.
 
R

Rick DeNatale

Sexy! :)

IMO something like this would make a nice addition to the core library.
Jumping through hoops for introspection is no fun. (At least this one
doesn't involve any string parsing.)

Note that the Method#inspect method gives you this same information in
string form:

irb(main):001:0> "".method( :== )
=> #<Method: String#==>
irb(main):002:0> String.instance_method( :== )
=> #<UnboundMethod: String#==>
irb(main):003:0> "".method( :id )
=> #<Method: String(Kernel)#id>
irb(main):004:0> String.instance_method( :id )
=> #<UnboundMethod: String(Kernel)#id>
irb(main):005:0> "".method( :map )
=> #<Method: String(Enumerable)#map>
irb(main):006:0> String.instance_method( :map )
=> #<UnboundMethod: String(Enumerable)#map>

Less or more reliable to use this with string parsing? Perhaps slightly
more, if only to be sure that the method resolution order is properly
followed.

Well although the ri documentation for Module#included_modules doesn't
say wo in so many words, it does in fact produce the list in the right
order.

The way an included module is implemented is that a 'hidden' proxy
class is inserted between the class which includes the module, and
it's superclass. It's hidden because it's marked as being a T_ICLASS.

The included_modules C code just walks the chain from the super class
and the superclass of the class, listing any T_ICLASSes that it finds.

Since this is the way that method lookup works, it's exactly the right order.
--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

IPMS/USA Region 12 Coordinator
http://ipmsr12.denhaven2.com/

Visit the Project Mercury Wiki Site
http://www.mercuryspacecraft.com/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,743
Messages
2,569,478
Members
44,899
Latest member
RodneyMcAu

Latest Threads

Top