From: Alexandre Mutel on 16 Nov 2009 16:01 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? Thanks! -- Posted via http://www.ruby-forum.com/.
From: Robert Klemme on 16 Nov 2009 17:16 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/
From: Alexandre Mutel on 16 Nov 2009 18:30 Robert Klemme wrote: > On 16.11.2009 22:01, Alexandre Mutel wrote: > Basically "include" behaves as if the inheritance chain at the time of > inclusion is copied. Thanks for your response. So it seems that every time a module is mixed-in another top-module, i have to reinclude the top-module into its includers? I tried the following "hack" and seems to work, I would be glad to have some feedback... not sure it's a good ruby habit... even if it's working! module ModuleIncluderTracker def includers() @includers end def included(mod) puts "#{self} included in #{mod}" if !(@includers.include? mod) @includers << mod end if (mod.respond_to? :reinclude) mod.reinclude end end def reinclude() @includers.each { |mod| puts "try to reinclude #{self} in #{mod}"; mod.module_eval "include #{self}"; } end end module A @includers = [] extend ModuleIncluderTracker def toto() "toto" end end module B @includers = [] extend ModuleIncluderTracker def self.late_include(mod) module_eval "include #{mod}" end end irb(main):037:0> include B B included in Object => Object irb(main):038:0> B.late_include "A" A included in B try to reinclude B in Object B included in Object => B irb(main):039:0> toto => "toto" With this, it keeps all the includers up-to-date with new module included (although i have not managed any kind of circular references... not sure if it's possible...) -- Posted via http://www.ruby-forum.com/.
From: Robert Klemme on 17 Nov 2009 14:56 On 17.11.2009 00:30, Alexandre Mutel wrote: > Robert Klemme wrote: >> On 16.11.2009 22:01, Alexandre Mutel wrote: >> Basically "include" behaves as if the inheritance chain at the time of >> inclusion is copied. > > Thanks for your response. So it seems that every time a module is > mixed-in another top-module, i have to reinclude the top-module into its > includers? Apparently: irb(main):001:0> module A; end => nil irb(main):002:0> c=Class.new { include A } => #<Class:0x1021d37c> irb(main):003:0> c.ancestors => [#<Class:0x1021d37c>, A, Object, PP::ObjectMixin, Kernel, BasicObject] irb(main):004:0> module B; end => nil irb(main):005:0> module A; include B; end => A irb(main):006:0> c.ancestors => [#<Class:0x1021d37c>, A, Object, PP::ObjectMixin, Kernel, BasicObject] irb(main):007:0> c.class_eval { include A } => #<Class:0x1021d37c> irb(main):008:0> c.ancestors => [#<Class:0x1021d37c>, A, B, Object, PP::ObjectMixin, Kernel, BasicObject] irb(main):009:0> > I tried the following "hack" and seems to work, I would be glad to have > some feedback... not sure it's a good ruby habit... even if it's > working! Personally I find that the more interesting question. Do you want to have the side effect of updating potentially many classes (and objects via their class and #extend)? Maybe there is a better design choice? I don't know your use case or what you need that behavior for. Generally Matz pics _very_ reasonable choices so I tend to assume that the aforementioned side effect is usually not wanted. Which does not mean that there is no use case for this. Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/
From: Alexandre Mutel on 18 Nov 2009 03:39 Robert Klemme wrote: > Personally I find that the more interesting question. Do you want to > have the side effect of updating potentially many classes (and objects > via their class and #extend)? Maybe there is a better design choice? I > don't know your use case or what you need that behavior for. Generally > Matz pics _very_ reasonable choices so I tend to assume that the > aforementioned side effect is usually not wanted. Which does not mean > that there is no use case for this. > Thanks for you response! You are right. I have resolved this without using this trick and using plain .extends/include as you mentioned. My use case is simple : i would like to develop a DSL language that provides sub-DSL language that you can switch at runtime. For example, the top DSL is inside module ALang and i have two sub language extension in ALang_B and ALang_C like this: module ALang def use(sublang) # remove all previously defined sublanguage method # ... # Load new sub language here instance_eval { require "alang_#{sublang}" } instance_eval "extend ALang_#{sublang}" end # here others A Language methods.... # ... end module ALang_B def myABFunction() "myAB" end def self.extended(base) # perform init (declare dynamic methods...etc.) end end module ALang_C def myACFunction() "myAC" end def self.extended(base) # perform init (declare dynamic methods...etc.) end end ________________ Using it like this: require "alang" include alang use :B myABFunction use :C # myABFunction should not be usable myACFunction ________________ Do you any project that use sub DSL language loaded/unloaded like this? -- Posted via http://www.ruby-forum.com/.
|
Next
|
Last
Pages: 1 2 Prev: something went wrong Next: Special characters in csv header using fastercsv |