Classes
Classes are templates from which new object instances are created. For example, to put the
greet method from above into a class you could write:
irb(main):001:0> class Manners
irb(main):002:1> def greet(name)
irb(main):003:2> puts "Hello, #{name}!"
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> m = Manners.new
=> #<Manners:0x404839c>
irb(main):007:0> m.greet "Reader"
Hello, Reader!
=> nil
The preceding code creates a new class named Manners, and adds the greet method to it. Finally, it creates a new instance of Manners, and uses it to greet the reader.
You should think of classes as being a living template for objects in Ruby. Unlike classes in .NET, which are defined at compilation time, you can extend classes in Ruby at any time, and when you've extended them, even existing instances of that class immediately gain the new behavior. Notice what happens when you attempt to say farewell:
irb(main):008:0> m.farewell "Reader"
NoMethodError: undefined method 'farewell' for
#<Manners:0x404839c>
from (irb):8
When you tried to call farewell, the system told you it didn't know what it was. Now extend the Manners class and give it the ability to say goodbye:
irb(main):009:0> class Manners
irb(main):010:1> def farewell(name)
irb(main):011:2> puts "Goodbye, #{name}!"
irb(main):012:2> end
irb(main):013:1> end
=> nil
irb(main):014:0> m.farewell "Reader"
Goodbye, Reader!
=> nil
After extending the Manners class, your existing instance of it can now bid the reader farewell.
The Manners class has two methods, and both take your name. You should probably re-write it so you can pass the name when you create it. Ruby calls the
initialize method with all the arguments you pass to
new. Here's an updated version of the Manners class:
irb(main):001:0> class Manners
irb(main):002:1> def initialize(name)
irb(main):003:2> @name = name
irb(main):004:2> end
irb(main):005:1> def greet
irb(main):006:2> puts "Hello, #{@name}!"
irb(main):007:2> end
irb(main):008:1> def farewell
irb(main):009:2> puts "Goodbye, #{@name}!"
irb(main):010:2> end
irb(main):011:1> end
=> nil
irb(main):012:0> m = Manners.new "Reader"
=> #<Manners:0x809fa08 @name="Reader">
irb(main):013:0> m.greet
Hello, Reader!
=> nil
irb(main):014:0> m.farewell
Goodbye, Reader!
=> nil
Notice that the class stores the name in an instance variable named
@name. Also note that inspecting the instance (the result, printed after line 12) includes the values of all the instance variables.
Class extensibility isn't limited to just the classes you define. You can also extend the built-in classes in Ruby:
irb(main):001:0> class Array
irb(main):002:1> def print_tr
irb(main):003:2> puts "<tr>"
irb(main):004:2> each { |item|
irb(main):005:3* puts " <td>#{item}</td>"
irb(main):006:3> }
irb(main):007:2> puts "</tr>"
irb(main):008:2> end
irb(main):009:1> end
=> nil
Irb(main):010:0> ["hello","world!"].print_tr
<tr>
<td>hello</td>
<td>world!</td>
</tr>
=> nil
Rails adds many extensions to the built-in types that provide a fluent interface. For example, you can write code such as
5.days.from_now and get back a time zone-aware date that is, well, five days from now.
The methods you've defined so far have all been instance methods; that is, they are methods that are available only on instances of a class. Ruby has static methods (sometimes called class methods) as well. In fact, you've already been calling a static method, without even thinking about it:
new.
You can add new static methods to any existing class:
irb(main):001:0> def String.concat(s1, s2)
irb(main):002:1> s1 + ' ' + s2
irb(main):003:1> end
=> nil
irb(main):004:0> String.concat 'hi', 'bye'
=> "hi bye"
You can also define them in the context of defining or extending the class using the "self" syntax:
irb(main):001:0> class String
irb(main):002:1> def self.concat(s1, s2)
irb(main):003:2> s1 + ' ' + s2
irb(main):004:2> end
irb(main):005:1> end
=> nil
irb(main):006:0> String.concat 'hi', 'bye'
=> "hi bye"