Как я могу инвертировать рубин, включают функцию

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

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 просто добавил ссылку на модуль в цепочку разрешения метода класса - но это поведение не соглашается с этим.

Кто-либо может сказать мне, что включает, на самом деле делает негласно, и как инвертировать это?

22
задан Glenjamin 8 March 2010 в 17:01
поделиться

4 ответа

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>

3
ответ дан 29 November 2019 в 05:55
поделиться

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

Дополнительная информация о различиях между include и extend

2
ответ дан 29 November 2019 в 05:55
поделиться

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

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

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

>> 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
5
ответ дан 29 November 2019 в 05:55
поделиться

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

ОПИСАНИЕ:

un предоставляет unextend и uninclude, чтобы обеспечить лучший опыт программирования, ориентированного на прототипы.

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

require 'un'
Whatever.uninclude Mixin

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

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

0
ответ дан 29 November 2019 в 05:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: