Need help with class variables and inheritance

J

John Doe

Hi,

Suppose i wrote something like this:

class TestClass
@@testmethod = lambda { puts "inside testmethod" }
def method_missing(name, *args)
eval("@@#{name}").call(*args)
end
end

irb(main):002:0> TestClass.new.testmethod
inside testmethod

It works fine but if I have more classes i don't want to duplicate the
same method_missing. I thought i could write this:

class TestSuperClass
def method_missing(name, *args)
eval("@@#{name}").call(*args)
end
end
class TestSubClass < TestSuperClass
@@testmethod = lambda { puts "inside testmethod" }
end

but then i get this error:

irb(main):003:0> TestSubClass.new.testmethod
NameError: (eval):1:in `method_missing': uninitialized class variable
@@testmethod in TestSuperClass

Is there any way to get it to work?
 
L

Leslie Viljoen

Hi,

Suppose i wrote something like this:

class TestClass
=A0@@testmethod =3D lambda { puts "inside testmethod" }
=A0def method_missing(name, *args)
=A0 =A0eval("@@#{name}").call(*args)
=A0end
end

irb(main):002:0> TestClass.new.testmethod
inside testmethod

It works fine but if I have more classes i don't want to duplicate the
same method_missing. I thought i could write this:

class TestSuperClass
=A0def method_missing(name, *args)
=A0 =A0eval("@@#{name}").call(*args)
=A0end
end
class TestSubClass < TestSuperClass
=A0@@testmethod =3D lambda { puts "inside testmethod" }
end

but then i get this error:

irb(main):003:0> TestSubClass.new.testmethod
NameError: (eval):1:in `method_missing': uninitialized class variable
@@testmethod in TestSuperClass

Is there any way to get it to work?


The @@variables are shared among subclasses, not superclasses. So you
could define the variable in the superclass:

class TestSuperClass
@@testmethod =3D 1
def method_missing(name, *args)
eval("@@#{name}").call(*args)
end
end

class TestSubClass < TestSuperClass
@@testmethod =3D lambda { puts "inside testmethod" }
end

TestSubClass.new.testmethod


-----
or, you could use an instance variable, since I'm not sure class
variables are really useful in Ruby:
-----

class TestSuperClass
def method_missing(name, *args)
eval("@#{name}").call(*args)
end
end

class TestSubClass < TestSuperClass
def initialize
@testmethod =3D lambda { puts "inside testmethod" }
end
end

TestSubClass.new.testmethod


-----
... but more importantly, why do you want to do this? There's likely
to be a better way.


More info on inheritance and class variables:
http://stackoverflow.com/questions/1251352/ruby-inherit-code-that-works-wit=
h-class-variables
 
J

John Doe

The @@variables are shared among subclasses, not superclasses. So you
could define the variable in the superclass:

class TestSuperClass
@@testmethod = 1


Yes but if i have 2 subclasses with 2 methods in each then i will need
to define 4 variables in the superclass.

@@method0 = @@method1 = @@method2 = @@method3 = 1

And every time i want to add a method in a subclass i will need to go to
the superclass code and add another one. That's the sort of duplication
i would like to avoid.

or, you could use an instance variable, since I'm not sure class
variables are really useful in Ruby:

class TestSubClass < TestSuperClass
def initialize
@testmethod = lambda { puts "inside testmethod" }
end
end


If you put something in initialize then when you change the code and
reload it in a running program (or running irb) you need to recreate all
existing objects. With class variables there is no need to.

... but more importantly, why do you want to do this? There's likely
to be a better way.


I know it's nothing useful but this is how i learn. I want to make an
alternative to the def keyword. For example, i want to have a way of
defining methods which take arguments in reverse.

defbackward:)mymethod) do |x,y,z|
[x,y,z]
end
irb(main):004:0> mymethod(1,2,3)
=> [3, 2, 1]

I thought i would use method_missing and this leads to the problem i
showed in the first post.

More info on inheritance and class variables:
http://stackoverflow.com/questions/1251352/ruby-inherit-code-that-works-with-class-variables


Right, this explains a lot. I ended up with:

class TestSuperClass
def self.testdefhash
@testdefhash
end
def self.testdef(name, &block)
(@testdefhash ||= {})[name] = block
end
def method_missing(name, *args)
self.class.testdefhash[name].call(*args)
end
end
class TestSubClassA < TestSuperClass
testdef:)testmethod) { puts "inside testmethod a" }
testdef:)anothermethod) { puts "inside anothermethod a" }
end
class TestSubClassB < TestSuperClass
testdef:)testmethod) { puts "inside testmethod b" }
testdef:)anothermethod) { puts "inside anothermethod b" }
end

irb(main):002:0> TestSubClassA.new.testmethod
inside testmethod a
irb(main):003:0> TestSubClassB.new.anothermethod
inside anothermethod b

So far it works. Thanks for help.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top