如何在模块中加载未知类?

时间:2011-03-26 09:39:29

标签: ruby

我有一些rb文件,都具有相同的结构:

class RandomName < FooBar
end

randomname是一个随机类名,它在每个rb文件中都有变化,但都是从Foobar继承的。

我如何从rb文件加载所有randomclass?

3 个答案:

答案 0 :(得分:4)

您可以在FooBar类中定义一个名为inherited的方法。看here

class FooBar
  def self.inherited(subclass)
    puts "New subclass: #{subclass}"
  end
end

每次创建子类时,您都会在回调中获得它。然后你可以用所有这些子类做任何你想做的事。

答案 1 :(得分:4)

我认为解决方案有两个部分:

  1. 如何动态实例化一个类

    一个。使用String#constantize from ActiveSupport

    klass = "SomeNamespace::SomeClassName".constantize
    klass.new
    

    湾使用Module#const_get(不处理名称空间)

    klass = const_get(:SomeClassName)
    klass.new
    
  2. 如何检测班级名称

    ruby​​中广泛使用的约定是在文件包含的类之后命名,因此random_name.rb将包含RandomName类。如果您遵循此约定,那么您可以执行以下操作:

    Dir["/path/to/directory/*.rb"].each do |file| 
      require file 
      file_name = File.basename(file.path, '.rb')
       # using ActiveSupport for camelcase and constantize
      file_name.camelcase.constantize.new 
    end
    
  3. 我认为你应该解释一下你想要完成的事情。您正在采取的方法似乎是非常规的,并且可能有一种更有效的方法来实现您的目标,而无需执行所有这些文件加载​​和具有随机名称的类的动态实例化。

    请记住,仅仅因为红宝石让你做某事,这并不意味着实际做到这一点是个好主意!

答案 2 :(得分:0)

我有类似的要求,将类名作为字符串传递。需要的一个技巧是它不必在开始时,所以我更喜欢只加载我需要的类。

我使用了eval,因为它没有任何Rails依赖项(我在这里编写纯Ruby代码)。

以下内容依赖于约定(Class位于同名文件中),但如果您确实知道类和文件,则此方法的优点是不需要目录中的每个文件,只能动态加载在你需要的时候你需要的。

klass = "classname"

begin

    # Load the file containing the class from same directory I'm executing in
    require_relative klass # Or pass a local directory like "lib/#{klass}"

    # Use eval to convert that string to a Constant (also capitalize it first)
    k = eval(klass.capitalize).new

rescue
    # Do something if the convention fails and class cannot be instantiated.

end

k.foo # Go ahead and start doing things with your new class.