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
>>
?> 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
···
from :0
http://www.google.com/search?q=ruby-talk+class+variables+shared
···
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!
FYI:
C:\>qri class_variable_set
···
On Mar 27, 4:48 pm, Siemen Baader <sbaa...@ruc.dk> wrote:
>> def ORM.table table
>> class_eval("@@table = :%s" % table)
>> end
----------------------------------------------
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
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...
@@vars are shared among all child classes. @var belong to only one class even
though methods which access them might be inherited - in otherwords you must
initialize them in each child. ruby provides not built-in way to do this.
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?
traits and attributes both solve this problem completely. traits.rb is a bit
heavy-weight and offers many other features. attributes.rb is only 42 lines
of code but solves the issue you are dealing with. i reccomend using
attributes.rb
# gem install attributes
http://codeforpeople.com/lib/ruby/attributes/attributes-3.2.0/README
to use with classes just do
class Base
class << self
attribute(:a){ 42 }
end
end
class Derived < Base
end
the will setup both classes so that the default value of 'a' is 42 and it is
not shared, but it can be overriden easily too
Derived.a = 42.0
traits info
# gem install trails
http://codeforpeople.com/lib/ruby/traits/traits-0.9.2/README
regards.
-a
···
On Wed, 28 Mar 2007, Siemen Baader wrote:
--
be kind whenever possible... it is always possible.
- the dalai lama
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
···
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!
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 .. ![:slight_smile: :slight_smile:](https://ruby-talk.trydiscourse.com/images/emoji/twitter/slight_smile.png?v=5)
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_variab_1.html
- siemen
# gem install trails
^^^^^^
http://codeforpeople.com/lib/ruby/traits/traits-0.9.2/README
Hey Ara, when can we expect ruby-on-trails? ![:stuck_out_tongue: :stuck_out_tongue:](https://emoji.discourse-cdn.com/twitter/stuck_out_tongue.png?v=12)
···
ara.t.howard@noaa.gov wrote:
--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
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
···
On 3/28/07, Siemen Baader <sbaader@ruc.dk> wrote:
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 .. ![:slight_smile: :slight_smile:](https://emoji.discourse-cdn.com/twitter/slight_smile.png?v=12)
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:
--->
O'Reilly Media - Technology and Business Training
- 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.com/~hemant