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

Hi List,

more questions from a Ruby-Newbie...

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

I am aware of Singleton Methods, but as they can extend instances,
(how) can I extend classes without changing their original class
definition in Ruby?

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

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

···

On 9/1/06, Markus Gaelli <gaelli@emergent.de> wrote:

Hi List,

more questions from a Ruby-Newbie...

Sam Roberts from Ruby-Core answered to my original question:
>> I am aware of Singleton Methods, but as they can extend instances,
>> (how) can I extend classes without changing their original class
>> definition in Ruby?
>>
>
> 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.

--
Rick DeNatale

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

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! :slight_smile:

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.

···

On 9/1/06, Phrogz <gavin@refinery.com> wrote:

> 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! :slight_smile:

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.

--
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/