我有一个外部文件:path_to_external_file.rb
,带有一些类定义:
class A
some_definitions
end
我想在模块B
中加载它,以便上面定义的类A
可以称为B::A
。我试过了:
class B
load('path_to_external_file.rb')
end
但是A
是在主要环境中定义的,而不是B
:
A #=> A
B.constants # => []
如何在某个类/模块中加载外部文件?
修改
我应该将外部文件作为字符串读取,并在Class.new{...}
和include
B
内的{{1}}内对其进行评估吗?
答案 0 :(得分:4)
你做不到。至少使用load
或require
,Ruby文件将始终在顶层上下文中进行评估。
您可以通过两种方式解决该问题:
class B::A
(但您可能试图避免这种情况)eval(File.read("path_to_external_file.rb"))
班级B
修改:也许,这个图书馆很有意思:https://github.com/dreamcat4/script/blob/master/intro.txt
答案 1 :(得分:3)
通常,将类定义为“A类”然后“神奇地”使其包含在模块B中是一个坏主意。如果要将类A引用为B :: A,则应使用任一类来定义它:
module B
class A
# contents
end
end
或:
class B::A
# contents
end
否则,任何阅读您代码的人都会感到困惑。在这种情况下,通过使用“技巧”,您无法获得清晰,简洁或方便的任何内容,因此直接的代码更好。这里有一个教训:Ruby的元编程功能很棒,但没有必要无偿使用它们。只有当你真正从中获得某些东西时才使用它们。否则你只是难以理解你的代码。
但是,在阅读了你的评论之后,在你的情况下看起来真的有理由做这样的事情。我建议以下解决方案甚至比你想象的更好:
m = Module.new
m.module_eval("class C; end")
m.constants
=> [:C]
m.const_get(:C)
=> #<Module:0xfd0da0>::C
你知道吗?如果需要“保证唯一”命名空间,可以使用匿名模块。您可以将这些模块存储在哈希或其他数据结构中,并根据需要从中提取类。这解决了您提到的问题,即您的应用的用户将添加他们自己的类,并且您不希望名称发生冲突。