modules2.rb

    注意,只会包含实例方法。在上面的示例中,已经包含了 greet(实例)方法,但是 MyModule.greet(模块)方法没有被包含…

    1. module MyModule
    2. GOODMOOD = "happy"
    3. BADMOOD = "grumpy"
    4. def greet
    5. return "I'm #{GOODMOOD}. How are you?"
    6. end
    7. def MyModule.greet
    8. return "I'm #{BADMOOD}. How are you?"
    9. end
    10. end

    正如它所包含的那样,greet 方法可以像使用当前作用域中的普通实例方法一样被使用…

    1. puts( greet )

    包含模块的过程也称为“混入”(mixing in) - 这解释了为什么包含的模块通常被称为 “mixins”。将模块混入到类定义中时,从该类创建的任何对象都将能够使用被混入模块的实例方法,就像它们在类本身中定义一样。

    modules3.rb
    1. class MyClass
    2. include MyModule
    3. def sayHi
    4. puts( greet )
    5. end
    6. end

    模块(Modules)可以被认为是离散的代码单元,可以简化可重用代码库的创建。另一方面,你可能更感兴趣的是使用模块作为实现多继承的替代方式。

    回到我在本章开头提到的一个示例,让我们假设你有一个剑(Sword)类,它不仅是一种武器(Weapon),也是一种珍宝(Treasure)。或许 Sword 是 Weapon 类的后代(因此继承了 Weapon 的 deadliness 属性),但它也需要具有 Treasure 的属性(例如 valueowner),并且这是拥有魔法(MagicThing)的精灵之剑。如果你在 Treasure 和 MagicThing 模块modules)而不是classes)中定义这些属性,则 Sword 类将能够以“混入”(mix in)方式包含这些模块其方法或属性:

    modules4.rb
    1. module MagicThing
    2. attr_accessor :power
    3. end
    4. module Treasure
    5. attr_accessor :value
    6. attr_accessor :owner
    7. class Weapon
    8. attr_accessor :deadliness
    9. end
    10. class Sword < Weapon
    11. include Treasure
    12. include MagicThing
    13. attr_accessor :name
    14. end

    Sword 对象现在可以访问 Sword 类本身,它的祖先类 Weapon,以及它的混入(mixed-in)模块 Treasure 和 MagicThing 的方法和属性:

    1. s = Sword.new
    2. s.name = "Excalibur"
    3. s.deadliness = "fatal"
    4. s.value = 1000
    5. s.owner = "Gribbit The Dragon"
    6. s.power = "Glows when Orcs Appear"
    7. puts(s.name)
    8. puts(s.deadliness)
    9. puts(s.value)
    10. puts(s.owner)
    11. puts(s.power)
    mod_vars.rb
    1. x = 1 # local to this program
    2. module Foo
    3. x = 50 # local to module Foo
    4. # This can be mixed in but the variable x won't then be visible
    5. def no_bar
    6. return x
    7. end
    8. def bar
    9. @x = 1000
    10. return @x
    11. end
    12. puts( "In Foo: x = #{x}" ) # this can access the „module local‟ x
    13. include Foo
    14. puts(x)
    15. puts( no_bar ) # Error! This can't access the module-local variable
    16. # needed by the no_bar method
    17. puts(bar)

    请注意,实例变量(instance variables)可用于混入方法(例如 bar)。但是,即使在混入方法的当前作用域中存在具有相同名称的局部变量时,局部变量也不可用(因此,即使 x 在当前作用域中已经声明,no_bar 也无法访问名为 x 的变量)。

    模块可以具有其自己的实例变量,这些变量仅仅属于模块“对象”。这些实例变量存在于模块方法的作用域内:

    inst_class_vars.rb

    但实例对象中引用的实例变量“属于”包含该模块的作用域:

    1. module X
    2. @instvar = "X's @instvar"
    3. def amethod
    4. @instvar = 10 # creates @instvar in current scope
    5. puts(@instvar)
    6. end
    7. end
    8. include X
    9. X.aaa #=> X's @instvar
    10. puts( @instvar ) #=> nil
    11. amethod #=> 10
    12. puts( @instvar ) #=> 10
    13. @instvar = "hello world"
    14. puts( @instvar ) #=> "hello world"
    1. module X
    2. @@classvar = "X's @@classvar"
    3. end
    4. include X
    5. puts( @@classvar ) #=> X's @@classvar
    6. @@classvar = "bye bye"
    7. puts( @@classvar ) #=> "bye bye"

    你可以使用 instance_variables 方法获取实例变量的名称数组:

    1. p( self.instance_variables )