Переопределить метод модуля из другого модуля - PullRequest
11 голосов
/ 04 февраля 2011

Я хочу переопределить метод из модуля A из другого модуля B, который будет обезьяна-патч A.
http://codepad.org/LPMCuszt

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

A.module_eval { include B } # why no override ???

class C
  include A
end

# must print 'A B', but only prints 'A' :(
C.new.foo

Ответы [ 4 ]

6 голосов
/ 04 февраля 2011
module A
  def foo
    puts 'A'
  end
end

module B
  def foo
    puts 'B'
    super
  end
end

include A # you need to include module A befor you can override method

A.module_eval { include B }

class C
  include A
end

C.new.foo # => B A
2 голосов
/ 04 февраля 2011

Включение модуля помещает его выше модуля / класса, который включает его в иерархию классов. Другими словами, A # foo не супер B # foo, а наоборот.

Если вы думаете о включении модуля в качестве способа выполнения множественного наследования, это имеет смысл, include SomeModule - это способ сказать: «Обращайтесь с SomeModule, как будто это родительский класс для меня».

Чтобы получить желаемый результат, вам нужно отменить включение, чтобы B включало A:

module A
  def foo; puts 'A' end
end

module B
  def foo; puts 'B'; super; end
end

B.module_eval { include A } # Reversing the inclusion

class C
  include B # not include A
end

puts C.new.foo

Редактировать в ответ на комментарий:

Затем либо включите и A, и B в C, а B включите после A:

# A and B as before without including B in A.

class C
  include A
  include B
end

или исправьте A в самой C и не беспокойтесь о B.

# A as before, no B.

class C
  include A

  def foo; puts 'B'; super; end
end

Единственный способ для этого - если поиск метода на C - это C -> B -> A, и нет способа сделать это без включения B в C.

1 голос
/ 22 апреля 2018

Это тоже одно из решений вашего вопроса.Я пытаюсь достичь с помощью хуков модуля included.Когда вы включаете модуль A в класс C . включено обратные вызовы, определенные в модуль A вызывается и выполняется.Мы включили модуль B на лету.Таким образом, наш модуль A метод foo переопределяется Module B foo для печати метода модуля суперкласса, только что названного super .

module A
  def self.included klass
    klass.send(:include, B)
  end
  def foo
    puts 'A'
  end
 end

module B
  def foo
   super
   puts 'B'
  end
end

class C
 include A
end
C.new.foo #out put A,B
0 голосов
/ 19 февраля 2018

Еще один способ сделать это - включить модуль B, если включен модуль A.

module A
  def foo
    puts "this should never be called!"
    "a"
  end
end

module B
  def foo
    "b"
  end
end

module A
  def self.included(base)
    base.class_eval do
      include B
    end
  end
end

class C
  include A
end

C.new.foo # "b"
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...