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