From: "Jesús Gabriel y Galán" Date: 2010-06-21T17:00:59+09:00 Subject: Re: Accessing Class Variables in mixed in define_method On Fri, Jun 18, 2010 at 10:08 PM, Jamie Quint wrote: > I am using define_method inside a module to dynamically create a class > after the module is mixed in. The module is writing out class variables > for the class it is mixed into (yes I am aware that class variables are > generally frowned upon but they are necessary in this instance) and then > subsequently trying to access them through the method being created with > define_method. > > The problem here is that define method is not able to access the class > variables through class_variable_get or through accessing them directly. > In the first case it fails because 'class_variable_get' is not a method > on the class (oMethodError: undefined method ‘class_variable_get’ for > #) In the second instance it fails because it thinks > the class variable is uninitialized (NameError: uninitialized class > variable @@c in M) > > It seems to be evaluating the '@@c' call in the context of the module > and the class_variable_get call in the context of the class in which > define_method is being called after it is mixed in. Does anyone know how > I can get at the class variable here in define_method? Sample code > below: > > Best, > Jamie > > module M >  def cv(methodname) >    if class_variable_defined?(:@@c) >      classvar = class_variable_get(:@@c) >      classvar[rand(10000)] = "random" >      class_variable_set(:@cc,classvar) There's a typo here: it should be :@@c This "works" for me: module M def cv(methodname) if class_variable_defined?(:@@c) classvar = class_variable_get(:@@c) classvar[rand(10000)] = "random" class_variable_set(:@@c,classvar) else class_variable_set(:@@c,{}) end define_method(methodname.to_sym) do self.class.send(:class_variable_get,:@@c) end end end class Foo extend M cv("mfoo") end I say "works" because the first time, @@c is initialized to {} but no value is set. You need to call cv again inside class Foo in order to create a value in the hash: irb(main):021:0* f = Foo.new => # irb(main):022:0> f.mfoo => {} if you call it again: irb(main):024:0> class Foo irb(main):025:1> cv("mfoo") irb(main):026:1> end => # irb(main):027:0> f.mfoo => {9035=>"random"} Then it creates an entry in the hash, and then accessing it through mfoo retrieves it. Hope this helps, Jesus.