On Fri, Jun 18, 2010 at 10:08 PM, Jamie Quint <jamiequint / gmail.com> 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 =91class_variable_get=92 for
> #<Foo:0x100124638>) 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
> =A0def cv(methodname)
> =A0 =A0if class_variable_defined?(:@@c)
> =A0 =A0 =A0classvar =3D class_variable_get(:@@c)
> =A0 =A0 =A0classvar[rand(10000)] =3D "random"
> =A0 =A0 =A0class_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 =3D class_variable_get(:@@c)
     classvar[rand(10000)] =3D "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 =3D Foo.new
=3D> #<Foo:0xb74aeb30>
irb(main):022:0> f.mfoo
=3D> {}

if you call it again:

irb(main):024:0> class Foo
irb(main):025:1> cv("mfoo")
irb(main):026:1> end
=3D> #<Proc:0xb74bb8d0@(irb):10>
irb(main):027:0> f.mfoo
=3D> {9035=3D>"random"}

Then it creates an entry in the hash, and then accessing it through
mfoo retrieves it.

Hope this helps,

Jesus.