Как можно отменить функцию включения ruby
Я объясню, что я ищу в коде, так как это, возможно, наиболее красноречиво:
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, но это, похоже, не имеет никакого значения для What what. Я предположил, что #include просто добавил ссылку на модуль в цепочку разрешения метода класса, но это поведение не согласуется с этим.
Может ли кто-нибудь сказать мне, что включает в себя фактически за кулисами, и как это сделать?
Ответы
Ответ 1
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 #< C:0x11b0d90>
Ответ 2
Как кажется, вы, вероятно, хотите выполнить их на экземплярах вместо целого класса, поэтому я бы немного изменил кодлорн-код, чтобы обрабатывать только один экземпляр вместо всех экземпляров класса.
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
Ответ 3
Я не уверен, что вы пытаетесь выполнить, но, возможно, вместо использования include
для добавления методов экземпляра вам нужно использовать extend
для добавления методов только к конкретным экземплярам класса, то вам не нужно будет их удалять.
Дополнительная информация о разнице между include
и extend
Ответ 4
Несколько лет назад я использовал gem evil для un-includes модулей и т.д., но, по-видимому, он больше не поддерживается. Поэтому я просто попробовал un (только на моем старом рубине 1.8.7). Работала хорошо, как рекламируется:
Описание:
un обеспечивает unextend и uninclude, чтобы обеспечить лучшее опытно-ориентированное программирование.
Если вы замените "# some magic here" (после установки un) на
require 'un'
Whatever.uninclude Mixin
вы получаете поведение, описанное вами - почти. Объект уже имеет метод, называемый методом, поэтому вместо него возникает ошибка "неправильного количества аргументов".
Было бы неплохо, если кто-то попробует его на ruby 1.9 или на jruby и сообщит о результатах (я делаю для этого вики сообщества сообществ).