Programming is the art of getting a computer to do useful things with information.
If you think about it that way, then you already know at least one programming language:
In the case of a calculator, the “information” is numbers and the “useful things” are adding, subtracting, multiplying, etc. Like any computer (or person), we get the calculator to do useful work by writing instructions that it can understand.
For example, if we press the keys 7 × 6 = (in that order), then the calculator will return
42 on the screen; but if we press the keys x 7 = 6, then it won’t.
6are known as data, or as I think of it, nouns.
=are known as methods, or as I think of it, verbs.
A basic calculator’s entire vocabulary consists of the following:
1 2 3 4 5 6 7 8 9 0 .
= + - × ÷ % ± AC
And there are only a few syntax rules:
It’s a very small language, but it demonstrates the same parts as any other programming language: data, methods, and syntax.
Got it? Good, because that’s basically all that there is to any other programming language, too! It’s just that its vocabulary will be bigger, and it will have a more grammar rules.
Let’s start learning your second programming language — Ruby! As we now know, that means we need to familiarize ourselves with Ruby’s data, methods, and the syntax for putting them together.
First of all, Ruby can work with many more kinds of data than just numbers. That’s what makes it much more powerful than the calculator language. Ruby has:
Each kind, or class, of data has its own set of methods that it can perform. For example:
Ruby is known as a “batteries included” language because it comes with so many methods out-of-the-box, saving the programmer the trouble of having to re-invent the wheel.
Finally, we can even make up our own nouns and verbs and add them to the language. For example, we can create a data type
Venue, give it a method that calculates the average rating from its reviews, and then use that method whenever we want.
One of the best things about Ruby is its wonderful open-source community: programmers very often share these new classes that they write with one another, making the language ever easier to use and ever more powerful.
So, in terms of data and methods, Ruby comes with a powerful set out-of-the-box and is always getting better. That’s good news! Here’s even more good news: to access all of this power, the primary syntax is straightforward. It looks like this:
Here’s a real example:
Here, you try it in the interactive Ruby sandbox below. In the black window that appears at the bottom, type:
This will launch interactive Ruby (IRB), a program that lets you evaluate one Ruby expression at a time.
irb(main) prompt that appears, you can now try out
If all went well, you should have seen
=> "HELLO WORLD!" in the black window at the bottom (known as the “terminal”). Yay1! What just happened?
The primary way to write an expression in Ruby is:
object.method. We ask the thing, or noun, on the left side of the dot to perform the action, or the verb, on the right side of the dot.
The computer then evaluates that expression and returns a new piece of data in its place (just like with the calculator).
In this case, we asked
"hello world!", which is a string (Ruby’s name for a piece of text2), to
upcase itself, which it (very) happily does, and we’re left with
"HELLO WORLD!" at the end of the day.
We’re using embedded, interactive read-evaluate-print-loops (REPLs) from a service called repl.it in these readings — really neat! Sometimes, it will be more convenient for you to open the REPL in its own tab, so that you can continue reading while still using it (instead of having it scroll off the page). Click the “Open in repl.it” button in the top-right corner to do so:
This might also be a good thing to try if REPLs get sluggish.
Different classes can perform different methods. Here are a few expressions to try out. Type each one into IRB.
7.odd? 7.even? "Mississippi".length "Raghu Betina".reverse "Your Name".swapcase
What do you expect will happen if we ask
"Mississippi" if it is
even?? Try it:
If you weren’t typing out every expression, then you’re doing this wrong. If you’re just reading, you won’t be successful at learning programming; you have to do in order to build up some muscle memory. Practice is crucial.
In fact, not only should you be typing the things I ask you to type, but you should also be trying out random other things that occur to you. (E.g., “What if I tried
Aha! If you were typing out every expression and running it, then
should have produced your very first error message! 🎉
Error messages can look scary, but one of the most important skills you have to develop when learning to program is to not panic when you see them. Slow down, read the error message, and see if you can make any sense of it at all. Over time, you will find that they are very helpful (and you will miss them if something goes wrong silently).
So, what do you think
undefined method `even?' for "Mississippi":String
In this case, it is saying: “Hey, friend — there’s no method called
"Mississippi", which is a
String. Sorry.” Fair enough, that makes sense.
The bottom line is — at all times as you are writing Ruby, you should be thinking: “What class is this object? What methods does this class have available?” Then, the syntax itself is simple —
Alright, so the primary syntax in Ruby is straightforward —
object.method. However, there’s a wrinkle: some methods require additional inputs. For example, there is a method called
gsub which we can call on
Strings, which will substitute characters with other characters. Try it:
"Java is a joy".gsub("Java", "Ruby")
gsub is short for “globally substitute”, because it will replace all occurrences of one substring with another substring.
In order to do its job, the
gsub method needs to know what substring to get rid of and what to replace it with. So we give it inputs, or arguments, which must come in parentheses immediately following the method. If the method takes multiple arguments, as
gsub does, then they are separated by commas.
"Java is a joy" with any string you like, and experiment with different arguments instead of
"Ruby". For example, maybe start with
"resume" and try to transform it into
gsub. What is the purpose of
gsub’s first argument, and what is the purpose of the second argument?
gsub is more often used to do things like removing illegal characters from usernames before saving, e.g.:
"" is an empty string, so all
@s will be replaced with nothing, i.e. removed.)
Unlike some other languages (e.g. Python) where indentation and spacing can change the entire meaning of a program, Ruby is, generally, very permissive about how you use whitespace. You can usually use spacing according to your own taste, and Ruby will be able to make sense of your code.
So, for example, whether you have spaces between arguments doesn’t matter; these two are equivalent:
"Raghu@Bet@ina".gsub("@", "") "Raghu@Bet@ina".gsub("@","")
(The most common style is to have one space after each comma.)
However, one situation in which whitespace does matter has to do with the parentheses around arguments:
"Raghu@Bet@ina".gsub("@", "") # good "Raghu@Bet@ina".gsub ("@", "") # bad!
Can you spot the difference? Don’t put a space between the method and the opening parenthesis.
It’s a very easy mistake to make, so I just wanted to warn you early on so you that can begin developing good muscle memory. Try the bad version in your sandbox and see what the error message looks like:
Programming boils down to:
Your skill level as a programmer is essentially the number of error messages that you have encountered in the past and now recognize. So start paying attention to them now — we want to collect ‘em all!
Here’s a debate that will rage until the end of time: what do you call this symbol?
Is it a number sign? Is it a pound sign? Is it a hashtag? Is it a waffle?
In this text, I’m going to refer to it as an octothorpe.
The octothorpe is used quite a bit in Ruby. You can see one important way in the example above, where I said
# bad! after some offending code. That is known as a “code comment”. The Ruby interpreter, when it sees the
#, will ignore it and everything that comes after it; allowing us to leave notes to ourselves and to each other. Use comments liberally.
Another nice trick is: when experimenting with some code and it’s not working, just comment it out and try a different approach on the next line. That way you can keep the old code around for reference without having to delete it, but it won’t break the program.
Now that you’ve seen arguments, you know all there is to know about crafting expressions in Ruby. No kidding:
object.method(arguments) is the vast majority of what we’ll be doing. That’s it.
However, so far we haven’t been doing much with the return value of each expression. We’ve just been reading it off the screen, and then dropping it on the ground. For example, try the following:
We’re not really able to make any forward progress when we only perform one operation at a time. Programs get interesting only when we start to take the return value of one expression and feed it into the next method. That’s how we craft our own novel, useful applications from the basic building blocks of Ruby.
So: let’s start to store our return values for future reference, instead of dropping them on the ground. We do this using variables, or as I like to think of them, boxes. Let’s get our feet wet:
Type the following:
s = "hello world!".upcase s
This creates a box, labels it
s, and stores the string
"HELLO WORLD!" in it.
The single equals sign,
=, is called the “variable assignment operator”.
When I read
s = "hello world!".upcase
out loud, I say “the string hello world dot upcase is assigned to the variable s”. I read the right side first, because that’s how Ruby reads it too; it first evaluates the expression on the right side of the
=, and then it stores the resulting value in the variable on the left.
Now add another line,
s = "hello world!".upcase s.reverse s
Great! Now we’re making progress.
What would you expect to happen if you add a third line so that your program reads:
s = "hello world!".upcase s.reverse s.gsub("L", "Z")
What do you think
s contains now? Try it:
Did it match your expectations?
Most Ruby methods don’t modify the object that they are called upon; they just return a modified copy. The original variable is untouched, so if we want to hold on to the new value then we better store that too. Type this:
s = "hello world!".upcase t = s.reverse u = t.gsub("L", "Z") u
Fortunately, we can create as many variables as we want.
It can get old coming up with different variable names for every step of the program. Instead, we usually want to re-use existing variables. We can throw away what we have in the box and put in something entirely different with the same assignment operator,
=. Type this:
s = "hi" s = 2.odd? s
We can even replace the value in the box with an updated version of the old value, because the expression on the right side of the assignment operator is evaluated before the assignment takes place. Type this:
s = "hello, world!" s = s.capitalize s = s.reverse s
That may look strange — how can we use
s on the left side and the right side of the
But it’s because this is not the equals sign from math class; this is the variable assignment operator, and the right side is evaluated first until only a single value is left; and then that object is assigned into the box on the left (replacing whatever was there before).
So you will very often see something like this:
counter = counter + 1
When we’re keeping track of e.g. how many times we’ve printed something out on the screen. We are taking the original value of
1 to it, and then replacing the contents of
counter with that new total.
You may have noticed that the variable assignment syntax is a departure from the primary syntax of
object.method. But we do it all day long, so we need to know it just as well. Our programs will end up looking like this (these are made-up method names, so this code won’t work):
storage_box_1 = "starting data".first_transformation storage_box_2 = storage_box_1.second_step storage_box_3 = storage_box_2.third_method.maybe_even("another", "one") # etc for dozens or hundreds of lines
First, the expression on the right side of the assignment operator will be evaluated until there are no methods left and there’s just a piece of data remaining.
Then, that value will be placed in the variable named on the left side of the assignment operator, which will be created if it doesn’t exist, or will have its value replaced if it does exist.
Most programs are just a long succession of statements where we do some work with
object.method and store the result in some variable, then we do some more work on that variable and store the result in yet another variable, and a hundred steps later we’ve produced our final result and we display that to our user.
When you are choosing your variable names, there are some rules:
a..z), numbers (
0..9), and underscores (
_) — they can’t contain spaces.
Please avoid naming your variables
z. Use underscores to separate words in multi-word variable names, since we can’t use spaces.
That’s it for the fundamental grammar of Ruby!
storage_box = noun.verb(input1, input2)
It’s not that much worse than the calculator language, is it? Of course, there’s a bit more syntax (like how to define our own nouns and verbs) that we need to learn, but for the most part,
object.method is the bulk of what we do.
Now we need to spend some time expanding our vocabulary — what are the most commonly used data types in Ruby, and what are some of their methods? That’s coming up next.
The name “string” is used in pretty much every programming language for the datatype that holds a piece of text, and refers to a string of characters; a holdover from back when we used to have to worry about conserving the computer’s physical storage space and had a separate datatype for an individual character. Now we usually don’t have to worry about storage space anymore, but the name “string” stuck with us. ↩