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

Recommended reading

Online courses

Puzzles

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:

Exercise 1.2

What do you think happens when you combine the following floats and integers?

Try computing these in irb:

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"

Show solution

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".

Show solution

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.

Show solution

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.

Show solution

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

Show solution

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

Show solution

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

Show solution

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”.

Show solution

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.

Show solution

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.

Show solution

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.

Show solution

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”.

Show solution

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.

Show solution

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 }

Show solution

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!.

Show solution

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.

Show solution

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

Show solution

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.

Show solution

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"]

Show solution

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.

Show solution

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.

Show solution

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"]

Show solution

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

Show solution

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

Show solution

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”.

Show solution

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]

Show solution

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:

* ** ***
** ** **
*** ** *

Show solution

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.

Show solution

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

Show solution

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

Show solution

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  |

Show solution

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 asnot 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

Show solution

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:

  1. 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).
  2. Add the value’s representation to the beginning to the row. If you don’t know how, google for “ruby array add to beginning”
  3. Make sure each of the cells is 9 characters wide.
  4. Join each of the row with the string " | ".
  5. Add the table headers row.
  6. Join all rows with the string "\n" (newline), and output the result.

Show solution

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

Show solution

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.

Show solution

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

Show solution

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.

Show solution

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”.

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.

Show solution

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:

image

Show solution

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:

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

Show solution