When we program, we generally have some data (or information) that's important to us; and we want to do something useful with it.
Let's consider a computer that you already know how to program:
When we're using (or programming) a calculator, our data are numbers and we want to tell the processor to add, subtract, multiply, and perform other calculations on them.
When we write an expression in the calculator language, we need to put together data and instructions in an order that makes sense; for example, if we press the keys 7 × 6 = in that sequence, we will see the intended output in the screen.
We refer to "an order that makes sense" as the language's syntax, or grammar. In the calculator language, × 7 = 6 would not be valid syntax.
A basic calculator's entire programming language vocabulary consists of the following:
1 2 3 4 5 6 7 8 9 0 .
= + - × ÷ % ± AC
and there are only a few syntax rules:
- Primary syntax: two numbers separated by operator followed by =
- numbers can contain a single decimal point
- numbers can be modified by the plus/minus sign
- numbers can be modified by the percentage sign
- can press AC to reset
It's a very small language, but it demonstrates the same parts as any other programming language: data, instructions, and syntax.
I think of them as nouns, verbs, and grammar. For each language we want to learn, we just have to learn what things we can work with, what we can do with those things, and how to put together valid expressions to tell the processor to do them.
Let's consider a slightly more complicated language that you already know: HTML.
- What kind of data do we work with in HTML?
- What kind of instructions do we give the processor (the browser) to handle our data?
- What syntax rules are there?
It seems to me that we have:
Arbitrary text content.
- Primary syntax:
<, element name,
</, element name,
- elements can be nested within other elements
- opening tags can contain attributes, which are separated from their values by a
=and the values are wrapped in
That's it! There are maybe even fewer syntax rules than the calculator language, so it didn't take us long to grasp the essence of it.
There are, however, more available instructions than in the calculator language (although surprisingly few). So we will have to still spend some time expanding our vocabulary before we master all of HTML.
CSS follows a similar pattern; the primary syntax is quite approachable:
We put our class name (preceded by a dot), followed by curly braces, followed by a list of property-value pairs that we want in our style rule.
CSS, though, does have a lot of available instructions. It also has a significant variety of available syntaxes to give you fine-grained control over which elements on the page are targeted.
So to master CSS, we would have to spend a lot of time both expanding our vocabulary and learning more advanced syntax rules.
Finally, let's think about how Ruby compares.
In terms of data, Ruby can work with:
- numbers like calculators
- text like HTML
- a lot more, including
Each class of data has its own set of instructions that it can perform:
- numbers can do the usual computations
- two dates can tell you how far apart they are from one another
- lists can tell how you long they are or sort themselves
Ruby is known as a "batteries included" language because it includes so many instructions 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 add a data type
Restaurant, teach it to calculate its average rating, and add that to its instruction set. Ruby programmers very often share these new classes with one another, making the language ever more powerful — Rails itself is largely just a collection of these new nouns and verbs related to web applications!
So, in terms of data and instructions, Ruby comes with a powerful set out-of-the-box and is infinitely extensible! That's good news. Here's even more good news: to access all of this power, the primary syntax is simple:
On the left side of the dot we have our data, or, formally, an object. A thing, or noun, as I think of it.
On the right side of the dot we have our instruction, or, formally, a method. An action, or verb, as I think of it.
In this case, we asked
"Hello", which is a
downcaseitself, which it happily does.
What if we try asking the number
9to downcase itself? Try it right now in
NoMethodError: undefined method 'downcase' for 9:Fixnum. It looks scary, but one of your main objectives during this course is to not panic when you see an error message. Slow down, read it carefully, 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 when something is going wrong silently.
In this case, it is saying: "Hey, dummy — you can't downcase 9, which is a number." Fair enough. (
Fixnummeans "integer", as opposed to
Floatwhich means "decimal number". Almost all programming languages use two distinct data types for those two things.)
At all times as you are writing Ruby, you should be thinking: What class of object do I have? What methods can I call on this kind of object?
Alright, so the primary syntax in Ruby is very simple —
object.method. However, here's one small wrinkle: some methods require additional inputs. For example, there is a method called
gsubwhich we can call on
Strings, which will substitute characters with other characters. Try it:
In order to do its job, the
gsubmethod needs to know what character to substitute and what to replace it with. So we give it inputs, or arguments, which must come in parentheses immediately following the method (no space after the method name). If the method takes multiple arguments, as
gsubdoes, then they are separated by commas.
gsubis more often used to do things like removing illegal characters from usernames before saving:
""is an empty string, so all
+s get replaced with nothing.)
Now that you've seen arguments, you know the full primary syntax of Ruby. No kidding:
object.method(argument1, argument2, ...)is the vast majority of what we'll be writing. That's it.
"But wait!," you say, "what about when I do math like
7 * 6? That is clearly not
object.method." A very good question. Try this instead:
Why does this work?
*is the name of a method on the
Fixnumclass, which takes an argument of another
Fixnum, and returns the product of the two. 😳💥😲
When Yukihiro Matsumoto designed the Ruby language, his goal was "developer happiness" (which was radical at that time, 1993, when most languages were geared for computer efficiency).
He knew that if he made developers type
7.*(6)every time they wanted to multiply two numbers, they would not be happy campers. So he included a few bits of "syntactic sugar", or shortcuts, that boil down to
object.methodunder the hood, but allow us to retain our sanity while typing. Phew.
One last thing: you can chain methods, like so:
Ruby evaluates the expression from left to right, replacing each
object.methodexpression with the
objectthat it returns and then evaluating the next
So you have to be careful and make sure that the
objectthat the first
object.methodreturns matches up with the second
method.What class of object do I have? What methods can I call on this kind of object?
Remember, you can use your up and down arrows to scroll through your command history. But Ruby has a more important way to save data: we can create a box in memory to hold it and give that box a name, like so:
s = "Hello" # Create a box, label it `s`, and store "Hello" in it
s # Retrieve the value in `s`
You could also throw away what you have in the box labeled
sand put in something new:
s = "hi"
s = 60 * 60
You could even replace the value in the box with an updated version of the old value, because the instructions on the right side of the equals sign are executed before the throwing away happens:
s = "hi"
s = s.capitalize
And you can create as many of these boxes as you want:
a = "hi"
b = "there"
c = "world"
So, in addition to
object.method, the syntax you need to know like the back of your hand is
storage_box = the_final_value.resulting_from_this(expression).will_be_stored
# This code won't actually work
First, the expression on the right will be evaluated until there are no instructions left and there's just a piece of data remaining.
Then, the value will be placed in a variable called
storage_box, which will be created if it doesn't exist, or will have its value replaced if it does.
Most programs are just a long succession of statements where we do some work with
object.methodand 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:
user_input = "D+h+H"
input_without_pluses = user_input.gsub("+", "")
downcased_input = input_without_pluses.downcase
"dhh" == downcased_input
# if true, choose another username!
When you are choosing your variable names, there are some rules:
- names can only contain lowercase letters, numbers, and underscores
- names cannot begin with a number
Rubyists strive to choose descriptive variable names, no matter how long they are, so that the code reads almost like English — avoid naming your variables
z. Use underscores to separate words in multiple word variable names.
That's it for the primary syntax of Ruby!
storage_box = object.method(argument1, argument2, ...)
Now, we need to spend some time expanding our vocabulary. Let's start with the most fundamental built-in classes that Ruby gives us.