Как я могу отменить функцию включения рубина - PullRequest
21 голосов
/ 08 марта 2010

Я объясню, что я ищу в коде, так как это, вероятно, наиболее кратко:

module Mixin
  def method
    puts "Foo"
  end
end

class Whatever
  include Mixin
end

w = Whatever.new
w.method
=> "Foo"

# some magic here
w2 = Whatever.new
w.method
=> NoMethodError

Я пытался просто отменить определение модуля Mixin с помощью remove_const, но, похоже, это ничего не меняет. Я предполагал, что #include просто добавил ссылку на модуль в цепочку разрешения методов класса - но такое поведение не согласуется с этим.

Может кто-нибудь сказать мне, что на самом деле делает "кулис" и как это изменить?

Ответы [ 4 ]

6 голосов
/ 08 марта 2010

Как кажется, вероятно, вы хотите выполнить это на экземплярах вместо всего класса, поэтому я бы немного изменил код Клочнера, чтобы он обрабатывал только один экземпляр вместо всех экземпляров класса.

module ModuleRemover

    def remove_module(mod, options = {})
      metaclass = class << self; self end
      mod.instance_methods.each {|method_name| metaclass.class_eval { undef_method(method_name.to_sym) }}
    end

end

Как указал Младен, было бы неплохо избегать удаления методов, перезаписанных в хост-классе, поэтому параметры [only, exclude] для этого метода были бы идеальными.

>> c1 = C.new
>> c1.foo
=> fooing
>> c1.extend(ModuleRemover)
>> c1.remove_module(Mod)
>> c1.foo
=> NoMethodError: undefined method `foo' for #< C:0x11b0d90>
>> c2 = C.new
>> c2.foo
=> fooing
4 голосов
/ 08 марта 2010
module Mod
  def foo
    puts "fooing"
  end
end

class C
  include Mod
  def self.remove_module(m)
    m.instance_methods.each{|m| undef_method(m)}
  end
end

>> c = C.new
>> c.foo
fooing
>> C.remove_module(Mod)
=> ["foo"]
>> c.foo
NoMethodError: undefined method `foo' for #&lt C:0x11b0d90>

3 голосов
/ 08 марта 2010

Я не уверен, что вы пытаетесь выполнить, но, возможно, вместо использования include для добавления методов экземпляра, вы хотите использовать extend для добавления методов только к конкретным экземплярам класса, тогда вам не нужно будет их удалять.

Больше информации о разнице между include и extend

0 голосов
/ 16 июля 2010

Несколько лет назад я использовал драгоценный камень зло для отключения модулей и т. Д., Но, видимо, он больше не поддерживается. Поэтому я просто попробовал un (только на моем старом ruby ​​1.8.7). Работает нормально, как рекламируется:

ОПИСАНИЕ:

un предоставляет расширенные возможности и функции uninclude для обеспечения лучшего опыта программирования, ориентированного на прототипы.

Если вы замените "# some magic here" (после установки un) на

require 'un'
Whatever.uninclude Mixin

вы получаете поведение, как описано вами - почти. В объекте уже есть метод с именем method, поэтому вместо этого вы получаете ошибку "неправильное количество аргументов".

Было бы неплохо, если бы кто-нибудь попробовал это на ruby ​​1.9 или jruby и сообщил о результатах (я делаю ответ для этого в вики).

...