Ruby Class Tutorial

Classes and interfaces are the primary building blocks of a typical Java application. Classes are the blue prints used to create objects in a running system. In contrast to Java, Ruby’s building blocks are classes, modules, and mixins. In this post we will take a tour of classes in Ruby.

Classes
To get started, lets define a basic Person class.

class Person
end

The above class is the simplest class type we can define in Ruby. The first thing you will notice is that the curly braces that are so pervasive in other programming languages are omitted here. This is not a typo. It is intentional. In fact, curly braces are rarely used in Ruby code blocks.

As in Java, we use the class reserve keyword to define a class type and the class name is capitalized in camel case. In Ruby, end is the reserved keyword used to demarcate the end of a code block such as an if statement, a method declaration, or a class definition. At this point, the Person class is the simplest class that we can define. Our Person class implicitly inherits from Object.

So far the Person class defined above is not even interesting enough to instantiate. As we know a class typically has state and behavior. Lets add two instance variables to our Person class to hold the first and last name and the necessary getters and setters in a very Java-like fashion.

class Person
  def fname
    @fname
  end
  def fname=(fname)
    @fname = fname
  end
  def lname
    @lname
  end
  def lname=(lname)
    @lname = lname
  end
end


There is a lot going on here so lets try to step through the code. First, notice that I have not declared any variables, private, public, or otherwise. Since Ruby is a dynamic programming language you don’t have to declare an instance variable until you need it. In the case of the first name, fname, we need the variable only in the accessor functions. The naming convention is a little different in Ruby than in Java and the set/get prefix is usually dropped out. Just to clarify, the fname and fname= methods are the getter and setter, respectively, for the @fname instance variable. In Ruby, the value of the last expression is returned in a function definition so we don’t have to explicitly use the return.

Ruby is widely known for its concise language constructs and typing in a setter and getter for each individual instance variable is so 1999, that is to say so Java-like. In Ruby accessor methods are optional. Ruby has a group of attribute functions that can very easily create the necessary getters and setters. The nomenclature in Ruby is reader and writer for these accessor methods. Here is a new implementation of the Person class using the attr_accessor method, which dynamically defines accessor methods for the symbol parameters.

class Person
  attr_accessor :fname, :lname
end

Notice that one line of code has replace four methods definitions. This one line of code does exactly the same thing as the four methods it replaced, it provides the necessary read and write methods for two instance variables. This simple example clearly demonstrates the strength of Ruby and how concise and succinct your Ruby code can be if pushed to its potential. It is almost like magic, now you see them now you don’t. It is important to remember that the fewer lines of code you write the fewer tests you have to maintain, and ultimately the fewer bugs you will need to fix. From my experience, the number of bugs is proportional to the number of lines of code.

Just as a comparison, in Java you can avoid manually typing in each getter and setter by using some IDE code generation command or wizard but new code will be written to your source file.

Initializers And Constructors
Classes are templates for creating object instances. Since we have already defined a Person class we can now create objects to represent a person. Lets create an object to represent the creator of Ruby and my personal hero Yukihiro Matsumoto.

matz = Person.new
matz.fname = "Yukihiro"
matz.lname = "Matsumoto"

It would be so much more convenient to set the name of a person at creation time. To accomplish this we need to define a constructor in our Person class. In Ruby to implement a constructor for a class you need to define a method named initialize. Here is an updated version of our person class with a constructor defined.

class Person
  attr_accessor :fname, :lname

  def initialize(fname, lname)
    @fname = fname
    @lname = lname
  end
end

Now we can construct a Person object using the initialize method in the following fashion.

matz = Person.new("Yukihiro", "Matsumoto")

The first thing that Java developers should note is that Ruby does not support method overloading. A typical Java class might have two or more constructors, but since Ruby does not support method overloading there can only be one initialize method. Ruby does issue an exception or warning if classes defines more than one initialize method, but last initialize method defined is the valid one.

Instance Methods
As mentioned earlier, a class defines state via attributes and behavior through methods. Now that our Person class has some state object variables defined, lets add behavior by adding methods.

In Ruby methods are defined using the def keyword. The signature of a method is the method name. As mentioned earlier the Ruby does not support method overriding so if two methods are defined with the same name the last implementation defined is used. Lets override the Object’s to_s method in our Person class. The to_s method is Ruby’s equivalent to the toString method in Java.

class Person
  attr_accessor :fname, :lname

  def initialize(fname, lname)
    @fname = fname
    @lname = lname
  end

  def to_s
    @lname + ", " + @fname
  end
end

The to_s method returns a String object representation of the object. In the case of our Person class, it now returns the concatenation of the last and first name. Also notice that we did not have to use the return keyword. In Ruby the value of the last expression of a method is the return value. Now to invoke the to_s method we can use any of the following lines of code.

# Explicitly call to_s
str_name = matz.to_s
puts str_name

# Implicitly call to_s
puts matz

Class Methods
As we just saw, instance methods are invoke using an object instance as the receiver. Ruby also supports class methods that belong to the class and not on an object instance. In Java class methods are also known as static methods. A good example of static methods are those defined in Java’s java.lang.Math class.

A good use of a class method is to implement a method that helps to create or find instance of a class. Using our Person class we will create a class method named find_by_name that will find a person object whose first name matches a string given as a parameter.

class Person
  attr_accessor :fname, :lname

  def initialize(fname, lname)
    @fname = fname
    @lname = lname
  end

  def to_s
    @lname + ", " + @fname
  end

  def self.find_by_fname(fname)
    found = nil
    ObjectSpace.each_object(Person) { |o|
      found = o if o.fname == fname
    }
    found
  end
end

To define a method as a class method, prefix the method name with the self keyword. The scope of self varies depending on the context. Inside an instance method, self resolves to the receiver object. Outside an instance method, but inside a class definition, self resolves to the class.

There are some implementation details in our class method find_by_fname that I will have to defer to another post. For now, just know that ObjectSpace retains a reference of all objects used in a running program. The ObjectSpace’s each_object method will return all instantiated objects for a given class. In our case, the each_object method would return all objects of type Person and we filter for the one whose first name matches the given parameter.

Before we can start looking up people with our find_by_fname class method we will need to create several Person objects that represent them. Because of my complete lack of imagination, I’ll continue to use Ruby evangelist, writers, programmers, hackers, and just plain old groupies in my examples.

Person.new("Yukihiro", "Matsumoto")
Person.new("David", "Thomas")
Person.new("David", "Black")
Person.new("Bruce", "Tate")

# Find matz!
puts Person.find_by_fname("Yukihiro")

As in Java, to invoke a class method prefix the class method call with the class name. It is also worth repeating, that in the context of a class method the self keyword will resolve to the class.

As a final word on the implementation of the our find_by_fname class method, you will notice that if we try to find ‘David’ it returns one matched object instead of two. I’ll leave that as an exercise to the reader return both David Thomas and David Black. As a hint I’ll just say that you can push matched objects into an array.

Inheritance
Inheritance is one of the three pillars of Object Oriented Programming, the other two pillars are encapsulation and polymorphism. Inheritance is a natural way to remix and reuse existing classes. The class that is inherited is known as the super class or base class. The class that inherits from the base class is known as the child class or subclass. The base class is usually more generic than the subclass.

In Ruby, inheritance is achieved with the less than (<) operator. To demonstrate this lets partially port Java’s Number and BigInteger classes to Ruby even though Ruby’s Fixnum and Bignum do a great job at manipulating numeric data. Lets start with the base class Number.

class Number
  def intValue
    @value
  end
end

As noted earlier to extend a class we use the less than operator.

class BigInteger < Number
  # Add a constructor with one parameter
  def initialize(value)
    @value = value
  end
end

Because of polymorphism, another of the three pillars of Object Oriented Programming, any instance of BigInteger can be treated as a Number. And because Ruby is a dynamic language a BigInteger can be manipulated as Number and then back as a BigInteger without explicitly casting the object. In Ruby this is commonly known as duck-typing. As they say, if it quacks like a duck and it walks like a duck then it must be of type Duck.

Related posts:

  1. Ruby Mixin Tutorial
  2. Reopening Ruby Classes
  3. Class HighLite Calendar
  4. Rails Plugin Tutorial
  5. Class HighLite Throwable
  6. Java.class


18 Responses to “Ruby Class Tutorial”

  • Derek Says:

    I think I’m confused by the post–not by the content, but by the expected audience. The requisite OOP knowledge level seems to bounce around. Sometimes it looks like it’s made for a true newbie; other times it seems like there’s not enough information for some of the concepts you address. But it actually looks like you intend to compare Ruby’s classes to Java’s. Java programmers, you would think, wouldn’t need some of the beginner information you include.

    I don’t know if it seems that way to others, as well. Hell, you wrote *something* to share with the world, so good on you.

    Here’s another small issue: you do not have to type class Person

  • TechKnow Says:

    Yo Derek, Thanks for your comments!!! My high school English teacher always told me to find my voice. I’ll try to revise the post so it flows better. I did want this to be useful to total Ruby newbies and I guess I do tend to speak from a Java perspective. Once again, thanks!

  • Derek Says:

    No problem. I hoped I didn’t sound too critical. Any Ruby/Rails information is good information, I say.

    It looks like my last comment got truncated.

    “Our Person class explicitly inherits from Object.” Person actually implicitly inherits. If you had to type it, the connection would be explicit.

  • Bradford Taylor Says:

    I disagree. As an experience Java programmer who just wants a quick intro to Ruby I think your scope is fine. True I know all about encapsulation, inheritance and polymorphism but it’s good to reference those, even in their basic concepts to use a common point of discussion.

    Kinda like Spock wouldn’t talk to McCoy about death until he had died so they would have a common point of reference.

  • Takuan Says:

    Great post!
    I agree with the first post about writing for java programmers but explaining OO stuff to them..
    I am lucky in that i used to do some OO stuff and a tiny bit of java so it was a great refresher and taught me exactly what i wanted to know.
    Please continue on!!!

  • John Joyner Says:

    One of the very best explanations of your topics I’ve read yet (I’ve been studying Ruby since the days when there were only two books).

  • ruby?static method « DevPoga Says:

    [...] http://www.juixe.com/techknow/index.php/2007/01/22/ruby-class-tutorial/  ?????class method… Posted by poga Filed in Ruby Tags: Ruby, self, [...]

  • David Says:

    Great intro to Ruby Classes thanks!
    I’ve been to a few other sites and too many seem to just throw in the dynamic accessors and move along without really explaining what they just did there…I finally get whats going on.

  • Pancho Says:

    This article helped me a lot, because I know a lot about Java, and almost nothing about Ruby, so it was useful to have some kind of comparison.
    Thank you!

  • JohnBoy Says:

    First, thanks as this is a much better introduction to Ruby classes than the three other popular sites I just tried.

    2 Q’s:

    1) If you define the accessors using:

    attr_accessor :fname, :lname

    then aren’t these two attributes pretty much just public? If you later decide that you need to do some functionality after assigning, say, the lname field (let’s just say increment some internal counter), then how would you do that? Would you need to back out of the shorthand version of declaring these two generic accessors and instead spell out each one?

    2) I noticed the if statement appears to be reversed from all the syntaxes I’ve ever seen. That is, the statement is before the condition. But I’ve also seen Ruby code with if statements that “read forward”, like other lang’s. Is this optional in Ruby?

    Thanks,

    John

  • Dennis Says:

    I am not experienced in Java and have only programmed in Ruby and I must agree with other commenters that this is one of the better explanations of the Ruby Class that I’ve come across .

    So, in my mind, anyone who is looking for a good discussion of Ruby Class can benefit from reading this article – not just Java programmers new to Ruby.

    Thank you – I’ll definitely be reading other Juixe Techknow articles given the quality of this one.

  • Mayumi Says:

    First of all, a great post!
    Coming from a strong Java background, it took me a little getting used to concise syntax of Ruby, but this post really help me relate to my knowledge of Java. Thanks again for the great post!

  • John Varghese Says:

    Great post. Helped me get started with OO ruby. Now on to bigger things.

  • Pradeep Says:

    Definitely a good amount of information to get me started with Ruby and eventually Rhodes Mobile framework. I have experience with C# and Java, and this tutorial is very helpful to me. Bookmarked !!

  • Andrew Shatnyy Says:

    Pretty descriptive. Enough to understand what is what.
    I would love to see something like that but for modules if it’s not yet posted.

  • yazid Says:

    Thank you,

    It was very useful for me also!

  • Rahul Says:

    Good comparison between Ruby and Java. Moving from java to ruby …as a starter, it was very useful.
    Thanks

  • danny Says:

    you made understanding constructors and the initialize method very easy for me. Thanks!

Leave a Reply