In an object-oriented programming language like Ruby, a class is a container that holds properties (class members) such as methods and variables. Classes can inherit properties from a parent or superclass, creating a hierarchy of classes with a base class at the root or top. In Ruby, the base class is Object
. Ruby uses single inheritance—that is, a Ruby class can inherit the properties of only one parent class. (Multiple inheritance, as is used in C++, allows a class to inherit from more than one parent.) You can define more than one class in a single file in Ruby. A class itself is an object, even if you don't directly instantiate it. Classes are always open, so you can add to any class, even a built-in one.
A class is defined with a class
keyword, and the definition concludes with an end
:
class
Hello definitialize
( name ) @name = name end def hello_matz puts "Hello, " + @name + "!" endend
hi = Hello.new( "Matz" ) hi.hello_matz # => Hello, Matz!
The initialize
method defines the instance variable @name
by storing a copy of the name
argument passed into the initialize
method. The initialize
method is a Ruby convention that acts like a class constructor in other languages, but not completely. At this point, the instance is already there, fully instantiated. initialize
is the first code that is executed after the object is instantiated; you can execute just about any Ruby code in initialize
. initialize
is always private; that is, it is scoped only to the current object, not beyond it. You access the instance variable @name
with the method hello_matz
.
To add a method to an existing class, such as the built-in class Array
, specify the following:
classArray
def array_of_ten (1..10).to_a end end arr = Array.new ten =arr.array_of_ten
p ten # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
As mentioned previously, an instance variable is a variable that is available from within an instance of a class, and is limited in scope because it belongs to a given object. An instance variable is prefixed by a single at sign (@
), like:
@name
= "Easy Jet"
You can define an instance variable inside a method or outside of one. You can only access an instance variable from outside an object via a method. You can, however, access an instance variable within the object without a method:
class Horse @name = "Easy Jet" end
This works if you only want to reference @name
from within the object. You have no way to retrieve the value of @name
directly from outside of the object. You must define a getter (accessor) method to retrieve the value:
class Horse
def name
@name = "Easy Jet"
end
end
h = Horse.new
h.name # => "Easy Jet"
You often want a setter in addition to a getter. A setter is an accessor method that sets the value of a variable:
class Horse
def name
@name
end
def name=( value )
@name = value
end
end
h = Horse.new
h.name= "Poco Bueno"
h.name # => "Poco Bueno"
The setter method name=
follows a Ruby convention: the name of the method ends with an equals sign (=
). This convention is not a requirement. You could call name=
whatever you like, as long as the characters are legal. Here is another version of the class Horse
that initializes the instance variable @name
with the standard initialize
method. Later the program creates an instance of the class by calling new
, and then accesses the instance variable through the accessor method horse_name
, via the instance horse
:
class Horse def initialize( name )@name
= name end def horse_name@name
end end horse = Horse.new( "Doc Bar" ) puts horse.horse_name # => Doc Bar
Ruby simplifies the creation of getters and setters by meta-programming with the methods attr
, attr_reader
, attr_writer
, and attr_accessor
, all from the Module
class. The attr
method creates a single getter method, named by a symbol, with an optional setter method (if the second argument is true
):
class Dog
attr
:bark, true
end
Dog.instance_methods - Object.instance_methods
# => ["bark", "bark="]
dog = Dog.new
dog.bark="Woof!"
puts dog.bark # => Woof!
By calling attr
with :bark
and true
as arguments, the class Dog
will have the instance methods bark
and bark=
. If you call attr
with only the :bark
argument, Dog
would have only the getter method bark
. (Notice that you can subtract out Object
's instance methods with -
when retrieving Dog
's instance methods.)
The attr_reader
and attr_writer
methods accept as arguments the names of one or more instance variables, then create corresponding methods that return (attr_reader
) or set (attr_writer
) the values of each instance variable. (Instance variables are not actually created until you assign values to them.) Consider this example:
class Dogattr_reader
:bark # getterattr_writer
:bark # setter end dog = Dog.new dog.bark="Woof!" puts dog.bark # => Woof! dog.instance_variables.sort # => ["@bark"] Dog.instance_methods.sort - Object.instance_methods # => [ "bark", "bark=" ]
Calling the attr_accessor
method does the same job as calling both attr_reader
and attr_writer
together, for one or more instance variables:
class Gaits
attr_accessor
:walk, :trot, :canter
end
Gaits.instance_methods.sort - Object.instance_methods # =>
["canter", "canter=", "trot", "trot=", "walk", "walk="]
A class variable is shared among all instances of a class, so only one copy of a class variable exists for a given class. In Ruby, a class variable is prefixed by two at signs (@@
). You must initialize a class attribute before you use it, such as @@times = 0
.
class Repeat@@total
= 0 def initialize( string, times ) @string = string @times = times end def repeat@@total
+= @times return @string * @times end def total "Total times, so far: " +@@total
.to_s end end data = Repeat.new( "ack ", 8 ) ditto = Repeat.new( "Again! ", 5 ) ditty = Repeat.new( "Rinse. Lather. Repeat. ", 2 ) puts data.repeat # => ack ack ack ack ack ack ack ack puts data.total # => Total times, so far: 8 puts ditto.repeat # => Again! Again! Again! Again! Again! puts ditto.total # => Total times, so far: 13 puts ditty.repeat # => Rinse. Lather. Repeat. Rinse. Lather. Repeat. puts ditty.total # => Total times, so far: 15
A class method is a method that is associated with a class (and with a module in Ruby), not an instance of a class. You can invoke class methods by prefixing the name of the method with the name of the class to which it belongs, such as to Math.sqrt(36)
. Class methods are also called static methods. You can also associate the name of a module with a method name, just like with a class, but to use such a method, you must include the module in a class. To define a class method, you simply prefix the name of the method with the name of the class or module (or self
) in the method definition:
class Area # Use self.rect or Area.rect # defself.rect
( length, width, units="inches" ) defArea.rect
( length, width, units="inches" ) area = length*width printf( "The area of this rectangle is %.2f %s.", area, units ) sprintf( "%.2f", area ) end endArea.rect
(12.5, 16) # => The area of this rectangle is 200.00 inches.
Another way you can define class methods is by using a class within a class and self
—a singleton class. In basic terms, a singleton is designed so that it can only be instantiated once. It is often used like a global variable. Ruby has a class for defining singleton objects; see http://www.ruby-doc.org/core/classes/Singleton.html. Consider this example:
class Areaclass << self
defrect
( length, width, units="inches" ) area = length*width printf( "The area of this rectangle is %.2f %s.", area, units ) sprintf( "%.2f", area ) end end endArea.rect
(10, 10) # The area of this rectangle is 100.00 inches.=> "100.00"
In this form, you don't have to prefix the method with the class name. A singleton class is tied to a particular object, can be instantiated only once, and is not distinguished by a prefixed name. The method rect
is also effectively a singleton method because it is tied to the singleton class. Here is a way to define a singleton method, one that is tied to a single object:
class Singleton end s = Singleton.new defs.handle
puts "I'm a singleton method!" ends.handle
# => I'm a singleton method!
As mentioned earlier, when a child class inherits or derives from a parent, it has access to the methods and properties of the parent class. Inheritance is accomplished with the <
operator:
class Name
attr_accessor :given_name, :family_name
end
class Address < Name
attr_accessor :street, :city, :state, :country
end
a = Address.new
puts a.respond_to?(:given_name) # => true
If the class Name
were in a different file, you'd just require
that file first, and then the inheritance operation works.
The system path is not necessarily the same thing as the Ruby path or load path. Ruby has a predefined variable called $LOAD_PATH
(which also has a Perl-like synonym, $:
). $LOAD_PATH
is an array that contains the names of directories that are searched by load
and require
methods when loading files. Ruby can also use the environment variables PATH
and RUBYPATH
(if they are set). PATH
is the system path and acts as a search path for Ruby programs, among other things; RUBYPATH
may be the same thing as PATH
, but because it takes precedence over PATH
, it is likely to hold other directories beyond it.
The visibility or access of methods and constants may be set with the following methods:
public
The method is accessible by anyone from anywhere; this is the default.
private
The receiver for the method is always the current object or self
, so its scope is always the current object (often helper methods; that is, ones that get called by other methods to perform some job).
protected
The method can be used only by instances of the class where it was defined, or by derived classes.
Methods following the keywords private
or protected
will have the indicated visibility, until changed or until the definition ends:
class Names def initialize( given, family, nick, pet ) @given = given @family = family @nick = nick @pet = pet end # the methods are public by default def given @given end def family @family end # all following methods private, until changedprivate
def nick @nick end # all following methods protected, until changedprotected
def pet @pet end end name = Names.new( "Klyde", "Kimball", "Abner", "Teddy Bear" )name.given
# => "Klyde"name.family
# => "Kimball" # see what happens when you call nick or petname.nick name.pet
You can also call the methods after a definition (you must use symbols for method names):
def pet
@pet
end
protected :pet
In addition to classes, Ruby also has modules. A module is like a class, but it cannot be instantiated like a class. A class can include a module so that when the class is instantiated, it gets the included module's methods and so forth. (The include
method comes from the Module
class: http://www.ruby-doc.org/core/classes/Module.html.) The methods from an included module become instance methods in the class that includes the module. This is called mixing in, and a module is referred to as a mixin. You can include more than one module (which is similar to multiple inheritance), but you can only inherit from one class (single inheritance). Because identifiers are overridden by the last definition of the identifier (e.g., for methods or constants), this scheme avoids name collision. A module is a form of a namespace in Ruby. A namespace is a set of names—such as method names—that have a scope or context. A Ruby class can also be considered a namespace.
A Ruby module associates a single name with a set of method and constant names. The module name can be used in classes or in other modules. Generally, the scope or context of such a namespace is the class or module where the namespace (module name) is included.
A module name must be a constant; that is, it must start with an uppercase letter. A module can contain methods, constants, other modules, and even classes. It can inherit from another module, but it may not inherit from a class. As a class may include a module, it may also include modules that have inherited other modules. Here's an example:
module Dice
# virtual roll of a pair of dice
def roll
r_1 = rand(6); r_2 = rand(6)
r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6
total = r1+r2
printf( "You rolled %d and %d (%d).\n", r1, r2, total )
total
end
end
class Game
include Dice
end
g = Game.new
g.roll
If the module Dice
and the class Game
were in separate files, just require
the file containing the module before including the module. The file containing the Dice
module might look like this:
module Dice # virtual roll of a pair of dice def roll r_1 = rand(6); r_2 = rand(6) r1 = r_1>0?r_1:1; r2 = r_2>0?r_2:6 total = r1+r2 printf( "You rolled %d and %d (%d).\n", r1, r2, total ) total end end
And the file containing the Game
class might look like this:
#!/usr/bin/env ruby require 'dice' class Game include Dice end g = Game.new g.roll
When you define module methods like class methods—that is, prefixed with the module name (or with self
)—you can call the method as shown here:
module Binary # def self.to_bin( num ) defBinary.to_bin
( num ) bin = sprintf("%08b", num) end endBinary.to_bin
( 123 ) # => "01111011"