An object can access the instance methods of a module by including that module using the include
method. If you were to include MyModule
in your program, everything inside that module would suddenly pop into existence within the current scope. So, the greet
method of MyModule
will now be accessible:
modules2.rb
include MyModule
Note that only instance methods are included. In the previous example, the greet
(instance) method has been included, but the MyModule.greet
(module) method has not. As it’s included, the greet
instance method can be used just as though it were a normal instance method within the current scope, whereas the module method, also named greet
, is accessed using dot notation:
puts( greet ) #=> I'm happy. How are you? puts( MyModule.greet ) #=> I'm grumpy. How are you?
The process of including a module is also called mixing in, which explains why included modules are often called mixins. When you mix modules into a class definition, any objects created from that class will be able to use the instance methods of the mixed-in module just as though they were defined in the class itself. Here the MyClass class mixes in the MyModule
module:
modules3.rb
class MyClass include MyModule def sayHi puts( greet ) end end
Not only can the methods of this class access the greet
method from MyModule
, but so too can any objects created from the class:
ob = MyClass.new ob.sayHi #=> I'm happy. How are you? puts(ob.greet) #=> I'm happy. How are you?
You can think of modules as discrete code units that may simplify the creation of reusable code libraries. On the other hand, you might be more interested in using modules as an alternative to multiple inheritance.
Returning to an example that I mentioned at the start of this chapter, let’s assume you have a Sword class that is not only a weapon but also a treasure. Maybe Sword is a descendant of the Weapon class (so it inherits the Weapon’s deadliness
attribute), but it also needs to have the attributes of a Treasure (such as value
and owner
). Moreover, since this happens to be an Elvish Sword, it also requires the attributes of a MagicThing. If you define these attributes inside Treasure
and MagicThing
modules rather than Treasure and MagicThing classes, the Sword class would be able to include those modules in order to “mix in” their methods or attributes:
modules4.rb
module MagicThing attr_accessor :power end module Treasure attr_accessor :value attr_accessor :owner end class Weapon attr_accessor :deadliness end class Sword < Weapon # descend from Weapon include Treasure # mix in Treasure include MagicThing # mix in MagicThing attr_accessor :name end
The Sword object now has access to the methods and attributes of the Sword class, of its ancestor class, Weapon, and also of its mixed-in modules, Treasure
and MagicThing
:
s = Sword.new s.name = "Excalibur" s.deadliness = "fatal" s.value = 1000 s.owner = "Gribbit The Dragon" s.power = "Glows when Orcs appear" puts(s.name) #=> Excalibur puts(s.deadliness) #=> fatal puts(s.value) #=> 1000 puts(s.owner) #=> Gribbit The Dragon puts(s.power) #=> Glows when Orcs appear
Note, incidentally, that any variables that are local to the module cannot be accessed from outside the module. This is the case even if a method inside the module tries to access a local variable and that method is invoked by code from outside the module, such as when the module is mixed in through inclusion:
mod_vars.rb
x = 1 # local to this program module Foo x = 50 # local to module Foo # this can be mixed in but the variable x won't be visible def no_bar return x end def bar @x = 1000 return @x end puts( "In Foo: x = #{x}" ) # this can access the module-local x end include Foo # mix in the Foo module
When you run this program, the puts
method executes when the module is initialized, and it displays the value of the module-local variable x
:
In Foo: x = 50
If you display the x
variable within the main scope of the program, the value of the variable x
local to the main scope of the program is used, not the value of the variable x
local to the module:
puts(x) #=> 1
But any attempt to execute the no_bar
method will fail:
puts( no_bar ) # Error: undefined local variable or method 'x'
Here the no_bar
method is unable to access either of the local variables named x
even though x
is declared both in the scope of the module (x = 50
) and in the current or “main” scope (x = 1
). But there is no such problem with instance variables. The bar
method is able to return the value of the instance variable @x
:
puts(bar) #=> 1000
A module may have its own instance variables that belong exclusively to the module “object.” These instance variables will be in scope to a module method:
inst_class_vars.rb
module X @instvar = "X's @instvar" def self.aaa puts(@instvar) end end X.aaa #=> X's @instvar
But instance variables that are referenced in instance objects “belong” to the scope into which that module is included:
module X @instvar = "X's @instvar" @anotherinstvar = "X's 2nd @instvar" def amethod @instvar = 10 # creates @instvar in current scope puts(@instvar) end end include X p( @instvar ) #=> nil amethod #=> 10 puts( @instvar ) #=> 10 @instvar = "hello world" puts( @instvar ) #=> "hello world"
Class variables are also mixed in, and like instance variables, their values may be reassigned within the current scope:
module X @@classvar = "X's @@classvar" end include X puts( @@classvar ) #=> X's @classvar @@classvar = "bye bye" puts( @@classvar ) #=> "bye bye"
You may obtain an array of instance variable names using the instance_variables
method:
p( X.instance_variables ) #=> [:@instvar, @anotherinstvar] p( self.instance_variables ) #=> [:@instvar]
Here, X.instance_variables
returns a list of the instance variables belonging to the X class, while self.instance_variables
returns the instance variables of the current, main, object. The @instvar
variable is different in each case.
In Ruby 1.9, the instance_variables
method returns an array of symbols. In Ruby 1.8, it returns an array of strings.
3.137.217.17