Domanda

I know, I can overwrite class method from module this way

class Foo
  class << self
    def some_static_method
      puts 'some_static_method'
    end
  end
end

module BAR
  class << Foo
    def some_static_method
      puts 'another_static_method'
    end
  end
end

class Foo
  include BAR
end

Foo.some_static_method # => 'another_static_method'

Is it possible for an instance method?

È stato utile?

Soluzione

You can do the following:

class Foo
  def self.some_static_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.instance_eval do
     def some_static_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.some_static_method

This should work

UPDATE

To override instance method use:

class Foo
  def some_instance_method; puts "Hello from Foo" end
end

module Bar
  def self.included(base)
    base.class_eval do
     def some_instance_method; puts "Hello from Bar" end
    end
  end
end

class Foo
  include Bar
end

Foo.new.some_instance_method

Altri suggerimenti

Your question is actually not about method overriding. It is about what class is referred to within a class ... construction in a module body.

When you do

module Bar
  class << Foo
    p self
  end
end
# => #<Class:Foo>

the << Foo points to the singleton class of the Foo in the main environment because class << Foo cannot define the singleton class directly of a class Foo that has not been defined in advance. So it looks up for Foo that is already defined, and such class is found in the main environment.

When you do

module Bar
  class Foo
    p self
  end
end
# => Bar::Foo

a new class Bar::Foo is created; the Foo points to this Bar::Foo that is newly created, and it does not point to the Foo in the main environment. In order to point to it, you have to explicitly specify that with ::.

module Bar
  class ::Foo
    p self
  end
end
# => Foo

If you are using Ruby > 2.0.0 then what you can use is Module#prepend. Instead of include you can prepend an module and that way all of the module's methods are overriding any existing class instance methods with the same name. You can see a quick example here.

Prior to Ruby 2, Rails had introduced a similar hack: #alias_method_chain

Here is a nice comparison of the two approaches.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top