From: Robert Klemme Date: 2009-11-17T07:20:05+09:00 Subject: Re: How to dynamically include a module and update top level? On 16.11.2009 22:01, Alexandre Mutel wrote: > Hi, > I'm new to Ruby programming, and I'm having some trouble to dynamically > include a module into another module. This question may have been > already posted, I tried to find it without any success, sorry to ask it > probably again (I found Ruby really powerful, but there are some obscure > behavior that i still don't understand!) > > So my problem is simple. When trying with "static" include, it's working > as i understand it: > > irb(main):001:0> module A > irb(main):002:1> def test() > irb(main):003:2> "test" > irb(main):004:2> end > irb(main):005:1> end > => nil > irb(main):006:0> module B > irb(main):007:1> include A > irb(main):008:1> end > => B > irb(main):009:0> include B > => Object > irb(main):010:0> test > => "test" > > But when I'm trying to load the module A through a module_eval on module > B, this is not working: > > module A > def self.included(mod) > puts "#{self} included in #{mod}" > end > > def testA() > "testA" > end > end > > module B > class Includer > def self.include_dyn(name) > B.module_eval "include #{name}" > end > end > end > > irb(main):017:0> include B > => Object > irb(main):018:0> Includer.include_dyn "A" > A included in B > => B > irb(main):019:0> testA > NameError: undefined local variable or method `testA' for main:Object > from (irb):19 > from :0 > > __________________________ > > The weird thing is the included callback is saying that A is include in > B... so why the testA method is not expanded to the top level? > after this, if i try to include B again, and call testA, it's working... > but i thought that as soon as a module is mixed-in, every method added > later are available to the top-includer... > > It's possible to dynamically mixin A into B, and automatically having > the includer of B (the top level in my example), being updated? The point in time of inclusion is important: your dynamic inclusion comes after you said "include B". If you create a new class, which includes B you will also see A's methods. Try this module A def self.included(x) printf "%p included in %p\n", x, self end def foo 123 end end module B end class T include B end puts "initially" p T.ancestors, B === T.new, A === T.new module B include A end puts "inclusion of A" p T.ancestors, B === T.new, A === T.new class S include B end puts "new class with B" p S.ancestors, B === S.new, A === S.new You will see $ ruby19 incl.rb initially [T, B, Object, Kernel, BasicObject] true false B included in A inclusion of A [T, B, Object, Kernel, BasicObject] true false new class with B [S, B, A, Object, Kernel, BasicObject] true true $ Basically "include" behaves as if the inheritance chain at the time of inclusion is copied. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/