Nick Vanderbilt
Nick Vanderbilt

Reputation: 1777

Why extend method is not putting puts value

module Lab
  def self.foo
    puts 'foo from lab'
  end
end

module M
  def foo
    puts 'foo from module'
    super
  end
end

module Lab
  extend M
end

Lab.foo

I was expecting that I would see

foo from module
foo from lab

However what I am getting is

foo from lab

What I am trying to do is to intercept the value of a method from a gem and do something. I can use alias_method_chain but I am trying not to use that.

Upvotes: 2

Views: 88

Answers (3)

yfeldblum
yfeldblum

Reputation: 65445

The methods defined on Lab directly take precedence over the methods defined in modules such as M that Lab extends.

So the foo defined directly on Lab takes precedence over M#foo, even though Lab.extend M.

To get what you want, do this:

module Lab
  module HasFoo
    # foo isn't defined directly on Lab directly anymore;
    # instead, it is defined in a separate module that
    # Lab extends
    def foo
      puts "foo from lab"
    end
  end

  extend HasFoo
end

module M
  def foo
    puts "foo from module"
    super
  end
end

module Lab
  # when Lab extends another module with foo, that changes
  # which concrete method the name foo gets resolved to
  extend M
end

# now you should see the module foo and then the lab foo
Lab.foo

Upvotes: 1

DJ.
DJ.

Reputation: 6784

If you are expecting

foo from module
foo from lab

Then you need to put super in Lab#foo, like so:

module Lab
  def self.foo
    super
    puts 'foo from lab'
  end
end

module M
  def foo
    puts 'foo from module'
  end
end

module Lab
  extend M
end

Lab.foo

Upvotes: 1

sawa
sawa

Reputation: 168199

When you include/extend a module M to a class C, and call a method C#method or C.method that is also defined for M, then C has priority over M in the search path of the method. In other words, you cannot overwrite a method by include/extend. You can only add new methods. See this related question.

In your case, Lab.foo is simply called. The following (without Lab.foo) will give you the desired result.

module M
  def foo
    puts 'foo from module'
  end
end

module Lab
  extend M
end

Lab.foo

# => foo from module

Note that your M's superclass is Module, and since Module#foo is not defined, the following will cause an error.

module M
  def foo
    puts 'foo from module'
    super
  end
end

module Lab
  extend M
end

Lab.foo

# => method undefined error

Upvotes: 0

Related Questions