我在app / classes文件夹中有一些现有的ruby类:
class A
...
end
class B
...
end
我想在模块MyModule
中对这些类进行分组我知道我可以这样做:
module MyModule
class A
...
end
class B
...
end
end
但是有一个元编程快捷方式可以做同样的事情,所以我可以“导入”所有现有的类吗?
谢谢, LUC
答案 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中您可以随时重新打开模块。然后就像你通常那样包括它们。