在类/模块中加载外部文件

时间:2012-01-23 03:00:32

标签: ruby class module load

我有一个外部文件: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}}内对其进行评估吗?

2 个答案:

答案 0 :(得分:4)

你做不到。至少使用loadrequire,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
你知道吗?如果需要“保证唯一”命名空间,可以使用匿名模块。您可以将这些模块存储在哈希或其他数据结构中,并根据需要从中提取类。这解决了您提到的问题,即您的应用的用户将添加他们自己的类,并且您不希望名称发生冲突。