Class variables per subclasses, defined in the superclass

Hi guys,

First the pastie, I got class_eval from #ruby-lang on freenode -
http://pastie.caboo.se/127003

I've commented out the Rails specific stuff so I'm sure this is a Ruby question.

What I'm trying to do is have a per-subclass variable created by a class method
on the super class (which is called from the subclass). Fun.

When I load in the file above I get

-- Processor::Sponge.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}
-- Processor::CampaignMonitor.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}
-- Processor::Base.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}

where the expected output is

-- Processor::Sponge.related_questions
=> {:location=>1, :phone_number=>1}
-- Processor::CampaignMonitor.related_questions
=> {:surname=>1, :email=>1, :forename=>1}
-- Processor::Base.related_questions
=> {} # possibly nil, it's not too important as it shouldn't be called directly

I'll be the first to admit I don't really understand class variables, is what
I'm trying to do possible without having to add anything to the subclass?

Alle martedì 11 dicembre 2007, Gareth Adams ha scritto:

Hi guys,

First the pastie, I got class_eval from #ruby-lang on freenode -
http://pastie.caboo.se/127003

I've commented out the Rails specific stuff so I'm sure this is a Ruby
question.

What I'm trying to do is have a per-subclass variable created by a class
method on the super class (which is called from the subclass). Fun.

When I load in the file above I get

-- Processor::Sponge.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}
-- Processor::CampaignMonitor.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}
-- Processor::Base.related_questions
=> {:surname=>1, :email=>1, :location=>1, :phone_number=>1, :forename=>1}

where the expected output is

-- Processor::Sponge.related_questions
=> {:location=>1, :phone_number=>1}
-- Processor::CampaignMonitor.related_questions
=> {:surname=>1, :email=>1, :forename=>1}
-- Processor::Base.related_questions
=> {} # possibly nil, it's not too important as it shouldn't be called
directly

I'll be the first to admit I don't really understand class variables, is
what I'm trying to do possible without having to add anything to the
subclass?

I think you need class instance variable, not class variables. Class instance
variable are instance variables of the class object itself. For example:

class A
  @var = 1
end

They follow the usual rules for instance variables. For example, to access
them from outside self (and this includes accessing them from instance
methods of the class), you need to provide suitable methods:

class A

  @var = 1
  
  def self.var
    @var
  end

  def a_method
    puts self.class.va
  end

end

Unlike class variables, class instance variables arent shared between parent
and children classes, so they should work for you (unless Rails, which I
don't know, requires class variables, of course).

To use class instance variables, you should replace @@related_questions with
@related_questions and remove the call to class_eval (they aren't needed
anymore).

I hope this helps

Stefano

class Base
  @thing1 = "Base 1"
  class << self
    attr_accessor :thing1
    attr_reader :thing2
  end
  def self.thing2=( val )
    @thing2 = "I am Thing2, and my value is '#{val}'"
  end
  self.thing2 = 'Base'
end

p Base.thing1, Base.thing2
#=> "Base 1"
#=> "I am Thing2, and my value is 'Base'"

# Set values for subclasses in the class...
class Bar < Base
  @thing1 = "Barthing1"
end
# ...or later
Bar.thing2 = "Barthing2"

p Bar.thing1, Bar.thing2
#=> "Barthing1"
#=> "I am Thing2, and my value is 'Barthing2'"

# But since class instance variables aren't shared
# the base class (and other subclasses) are unchanged
p Base.thing1, Base.thing2
#=> "Base 1"
#=> "I am Thing2, and my value is 'Base'"

···

On Dec 11, 10:58 am, Gareth Adams <gareth.ad...@gmail.com> wrote:

What I'm trying to do is have a per-subclass variable created by a class method
on the super class (which is called from the subclass). Fun.