Override ruby constant in subclass so inherited methods use new constant instead of the old?

Ruby

Ruby Problem Overview


In Ruby, is there a way to 'override' a constant in a subclass in such a way that calling an inherited method from the subclass results in that method using the new constant instead of the old one? For example:

class SuperClass
  CONST = "Hello, world!"
  def self.say_hello
    CONST
  end
end

class SubClass < SuperClass
  override_const :CONST, "Hello, Bob!"
end

SuperClass.say_hello # => "Hello, world!"
SubClass.say_hello   # => "Hello, Bob!"

If not, is there perhaps a way to do something like this instead?

class SuperClass
  CONST = "Hello, world!"
  def self.say_hello
    CONST
  end
end

SubClass = SuperClass.clone
SubClass.send(:remove_const, :CONST)
SubClass.const_set(:CONST, "Hello, Bob!")

SubClass.say_hello # => "Hello, Bob!"

Note: I tried my second example out in irb, and it seems to work except that class methods can't seem to access CONST after I clone the class:

irb(main):012:0> SubClass.say_hello
NameError: uninitialized constant Class::CONST
        from (irb):4:in `say_hello'
        from (irb):12
        from C:/Ruby193/bin/irb:12:in `<main>'

Ruby Solutions


Solution 1 - Ruby

I've done this by simply redefining the constant in the subclass, and then referring to it in methods as self.class::CONST in instance methods and self::CONST in class methods. In your example:

class SuperClass
  CONST = "Hello, world!"
  def self.say_hello
    self::CONST
  end
end

class SubClass < SuperClass
  CONST = "Hello, Bob!"
end

SubClass.say_hello #=> "Hello, Bob!"

Solution 2 - Ruby

You can refer to a constant like this in the parent class:

For a instance method: self.class::CONST

For a self method: self::CONST

class SuperClass
  CONST = "Hello, world!"
  def print_const
    puts self.class::CONST
  end

  def self.print_const
    puts self::CONST
  end

end

class SubClass < SuperClass
  CONST = "Hello, Bob!"
end

SubClass.new.print_const #=> "Hello, Bob!"
SubClass.print_const #=> "Hello, Bob!"

Solution 3 - Ruby

If you have the luxury of being able to change the base class, consider wrapping the "constants" that need changing in class methods in the base class and overriding them as needed in subclasses. This removes the potential for confusion between parent and subclass constants. For the example, this would be as follows:

class SuperClass
  CONST = "Hello, world!".freeze

  def self.const
    CONST
  end

  def self.say_hello
    const
  end
end

class SubClass < SuperClass
  CONST = "Hello, Bob!".freeze

  def self.const
    CONST
  end
end

SubClass.say_hello #=> "Hello, Bob!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAjedi32View Question on Stackoverflow
Solution 1 - RubyZach KempView Answer on Stackoverflow
Solution 2 - RubyBhacazView Answer on Stackoverflow
Solution 3 - RubycoberlinView Answer on Stackoverflow