I’ve been doing a lot of learning about Ruby lately. All the cool kids are doing it these days so I figured I ought to dive in and teach myself. I’ll probably be doing a series of blog posts like this one on Ruby 101 type of stuff. So if you already know Ruby… well, sorry.
Some Background
So Ruby was created in 1995 by this guy “Matz”. The language itself is sort of a mixture of Smalltalk and Lisp, wherein it’s infix based messages and receivers and everything is an object (‘everything’ as in everything; not ‘everything’ as in everything in Java is an object). The general theme in Ruby’s ecosystem is to be as clean and readable as possible by enabling the creation of DSLs appropriate to whatever task you’re facing.
Classes
Ruby is an OO language so let’s dive right in and see what a class looks like.
class Person
def initialize(name)
@name = name
end
def name
@name
end
def name=(name)
@name = name
end
end
some_person = Person.new('Ben')
puts some_person.name # prints 'Ben'
some_person.name = 'Joe'
puts some_person.name # prints 'Joe'
Methods in ruby are defined by the ‘def’ keyword. If there are no arguments to the method the parenthesis can be omitted. Methods can be suffixed with characters like ‘?’, ‘!’, ‘=’, etc, and each conventionally carries some meaning. In the case above the ‘name=’ method will allow us to use assignment. The ‘initialize’ method is the constructor and is called when you call ‘Person.new’. The ‘@’ prefix on a variable indicates it’s a member variable (member variables are always private). When calling methods, the parenthesis are optional, which is why our usage of the assignment method above doesn’t need parenthesis. We could have just as easily called it like so:
some_person.name=('Joe')
But that’s not very asthetically pleasing.
Generators
One of the key things you’ll discover about Ruby is that it aims to increase developer happiness by removing unnecessary cruft. As it turns out, the above example can be simplified like so:
class Person
attr_accessor :name
def initialize(name)
@name = name
end
end
The ‘attr_accessor’ generates some code given the ‘:name’ label (more on that in a minute). The code it generates is essentially what we saw in the first example. Also available is a ‘attr_reader’ generator that will only generate the ‘getter’ and a ‘attr_writer’ that will only generate the ‘setter’.
Symbols
So what’s that weird ‘:name’ thing? It’s a symbol, which can be thought of as a global constant string object with an underlying numeric representation for the compiler. That’s a mouthful, but the general idea is that if the same string is going to appear in various places in your code then you can use a label to save on memory. Symbol use in Ruby is extensive, so you’ll see them everywhere.
Inheritance
Traditional inheritance in Ruby is accomplished like so:
class Student < Person
end
If you're familiar with OO inheritance in other languages you won't be surprised by much about the implementation in Ruby (except a few corner cases). So why did I say 'traditional' inheritance above? Well, it's because in Ruby you also have the concept of a mix-in.
Mix-ins
I won't cover it in depth here (but probably will in a future blog post), but here's what a mixin looks like:
module Knightable
def knight!
@name = "Sir #{@name}"
end
end
class Person
include Knightable
attr_accessor :name
def initialize(name)
@name = name
end
end
some_person = Person.new('Ben')
puts some_person #prints 'Ben'
some_person.knight!
puts some_person #prints 'Sir Ben'
Here we mixed in a module method which expects a member variable '@name' to exist and operate on. The 'knight!' method implies it changes the receiver object by having the suffix '!'.
Well thats all for this blog post. You may see more Ruby 101 posts soon!