This Notebook Server was launched just for you. It's a temporary way for you to try out a recent development version of the IRuby/Jupyter notebook.
**WARNING**
Don't rely on this server for anything you want to last - your server will be *deleted after 10 minutes of inactivity*.
To run the code below:
SHIFT+ENTER on your keyboard or press the play button () in the toolbar above.Ruby is a dynamic, open source programming language with a focus on simplicity and productivity. It has an elegant syntax that is natural to read and easy to write.
The following examples and tutorials are excerpts taken from the Ruby in twenty minutes.
In [1]:
"Hello World"
Out[1]:
In [2]:
puts "Hello World"
puts is the basic command to print something out in Ruby. puts always returns nil, which is Ruby’s absolutely-positively-nothing value.
In [3]:
3+2
Out[3]:
Next, let’s try three squared:
In [4]:
3**2
Out[4]:
In Ruby ** is the way you say “to the power of”. But what if you want to go the other way and find the square root of something?
In [5]:
Math.sqrt(9)
Out[5]:
Ok, wait, what was that last one? If you guessed, “it was figuring out the square root of nine,” you’re right. But let’s take a closer look at things. First of all, what’s Math?
Math is a built-in module for mathematics. Modules serve two roles in Ruby. This shows one role: grouping similar methods together under a familiar name. Math also contains methods like sin() and tan().
Next is a dot. What does the dot do? The dot is how you identify the receiver of a message. What’s the message? In this case it’s sqrt(9), which means call the method sqrt, shorthand for “square root” with the parameter of 9.
The result of this method call is the value 3.0. You might notice it’s not just 3. That’s because most of the time the square root of a number won’t be an integer, so the method always returns a floating-point number.
What if we want to remember the result of some of this math? Assign the result to a variable.
In [6]:
a = 3 ** 2
Out[6]:
In [7]:
b = 4 ** 2
Out[7]:
In [8]:
Math.sqrt(a+b)
Out[8]:
As great as this is for a calculator, we’re getting away from the traditional Hello World message that beginning tutorials are supposed to focus on... so let’s go back to that.
What if we want to say “Hello” a lot without getting our fingers all tired? We need to define a method!
In [9]:
def hi
puts "Hello World!"
end
Out[9]:
The code def hi starts the definition of the method. It tells Ruby that we’re defining a method, that its name is hi. The next line is the body of the method, the same line we saw earlier: puts "Hello World". Finally, the last line end tells Ruby we’re done defining the method. Ruby’s response => :hi tells us that it knows we’re done defining the method. This response could be => nil for Ruby 2.0 and earlier versions. But, it’s not important here, so let’s go on.
In [10]:
hi
In [11]:
hi()
Well, that was easy. Calling a method in Ruby is as easy as just mentioning its name to Ruby. If the method doesn’t take parameters that’s all you need. You can add empty parentheses if you’d like, but they’re not needed.
What if we want to say hello to one person, and not the whole world? Just redefine hi to take a name as a parameter.
In [12]:
def hi(name)
puts "Hello #{name}!"
end
Out[12]:
In [13]:
hi("Matz")
So it works… but let’s take a second to see what’s going on here.
What’s the #{name} bit? That’s Ruby’s way of inserting something into a string. The bit between the braces is turned into a string (if it isn’t one already) and then substituted into the outer string at that point. You can also use this to make sure that someone’s name is properly capitalized:
In [14]:
def hi(name = "World")
puts "Hello #{name.capitalize}!"
end
Out[14]:
In [15]:
hi "chris"
In [16]:
hi
A couple of other tricks to spot here. One is that we’re calling the method without parentheses again. If it’s obvious what you’re doing, the parentheses are optional. The other trick is the default parameter World. What this is saying is “If the name isn’t supplied, use the default name of "World"”.
In [17]:
class Greeter
def initialize(name = "World")
@name = name
end
def say_hi
puts "Hi #{@name}!"
end
def say_bye
puts "Bye #{@name}, come back soon."
end
end
Out[17]:
The new keyword here is class. This defines a new class called Greeter and a bunch of methods for that class. Also notice @name. This is an instance variable, and is available to all the methods of the class. As you can see it’s used by say_hi and say_bye.
So how do we get this Greeter class set in motion? Create an object.
Now let’s create a greeter object and use it:
In [18]:
greeter = Greeter.new("Pat")
Out[18]:
In [19]:
greeter.say_hi
In [20]:
greeter.say_bye
Once the greeter object is created, it remembers that the name is Pat. Hmm, what if we want to get at the name directly?
In [21]:
greeter.@name
Nope, can’t do it.
Instance variables are hidden away inside the object. They’re not terribly hidden, you see them whenever you inspect the object, and there are other ways of accessing them, but Ruby uses the good object-oriented approach of keeping data sort-of hidden away.
So what methods do exist for Greeter objects?
In [22]:
Greeter.instance_methods
Out[22]:
Whoa. That’s a lot of methods. We only defined two methods. What’s going on here? Well this is all of the methods for Greeter objects, a complete list, including ones defined by ancestor classes. If we want to just list methods defined for Greeter we can tell it to not include ancestors by passing it the parameter false, meaning we don’t want methods defined by ancestors.
In [23]:
Greeter.instance_methods(false)
Out[23]:
Ah, that’s more like it. So let’s see which methods our greeter object responds to:
In [24]:
greeter.respond_to?("name")
Out[24]:
In [25]:
greeter.respond_to?("say_hi")
Out[25]:
In [26]:
greeter.respond_to?("to_s")
Out[26]:
So, it knows say_hi, and to_s (meaning convert something to a string, a method that’s defined by default for every object), but it doesn’t know name.
In [27]:
class Greeter
attr_accessor :name
end
In Ruby, you can open a class up again and modify it. The changes will be present in any new objects you create and even available in existing objects of that class. So, let’s create a new object and play with its @name property.
In [28]:
greeter = Greeter.new("Andy")
Out[28]:
In [29]:
greeter.respond_to?("name")
Out[29]:
In [30]:
greeter.respond_to?("name=")
Out[30]:
In [31]:
greeter.say_hi
In [32]:
greeter.name="Betty"
Out[32]:
In [33]:
greeter
Out[33]:
In [34]:
greeter.name
Out[34]:
In [35]:
greeter.say_hi
Using attr_accessor defined two new methods for us, name to get the value, and name= to set it.
In [36]:
class MegaGreeter
attr_accessor :names
# Create the object
def initialize(names = "World")
@names = names
end
# Say hi to everybody
def say_hi
if @names.nil?
puts "..."
elsif @names.respond_to?("each")
# @names is a list of some kind, iterate!
@names.each do |name|
puts "Hello #{name}!"
end
else
puts "Hello #{@names}!"
end
end
# Say bye to everybody
def say_bye
if @names.nil?
puts "..."
elsif @names.respond_to?("join")
# Join the list elements with commas
puts "Goodbye #{@names.join(", ")}. Come back soon!"
else
puts "Goodbye #{@names}. Come back soon!"
end
end
end
Out[36]:
In [37]:
mg = MegaGreeter.new
mg.say_hi
mg.say_bye
In [38]:
# Change name to be "Zeke"
mg.names = "Zeke"
mg.say_hi
mg.say_bye
In [39]:
# Change the name to an array of names
mg.names = ["Albert", "Brenda", "Charles", "Dave", "Engelbert"]
mg.say_hi
mg.say_bye
In [40]:
# Change to nil
mg.names = nil
mg.say_hi
mg.say_bye
There are a lot of new things thrown into this final example that we can take a deeper look at.
So, looking deeper at our new program, notice the initial lines, which begin with a hash mark (#). In Ruby, anything on a line after a hash mark is a comment and is ignored by the interpreter. The first line of the file is a special case, and under a Unix-like operating system tells the shell how to run the file. The rest of the comments are there just for clarity.
Our say_hi method has become a bit trickier:
In [41]:
# Say hi to everybody
def say_hi
if @names.nil?
puts "..."
elsif @names.respond_to?("each")
# @names is a list of some kind, iterate!
@names.each do |name|
puts "Hello #{name}!"
end
else
puts "Hello #{@names}!"
end
end
Out[41]:
It now looks at the @names instance variable to make decisions. If it’s nil, it just prints out three dots. No point greeting nobody, right?
If the @names object responds to each, it is something that you can iterate over, so iterate over it and greet each person in turn. Finally, if @names is anything else, just let it get turned into a string automatically and do the default greeting.
Let’s look at that iterator in more depth:
In [42]:
@names = ["Albert", "Brenda", "Charles", "Dave", "Engelbert"]
@names.each do |name|
puts "Hello #{name}!"
end
Out[42]:
each is a method that accepts a block of code then runs that block of code for every element in a list, and the bit between do and end is just such a block. A block is like an anonymous function or lambda. The variable between pipe characters is the parameter for this block.
What happens here is that for every entry in a list, name is bound to that list element, and then the expression puts "Hello #{name}!" is run with that name.
Most other programming languages handle going over a list using the for loop, which in C looks something like:
for (i=0; i<number_of_elements; i++)
{
do_something_with(element[i]);
}
This works, but isn’t very elegant. You need a throw-away variable like i, have to figure out how long the list is, and have to explain how to walk over the list. The Ruby way is much more elegant, all the housekeeping details are hidden within the each method, all you need to do is to tell it what to do with each element. Internally, the each method will essentially call yield "Albert", then yield "Brenda" and then yield "Charles", and so on.
The real power of blocks is when dealing with things that are more complicated than lists. Beyond handling simple housekeeping details within the method, you can also handle setup, teardown, and errors—all hidden away from the cares of the user.
In [43]:
# Say bye to everybody
def say_bye
if @names.nil?
puts "..."
elsif @names.respond_to?("join")
# Join the list elements with commas
puts "Goodbye #{@names.join(", ")}. Come back soon!"
else
puts "Goodbye #{@names}. Come back soon!"
end
end
Out[43]:
The say_bye method doesn’t use each, instead it checks to see if @names responds to the join method, and if so, uses it. Otherwise, it just prints out the variable as a string.
This method of not caring about the actual type of a variable, just relying on what methods it supports is known as “Duck Typing”, as in “if it walks like a duck and quacks like a duck…”.
The benefit of this is that it doesn’t unnecessarily restrict the types of variables that are supported. If someone comes up with a new kind of list class, as long as it implements the join method with the same semantics as other lists, everything will work as planned.
So that’s it for the quick tour of Ruby. There’s a lot more to explore, the different control structures that Ruby offers; the use of blocks and yield; modules as mixins; and more. I hope this taste of Ruby has left you wanting to learn more.
If so, please head on over to our Documentation area, which rounds up links to manuals and tutorials, all freely available online.
Or, if you’d really like to dig into a book, check the book list (off-site link) for titles available for sale online or at your local bookseller.