Ruby:如何要求并实例化目录中的所有文件?

Ruby:如何要求并实例化目录中的所有文件?,ruby,Ruby,我正在开发一个Gem,它允许用户自动要求、实例化和注册特定目录中的类。我只是不知道如何做到这一点。这就是我到目前为止想到的 Dir[Dir.pwd + '/extensions/*.rb'].each do |file| require file extension_class = # instantiate the class here MyApp.extensions << extension_class end Dir[Dir.pwd+'/extensions/*

我正在开发一个Gem,它允许用户自动要求、实例化和注册特定目录中的类。我只是不知道如何做到这一点。这就是我到目前为止想到的

Dir[Dir.pwd + '/extensions/*.rb'].each do |file|
  require file
  extension_class = # instantiate the class here
  MyApp.extensions << extension_class
end
Dir[Dir.pwd+'/extensions/*.rb']|
需要文件
extension_class=#在这里实例化类

MyApp.extensions这是一个有趣的想法,让我挠头了一阵。我无法用谷歌搜索找到一个即时的解决方案,所以我对谷歌语言进行了一些研究。我提出了三个基本想法:

  • 跟踪所有加载的类,并在它们进入时抓取新类
  • 使用命名方案将文件名与类关联
  • 在所需的类上使用某种类型的内省器,这样他们就可以注册自己以备将来包含
我决定我最喜欢第一个选择;它不需要您以特定的方式构造文件,也不需要为了知道这样需要它们而扩充类。这是一个基本的实现,借用了您的初始结构:

classes = ObjectSpace.each_object(Class).to_a
Dir[Dir.pwd + '/extensions/*.rb'].each do |file|
  require file
  changed_classes = ObjectSpace.each_object(Class).to_a
  (changed_classes - classes).each do |extension_class|
    MyApp.extensions << extension_class
  end
  classes = changed_classes
end
classes=ObjectSpace。每个对象(类)。到
Dir[Dir.pwd+'/extensions/*.rb'].每个do |文件|
需要文件
将每个对象(类)更改为
(已更改的|u类-类)。每个do|扩展|u类|

MyApp.extensions这是一个有趣的想法,让我挠头了一阵。我无法用谷歌搜索找到一个即时的解决方案,所以我对谷歌语言进行了一些研究。我提出了三个基本想法:

  • 跟踪所有加载的类,并在它们进入时抓取新类
  • 使用命名方案将文件名与类关联
  • 在所需的类上使用某种类型的内省器,这样他们就可以注册自己以备将来包含
我决定我最喜欢第一个选择;它不需要您以特定的方式构造文件,也不需要为了知道这样需要它们而扩充类。这是一个基本的实现,借用了您的初始结构:

classes = ObjectSpace.each_object(Class).to_a
Dir[Dir.pwd + '/extensions/*.rb'].each do |file|
  require file
  changed_classes = ObjectSpace.each_object(Class).to_a
  (changed_classes - classes).each do |extension_class|
    MyApp.extensions << extension_class
  end
  classes = changed_classes
end
classes=ObjectSpace。每个对象(类)。到
Dir[Dir.pwd+'/extensions/*.rb'].每个do |文件|
需要文件
将每个对象(类)更改为
(已更改的|u类-类)。每个do|扩展|u类|

MyApp.extensions听起来像是在为软件编写扩展编写系统。由于扩展类在某些方面可能都是相似的,例如共享一些公共方法,因此有一个名为
extension
的基类是有意义的,所有扩展类都从该基类继承

事实上,这对于所述问题非常有用,因为当用户从类继承时,您可以检测到它,并将子类添加到列表中。以下是一些概念验证代码:

class Extension
  class << self
    attr_reader :list
  end
  @list = []

  def self.inherited(klass)
    @list << klass.new
  end
end

# The MyExt class would be in another file, loaded by require.
class MyExt < Extension
end

p Extension.list   # => [#<MyExt:0xb777d884>]
类扩展

类听起来您正在创建一个用于编写软件扩展的系统。由于扩展类在某些方面可能都是相似的,例如共享一些公共方法,因此有一个名为
extension
的基类是有意义的,所有扩展类都从该基类继承

事实上,这对于所述问题非常有用,因为当用户从类继承时,您可以检测到它,并将子类添加到列表中。以下是一些概念验证代码:

class Extension
  class << self
    attr_reader :list
  end
  @list = []

  def self.inherited(klass)
    @list << klass.new
  end
end

# The MyExt class would be in another file, loaded by require.
class MyExt < Extension
end

p Extension.list   # => [#<MyExt:0xb777d884>]
类扩展

类这似乎有点糟糕,因为文件中定义的每个新类都被注册为“扩展名”,因此不可能有任何助手类。这是一个非常优雅的解决方案!我喜欢区分
更改类
+1.@DavidGrayson-我同意。我们可以想象,提出某种约定来解决这个问题,但它最终会针对应用程序。我想想出一个更干净的第四种方法。我只需要使用const_get(file_name.camelize)。另外,使用Dir.pwd也不是一个好主意,因为如果从其他目录启动脚本,它将无法工作;我会使用File.expand_path(“..”,File)。在我的回答中建议使用文件名,但它有自己的缺点。我同意pwd,可能不应该从问题中复制这个习语。这似乎有点糟糕,因为文件中定义的每个新类都被注册为“扩展名”,因此不可能有任何帮助类。相当优雅的解决方案!我喜欢区分
更改类
+1.@DavidGrayson-我同意。我们可以想象,提出某种约定来解决这个问题,但它最终会针对应用程序。我想想出一个更干净的第四种方法。我只需要使用const_get(file_name.camelize)。另外,使用Dir.pwd也不是一个好主意,因为如果从其他目录启动脚本,它将无法工作;我会使用File.expand_path(“..”,File)。在我的回答中建议使用文件名,但它有自己的缺点。我同意pwd,可能不应该从问题中复制这个习惯用法。最简单的解决方案是以类命名文件。然后您可以使用文件名。最简单的解决方案是以类命名文件。然后可以使用文件名。