Constants

  module MyModule
    MyConstant = 'Outer constant'

    class MyClass
      MyConstant = 'Inner constant'
    end
  end

这段代码中的所有常量像文件系统一样组织成树形结构,模块和类像目录,而常量像文件。跟文件系统一样,只要不在同一个目录下,不同文件的文件名可以相同。可以像文件系统一样通过路径方式来引用一个常量,例如,可以这样: MyModule::MyClass::MyConstant 。

  module M
    Y = 'another constant'

    class C
      ::M::Y      #=> "another constant"
    end
  end

如果深入探究常量的树形结构,则还可以在常量前加一组双冒号表示根路径,从而得到一个绝对路径。

  M.constants                 #=> [:C, :Y]
  Module.constants[0..1]      #=> [:Object, :Module]

Module 类提供了两个叫 constants 的方法,其中一个是实例方法,另一个则是类方法。 Module#constants 方法返回当前范围内的常量,这有点像文件系统中的 ls 命令。 Module.constants 方法返回当前程序中所有顶级常量。

关于 load 和 require

比如在网上找到一个 motd.rb 文件用来在控制台上显示“当天的消息”, 且想把这段代码集成到最新的程序中去,那么可以使用 load 执行该文件来显示消息: load(‘motd.rb’)。

不过,使用 load 方法有一个副作用,motd.rb 文件很可能定义了变量和类。尽管变量在加载完成后会落在当前作用域之外,但常量不会(落在当前作用域中)。这样,motd.rb 可能会通过它的常量(尤其是类名)污染当前程序的命名空间。

可以通过使用第二个可选参数来强制其常量仅在自身范围内有效:load(‘motd’, true)。通过这种方式加载的文件,Ruby 会创建一个匿名模块,使用它作为 命名空间 来容纳 motd.rb 中定义的所有常量,加载完成后,该模块会被销毁。

require 方法与 load 方法颇为类似,但是它的目的不同。通过 load 方法可以执行代码,而 require 则是用来导入类库。这就是 require 方法没有第二个可选参数的原因。在这些库中的类名通常是你导入这些类库时所希望得到的,因此没有理由在加载后销毁它们。

What Happens When You Call a Method?

  • 当调用一个方法时,Ruby 会做两件事:
    1. 找到这个方法,这个过程称为 方法查找
    2. 执行这个方法,为了做到这一点需要一个叫做 self 的东西。

Method Lookup

为了查找一个方法,Ruby首先在 接收者 的类中查找,然后一层层地在祖先链中查找,直到找到这个方法为止。可以调用 ancestors 方法来获得一个类的祖先链。

祖先链当中是包含模块的,当你在一个类(甚至可以是另一个模块)中包含(include)一个模块时,Ruby 会创建一个封装该模块的匿名类,并把这个匿名类插入到祖先链中,其位置正好在包含它的类的上方。

Object 类包含了 Kernel 模块,因此 Kernel 就进入了每个对象的祖先链,这样在每个对象中可以随意调用 Kernel 模块的方法。如果给 Kernel 模块增加一个方法,这个 内核方法 就对所有对象可用,比如 print 方法。

Method Execution

比如调用一个名叫 my_method 的方法,我们先找到了这个方法,发现这个方法定义如下:

  def my_method
    temp = @x + 1
    my_other_method(temp)
  end

我们都知道 @x 实例变量和 my_method 方法都属于接收者,也就是最初调用 my_method 方法的对象,但 Ruby 是不知道的。当调用一个方法时, Ruby 需要持有一个接收者的引用,这样才知道哪个对象是接收者,再用它来执行这个方法。

  • 每一行代码都会在一个对象中被执行,这个对象就是所谓的 当前对象,当前对象也可以用 self 表示,可以用 self 关键字来访问它。

  • 在给定时刻,只有一个对象能充当当前对象。当调用一个方法时,接收者就成为 self。从这一刻起,所有的实例变量都是 self 的实例变量,所有没有明确指明接收者的方法都在 self 上调用。

  • 任何时刻只要调用某个对象的方法,那个对象就成为 self。如果还没有调用任何方法,那这时谁是 self 呢?可以运行 irb 要答案:

    self          #=> main
    self.class    #=> Object
    

    当开始运行 ruby 程序时,ruby 解释器会创建一个名为 main 的对象作为当前对象,这个对象有时被称为 顶级上下文,这个名字的由来是因为这时处在调用堆栈的顶层:这时要么没有调用任何方法,要么调用的所有方法都已经返回了。

self 的角色通常由最后一个接收到方法调用的对象来充当。不过,在类和模块定义中(并且在任何方法定义之外), self 的角色由这个类或模块担任:

  class MyClass
    self           #=> MyClass
  end