Ruby类加载机制

时间:2013-04-18 20:51:07

标签: ruby

我从Ruby编程语言开始,在开始研究Rails框架之前,我有兴趣深入理解它。

我目前有点失望,因为每个人都只关心Rails框架,而且语言的其他方面都没有深入讨论,比如它的类加载机制。

考虑到我开始做一些桌面/控制台实验,我想更好地理解以下事项:

  1. 将每个Ruby类放在一个单独的Ruby文件中是一个好习惯吗? (* .RB)
  2. 如果我有,让我们说.. 10个类......并且所有这些类都相互引用,通过相互实例化并调用彼此的方法,我应该在每个文件中添加一个'require'语句来说明需要哪些类在该文件中的类? (就像我们在每个Java类文件中使用'import'语句一样?)
  3. 在类声明之前或之后(内部)放置'require'语句会有区别吗?
  4. 什么可以被视为正确的Ruby程序的“切入点”?它告诉我任何.rb脚本都足够了,因为该语言没有像C或Java这样的约定,我们总是需要一个'main'函数的方法。
  5. 是否在执行Ruby程序时将类加载视为“阶段”?我们是否应该在开始时加载应用程序所需的所有类?
  6. 当我们运行需要它们的代码时,解释器本身是否应该负责查找和加载类?通过搜索$ LOAD_PATH变量中的路径,就像Java使用$ CLASSPATH?
  7. 一样

    谢谢。

3 个答案:

答案 0 :(得分:5)

一般而言,为每个Ruby类创建一个单独的.rb文件是一个好习惯,除非这些类具有实用性,并且太过微不足以保证分离。这个实例就是一个自定义的Exception派生类,将它放在一个单独的文件中会比它的价值更麻烦。

传统认为类的名称和文件名是相关的。在类被称为ExampleClass的地方,该文件被称为example_class,它的“下划线”版本。在某些情况下,你会坚持这个惯例,但只要你保持一致就不应该有问题。如果遵循惯例,Rails ActiveSupport自动加载器将帮助你很多,所以很多人都遵循这种做法。

同样,您需要将应用程序组织到libbin等文件夹中,以便将命令行脚本与后端库分开。命令行脚本通常不具有.rb扩展名,而库应该是。

说到require,应该谨慎使用。如果您正确构建了库文件,那么一旦您在顶级文件上调用require,它们就会自动加载。这是通过autoload功能完成的。

例如,lib/example_class.rb可能如下所示:

class ExampleClass
  class SpecialException < Exception
  end

  autoload(:Foo, 'example_class/foo')

  # ...
end

您可以在单独的目录或文件下组织其他内容,例如lib/example_class/foo.rb,其中可能包含:

class ExampleClass::Foo
  # ...
end

您可以一直将autoloads链接起来。这样做的好处是只加载实际引用的模块。

有时您会希望将require推迟到类实现中的某个位置。如果您希望避免在繁重的库中加载,除非使用特定功能,此功能在一般情况下不可能使用,否则这非常有用。

例如,您可能不想加载YAML库,除非您正在进行一些调试:

def debug_export_to_yaml
  require 'yaml'

  YAML.dump(some_stuff)
end

如果查看常见Ruby gem的结构,“入口点”通常是库的顶层或包含此库的实用程序脚本。因此,对于示例ExampleLibrary,您的入口点将为lib/example_library.rb,其结构将包括其余的按需。您可能还有一个脚本bin/library_tool可以为您执行此操作。

至于什么时候加载东西,如果有很高的可能性被使用,请提前加载以提前支付价格,所谓的“急切加载”。如果它被使用的可能性很小,可以根据需要加载它,或者在它被调用时保持“延迟加载”。

了解一些简单但受欢迎的宝石的来源,以了解大多数人如何构建他们的应用程序。

答案 1 :(得分:1)

我会尝试用第一个来帮助你:

  
      
  1. 将每个Ruby类放在一个单独的Ruby文件中是一个好习惯吗? (* .RB)
  2.   

归结为这些课程的密切关系。我们来看几个例子。看这堂课:https://github.com/resque/resque/blob/master/lib/resque.rb ,它"imports"几个类的功能,虽然它们一起工作,但它们并不紧密相关,不能捆绑在一起。

另一方面,请看一下这个模块:https://github.com/resque/resque/blob/master/lib/resque/errors.rb。它捆绑了5个不同的类,但它们确实属于一起,因为它们基本上都代表相同的。

此外,从设计的角度来看,一个好的重击规则可能会问自己,还有谁在使用这个类/功能(意味着代码库的其他部分需要它)?

假设您要表示由Click执行的WheelScrollMouse。在这个简单的例子中,将这些类捆绑在一起会更有意义:

module ComputerPart
   class Mouse; end
   class WheelScroll; end
   class Click; end
end

最后,我建议您仔细阅读其中一些热门项目的代码,以了解社区通常如何做出这些决定。

答案 2 :(得分:0)

1。)我遵循这种做法,但没有必要,如果你愿意,你可以把一堆类放在一个文件中。

2。)如果类在同一个文件中,不是,那么在运行脚本时它们都可以访问。如果它们位于单独的文件中,那么您应该要求它们,您还可以要求文件(自己)所在的整个目录。

3.)是的,它应该在文件的顶部。

4。)在ruby中,一切都从Main对象下降,Interpreter只是为你创建它。如果您正在编写OO ruby​​而不仅仅是脚本,那么入口点将是您调用的第一个类的init方法。

5.。)是的,在程序运行之前,它会加载所有依赖项。

6。)我认为它是这样做的,您只需要在文件顶部需要正确的文件,之后您可以根据需要使用它们,而无需再次隐式加载它们。