Ruby for Newbies: Working with Classes


Ruby is a one of the most popular languages used on the web. We’ve recently started a new screencast series here on Nettuts+ that will introduce you to Ruby, as well as the great frameworks and tools that go along with Ruby development. In this chapter, we'll take a look at creating our own Ruby classes.

Catch Up

View Screencast

Press the HD button for a clearer picture.

Modifying a Blank Object

In chapter two, we learned how to add methods to an already-existing object. If we want to start with a blank object that we can then augment with methods and properties, we can just create an instance of the Object class.

o =
def o.my_method
  1 + 1
o.my_method # => 2

What about properties? Well, Ruby has instance variables (variables that each instance of an object gets); an instance variable starts with an ‘at’ sign (@). You can get and set these instance variables by creating functions especially for that purpose.

def o.set_name ( name )
  @name = name

def o.get_name

o.set_name "Andrew"
o.get_name # => Andrew

You should note that the variable @name doesn’t need to be initialized anywhere. Ruby takes care of keeping that organized for you. Now, we can set and get the instance variables @name. However, isn’t it rather ugly to use set_name and get_name for properties? Doing something like = "Andrew" to write and to read would be so much more natural. We’ll see how to do this in a minute; but for now, let’s start creating a class of our own.

Creating a Class

It’s pretty simple to create a class. Just use the following syntax. In this lesson, we’ll be creating a pretty useless Person class:

class Person


Again, super-simple. Let’s start filling it in.

Creating Properties

We’ve seen how to create properties: they’re just method wrappers for instance variables. However, we want them to act more like the way you would expect properties to act. It’s easy for the get method:

def name

Since we’re inside the class, we don’t have to give the name of an object in the method signature; just the name of the method will do. When we create an instance of the Person class—say, p1—we’ll be able to call this in the usual way—

But how can we improve the look of setting the @name variable?

Ruby gives us an incredible bit of sugar to make this really cool. Check this out:

def name= name
  @name = name

Okay, so what? This way, we’re writing"joe") or at least"joe", because parenthesis aren’t required. Is that much better? Well, here’s the cool part: you can put in the spaces and Ruby won’t skip a beat: = "joe"

Now, we can write and read our instance variables the way you would expect properties to be read.

But it gets even better. Setting properties via methods like this gives you the opportunity to do something with the value that the user of your class passes in—something more than just assign it to an instance variable, if that's appropriate for your class. However, there’s a good chance that most of the time you’ll do just as we have here: simply set or get the instance variables. In that case, Ruby makes it even easier. Just add this at the top of your class:

attr_accessor :name, :age, :your_properties_here

Pass attr_accessor the names of your properties as symbols. This creates the var and var= methods for you. Then, you’ll be able to use the @ versions wherever you need to in your code.

If you want read-only or write-only properties, you can use attr_reader or attr_writer, respectively. Of course, if you use, say, attr_writer, you can then create a custom reader method if needed.

Creating Instance Method

We’ve seen how to create instance methods; don’t forget you can use those property values if you need to:

def greet
  "#{@name} says, 'Hello there!'"

Creating a Constructor

Often, you’ll want to perform some set-up code when an instance of a class is created. This is done in a constructor function. In Ruby, the constructor function is named initialize. Pop this near the top of our Person class:

def initialize (name, age, job = 'unemployed')
  @name = name
  @age = age
  @job = job

As you can see, initialize takes three parameters. The third one, job, is optional, because we’ve given it a default value. Of course, this works for any function, not just a constructor function. Now, when we want to create an instance of person, we have to do the following:

joe  ="Joe", 35, "plumber")
jill = "Jill", 14

Creating Private Methods

Private methods are functions that can only be called by other functions within the class; they aren’t exposed to the outside world. The usual way to create private methods is this: under all your public code (the instance and class methods), add the keyword private. Any functions that follow this keyword are private.

  # instance and class methods above

  def get_real_weight
end # of the class

If you try to call this method on an instance of Person, it won’t work.

Creating Class Methods and Variables

Class methods and properties are functions and variables that aren’t accessible from instances of a class, but from the class itself. For example, let’s create a class method that returns the number of Person instances we have created.

First, we have to create a class variable that will hold the number of Person instances we have created. Class variables are prefixed with two at-signs. So, add this to your class, preferably under the attr_* lines:

@@count = 0

Now, whenever we make a new Person, we want to increment this variable. What’s run every time we make a Person? initialize, of course; so update it accordingly. Now it looks like this:

def initialize (name, age, job = 'unemployed')
  @name = name
  @age = age
  @job = job

  @@count += 1

Then of course we have to create the class method:

def self.count

Now, give this a try:

joe  ="Joe", 35, "plumber")
jill ="Jill", 13)
bob  = "Bob", 70

Person.count # => 3

Note - Ruby doesn't really have class methods (or static methods, as some languages call them). There's actually a pretty cool bit of "magic" going on under the surface that makes these look like class methods. We'll get into that—usually called metaprogramming—in a future chapter.


That’s it for today; if you have any questions, let me know in the comments. Next time, we’ll explore many common methods on the built-in Ruby classes.

PS - I’ve been playing with the sound settings on my microphone. Is the volume in this screncast loud enough, or should it be higher?