Ruby For Beginners
Welcome to the sei-GA ruby for begginers.
Click on the left to begin the exercises!
Below is about this original set of content:
From: Ruby Monday Study Group curriculum for beginners
This book has been written after we have run 4 beginners groups at our Ruby Monstas groups in Berlin, and it outlines the current state of our beginner groups curriculum.
After completing this curriculum you’ll be able to read, understand, and write basic Ruby code yourself:
You can use this knowledge to create small tools that might help you in your day-to-day work (such as converting numbers, or extracting data from files) that normally would cost a lot of manual work. You’ll be able to jump into other tutorials, and have a much easier time understanding what they’re talking about. And you can start working on our next curriculum which will walk you through the basics of building an actual web application.
If you’d like to print this book, or export it as a PDF try using this page, which is a single-page version of the entire book.
You can find the source code of this book here.
Preface
Read this book at your own pace, and do exercises at your own pace.
We recommend reading at least a page a day (ideally more), and taking some more time, at least once a week, in addition to the weekly meeting on Mondays. It often helps to meet with others, have some coffee and cake, and hang out while reading some more of this book, or doing a few exercises together.
We suggest that you read the book from beginning to end, and do exercises as you go. If you come across chapters that you feel are too theoretical you can skip them for the time being and come back to them later, if needed.
If you’d prefer to jump right in, you can also skip over the introductory
chapters. Jump to the chapter “Your tools”, and read the introductory
chapters later. If you already feel familiar with your editor and terminal, and
know how to use ruby
to execute a Ruby file, then you can skip over the
chapter “Your tools”, too.
Take notes about whatever questions come up during the week, things that you don’t understand, and everything else worth mentioning (for example, epiphanies you have, or things you found interesting). Bring your notes to the study group so we can talk about them in the group.
Please help us improve this book for others: Whenever you find something unclear or missing then please tell us. You can do this during the study group, email the mailing list, or ideally file an issue here. (This also helps you get familiar with GitHub, which we will use a lot later on.)
By using the name “Ada” in examples in this book we give credit to Ada Lovelace, the world’s first computer programmer :)
Resources
We also recommend looking at, reading, and working through other resources, as much as you can. Every beginners book expresses things a little bit differently, in a different order, and from a different angle.
Overview
- Codecademy Ruby Glossary
- Rails Beginner Cheat Sheet by Tobias Pfeiffer
- Ruby Docs Cheat Sheet
- Ruby API documentation
Recommended reading
- Ruby in 100 minutes by JumpstartLab
- A Beginner’s Guide To Ruby by Marc Gayle
- Learn to Program by Chris Pine
- Ruby for Webdesigners by Patrick J. Sparrow
- The Poignant Guide by Why
- Mr. Neighborly’s Humble Little Ruby Book by Jeremy McAnally
- Beginning Ruby by Peter Cooper
- Programming Ruby, “The pickaxe” by Dave Thomas
- Eloquent Ruby by Russ Olsen
Online courses
Puzzles
- Ruby Warrior by Ryan Bates and Bloc.io
Role model stories
Resources for coaches
Exercises
Learn Ruby Exercises!!
Working with Numbers
In order to start irb
open your terminal and type irb
, then hit the
return
key (enter
). In order to quit irb
again (and get back to your
system shell prompt) you can type exit
or press ctrl-d
, which does the
same.
Exercise 1.1
In irb
, calculate:
- How many hours are in a year.
- How many minutes are in a decade?
- How many seconds old are you?
Exercise 1.2
What do you think happens when you combine the following floats and integers?
Try computing these in irb
:
3.0 / 2
3 / 2.0
4 ** 2.0
4.1 % 2
Is the result a float or an integer?
Exercise 1.3
Methods are a way of “doing something with an object”. E.g. in Ruby, numbers have two methods that allow you to check whether the number is odd or even.
Look through the documentation for integer
numbers (called Fixnum
) and find the methods that tell if a number is odd or
even.
Exercise 1.4
In irb
, use these methods to find out if certain numbers are odd or even.
Numbers like 0, 1, 2, 99, -502
etc.
You can use a method by appending a dot .
and then the method name
to the object. E.g. -99.abs
uses (we also say: “calls”) the method
abs
on the number -99
.
Try for yourself what it does, and google for “ruby abs” to find the documentation for this method.
Working with Strings
In order to start irb
open your terminal and type irb
, then hit the
return
key (enter
). In order to quit irb
again (and get back to your
system shell prompt) you can type exit
or press ctrl-d
, which does the
same.
Exercise 2.1
What do you think this will do?
$ irb
> "hello".length + "world".length
Try it yourself.
Exercise 2.3
Skim through the documentation for strings in the Ruby documentation, and look for a method that prepends one string to another string.
Using that method prepend the string "Learning "
to the string "Ruby"
Exercise 2.4
Skim through the documentation for strings in the Ruby documentation, and look for a method that removes characters from a string.
Using that method turn the string "Learning Ruby"
into the string "Lrnng Rb"
.
Exercise 2.5
Find out how to convert the string "1.23"
into the number 1.23
.
You can either, again, skim the documentation page for strings, or google for “ruby convert string to number”.
Then also find out what method can be used to turn the string "1"
into the
number 1
(remember floats and integers are different kinds of numbers).
Confirm that you have found the right methods by trying them in irb
.
Exercise 2.6
There is a method that allows to justify a string, and padding it with another string.
Find that method and use it on the string "Ruby"
together with "<3"
so that
you get the following string back:
"Ruby<3<3<3"
We’ll admit that this is a rather creative usage of this method. Normally you’d use it to align strings to columns (e.g. so that they line up nicely when you format a table). You’ll use this method in other exercises later on.
Working with Arrays (1)
Before you get started, make sure you have your text editor and terminal open,
and you have navigated to your exercises directory in the terminal. E.g. cd
~/ruby-for-beginners/exercises
.
Exercise 3.1
Create a new, empty file. Save it as arrays_1-1.rb
. Fill in the following
line:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# your code goes here
So that, when you run your code (run ruby arrays_1-1.rb
), you get the
following output:
5
Exercise 3.2
Copy your file to a new file: cp arrays_1-1.rb arrays_1-2.rb
, then open this
new file.
Add another line before the line that you just added, so that, when you run your code, you get the following output:
99
Exercise 3.3
Make a new file arrays_1-3.rb
, and fill in the following line:
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# your code goes here
p numbers
So that you get the following output:
[2, 4, 6, 8, 10]
Read the documentation for the method select
that you can use on arrays
on the Ruby documentation
Exercise 3.4
Again, copy your last file to a new file: cp arrays_1-3.rb arrays_1-4.rb
,
then open this new file.
Now change the code that you just added so that you get the following output:
[10, 8, 6, 4, 2]
The method select
that you used in the last exercise returns an array.
On this array (the return value) you can use another method, by, again, just
appending a dot .
and the method name to it, i.e., to the end of the line.
There is another method that reverses the order of the array. You can find it by googling for “ruby array reverse”.
Exercise 3.5
Again, copy your last file to a new file: cp arrays_1-4.rb arrays_1-5.rb
,
then open this new file.
Now change your code so that you get the following output:
[10, 8, 4, 2]
Bonus: Find at least three different solutions for this last change.
Working with Hashes (1)
Before you get started, make sure you have your text editor and terminal open,
and you have navigated to your exercises directory in the terminal. E.g. cd
~/ruby-for-beginners/exercises
.
Exercise 4.1
Make a new file hashes_1-1.rb
, and fill in the following line:
dictionary = { :one => 'uno', :two => 'dos', :three => 'tres' }
# your code goes here
So that it prints out dos
.
Exercise 4.2
Make a new file hashes_1-2.rb
, and fill in the following line:
dictionary = { :one => 'uno', :two => 'dos', :three => 'tres' }
# your code goes here
puts dictionary[:four]
So that it prints out cuatro
.
Exercise 4.3
Copy that file to a new file cp hashes_1-2.rb hashes_1-3.rb
, and change your
code so that it prints out the following.
Cuatro
There’s a method that upcases the first letter of a string. Find it by googling for “ruby string upcase first letter”.
Exercise 4.4
There is a method on hashes that allows to check if a certain key is defined on the hash. Find that method by googling for “ruby hash key defined”.
Try this method in irb
by creating a hash like the one above, calling the
method and passing keys like :one
, :two
, :four
, and :ten
.
Exercise 4.5
There is a method on hashes that flips keys and values. Find that method on the Ruby documentation about hashes
Make a new file hashes_1-5.rb
, and fill in the following line using that
method:
dictionary = { :one => 'uno', :two => 'dos', :three => 'tres' }
# your code goes here
This should then output:
{ 'uno' => :one, 'dos' => :two, 'tres' => :three }
Defining methods
Exercise 5.1
Write a method greet
that takes a name, prepends "Hello "
, and appends an
exclamation mark "!"
:
def greet(name)
# your code goes here
end
puts greet("Ada")
This should print out Hello Ada!
.
Exercise 5.2
Once you’ve implemented the method this should print out: Hello Ada!
.
Now change your method so that instead of always using "Hello "
it picks a
random string from the array ["Hello", "Hi", "Ohai", "ZOMG"]
.
Every time you run the program it should print out either "Hello Ada!"
, "Hi
Ada!"
, "Ohai Ada!"
, or "ZOMG Ada!"
.
The method shuffle
on arrays does, well, shuffle the array :) That
means it changes the order of the elements in the array in a random way.
Exercise 5.3
Write a method that converts a distance (a number) from miles to kilometers:
def miles_to_kilometers(miles)
# your code goes here
end
puts miles_to_kilometers(25)
This should print out:
40.2336
Exercise 5.4
Write a method leap_year?
that takes a year (a number), and calculates if it is a leap year.
def leap_year?(year)
# your code goes here
end
p leap_year?(2012)
p leap_year?(2015)
This should print out:
true
false
Hint: The operator %
returns the rest of a division. E.g. 14 % 3
returns 2
.
Bonus: Also make it so that the method returns true
for the year 2000
and
false
for 1900
… because that’s really the definition of leap years.
Working with Arrays (2)
Note: At the moment these exercises require reading up until “Block return values”.
You should know how to use the method collect
on arrays.
Before you get started, make sure you have your text editor and terminal open, and
you have navigated to your exercises directory in the terminal. E.g. cd
~/ruby-for-beginners/exercises
.
Exercise 6.1
Create a new, empty file. Save it as arrays_2-1.rb
. Fill in the following line:
words = ["one", "two", "three", "four", "five"]
# your code goes here
p words
So that you get the following output:
["one", "three", "five"]
Exercise 6.2
Copy your file to a new file: cp arrays_2-1.rb arrays_2-2.rb
, then open this
new file.
Now change your code so that you get the following output:
["One", "Three", "Five"]
Google for ruby string uppercase first letter
.
Exercise 6.3
Copy your file to a new file: cp arrays_2-2.rb arrays_2-3.rb
, then open this
new file.
Now change your code so that you get the following output:
["One <3", "Three <3", "Five <3"]
Use string interpolation for this.
Exercise 6.4
Copy your file to a new file: cp arrays_2-3.rb arrays_2-4.rb
, then open this
new file.
Now change your code so that you get the following output:
["One <3", "Three <3<3<3", "Five <3<3<3<3<3"]
Exercise 6.5
Copy your file to a new file: cp arrays_2-4.rb arrays_2-5.rb
, then open this
new file.
Now change your code so that you get the following output (hint: again, that’s now a string, not an array):
One <3, Three <3<3<3, Five <3<3<3<3<3
Exercise 6.6
Copy your file to a new file: cp arrays_2-5.rb arrays_2-6.rb
, then open this
new file.
Now change your code so that you get the following output, using the newline
character "\n"
:
One <3
Three <3<3<3
Five <3<3<3<3<3
Exercise 6.7
Copy your file to a new file: cp arrays_2-6.rb arrays_2-7.rb
, then open this
new file.
Now change your code so that you get the following output, aligning the second column:
One <3
Three <3<3<3
Five <3<3<3<3<3
As you may guess, strings have a method that is helpful for this. Ask Google: “ruby string align”.
Working with Nested Arrays
Note: At the moment these exercises require reading up until “Block return values”.
You should know how to use the method collect
on arrays.
Before you get started, make sure you have your text editor and terminal open, and
you have navigated to your exercises directory in the terminal. E.g. cd
~/ruby-for-beginners/exercises
.
Exercise 7.1
Make a new file nested_arrays-1.rb
, and fill in the following line:
numbers = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]
]
# your code goes here
p sums
So that you get the following output:
[6, 15, 24]
Exercise 7.2
Make a new file nested_arrays-2.rb
, and fill in the following line:
Fill in the following line
numbers = [
[1, 2, 3],
[2, 2, 2],
[3, 2, 1]
]
# your code goes here
lines.each { |line| puts line }
So that you get the following output:
* ** ***
** ** **
*** ** *
Working with Hashes (2)
Exercise 8.1
Make a new file hashes_2-1.rb
, and dd the following lines:
languages = {
:de => 'German',
:en => 'English',
:es => 'Spanish',
}
dictionary = {
:de => { :one => 'eins', :two => 'zwei', :three => 'drei' },
:en => { :one => 'one', :two => 'two', :three => 'three' },
:es => { :one => 'uno', :two => 'dos', :three => 'tres' }
}
Now, at the end of the file, add code that prints out the following:
In German, eins means one, zwei means two, drei means three.
In Spanish, uno means one, duo means two, tres means three.
Exercise 8.2
Now, in a new file hashes_2-2.rb
, with the same hashes from above, add code
that prints out the following table:
de eins zwei drei
en one two three
es uno dos tres
Exercise 8.3
Copy your file to a new file cp hashes_2-2.rb hashes_2-3.rb
and change your
code so that it aligns the table columns:
de eins zwei drei
en one two three
es uno dos tres
Exercise 8.4
Copy your file to a new file cp hashes_2-3.rb hashes_2-4.rb
and change your
code so that it adds delimiters:
| de | eins | zwei | drei |
| en | one | two | three |
| es | uno | dos | tres |
Truthiness
Exercise 9.1
Make a new file truthiness-1.rb
, and add the following lines:
This exercise is about validating what we’ve learned about truthiness.
You have the following array:
objects = [true, false, 0, 1, "", [], Object.new, Class.new, Module.new]
Add some code that outputs the following table. The last column should be
filled in with by either true
or false
depending what the operation
!!object
, which is the same as
not not object` for each of the objects
returns:
object | !!object
true | [true|false]
false | [true|false]
nil | [true|false]
0 | [true|false]
1 | [true|false]
"" | [true|false]
[] | [true|false]
#<Object:0x007fb3dc0ea1b8> | [true|false]
#<Class:0x007fb3dc0e2cd8> | [true|false]
#<Module:0x007fb3dc0d9ea8> | [true|false]
You can use the method inspect
in order to, for each of the values, get a
representation that looks like the code.
Of course you will get different object ids for the object, class, and module instances everytime you run your code.
So let’s prettify this table by removing the object ids. You can do this
calling sub(/:.*>/, ">")
on whatever inspect
returns.
Your table should now look like this:
object | !!object
true | true
false | false
nil | false
0 | true
1 | true
"" | true
[] | true
#<Object> | true
#<Class> | true
#<Module> | true
Bonus: Exercise 9.2
Copy your file to a new file truthiness-2.rb
, and change your code so that
it outputs the following table. Fill each cell with the result that ==
returns for each combination.
| true | false | 0 | 1 | "" | [] | #<Object> | #<Class> | #<Module>
true | | | | | | | | |
false | | | | | | | | |
0 | | | | | | | | |
1 | | | | | | | | |
"" | | | | | | | | |
[] | | | | | | | | |
#<Object> | | | | | | | | |
#<Class> | | | | | | | | |
#<Module> | | | | | | | | |
Tip: Break this up in sub-tasks:
- Write some code that collects an array of arrays containing all rows: An
array
rows
that has many arrays, each of which holds 9 results (cells). - Add the value’s representation to the beginning to the row. If you don’t know how, google for “ruby array add to beginning”
- Make sure each of the cells is 9 characters wide.
- Join each of the row with the string
" | "
. - Add the table headers row.
- Join all rows with the string
"\n"
(newline), and output the result.
The Email Class
Exercise 10.1
In a new file email_1.rb
write a class Email
that has a subject
,
date
, and from
attribute. Make it so that these attributes can be populated
through new
and initialize
.
The following code
class Email
# fill in this class body
end
email = Email.new("Homework this week", "2014-12-01", "Ferdous")
puts "Date: #{email.date}"
puts "From: #{email.from}"
puts "Subject: #{email.subject}"
should then output the following:
Date: 2014-12-01
From: Ferdous
Subject: Homework this week
Exercise 10.2
Once you have this class, copy your file to email_2.rb
.
Change your class so that the initialize
method now takes a subject
string,
and a headers
hash. This is then more in line with how actual emails are
stored in the real world: the values date
and from
are stored on a hash,
which is called the “email headers”.
Doing so, in the code above the only line you should change is the one that instantiates the email object, which should now read:
email = Email.new("Keep on coding! :)", { :date => "2014-12-01", :from => "Ferdous" })
Your program should now still produce the same output.
The Mailbox Class
Exercise 11.1
In a new file mailbox-1.rb
Write a class that has a name
and emails
attribute. Make it so that the these attributes can be populated through the
initialize
method (name
being a string, and emails
being an array of
Email
instances).
The following code
class Email
# your class from the last exercise
end
class Mailbox
# fill in this class body
end
emails = [
Email.new("Homework this week", { :date => "2014-12-01", :from => "Ferdous" }),
Email.new("Keep on coding! :)", { :date => "2014-12-01", :from => "Dajana" }),
Email.new("Re: Homework this week", { :date => "2014-12-02", :from => "Ariane" })
]
mailbox = Mailbox.new("Ruby Study Group", emails)
mailbox.emails.each do |email|
puts "Date: #{email.date}"
puts "From: #{email.from}"
puts "Subject: #{email.subject}"
puts
end
should then output the following:
Date: 2014-12-01
From: Ferdous
Subject: Homework this week
Date: 2014-12-01
From: Dajana
Subject: Keep on coding! :)
Date: 2014-12-02
From: Arianne
Subject: Re: Homework this week
The Mailbox Text Formatter
The mailbox text formatter exercise is a milestone in the beginners group curriculum, and it may take a little bit longer to complete it. That is fine, and, to some extent, the point :)
Exercise 12.1
Make a new file mailbox_text-1.rb
. Fill in and complete the following
class definitions:
class Email
# your class from the last exercise
end
class Mailbox
# your class from the last exercise
end
class MailboxTextFormatter
# fill in this class body
end
emails = [
Email.new("Homework this week", { :date => "2014-12-01", :from => "Ferdous" }),
Email.new("Keep on coding! :)", { :date => "2014-12-01", :from => "Dajana" }),
Email.new("Re: Homework this week", { :date => "2014-12-02", :from => "Ariane" })
]
mailbox = Mailbox.new("Ruby Study Group", emails)
formatter = MailboxTextFormatter.new(mailbox)
puts formatter.format
Your goal is to complete the code in a way so it outputs the following:
Mailbox: Ruby Study Group
+------------+---------+------------------------+
| Date | From | Subject |
+------------+---------+------------------------+
| 2014-12-01 | Ferdous | Homework this week |
| 2014-12-01 | Dajana | Keep on coding! :) |
| 2014-12-02 | Ariane | Re: Homework this week |
+------------+---------+------------------------+
You are allowed to add as many methods to the classes Email
, Mailbox
and
MailboxTextFormatter
as you deem useful. In your final solution you are not
allowed to change any of the code outside (after) the class definitions. For
debugging purposes, you can, of course, change all the code you want :)
If you do this exercise in one of our study groups then best do it together with someone else. We found pairs to work best, and a three person team would be better than doing it on your own.
Try to come up with a working solution first. It doesn’t matter how elegant, generic, or pretty it is. Whatever produces the required output is fine for a first solution.
Then, later, look at your code, and try to improve it by cleaning up everything that you don’t like, or deam ugly.
Eventually, one goal to aim for would be: Adding another column to the table only requires mimimal changes, e.g. changes to one or two places in your formatter class.
The Mailbox Html Formatter
Separation of concerns
One question that may have come up while working on the mailbox text formatter exercise is:
Why would we have a separate class for formatting the ASCII table (that is, a
plain text table that uses characters like +
, -
, and |
)?
The reason is: We want each one of our classes to encapsulate one concept that is useful in our application. We also say: each one of our classes should be concerned with one responsibility.
An email vaguely resembles the concept of an analog letter, written on paper: some message is being sent from one person to another. Nowadays everyone knows what an email is: it stores all information about this particular message. The same is true for mailboxes, which are used to store a bunch of emails. Formatting a number of emails in order to be displayed on a text based terminal is a very different concept, and concern.
Therefore it makes a lot of sense to have three different classes implement each one of these concepts, or concerns. And it even makes so much sense that it is called a design principle in programming: The principle of separation of concerns.
Aside from being comprehensible and mapping to concepts that we already know, one other advantage is: We can now easily implement other formatter classes that format our emails in a different way, suitable to be displayed in other media.
And that’s what this exercise is about: We want to display our mailbox contents in HTML, the format that browsers like to use. If you are unfamiliar with what HTML is, and how it looks like, you can read up on it here. This will be our first step towards learning how to build a web application.
Model, View, Controller
Before we get to that, we’d like to point out one other aspect, that you’ll remember when we get to talk about the architecture that Rails use to structure and separate concerns, called “model, view, controller”.
- The two classes
Email
andMailbox
in your application are models: they are concerned with modelling those “real-world” things that your users are interested in: they want to work with emails. - The class
MailboxTextFormatter
on the other hand is a view: It is used in order to generate a certain representation, in a format that is suitable to a certain medium (the terminal, in our case). - You don’t have a controller class so far, but the little bit of code at the end of the file does what a controller usually would do: it generates some models (the emails, and the mailbox objects) and passes them to the view (the formatter) in order to be rendered into something that can then be returned and displayed.
If this doesn’t make a whole lot of sense to you at the moment, don’t worry. You’ll understand it more once we build our first Rails application.
Exercise 13.1
Ok, now to our exercise. We will start over with the same code again, except
that our formatter class now will be called MailboxHtmlFormatter
.
Copy your file mailbox_text-1.rb
to mailbox_html-1.rb
and change it
like so. Then fill in the MailboxHtmlFormatter
class.
class Email
# your class from the last exercise
end
class Mailbox
# your class from the last exercise
end
class MailboxHtmlFormatter
# fill in this class body
end
emails = [
Email.new("Homework this week", { :date => "2014-12-01", :from => "Ferdous" }),
Email.new("Keep on coding! :)", { :date => "2014-12-01", :from => "Dajana" }),
Email.new("Re: Homework this week", { :date => "2014-12-02", :from => "Ariane" })
]
mailbox = Mailbox.new("Ruby Study Group", emails)
formatter = MailboxHtmlFormatter.new(mailbox)
puts formatter.format
Your goal is to complete the code in a way so it outputs the following:
<html>
<head>
<style>
table {
border-collapse: collapse;
}
td, th {
border: 1px solid black;
padding: 1em;
}
</style>
</head>
<body>
<h1>Ruby Study Group</h1>
<table>
<thead>
<tr>
<th>Date</th>
<th>From</th>
<th>Subject</th>
</tr>
</thead>
<tbody>
<tr>
<td>2014-12-01</td>
<td>Ferdous</td>
<td>Homework this week</td>
</tr>
<tr>
<td>2014-12-01</td>
<td>Dajana</td>
<td>Keep on coding! :)</td>
</tr>
<tr>
<td>2014-12-02</td>
<td>Ariane</td>
<td>Re: Homework this week</td>
</tr>
</tbody>
</table>
</body>
</html>
Does that look scary? A little bit, maybe. It’s probably fair to say that manually writing HTML isn’t very popular amongst most programmers. Therefore there are quite a few tools that make our lives easier. And your task is to write such a tool.
Also, this exercise should actually be easier for you to complete than the previous one. You already have a bunch of practice in iterating over emails, and working with arrays and strings. And this time, you don’t need to deal with the maximum length of strings per column. You can just interpolate things together.
Storing our HTML to a File
Exercise 14.1
In this exercise our goal is to store the generated HTML for our mailbox to a file, so that we can finally view it in an actual browser.
Your objective is to write a file (using Ruby) that contains all the HTML from the last exercise.
Building on the last exercise, copy your file to a new file cp mailbox_html-1.rb
mailbox_file-1.rb
and change the last line:
Instead of passing the HTML to puts
you should be passing it to a different
method, so that running your program writes the HTML file that we are after.
In order to find that method try googling for “ruby write file”. Call this
file emails.html
.
When you open this file in a text editor you should see the same HTML from the last exercise. When you open it in your browser it should look like this:
Reading from a CSV File
So far our program has all the email data hardcoded: All the data is baked right into our code. Everytime you run it, it will display all the same emails. Obviously that’s not a very useful for a real world program.
Let’s change this to read our data from an external data source instead.
One very simple and pretty popular way to store data to files is using the format CSV. This stands for “comma separated values” (although, often times semicolons are used as a separator instead of commas), and it is something that spreadsheets can read and export. Being able to work with CSV can be pretty handy: just write a little Ruby script, and filter that data, or work with it otherwise.
The first line in the code below require "csv"
makes Ruby’s CSV library
available to your program so that you can then use the class CSV
.
Exercise 15.1
Building on the same code from the last exercises, your objective is to
read the email data from a file emails.csv
. This file should be stored
in the same directory as your Ruby program, and contain the following data:
Date,From,Subject
2014-12-01,Ferdous,Homework this week
2014-12-01,Dajana,Keep on coding! :)
2014-12-02,Ariane,Re: Homework this week
2014-12-11,Maria,I'm back in Berlin
You can create that file by copying the four lines from above to your editor.
In order to complete this exercise you’ll need to find out how to:
- Read the contents of a file to Ruby, as a string
- Parse this string as CSV (google for “ruby csv” and/or look at the documentation)
- For each of the rows, ignoring the header line, create an
Email
instance
In other words, you should replace the following lines of code:
emails = [
Email.new("Homework this week", { :from => "Ferdous", :date => "2014-12-01" }),
Email.new("Keep on coding! :)", { :from => "Dajana", :date => "2014-12-01" }),
Email.new("Re: Homework this week", { :from => "Ariane", :date => "2014-12-02" })
]
Once you have figured out how to read and parse the CSV file, and create an
array of Email
instances out of that data, your next task is to encapsulate
all of that into a class EmailsCsvStore
. This class should take a filename,
and have a method read
, which returns the emails array.
In the end that part of the code should read:
require "csv"
class Email
# your class from the last exercise
end
class Mailbox
# your class from the last exercise
end
class MailboxHtmlFormatter
# your class from the last exercise
end
class EmailsCsvStore
def initialize(filename)
# fill in this method
end
def read
# fill in this method
end
end
store = EmailsCsvStore.new('emails.csv')
emails = store.read
mailbox = Mailbox.new("Ruby Study Group", emails)
formatter = MailboxHtmlFormatter.new(mailbox)
# your code from the last exercise, writing the file