[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

dynamically adding class variables

Siemen Baader

3/27/2007 10:48:00 PM

Hi,

I am writing an object relational mapper for an educational project
where I need to add new class variables to classes in an inheritance
hierarchy. The variables hold class-specific information such as which
tables are mapped and validation logic so they cannot be shared among
the hierarchy like inherited class variables from the superclass would.
Because of that I could not declare them in the parent and just
initialize them in the subclasses. Instead, I decided to add and set
them at runtime after subclassing.

However, i think ruby behaves a bit odd here. In class methods inherited
from the superclass I can see the class variables through the method
class_variables, but to use them in the child class I have to re-open
the children and re-define the class methods which use the variables!


?> class ORM
>> def ORM.table table
>> class_eval("@@table = :%s" % table)
>> end
>>
?> def ORM.vars
>> class_variables
>> end
>> def ORM.table?
>> @@table
>> end
>> end
=> nil
>>
?> class Article < ORM
>> table :articles
>> end
=> :articles
>>
?> Article.vars
=> ["@@table"]
>> Article.table?
NameError: uninitialized class variable @@table in ORM
from (irb):22:in `table?'
from (irb):31
from :0
>>
?> class Article
>> def Article.table?
>> @@table
>> end
>> end
=> nil
>>
?> Article.table?
=> :articles

Could anyone enlighten me on why class_variables finds the class
variable in the subclass and why the class methods act like they were
invoked on the parent class? Apparently class_variables finds the
variables in a different way than ruby does when it evaluates the method
code...

Also, has anyone a good idea how I can give each child class variables
which are shared among all instances of the classes but isolated from
parents and other children?

thanks,
siemen baader
8 Answers

Gavin Kistner

3/27/2007 11:08:00 PM

0

On Mar 27, 4:48 pm, Siemen Baader <sbaa...@ruc.dk> wrote:
> However, i think ruby behaves a bit odd here. In class methods inherited
> from the superclass I can see the class variables through the method
> class_variables, but to use them in the child class I have to re-open
> the children and re-define the class methods which use the variables!

http://www.google.com/search?q=ruby-talk+class+variab...

Gavin Kistner

3/27/2007 11:20:00 PM

0

On Mar 27, 4:48 pm, Siemen Baader <sbaa...@ruc.dk> wrote:
> >> def ORM.table table
> >> class_eval("@@table = :%s" % table)
> >> end

FYI:

C:\>qri class_variable_set
----------------------------------------------
Module#class_variable_set
obj.class_variable_set(symbol, obj) => obj
------------------------------------------------------------------------
Sets the class variable names by _symbol_ to _object_.

class Fred
@@foo = 99
def foo
@@foo
end
end

def Fred.foo
class_variable_set(:@@foo, 101) #=> 101
end
Fred.foo
Fred.new.foo #=> 101

However, given your problems, I would advise using instance variables
on the class itself along with accessor methods for them.

Instead of:

class Foo
@@bar = 12
def jam
p @@bar
end
end

Use:

class Foo
@bar = 12
class << self
attr_accessor :bar
end
def jam
p self.class.bar
end
end

Ara.T.Howard

3/27/2007 11:27:00 PM

0

Gary Wright

3/27/2007 11:38:00 PM

0


On Mar 27, 2007, at 6:50 PM, Siemen Baader wrote:
> I am writing an object relational mapper for an educational project
> where I need to add new class variables to classes in an
> inheritance hierarchy. The variables hold class-specific
> information such as which tables are mapped and validation logic
> so they cannot be shared among the hierarchy like inherited class
> variables from the superclass would. Because of that I could not
> declare them in the parent and just initialize them in the
> subclasses. Instead, I decided to add and set them at runtime after
> subclassing.
>
> However, i think ruby behaves a bit odd here. In class methods
> inherited from the superclass I can see the class variables through
> the method class_variables, but to use them in the child class I
> have to re-open the children and re-define the class methods which
> use the variables!

Don't use Ruby 'class variables' use Ruby 'class instance variables'.

Programmers coming to Ruby and expecting per class state often gravitate
towards the mis-named 'class variables' when what they *really* want are
'class instance variables'.

I fault the misleading name and explanations in Pickaxe and The Ruby Way
for this never ending source of confusion. For example on p. 33 of
the Pickaxe:

"Sometimes classes themselves need to have their own states. This is
where class variables come in."

And on page 3 and 4 of The Ruby Way is a several paragraph
description of
per class state that consistently uses the term 'class variable' when,
with respect to Ruby, 'class instance variable' is more applicable.

Gary Wright




Joel VanderWerf

3/28/2007 2:05:00 AM

0

ara.t.howard@noaa.gov wrote:
> # gem install trails
^^^^^^
^^^^^^
> http://codeforpeople.com/lib/ruby/traits/traits-0....

Hey Ara, when can we expect ruby-on-trails? :P

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Ara.T.Howard

3/28/2007 2:15:00 AM

0

Siemen Baader

3/28/2007 12:56:00 PM

0

Thanks very much for the answers Phrogz, Ara and Gary!

I actually had it set up with class instance vars first, but they were
so longish to access (self.class.method) that I thought there had to be
a cleaner, more rubyish solution I was missing...

Also thanks for the google link, it was great help to me even though the
query is pretty obvious, at least after you see it .. :)

As for the strange beavior af class variables:

- It seems ok to me that they are singleton in the whole inheritance
tree; that's a design choice.

- But: Is it intended behaviour that they can be seen by class_variables
but not used in class methods like in my example and here:

--->
http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_var...

- siemen

hemant

3/28/2007 1:07:00 PM

0

On 3/28/07, Siemen Baader <sbaader@ruc.dk> wrote:
> Thanks very much for the answers Phrogz, Ara and Gary!
>
> I actually had it set up with class instance vars first, but they were
> so longish to access (self.class.method) that I thought there had to be
> a cleaner, more rubyish solution I was missing...
>

Well I have written this small bit of code, which makes use of class
instance variable still more simpler:

class Object

def self.metaclass; class << self; self; end; end

def self.iattr_accessor *args

metaclass.instance_eval do
attr_accessor *args
end

args.each do |attr|

class_eval do
define_method(attr) do
self.class.send(attr)
end
end

end
end
end

This is how you use it:

class Foobar
iattr_accessor :foo
end

Foobar.foo = "blah"
p Foobar.foo

lol = Foobar.new
p lol.foo


> Also thanks for the google link, it was great help to me even though the
> query is pretty obvious, at least after you see it .. :)
>
> As for the strange beavior af class variables:
>
> - It seems ok to me that they are singleton in the whole inheritance
> tree; that's a design choice.
>
> - But: Is it intended behaviour that they can be seen by class_variables
> but not used in class methods like in my example and here:
>
> --->
> http://www.oreillynet.com/ruby/blog/2007/01/nubygems_dont_use_class_var...
>
> - siemen
>
>


--
gnufied
-----------
There was only one Road; that it was like a great river: its springs
were at every doorstep, and every path was its tributary.
http://people.inxsasia.c...