Programming Fundamentals - Part 1 - The Basics
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.
In this course, we'll be using Ruby (and a framework built on top of it, Ruby-on-Rails) for the majority of our programming exercises. But it actually doesn't much matter what language we use - especially here at the beginning. These foundational programming concepts are similar across languages.
Let's get started!
Go to this lesson's repository and open it in Gitpod.
Data Types - Numbers & Text
Ruby is known as an object-oriented language - at its core are objects. You can think about objects as data. There are many different types of objects, but let's look at the most basic (or primitive) types first: numbers and text.
In Gitpod, look inside the code-along
directory and open the file 1-data.rb
. Before typing anything into the file, notice that text in the file is not code. These are code comments - they serve no functional purpose, but rather are describing the code/file for our benefit as programmers. Every language has a way to add code comments. In ruby, we use the #
symbol at the beginning of the line to tell the computer that what follows is a code comment and can be ignored. You can add your own code comments whenever you want.
Numbers
Ok, now let's write some code - and when you do, notice the difference in color denoting actual code vs a comment. Type the following under the # Numbers
comment.
# Numbers
puts 2
puts 5
The puts
method will print out the data (the value on the right side of puts
) when the code is executed. So this code will print out the number 2
and then it will print out the number 5
.
To execute code in your ruby file, you can use the Terminal panel and type ruby
+ the file name: ruby 1-data.rb
. One caveat, you first need to navigate to the directory where that file lives. If you don't, you'll get an error message like this:
ruby: No such file or directory -- 1-data.rb (LoadError)
If you're in the right directory, you should see the following output:
2
5
🎉 Congratulations, you just ran your first ruby application!
Numbers on their own aren't very interesting - let's do something with those numbers. Under the next comment, let's do some math.
# Perform simple math with numbers
puts 2 + 5
puts 2 - 5
Run the file again - ruby 1-data.rb
- the output is what you'd expect:
2
5
7
-3
Note: eventually, we'll stop running individual files and instead will run groups of files as an entire application. But for now, this will be our cadence - write some code in a file, save the file, execute it to see what it does, repeat.
Here's how we do basic math in Ruby. We use an asterisk (*
) for multiplication, a slash (/
) for division, (**
) for exponentiation, and (%
) for modulus (remainder arithmetic).
puts 3 + 3
# 3 + 3 = 6
puts 3 * 3
# 3 * 3 = 9
puts 3 / 3
# 3 / 3 = 1
puts 3 ** 3
# 3 ** 3 = 27
puts 9 % 3
# 9 % 3 = 0
puts 10 % 3
# 10 % 3 = 1
puts 5 / 2
# 5 / 2 = 2
Whoa - that last expression was probably a surprise: 5
divided by 2
is definitely not supposed to equal 2
. What's going on?
We've been looking at numbers as a data type, but actually there are different types of numbers. These have all been Integers (whole numbers). And when performing division, if both numbers are integers, the result will also be an integer. If we want more precision, one of the numbers needs to be a Float (a number with a decimal point):
puts 5.0 / 2
# 5.0 / 2 = 2.5
Curious how order of operations works? For example: puts 2 + 5 * 5
. When you're not sure what some code might do, don't be afraid to just try it! It might work or it might not, but you'll learn by trying and you can always revert your changes.
Did you try it? The output should be 27
. Is that what you'd expect? Instead of evaluating the code left to right, the multiplication occurs first and then the addition. To force the addition to be first, you can use parentheses to establish an explicit order of operations:
puts (2 + 5) * 5
And now the output is 35
. Next, let's take a look at text in ruby.
Text
If we want to output Hello, world!, what code would you write? You might try puts Hello, world!
. In fact, if you haven't yet, type that code underneath the # Strings
comment and run the file. What happens?
You'll probably get an error: uninitialized constant Hello (NameError)
Before we fix the error, let's celebrate - you're first error! Of course we want our code to be error-free, but errors are great! They help guide us to writing better code. Don't be afraid of errors. Read them, try to understand them, determine exactly which line of code is causing them, and then fix them.
The error here is saying that the computer doesn't recognize the word Hello
. The computer needs to be able to distinguish between text that is ruby code (like puts
) and text that is purely data. The latter (text as data) is called a String
in most programming languages. And to identify it to the computer, we wrap it in quotes:
# Strings
puts "Hello, world!"
The quotes around "Hello, world!"
tell the computer that this is data, not some ruby method Hello
. You can actually use either single quotes ('
) or double quotes ("
), but we'll mostly use double quotes. And now when you run the file, you should see:
2
5
7
-3
Hello, world!
A few things to notice before we move on... First, although we used quotes to denote a string in our code, the output doesn't include the quotes. Second, no matter how many blank lines we put in between lines of code in the file, the output ignores them.
Like numbers, we can also do a bit more with strings. Let's combine separate strings together:
# Combine strings together
puts "ruby is " + "fun!"
The output is ruby is fun!
. Adding strings together is called string concatenation. Does your output look like ruby isfun!
? Don't forget the space inside the quotes. We'll stop pointing this out, but once again, every language has some form of concatenation, often using the plus (+
) sign.
We can get a little crazy with our string manipulation. Try this:
puts "tacos" * 3
What's the output? Is it surprising? Not every language can easily combine different data types, but ruby can...sometimes. As a language, ruby
is optimized for developer happiness. What does that mean? The language lets us write code that reads nicely or makes sense to us as humans.
It doesn't go too far though. If you try to add strings and numbers, you'll get an error:
puts "tacos: " + 3
Error:TypeError: no implicit conversion of Integer into String
This TypeError
simply means that we tried to add two pieces of data together of different types: one was text but the other was a number. The +
operator isn't smart enough to know what to do in this case. If you really want to combine these for some reason, one solution would be type conversion.
We can tell Ruby to convert the number 3 into a string, like this: 3.to_s
. This 3
is an Integer and, like other data types, integers have a collection of built-in methods that they can execute. To do so, we use dot notation like this: object.method
. The to_s
is an Integer method that converts the integer into a String. We can now combine the strings together: puts "tacos: " + 3.to_s
. We'll see another solution to this in a bit.
Variables
Variables are at the heart of any programming language. What is a variable? A variable is an arbitrary name used to hold some data in memory, which can then be referred to and recalled later as needed. Variables can be assigned a value (setting) and can read back their value (geting).
Under the # Variables
comment, let's assign a couple variables:
# Variables
x = 2
y = 5
Note the variable name goes on the left and the data or value is on the right. We are telling the computer to remember the number 2
as the variable x
. Now, to read the values of those variables:
puts x
puts y
And, you may have guessed, we can combine variables just as we would their underlying values:
puts x + y
puts x - y
These variable names might be ok in this situation, but generally we want to use descriptive variable names. Variable naming is important - it's an art. It's not unusual to catch groups of software developers debating over what name to use for a variable or method in their code. Let's assign a couple more variables and see why.
x = "tacos"
y = 3
puts x * y
First off, note that variables can be reassigned - the old value is forgotten and replaced with the new value. At a glance, the above names might seem fine. But, imagine a very big file with hundreds of lines of code... When you see the variable x
later in that code, will you remember that it refers to a string of food? Probably not. And even in these 3 lines of code, it's unnecessarily obfuscating the intention of the code. At a glance, you might think the intention is to be multiplying numbers, which isn't the goal at all. Let's use descriptive variable names:
food = "tacos"
quantity = 3
puts food * quantity
From the computer's perspective, this code is functionally identical. But to our human eye, the intention is much clearer. And hundreds of lines of code later, use of these variables will be even more helpful. Good variable names is a gift to our future selves and any collaborating developers.
A few rules about variables in ruby...
- They must begin with a letter, but then can include numbers.
- They should be all lowercased.
- They cannot include special characters except for underscore (
_
), which is used to separate words.
Now that we have variables, we look at another common way to combine strings. Often we have a string template, but want to replace one part with some dynamic data that will change. For example, instead of "Hello, world!"
, let's greet a user by their first name:
# Combine strings and variables
first_name = "Mando"
greeting = "Hello, #{first_name}!"
puts greeting
This is called string interpolation, where a variable gets dropped into the string replacing the #{}
section. This is another way to fix the TypeError
from earlier:
puts "tacos: #{3}"
The string interpolation automatically converts the number 3
into a string. But now that we have variables, let's use them instead:
puts "#{food}: #{quantity}"
We'll end this section with some other built-in ruby methods we can perform on strings. Here are some examples to try yourself:
puts "Hello " + "there!"
puts "Hello".length
puts "how are you today?".capitalize
puts "computer".reverse
creed = "This Is The Way"
puts creed.upcase
puts creed.downcase
puts creed.swapcase
And, if you're wondering what else is possible, here's ruby documentation with all of the built-in String methods: https://ruby-doc.org/core-3.0.3/String.html.
Be curious and just try things! If you get stuck and need to revert your code, you can use the code-along-complete/1-data.rb
file for reference.
Lab
Time for a lab to practice working with these foundational concepts. Instructions are in the file 1-data.rb
in the labs
directory.