What is the proper syntax/code to include a Module into another Module? My attempt below is not working. --Brian module Foo def xxx; "this is xxx" end end module Enumerable include Foo end puts .xxx #does not work, xxx not defined for Array. Array includes Enumerable, right?
on 2007-02-19 17:48
on 2007-02-19 19:10
Brian Buckley schrieb: > > puts .xxx #does not work, xxx not defined for Array. Array > includes Enumerable, right? Brian, this isn't a problem of your syntax/code, but a (well known) problem of the Ruby interpreter. There's no known solution yet. You have to change the Enumerable module directly. Regards, Pit
on 2007-02-20 03:00
Thanks, Pit. Rounding this out, I notice now that classes that "include Enumerable" after Enumerable is enhanced by "include Foo" have the extra method, but classes that "include Enumerable" before Enumerable is enhanced don't (core class Array is in this category). Interesting to learn this behavior is considered a bug, and may one day be fixed. Interestingly, re-including Enumerable to Array, i.e., the line class Array; include Enumerable end corrects the bug for Array --- this is not necessarily a useful thing to know since as you suggest putting code directly into Enumerable rather than by using an include appears to be the way to go here. --Brian
on 2007-02-20 06:33
Hi, (i'm no ruby internals expert, just having some fun poking at rhg) On Tuesday 20 February 2007 02:59, Brian Buckley wrote: > Thanks, Pit. > Interesting to learn this behavior is considered a bug, and may one > day be fixed. It is due the way method inheritance is implemented right now. In MRI, every object has a linked list of classes from which inherits methods. This list contains either "plain" ruby classes, and other "hidden" metaclasses, that serve to purposes such as singleton methods, class methods and module inclusion. The latter is implemented by inserting in the linked list a new "include class" whose mehtod table points to the included module's method table. This means that when you do class A include M end the ruby interpreter will build such an inheritance list: M | | A -> (iM) -> Object so, instances of A will have access to M's methods via the iM include class. When you do module M1 end module M2 include M1 end class A include M2 end two include classes are created for A, pointing to every module in the chain: +-------> M2 | | | (iM2) | | | M1 | | A -> (iM2') -> (iM1) -> Object ... that's why: > Interestingly, re-including Enumerable to Array, i.e., the line > > class Array; include Enumerable end ... fixes the problem, because this include causes the include class of your module to be added to Array's inheritance chain ... > corrects the bug for Array --- this is not necessarily a useful thing > to know since as you suggest putting code directly into Enumerable > rather than by using an include appears to be the way to go here. ... and also why adding code to enumerable works, because you are changing the method table already pointed by the include class in Array's inheritance linked list. Ruby internals are really really beautiful :) : http://www.ruby-doc.org/core/classes/Class.html : http://rhg.rubyforge.org/chapter04.html