0

I need to override a class method for some instances of the class

class Foo
  def eigen_class
    class << self
      self
    end
  end

  def self.foo
    "original foo"
  end

  def override_foo
    class << self
      def self.foo
        "overridden foo"
      end
    end
  end
end

foo = Foo.new
foo.override_foo
foo.class.foo # => "original foo"
foo.eigen_class.foo # => "overridden foo"

foo2 = Foo.new
foo2.eigen_class.foo # => "original foo"

Is there a way to call overridden method without explicitly getting eigenclass?

synapse
  • 5,588
  • 6
  • 35
  • 65

2 Answers2

0

You're assigning that method to the wrong context. Here's a fix:

class << foo.class
  def foo
    "foo"
  end
end

This bolts the method on to the Foo class, not the eigenclass of that particular instance.

tadman
  • 208,517
  • 23
  • 234
  • 262
  • I don't to override it for all instances of the class, just for some of them. I've corrected the code in the original question. – synapse Nov 19 '12 at 16:48
  • 1
    You can't override the class method for *some* of the instances of the class. It's an all or nothing deal. Maybe what you need is a specialized sub-class? You could also create an instance wrapper method that usually calls the class method but could be over-ruled by your technique. – tadman Nov 19 '12 at 18:51
0

Since the implementation of foo can vary per instance, I recommend simply using a regular method (i.e. an instance method, not a class method). You can do this very easily with a module, keeping all your overrides self-contained.

module FooOverrides
  def foo
    "overridden foo"
  end
end

class Foo
  def foo
    "original foo"
  end

  def override_foo
    self.extend(FooOverrides)
  end
end

foo = Foo.new
foo.override_foo
foo.foo # => "overridden foo"

foo2 = Foo.new
foo2.foo # => "original foo"

Alternatively, if you really wanted to call foo.class.foo, you could override #class to return the eigen_class.

class Foo
  def override_foo
    class << self
      def self.foo
        "overridden foo"
      end

      def class
        eigen_class
      end
    end
  end
end

In general, it's not good to override methods defined on Object like #class since it could have unintended consequences.

Jonathan Tran
  • 15,214
  • 9
  • 60
  • 67