If I want a class and its children to have different values for the same
class variables, how would I go about making that happen?
- donald
If I want a class and its children to have different values for the same
class variables, how would I go about making that happen?
- donald
Hi Donald, has been a long time...
504/4 > cat subclass-vars.rb && ruby subclass-vars.rb
#!/usr/bin/ruby
# vim: sts=2 sw=2 nu expandtab tw=0:
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
If I want a class and its children to have different values for the same
class variables, how would I go about making that happen?- donald
#
P = Class.new { @a = 42 }
class << P
attr_accessor :a
end
S = Class.new P
puts P.a
puts S.a
S.a = 43
puts P.a
puts S.a
------>
42
nil
42
43
Hopefully I understood what you wanted.
Cheers
Robert
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
Ball, Donald A Jr (Library) wrote:
If I want a class and its children to have different values for the same
class variables, how would I go about making that happen?- donald
Instead of:
class A
def A.var=(v)
@@var = v
end
def A.var
@@var
end
end
class B < A
end
where A and B will share the class variable, use a class instance
variable instead:
class A
def A.var=(v)
@var = v
end
def A.var
@var
end
end
class B < A
end
where A and B will have different class instance variables.
You can use the attr_accessor notation to create class instance variable
getters and setters like this:
class A
class << self
attr_accessor :var
end
end
best,
Dan
--
Posted via http://www.ruby-forum.com/\.
Thanks to you and Robert for the quick answers. I think I get it now; I
was a little fuzzy on the notion of class instance variables before. I
now use a construct like so:
class A
class << self
attr_accessor :var
end
end
class B < A
class << self
def var
@var || superclass.var
end
end
end
to allow subclasses's instance variables to default to their
superclass's until and unless overridden. I'll admit the class << self
syntax continues to mystify somewhat; can anyone proffer an explanation
that would help me grok it fully?
- donald
Actually, I spoke too quickly. If I use this construct:
class A
class << self
attr_accessor :var
end
endclass B < A
class << self
def var
@var || superclass.var
end
end
end
How can I initialize var in A? I've tried:
class A
class << self
@var = 'foo'
attr_accessor :var
end
end
to no avail. Also tried doing it in an initialize method. I'm still
missing something key, I think.
- donald
Thanks to you and Robert for the quick answers. I think I get it now; I
was a little fuzzy on the notion of class instance variables before. I
now use a construct like so:class A
class << self
attr_accessor :var
end
endclass B < A
class << self
def var
@var || superclass.var
end
end
endto allow subclasses's instance variables to default to their
superclass's until and unless overridden.
That was the point I missed, but of course you did that nicely :).
I'll admit the class << self
syntax continues to mystify somewhat; can anyone proffer an explanation
that would help me grok it fully?
I will take a chance by saying that
class << A
def x...
end
end
is the same as
class A
def self.x
end
end
although there might be some subtle differences
Do e.g, this
class << A
puts self
end
you can see kind of a Proxy object, but it behaves pretty much transparently.
Cheers
Robert
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
Hi --
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
Thanks to you and Robert for the quick answers. I think I get it now; I
was a little fuzzy on the notion of class instance variables before. I
now use a construct like so:class A
class << self
attr_accessor :var
end
endclass B < A
class << self
def var
@var || superclass.var
end
end
endto allow subclasses's instance variables to default to their
superclass's until and unless overridden. I'll admit the class << self
syntax continues to mystify somewhat; can anyone proffer an explanation
that would help me grok it fully?
Possibly; have a look at: http://www.rubypal.com/singletons.html
David
--
Upcoming Rails training by Ruby Power and Light:
Four-day Intro to Intermediate
May 8-11, 2007
Edison, NJ
http://www.rubypal.com/events/05082007
On Wed, May 02, 2007 at 06:33:57AM +0900, Ball, Donald A Jr (Library) wrote:
I'll admit the class << self
syntax continues to mystify somewhat; can anyone proffer an explanation
that would help me grok it fully?
class A
class << self
@var = 'foo'
attr_accessor :var
end
endto no avail. Also tried doing it in an initialize method. I'm still
missing something key, I think.
class A
@var = 'foo'
class << self
attr_accessor :var
end
end
(warning, the following explanation is not really correct)
class << self is sort of A's class (the class of the class) (It's actually
A's singleton class). By putting @var='foo' inside class << self you set the
class of A's instance var @var to 'foo' not A's @var to foo.
- donald
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
I always liked this explanation:
http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html
hth,
-Harold
On 5/2/07, Brian Candler <B.Candler@pobox.com> wrote:
On Wed, May 02, 2007 at 06:33:57AM +0900, Ball, Donald A Jr (Library) wrote:
> I'll admit the class << self
> syntax continues to mystify somewhat; can anyone proffer an explanation
> that would help me grok it fully?
Going a little further in answering Donald's question.
Instance variables come into being when they are initialized by code
running in the context of the instance. Usually that's method code.
This works in the case of class methods, class instance variables are
just instance variables of the class.
However since, I think what we are looking for is a way to initialize
class instance variables in a way analogous to class variables, we
really don't always want to define a method. Here's one way to
accomplish class instance variable intialization in-line in a class
(re)definition.
class A
instance_eval {@var = 'foo'}
class << self
attr_accessor :var
end
end
since within the class (re)definition self IS the class, instance_eval
runs the block in the context of the class.
On 5/1/07, Logan Capaldo <logancapaldo@gmail.com> wrote:
On 5/1/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
>
> class A
> class << self
> @var = 'foo'
> attr_accessor :var
> end
> end
>
> to no avail. Also tried doing it in an initialize method. I'm still
> missing something key, I think.class A
@var = 'foo'
class << self
attr_accessor :var
end
end(warning, the following explanation is not really correct)
class << self is sort of A's class (the class of the class) (It's actually
A's singleton class). By putting @var='foo' inside class << self you set the
class of A's instance var @var to 'foo' not A's @var to foo.
--
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/
<snip>
class A
instance_eval {@var = 'foo'}
I guess I lost you here Rick, is this for didactic purpose, or am I
wrong by saying that
instance_eval { @var = 'foo' }
is *exactly* the same as
@var = 'foo'
....
<snip>
Cheers
Robert
On 5/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
Okay, so maybe this turns out to be a not-so-simple subclass question
after all. I appreciate all the thoughtful answers and links, I'm pretty
close to wrapping my head around it all. I'm still having trouble with
class instance variable initialization, and have come up with code
sample which should illustrate the point:
class Breakfast
def self.add_food(*args)
@foods ||= []
args.each do |arg|
@foods << arg
end
end
def self.foods
if superclass.respond_to?(:foods)
superclass.foods + @foods
else
@foods
end
end
add_food :eggs
end
class RubyBreakfast < Breakfast
add_food :grapefruit, :chunky_bacon
end
class BoringBreakfast < Breakfast
add_food :dry_toast, :gruel
end
Everybody loves breakfast, right? This code works great, except... maybe
I don't want Breakfast to have :eggs by default, but if I remove the
add_food :eggs from Breakfast, then Breakfast.foods returns nil instead
of [] since @foods isn't initialized until add_food is called, and
RubyBreakfast.foods throws an exception trying to its delicious foods
array to nil. But I'll be damned if I can figure out how to properly
initialize @foods in Breakfast. Can someone point me in the proper
direction?
- donald
D'oh! You're right of course.
It's like those times when I ask my wife if she's seen my eyeglasses
and she tells me that I'm wearing them!
On 5/2/07, Robert Dober <robert.dober@gmail.com> wrote:
On 5/2/07, Rick DeNatale <rick.denatale@gmail.com> wrote:
<snip>
>
> class A
> instance_eval {@var = 'foo'}
I guess I lost you here Rick, is this for didactic purpose, or am I
wrong by saying thatinstance_eval { @var = 'foo' }
is *exactly* the same as
@var = 'foo'
....
<snip>
--
Rick DeNatale
My blog on Ruby
http://talklikeaduck.denhaven2.com/
Okay, so maybe this turns out to be a not-so-simple subclass question
after all. I appreciate all the thoughtful answers and links, I'm pretty
close to wrapping my head around it all. I'm still having trouble with
class instance variable initialization, and have come up with code
sample which should illustrate the point:class Breakfast
def self.add_food(*args)
@foods ||=
just initialize @foods in the class
class Breakfast
@foods = # class instance variable, I did this in my original example
# because of (1)
def self.add_food( *args)
@foods += args
end
......
<snip>
Everybody loves breakfast, right? This code works great, except... maybe
I don't want Breakfast to have :eggs by default, but if I remove the
add_food :eggs from Breakfast, then Breakfast.foods returns nil instead
of since @foods isn't initialized until add_food is called, and
RubyBreakfast.foods throws an exception trying to its delicious foods
array to nil. But I'll be damned if I can figure out how to properly
initialize @foods in Breakfast. Can someone point me in the proper
direction?
Hopefully I did, if not continue asking I am a bad teacher, I know :(.
(1)
class A
@cl_inst_var = 42
end
is the same (unless class A has been defined before) as
A = Class.new { @cl_inst_var = 42 }
Cheers
Robert
On 5/2/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
just initialize @foods in the class
class Breakfast
@foods = # class instance variable, I did this in my
original example
# because of (1)
def self.add_food( *args)
@foods += args
end......
but then @foods doesn't exist in RubyBreakfast and BoringBreakfast. I
mean, sure, I could cut'n'paste @foods = in each of them, but that
doesn't smell right. In the superclass, I want a chunk of code that
initializes a class instance variable in itself and each of its class
descendents.
In point of fact, I can work around the @foods.nil? case in the
self.foods method, but I'd rather figure out either how to do this or
why it's a bad idea to do it.
- donald
Ball, Donald A Jr (Library) schrieb:
In point of fact, I can work around the @foods.nil? case in the
self.foods method, but I'd rather figure out either how to do this or
why it's a bad idea to do it.
Donald, I would add
def self.my_foods
@foods ||=
end
and then use my_foods instead of @foods in the other two methods. You could also take a look at Ara's attributes library:
http://codeforpeople.com/lib/ruby/attributes/attributes-3.2.0/README
Regards,
Pit
> just initialize @foods in the class
>
> class Breakfast
> @foods = # class instance variable, I did this in my
> original example
> # because of (1)
> def self.add_food( *args)
> @foods += args
> end
>
> ......but then @foods doesn't exist in RubyBreakfast and BoringBreakfast. I
mean, sure, I could cut'n'paste @foods = in each of them, but that
doesn't smell right. In the superclass, I want a chunk of code that
initializes a class instance variable in itself and each of its class
descendents.
You mean you want to have your cake *and* eat it ;)?
Sure enough, but there is no simple solution, you could do something like this
class Module
def inherit_cl_inst_vars # refinement via args as you wish
superclass.instance_variables.each do
> ivar |
instance_variable_set ivar,
superclass.instance_variable_get( ivar )
end
end
end
class A
@a = 42
end
class B < A
inherit_cl_inst_vars
end
class << A
attr_accessor :a
end
puts A.a
puts B.a
B.a=1764
puts A.a
puts B.a
In point of fact, I can work around the @foods.nil? case in the
self.foods method, but I'd rather figure out either how to do this or
why it's a bad idea to do it.- donald
Robert
On 5/2/07, Ball, Donald A Jr (Library) <donald.ball@nashville.gov> wrote:
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw
You can use #inherited to trigger your own class initialization:
class Base
class <<self
def inherited(other)
other.instance_eval { initialize_class }
end
def initialize_class
@foo = 42
end
attr_accessor :foo
end
initialize_class
end
class Subclass < Base
puts "foo is #{@foo}" # 42
end
puts Subclass.foo # 42
puts Class.new(Base).foo # 42
Gary Wright
On May 2, 2007, at 2:57 PM, Ball, Donald A Jr (Library) wrote:
In the superclass, I want a chunk of code that
initializes a class instance variable in itself and each of its class
descendents.
Wow that scales much better than mine Gary, nice.
However maybe you want to inherit @foo dynamically, that is
I suggest this slight adaptation of Base
529/29 > cat inherited.rb && ruby inherited.rb
# vim: sts=2 sw=2 expandtab tw=0 nu:
class Base
@foo = 42
class <<self
def inherited(other)
other.instance_eval { initialize_class }
end
def initialize_class
@foo = superclass.instance_variable_get("@foo")
end
attr_accessor :foo
end
end
class Subclass < Base
puts "Sub foo is #{@foo}" # 42
end
Base.foo = 1764
class Another < Base
puts "Another foo is #{@foo}" # 42
end
puts Subclass.foo # 42
puts Class.new(Base).foo # 42
Sub foo is 42
Another foo is 1764
42
1764
What do you think, anyway the two behaviors might be what you want, I
actually need the second behavior.
Cheers
Robert
On 5/3/07, Gary Wright <gwtmp01@mac.com> wrote:
On May 2, 2007, at 2:57 PM, Ball, Donald A Jr (Library) wrote:
> In the superclass, I want a chunk of code that
> initializes a class instance variable in itself and each of its class
> descendents.You can use #inherited to trigger your own class initialization:
class Base
class <<self
def inherited(other)
other.instance_eval { initialize_class }
end
def initialize_class
@foo = 42
end
attr_accessor :foo
end
initialize_class
endclass Subclass < Base
puts "foo is #{@foo}" # 42
endputs Subclass.foo # 42
puts Class.new(Base).foo # 42Gary Wright
--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw