Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I override a variable in a Ruby subclass without affecting the superclass?

Tags:

ruby

Let's say I have a class with a few "static" variables. I want to a subclass of that class to be able to override those variables without affecting the original class. This isn't possible using class variables, since those appears to be shared between subclasses and superclasses:

class Foo
  @@test = "a"

  def speak; puts @@test; end
end

class Bar < Foo
  @@test = "b"
end

Bar.new.speak
# b

Foo.new.speak
# b

It isn't possible using constants either:

class Foo
  TEST = "a"

  def speak; puts TEST; end
end

class Bar < Foo
  TEST = "b"
end

Bar.new.speak
# a

Foo.new.speak
# a

Methods defined in the superclass ignores constants in the subclass.

The obvious workaround is to define methods for the variables that needs to be "overridable":

class Foo
  def test; "a"; end
end

But that feels like a hack. I feel like this should be possible using class variables and that I'm probably just doing it wrong. For example, when I subclass Object (which is what happens by default):

class Foo < Object
  @@bar = 123
end

Object.class_variable_get(:@@bar)
# NameError: uninitialized class variable @@bar in Object

Why isn't @@bar set on Object like it was in my Bar < Foo example above?


To summarize: how do I override a variable in a subclass without affecting the superclass?

like image 908
Hubro Avatar asked Oct 15 '13 13:10

Hubro


2 Answers

Class constants does what you want, you just need to use them differently:

class Foo
  TEST = "a"

  def speak
    puts self.class::TEST
  end
end

class Bar < Foo
  TEST = "b"
end

Bar.new.speak # => a
Foo.new.speak # => b
like image 187
Sahil Dhankhar Avatar answered Sep 22 '22 13:09

Sahil Dhankhar


Add a variable to the class itself (as in the class instance, rather than a class variable):

class Foo
  @var = 'A'

  class << self
    attr_reader :var
  end

  def var
    self.class.var
  end
end

class Bar < Foo
  @var = 'B'
end

Foo.var # A
Foo.new.var # A
Bar.var # B
Bar.new.var # B
like image 30
Denis de Bernardy Avatar answered Sep 23 '22 13:09

Denis de Bernardy