Ruby 2.0如何在包含模块后从模块中取出模块?

时间:2013-10-19 03:19:12

标签: ruby-on-rails ruby metaprogramming

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关键字的事实?

enter image description here

4 个答案:

答案 0 :(得分:7)

如果您真的需要这种功能,可以使用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

答案 1 :(得分:1)

我对此并不满意,但如果两个模块包含相同的方法名称,它确实有效。

文件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的观察。经过反思,我发现这既不重要也不有趣,所以不用它的头。

答案 2 :(得分:1)

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

编辑:好的,实际上,OP是What is the opposite of Ruby's include?的副本,因此根据@eliahbanister的答案,相关的库是https://github.com/yrashk/rbmodexcl和{{ 3}}

答案 3 :(得分:0)

如果您要创建一个可以动态选择是否包含模块的类,则可以通过在初始化期间将模块包含在singleton类中来实现。

这不会像在一个对象的单例类中“取消包含”该模块,而同时又将其包含在该类本身中一样(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功能,那么就值得考虑您到底想使用什么功能了-就像“动态包含”一样?