将现有类添加到模块中
我在app / classes文件夹中有一些现有的ruby类:
class A ... end class B ... end
我想在模块MyModule中对这些类进行分组
我知道我可以这样做:
module MyModule class A ... end class B ... end end
但是有一个元编程快捷方式可以做同样的事情,所以我可以“导入”所有现有的类?
谢谢,吕克
使用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
module Foo A = ::A B = ::B end Foo::A.new.bar
请注意,常量上的::
前缀首先开始搜索全局命名空间。 像领导/
在路径名上。 这允许您将全局类A
与模块化常量Foo::A
分开来。
@ Squeegy的答案已经告诉你该做什么,但我认为理解为什么这样做同样重要。 它实际上非常简单:Ruby中的类并不特别。 它们就像任何其他对象一样被赋予变量,就像任何其他变量一样。 更确切地说:它们是Class
类的实例,它们通常被赋值为常量(即名称以大写字母开头的变量)。
所以,就像你可以将任何其他对象别名为多个变量:
a = '' b = a a << 'Hello' c = b b << ', World!' puts c # => Hello, World!
您还可以将类别名替换为多个变量:
class Foo; end bar = Foo p bar.new # => #
如果你想将类移动到命名空间而不是仅仅别名它们,你还需要将原始变量设置为其他对象,如nil
,以及@ Squeegy的答案:
::A = nil ::B = nil
是的,在您的模块中创建类并让它inheritance自您的外部类。 例如,
class A ... end module MyModule class NewA < A end end
MyModule :: NewA类将具有A类的所有属性和方法。
然后,ruby中的模块永远不会被锁定,所以没有什么能阻止你直接将类定义写入模块。
如果你想将它们放在一个模块中,我没有看到首先将它们包含在全局命名空间中,然后将它们置于模块中。 我想你想做什么(虽然我怀疑它是一件好事)是这样的:
文件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中您可以随时重新打开模块。 然后就像你通常那样包括它们。