将现有类添加到模块中

时间:2010-08-27 07:06:43

标签: ruby module metaprogramming

我在app / classes文件夹中有一些现有的ruby类:

class A
   ...
end

class B
   ...
end

我想在模块MyModule

中对这些类进行分组

我知道我可以这样做:

module MyModule
  class A
      ...
   end
   class B
      ...
   end
end

但是有一个元编程快捷方式可以做同样的事情,所以我可以“导入”所有现有的类吗?

谢谢, LUC

5 个答案:

答案 0 :(得分:8)

module Foo
  A = ::A
  B = ::B
end

Foo::A.new.bar

请注意,常量上的::前缀首先会搜索全局命名空间。就像路径名上的前导/一样。这允许您将全局类A与模块化常量Foo::A区分开来。

答案 1 :(得分:5)

使用const_missing挂钩。如果在当前模块中找不到常量,请尝试在全局命名空间中解析:

class A; end
class B; end

module M
    def self.const_missing(c)
        Object.const_get(c)
    end
end

M::A.new
M::B.new

答案 2 :(得分:3)

@ Squeegy的答案已经告诉你该做什么,但我认为理解为什么有效同样重要。它实际上非常简单:Ruby中的类并不特别。它们就像任何其他对象一样被赋予变量,就像任何其他变量一样。更确切地说:它们是Class类的实例,它们通常被分配给常量(即名称以大写字母开头的变量)。

因此,就像您可以将任何其他对象别名为多个变量:

a = ''
b = a
a << 'Hello'
c = b
b << ', World!'
puts c # => Hello, World!

您还可以将类别名替换为多个变量:

class Foo; end
bar = Foo
p bar.new # => #<Foo:0x1d9f220>

如果你想类移动到命名空间而不是仅仅别名它们,除了@ Squeegy之外,你还需要将原始变量设置为其他对象,如nil。回答:

::A = nil
::B = nil

答案 3 :(得分:1)

是的,在你的模块中创建类并让它继承自你的外部类。 例如,

class A
...
end

module MyModule
 class NewA < A
 end
end

MyModule :: NewA类将具有类A的所有属性和方法。
然后,ruby中的模块永远不会被锁定,所以没有什么能阻止你直接将类定义写入模块。

答案 4 :(得分:1)

如果你想将它们放在一个模块中,我没有看到首先将它们包含在全局命名空间中,然后将它们置于模块中。 我想你想做什么(虽然我怀疑这是件好事)是这样的:

档案classes/g1.rb

class A1
  def self.a
    "a1"
  end
end

class B1
  def self.b
    "b1"
  end
end

档案classes/g2.rb

class A2
  def self.a
    "a2"
  end
end

class B2
  def self.b
    "b2"
  end
end

档案imp.rb

module MyModule
  ["g1.rb", "g2.rb"].each do |file|
    self.class_eval open("classes/#{file}"){ |f| f.read }
  end
end

puts defined? MyModule
puts defined? A1
puts defined? MyModule::A1

puts MyModule::A1.a
puts MyModule::B2.b

输出

constant
nil
constant
a1
b2

我可以想到这种方法的一些缺点(一方面难以调试,加载可能有点慢,尽管我只是猜测)。

你为什么不这样做:

Dir["classes/*.rb"].each do |file|
  contents = open(file) { |f| f.read }
  open(file, "w") do |f| 
    f.puts "module MyModule\n"
    contents.each { |line| f.write "  #{line}" }
    f.puts "\nend"
  end
end

这将修复您的类在您的模块中,因为在ruby中您可以随时重新打开模块。然后就像你通常那样包括它们。