ruby add class variable dynamically

4.5k views Asked by At

Example:

class Base
  @@var = "base"

  def self.assign_var(var)
    @@var = var
  end

  def self.show_var
    @@var
  end

  def initialize
    p @@var
  end

end

class A < Base
  assign_var("a")
end

class B < Base
  assign_var("b")
end

class C < Base
  assign_var("c")
end

p A.show_var # "c"
p B.show_var # "c"
p C.show_var # "c"
a = A.new # "c"
b = B.new # "c"
c = C.new # "c"

How to make them to show their own value assigned in their class? like this:

p A.show_var # "a"
p B.show_var # "b"
p C.show_var # "c"
a = A.new # "a"
b = B.new # "b"
c = C.new # "c"

UPDATE

I need to access this var in the initializer.

class Base
  @var = "base"

  def self.assign_var(var)
    @var = var
  end

  def self.show_var
    @var
  end

  def initialize
    p @var
  end
end

class A < Base
  assign_var("a")
end

class B < Base
  assign_var("b")
end

class C < Base
  assign_var("c")
end

p A.show_var # "a"
p B.show_var # "b"
p C.show_var # "c"
a = A.new # nil
b = B.new # nil
c = C.new # nil

If I use Vu's solution, it is not working... Any ideas?

2

There are 2 answers

1
Cary Swoveland On

Please treat the following as an extended comment on @Vu's answer. He gave a good answer (+1), but intentionally kept close to the OP's code. I would merely like to point out that the usual way of doing this would be to use class instance variables (as Vu has done) and accessors for those variables:

class Base
  @var = "base"
  class << self
    attr_accessor :var
  end
end

class A < Base
  @var = "a"
end

class B < Base
  self.var = "b"
end

Base.methods(false)      #=> [:var, :var=]
A.methods(false)         #=> []
A.methods.include?(:var) #=> true
A.method(:var=)          #=> #<Method: A(Base)
A.method(:var).owner     #=> #<Class:Base>

Base.instance_variables  #=> [:@var]
A.instance_variables     #=> [:@var]

Base.var #=> "base"
A.var    #=> "a"
B.var    #=> "b"
Base.var = 'cat'
Base.var #=> "cat"
A.var    #=> "a"
1
Vu Minh Tan On

Class variable is not redefined in subclasses. You can use class level instance variable in this case:

class Base
  @var = "base"

  def self.assign_var(var)
    @var = var
  end

  def self.show_var
    @var
  end
end

class A < Base
  assign_var("a")
end

class B < Base
  assign_var("b")
end

class C < Base
  assign_var("c")
end

p A.show_var # "a"
p B.show_var # "b"
p C.show_var # "c"

For more information: http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/