【问题标题】:Ruby 2.0 How do I uninclude a module out from a module after including it?Ruby 2.0 如何在包含模块后从模块中取消包含模块?
【发布时间】:2013-10-28 00:34:56
【问题描述】:
module X
end

module Y
end

module Z
  #TODO include X replacement of including Y
  #TODO include Y replacement of including X
end

有没有办法解决 ruby​​ 不包含 uninclude 关键字这一事实??

【问题讨论】:

  • @LoganSerman ruby​​ 2.0 答案我寻求
  • include X 替换 include Y 是什么意思?
  • @ArupRakshit 在包含 X 时从祖先链中删除 Y,反之亦然
  • @ArupRakshit 好主意 :)

标签: ruby-on-rails ruby metaprogramming


【解决方案1】:

如果你真的需要这种功能,你可以使用refinements

class Foo
end

module X
  def x
    puts 'x'
  end
end

module Y
end

module R
  refine Foo do
    include X
    include Y
  end
end

# In a separate file or class
using R
# Foo now includes X and Y
Foo.new.x

# In a different file or class
# Foo no longer includes X and Y
Foo.new.x # NoMethodError

【讨论】:

    【解决方案2】:

    真正的答案是,在 Ruby 中,无论是 1.x 还是 2.x,一旦包含一个模块,就无法取消包含。但我知道有人在某处编写了允许取消包含模块的 Ruby 扩展。

    编辑:好的,实际上,OP 是What is the opposite of Ruby's include? 的副本,所以根据@eliahbanister 的回答,有问题的库是https://github.com/yrashk/rbmodexclhttps://github.com/banister/mixology19

    【讨论】:

    • Boris 和调酒学一样太老了 - 期待问题,我无法应对 C 挑战,我正在检查 davogones 和 cary 答案,加载是智能解决方案,细化更清洁。如果改进对我有用,肯定会让世界知道它是必要的!
    • 你是绝对正确的。我没有尝试过那些库。我认为Matz一开始没有提供这个功能一定是有原因的。
    【解决方案3】:

    我对此不太满意,但如果两个模块包含相同的方法名称,它确实可以工作。

    文件c.rb

    module A
      def me
        puts "I am C"
      end
      def whosit?
        puts "It's me, Becky"
      end
    end
    

    文件 d.rb

    module A
      def me
        puts "I am D"
      end
    end
    

    然后

    class X
      load('c.rb')
      include A
    end
    
    x = X.new
    
    x.me # => I am C
    x.whosit? # => It's me, Becky
    load('d.rb')
    x.me # => I am D
    x.whosit? # => It's me, Becky !! Unwanted !!
    load('c.rb')
    x.me # => I am C
    

    load() 只是打开模块 A 并更改和/或添加代码;它没有触及的东西仍然存在。 load() 不是很聪明。我认为它基本上是一个eval(),如果它多次加载同一个文件,它可能不在乎。

    要使用它,不要同时使用require c.rb 或 d.rb。

    编辑:在之前的编辑中,我添加了关于require_relative 的观察。回想起来,我发现它既不相关也不有趣,所以别想了。

    【讨论】:

      【解决方案4】:

      如果你想创建一个可以动态选择是否包含模块的类,你可以通过在初始化时将模块包含在单例类中来实现。

      这不会让你得到与在一个对象的单例类中“取消包含”模块相同的东西,同时保持包含在类本身中(这是我想到的uninclude),但它可能匹配一些上述细化解决方案的功能(具有相同问题)具有不同的模式,如果这会激发您的一些想法。

      module A
        def hi; :hi; end
      end
      
      class Foo
        def initialize(include_a = true)
          singleton_class.include(A) if include_a
        end
      end
      
      Foo.new.hi
      # => :hi
      
      Foo.new(false).hi
      # NoMethodError: undefined method `hi' for #<Foo:0x00007fe19a973f00>
      

      了解这是一个老问题,但如果您正在寻找uninclude 功能,那么值得真正考虑一下您究竟想用它做什么 - 像“动态包含”这样的东西就足够了吗?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多