Classes in Ruby—and other languages—are a way of organizing objects into mini code-factories: where the class itself is a template that gets filled out for each copy, or instance, of itself. A great real-world explanation of classes is in role-playing games where at the beginning you create your own character (and credit for this thought goes to the Invent With Python blogger). Your character will belong to a class—it'll be a Warrior, or a Druid, or a Healer, etc—but it will be unique to you, because it will have a name that you give it, and other information like special clothes that it wears because you decided on them, etc. Based on its class, your character will also have its own behaviours: it will be able to heal other characters if it's a Healer, or talk to plants if it's a Druid, or kick some serious butt if it's a Warrior, etc, and for the most part, these special behaviours will not be available to characters from other classes.

Similarly, a Ruby class has state—attributes like name, etc—and behaviours—methods that instances of itself can execute. We can think of attributes as things that describe the object and give it an identity from other instances of that class: it'll have its own name, for example. So attributes are things that that instance of the class IS, and its methods are things that it DOES.

When a copy of the class is taken to create a new instance of that class, it is given its own state/attributes. To illustrate, here's a Book class:

Books in the real world aren't meant to DO anything on their own (not that that stops them from being powerful forces...), but they are certainly meant to have unique attributes: their own title and author, for example. In the example above, the class Book is a set of code that, when a copy of itself is made and given a title and an author, will be a unique Book object.

The methods title and author expose the values contained inside the instance variables @title and @author respectively. (Instance variables are variables that are expressely there to hold values for a specific instance of that class: they are available anywhere inside the class to give their value or to have that value altered.) Using attr_reader, we can abstract away those simple title and author methods into the following: attr_reader :title, :author, which under the hood is exactly what those little methods are, just differently written. Here's the Book class updated to use attr_reader:

Looks like the parts inside initialize changed too! Like attr_reader, writing variable assignments like this is just a shorter, one-line way of doing the same thing as before.

Now let's make a Library class:

Our Library class is a little more complex than our Book class. Our Library class has methods that allow it to DO stuff, not just BE stuff: it can add_book into itself, it can suggest_a_book to the user, and it can suggest_an_author too. Don't focus too much on the code inside add_book just yet, we'll get to it in a moment. Right now, let's make a new Library object, and ask it to show itself to us using p:

That's a very interesting bit of code right there in the comments: when we asked my_library to show itself to us, it printed out that long string of characters. The first part is clear: it's telling us what class it belongs to. The next bit of numbers is its object ID; and that last part, the @books=[], is its attribute books, which we said is empty when we first initialize our Library. (Since all libraries start out empty at first and get filled up with books over time.) So now, let's add some books to our library using the add_book method:

So before, our library had an empty array for @books attribute: but now it's filled with 4 Book objects, each with their own attributes of @title and @author! This is because the Library method add_book takes two arguments, title and author, and uses those arguments to create a new Book object each time it is called; then it "shovels" the new Book object as a whole—including its object ID and everything else about it, like its attributes—into the @books array.

It's a bit hard to read those long indecipherable object strings. Let's ask it to show us its books in a nicer way:

That's much nicer! @books holds the value of an array of objects, and the array method each allows us to iterate over @books and ask each book object to put itself to the console in the way we've specified.

Now let's try out its rather pushy suggest_a_book and suggest_an_author methods:

Super nifty! That's all for today, I'm feeling like opening up my copy of The Well Grounded Rubyist now.