Christoph Petschnig
Christoph Petschnig

Reputation: 4157

Overwrite class method from another module

I want to modify the existing module A from a library:

module A
  class << self
    def foo
      bar('Baz')
    end

    private

    def bar(val)
      val.upcase
    end
  end
end

A.foo
=> "BAZ"

module B
  extend A

  def self.bar(val)
    val.downcase
  end
end

B.foo            # hoping for 'baz', but instead:
NoMethodError: undefined method `foo' for B:Module

Is there a way to re-use method .foo from A and only modify method .bar?

Upvotes: 1

Views: 208

Answers (2)

tosch
tosch

Reputation: 86

extend A doesn't work, because foo and bar are no instance methods of A, but of A's singleton class. To re-use those methods, you have to either create a copy of A as mudasobwa described, or you can use a refinement of A's singleton class like this:

module B
  extend(refine(A.singleton_class) do
    def bar(val)
      val.downcase
    end
  end)
end

B.foo # => "baz"

You cannot use extend A.singleton_class as extend doesn't accept a class as argument. refine returns a module which is exactly what's needed.

Upvotes: 4

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 121010

Assuming you have A declared as above, the following code would do:

▶ B = A.clone
#⇒ B
▶ (class << B; self; end).send :define_method, :bar do |val|
  val.downcase
end
▶ A.foo
#⇒ "BAZ"
▶ B.foo
#⇒ "baz"

There probably should be less tricky way, but I can’t yet figure it out.

Upvotes: 2

Related Questions