Learn Ruby the Hard Way, Exercise 23: Read Some Code

Study Drills

  • Goto Bitbucket.org, github.com, or gitorious.orge and search for “Ruby” Pick a random project
  • Click on the source tab and browse through the list of files and directories until you find a .rb file

I went to Github and searched for ‘Ruby Project’ and found the below in a random rb file in a ruby project someone was making to teach how to a bank account program.

Here is the code:

ex23 code 2

  • Start at the top and read through the code, taking notes on what you think it does.

ex23 code.png

  • if any symbols or strange words seem to interest you, write them down to search later.

attr_reader, include, .inject, self.class,


There’s a few things I researched but don’t really know how to use properly yet like attr_reader….however I did look up and learn about classes and objects which was most satisfactory.




Learn Ruby The Hard Way, Excercise 22: What Do You Know So Far?

This exercise asks you to go through the book and find and write down every word and symbols covered so far and write down next to it what its name is and what it does. After I made this list I spent a few days practicing.

= Assignment operator. Assigns value of right operand to left operand.
# Octothrope, pound sign, used for making single line comments on code
” “ Double quotation marks used to put string information. Recognises string interpolation
‘ ‘ Single quotation marks used to print string information. Doesn’t recognise string interpolation
“”” Multiline String comments
#{ } String interpolation. Ruby evaluates between { } & the result is embedded in the string. This saves space as “Hello #{Ben}” creates only 1 new string object, whereas “Hello” + name + “!” creates 3 new string objects.
{ } Curly braces. Can stand in for keywords do end.
.gets  a method that gets standard input from users keyboard. Or reads single line from file object.
.chomp Removes trailing newline character that will be imported into a string with .gets or when reading lines in file objects
$stdin standard input. Used with .gets explicitly tells the program to get input from user rather than from ARGV/command line.
ARGV  argument variable that holds arguments input from the command line. It then unpacks and assigns the value to variables right of the = symbol like how other variables are assigned.

Arithmetic Operators
+ Adds floats, Integers & strings (joins together, doesn’t perform a math function!)
subtracts floats, integers
* multiply, multiplies floats and integers. Can be used with puts to put strings to console.
% Modulus. Used to find the remainder of a division i.e. 100 % 15 = 10
/ Division.
** Exponentiation – Multiplies a number by itself a specified number of times.
Comparison Operators
== Equals to. Checks if two operands are equal (true) or not.
!= Not equals to. Checks if the value of two operands not equal (true) or are equal.
> Greater than. Checks if the value of the left is greater than the right, if yes the condition is true
>= Great than or equals to.
Less than. Checks if the value on the left is less than the right value, if yes the condition is true.
<= less than or equals to.
<=> Combined comparison operator. Returns 0 if first operand equals second, 1 if first operator is greater than second. -1 if first operand is less than second. This isn’t in the book but it’s cool.
Escape sequences
\n for spreading string information over a newline
\’ tells ruby to ignore the following ‘and treat it as part of the string
\” tells ruby to ignore the following “and treat it as part of the string
\t horizontal  creates a horizontal tab in a string.

File Methods
.open Opens a file object, assigned to variable. Takes filename as a parameter.
.read File method. Reads data from a file
.close. Closes file object. Takes filename in () as parameter.
.write – Writes string data to the file if the file object is open in correct mode.
.truncate  – erases file bytes to a certain value specified inside the () parameters.
.seek – sets file pointer to specified point according to bytes given inside () parameters

String methods
.length checks length of strings
.to_i method to convert strings into integers
.to_f method that converts strings to integers
.to_s method that converts integers and floats to strings
Variable – a name for an object that has value (stores it) that can be referenced and manipulated by the program. Basically a container for information, the purpose being to label and store it in memory. In Ruby there are different types of variables, none of which I understand except that global variables are variables that can be accessed from anywhere in the program, and local variables that are local to the code construct they are declared in for example a variable declared within a loop .  Local variables must begin with an underscore or lower case.

PEMDAS – Acronym for the standard order of evaluation (used in America). Stands for Parenthesis, Exponent, Multiplication, addition, Subtraction.




Learn Ruby The Hard Way, Excercise 21: Funcitons Can Return Something

This is the code for excercise 21:

ex21 2


This exercise showed using return in a function and that you can set variables to be equals to the value returned by a function as on lines 24-27. These Functions are used in the formula on line 33 together with variables and the returned value from other functions running. Madness!

Study Drills

  1. If you aren’t really sure what return does, try writing a few of your own functions and have them return some values. You can return anything that you can put to the right of an =.

I get it but I made an alternative (overcomplicated) addition function below anyway:

def math_add(a,b)
 while b!=0
 return a

result =math_add(10,5)


The function returns 11 if you call return inside the while-end statement. This is because when the function is called and reaches the return statement it finishes running and instantly returns the value it has at that point, in this case it had only run once so returned 11 rather than 15.

2.  At the end of the script is a puzzle. I’m taking the return value of one function   and using it as the argument of another function. I’m doing this in a chain so that I’m kind of creating a formula using the functions. It looks really weird, but if you run the script, you can see the results. What you should do is try to figure out the normal formula that would recreate this same set of operations.

Either of these will work:

35 + 74 - (50 / 2 * 180) 
age  + height - (iq / 2 * weight)


3. Once you have the formula worked out for the puzzle, get in there and see what happens when you modify the parts of the functions. Try to change it on purpose to make another value.

Sure here you go. I moved the position of the functions multiply, divide and subtract:

what = add(age, multiply(height, divide(weight, subtract(iq, 2))))

age + weight / ( iq - 2 ) * height 

4. Do the inverse. Write a simple formula and use the functions in the same way to calculate it.

I found this baffling so this was the best I could do, both returned 3710.

simple_formula = height *iq + age - weight / 7 
forumula = add(multiply(height, iq),(subtract(age, divide(weight, 7))))

5. Remove the word return, and see if the script still works. You’ll find that it does because Ruby implicitly returns whatever the last expression calculates. However, this isn’t clear, so I want you to do it explicitly for my book.


Final points:

I HATE all these formulas.

Learn Ruby The Hard Way, Excercise 20: Functions and Files

This excercise showed off increasing values by increments, manipulating files with functions and the .seek function.

ex20 1
excercise 20 code
ex20 2
excercise 20 output

On the f.gets.chomp

I found function def print_a_line on lines 11-13 quite baffling at first –  as in why oh why is it calling .gets and then .chomp. Bearing in mind I still don’t know much about ruby this is my thinking:  When the fucntion is called on line 28, current file – the file object for input_file is given as the second parameter for print_a_line. The functions instructions tell it to puts the file contents using gets. I cut the .gets.chomp out of the function so it looked like this:

def print_a_line(line_count, f)
 puts "#{line_count}, #{f}"

Running the script just printed the file name, I guess because we called .gets on f it’s telling ruby to get it’s contents of the file directly from the whatever file it has access to.


The .chomp is necessary because each line of text in test.txt has a hidden line separator attached at the end, when this is imported into ruby as a string this stays attached. If you run the .length method afterwards without the chomp the string returned will be 1 character longer than expected.


Study drills

1. Write English comment fort each line to undertand what the line does:

ex20 4.png

2. Each time print_a_line is run, you are passing a variable current_line. Write out what current_line is equal to on each function call, and trace how it becomes line_count in print_a_line.

The variable current_line initialy has an integer value of 1 assigned to it (line 45), this is then updated on line 51 to be equals to 2, and on line 55 to be equals to 3 using the += shorthand operator. The current_line variable is used as a parameter for print_a_line filling the spot for the  line_count argument in print_a_line (i’m not sure what the exact terminology is here!)

3. Find each place a function is used, and check its def to make sure that you are giving it the right arguments?

Checked – it’s all correct.

4. Research online what the seek function for file does. Try ri File and see if you can figure it out from there.

Ruby uses file pointers when reading and writing data, kind of like the cursor in a text document and moves left to right, donwards from begining to end. Seek is a method to set the position of the file pointer to wherever we want using the parameters. It works with bytes rather than characters

5. Research the shorthand notation += and rewrite the script to use += instead.

+= is shorthand assignment operator, it’s short for

number1 = number 1 + number 2

Some other stuff I picked up:

  1. When calling a function if you’re using variables like this : practice_function(‘cheese’, ‘crackers’) make sure to put the arguments inside quotation ‘  ‘ marks. It isn’t needed for variables with integer value.


2. You can set a default value of a functions argument in ruby like this.

def my_method(x, y, z=50)

When the function gets run it will use the default value of z if you don’t supply one.


Learn Ruby the Hard Way, Excercise 19: Functions and Files

This excercise expanded on what can be done with functions and ways to call them.

ex19 1
Ex19 code

There is only one function used here, written on lines 1-6. Lines 8-21 show some ways to call a function.

ex19 2
ex19 consol output


Study Drills

1. Go back through the script and type a comment above each line explaining in English what it does.

Sure here you go:

ex19 3


2. Start at the bottom and read each line backwards, saying all the important characters.


3. Write at least one more function of your own design and run it 10 different ways.

I made a function that shows the amount a percentage(x) is of another number (y). I ran this a few different ways using math functions inside the parameters, using the assignment operator = to create variables. I also used $stdin.gets and ARGV, and performed the .to_s function inside the parameters.

ex19 overkill
study drill 3
ex19 overkill2
study drill 3 output


Final points

  1. Typing clear in powershell will clear everything. Usefull if it is becoming cluttered and confusing.
  2. Having global variables which have the same name as function variables makes things unnecessarily confusing
  3. You can call a function within a function.
  4. functions can have upto 5 arguments, after which time they became difficult to use

Learn Ruby the Hard way, Excercise 18: Names, Variables, Code, Functions

This excercise was pretty cool and introduced Functions. As I understand it and the author puts it functions are basically mini scripts that are defined by the user. Here is the code for excercise 18:

ex18 1

As the author puts it they do three things:

  1. Name pieces of code in the way that variables name strings and numbers
  2. Take arguments like how scripts take ARGV
  3. Using 1 and 2 they let you create mini scripts that do stuff

Lines 1-20 above, exlcuding the comments using the # octothorpe, are the functions being defined. Lines 22-25 are each of those functions being called or run by simply typing the name in and specifiying the arguments the functions are to use inside the ( ).

The *args on line two is just a bit of code that tells ruby to take all of the arguments to the functiuon and put them in args as a list just like ARGV arrays. I’ll read up on what that actually means another time!

This is the code on the consol:

ex18 2.png


1. def print_two_again(arg1, arg2)
2.   puts "arg1: #{arg1}, arg2: #{arg2}"
3. end

I actually got functions pretty quickly but to recap in the example above. On line the first line we call ‘def’ to start making the function and then we name it in the example above ‘print_two_again.’ Straight after this on the same line the arguments are put in parentheses, seperated by comas.

The seocnd line contains what we want the function to do with the arguments above, in this case it puts two strings using string interprolation, this can be more than one line as long as it is indented by two spaces.

The third line ends the function by calling end.

Here is another one of my world class diagrams.

ex18 flow chart

Final points

  1. Functions names can be anything that starts with a letter and can contain letters, numbers and underscores.
  2. This excercise introduced the concept of jumping. That is for example the script normally runs from the top line to the bottom line. When the script is running, once whatever it is that reads it gets as far as line 24 where we called the function print_two the script jumps back up to line 1 where print_two is made, runs print_two using the argumetns we provided then once it is finished jumps back and moves on to line 25.


Learn Ruby the Hard Way, Excercise 17: More Files

This excercise showed how to open two files and copy data from one to another, we entered two arguments at the command line; ‘test.txt’ and ‘new_file.txt’. Here is the code:

ex17 1.png

And here is what it looked like on the consol:

ex17 2.png

I also discovered a useful way to create new text files with content using powershell.

                         echo "This is a test file." > test.txt
                         cat test.txt

This exercise also showed us a fancy new function File.exist? to check if to_file existed on the disk yet, it did not so this returned false when the script ran. The syntax to use this was to place to_file as a parameter thus: File.exist?(to_file.) As the author states you can call functions inside of File to do things with files which is pretty cool. Also this introduced the .length method which we can use this way as in a if statement:

if s.length <= 25


It took me a while to get my head around this exercise so I drew a diagram to show my understanding of how things work in this script.  I’m still learning so if anyone reads this (no one does) take it with a pinch of salt.


ex 17 flowchart

Study Drills

1.This script is really annoying. There no need to ask you before doing the copy, andit prints toomuch out on the screen. Try to make the script more friendly to use by removing features.

Sure here you go.

ex17 4


2.See how short you can make the scirpt. I could make this one line long.

I really tried but couldn’t do it. I did some research and found out it could be written out like this:

File.write(ARGV.last, File.read(ARGV.first))

My understandin gof this is:

The File Method with .write called on ARGV.last. But first, as stuff inside () evaluates first , we call File.read on ARGV.first, which is basically the first item in the ARGV array, the first filename we passed at the command line like ‘test.txt’.

File.write is called on ARGV.last, or the last item in the array / the second argument passed at the commands line like ‘new_file.txt’.  So essnetialy this script says copy from A to B the same way the one above does. I’m not sure however if this method actually closes the file and don’t know enough yet to devise a way of checking.


3.Notice at the end of What you should see i used something called cat? It’s an old command that “con*cat*enates” file together, but mostly it just an easy way to print a file to the screen. Type man cat to read about it.

See above.

4. Find out why you had to write out_file.close in the code

I remember reading somewhere that Ruby has a facility running behind the scenes called the ‘Garbage collector’ that finds and closes open files but I wouldn’t like to assume that this will work in all circumnstances. Leaving files open can drain system resources and also editing files becomes impossible if it’s already open in another mode.

When you close a file the pending data you had is written and saved to the file (if thats what your script supposed to do.)



Learn Ruby the hard way, Excercise 16: Reading and writing files

This excercise introduced, well, reading and writing stuff. Here is the code:

filename = ARGV.first

puts "We're going to erase #{filename}"
puts "If you don't want that, hit CTRL-C (^C)."
puts "If you do want that, hit RETURN."

puts "opening the file...."
target = open(filename, 'w')

puts "Truncating the file. Goodbye!"

puts "Now we're going to ask you for three lines."

print "line 1: "
line1 = $stdin.gets.chomp
print "line 2: "
line2 = $stdin.gets.chomp
print "line 3: "
line3 = $Stdin.gets.chomp
puts "Now we're going to write these to the file."


puts "And finally, we close it."

This output the following to the consol

ex16 consol1

This excercise has the user input a filename into the ARGV array, the contents of ARGV are assigned to the variable target and then this file’s contents are erased with truncate. We then write information to target using gets. The original filename given in the command line doesn’t matter – it could have been swiss_cheese and it would still work fine.

As I hadn’t created a the text file test.txt before running the script,  the line target = open(filename, ‘w’) created it in the location where the ruby script was running from.

This excercise introduced and brushed up on the following functions:

  • close – closing a file
  • read – reading the contents of a file
  • readline – reading just one line of a text file
  • truncate – empties a file.
  • write – writes stuff to a file when you put it inside parentheses i.e target.write(“stuff”) In this excercise we used the parameter w for write only mode. This means we can write to a file but not read from it , the file pointer starts at the begining of the file and erases everything.

Study Drills

1.If you do not undertstand this script, go back through it and use command trick to get it squared away in your mind. One simple English comment above each line will help you understand or at least let you know what you need to research more.

I get this script however the comment trick is a good thing to do when you started learning ruby not long ago.  Here are the english comments for the script anayway:

ex16 study drill 2.png

2. Write a script similar to the last exercise that uses read and ARGV to read the file you just creat

ex16 reader.png
Study drill 2 code
ex 16 study drill consol
Study drill 2 consol

3. There’s too much repetition in this file, use strings, formats and escape to print out line1, line2, line3 with just one target.write() command instead of six.

Ok so I decided to cheat and not use escape sequence at all and cut out the .chomp fucntion so the string will still contain a new line / RETURN when the user enters types in the names for line1, line2 and line3

ex16 study drill 3.png

However this seemed a little sloppy so after copying someone else’s code researching another blog I discovered it could be done more succinctly as:

ex 16 study drill 3 2.png

4. Find out why we had to pass a ‘w’ as an extra parameter to open. Hint: Open tries to be safe by making you explicitly say you want to write a file.

We had to give ‘w’ as a parameter as by default ruby will open the file in ‘r’ mode which is read only. When I changed the open parameter to ‘r’ I got the following message:

ex16.rb:13:in 'truncate' not opened for writing <IOERROR>

Meaning Ruby can’t run truncate if the file is opened in read only mode.

5. If you open the file with ‘w’ mode, then do you really need the target.truncate()?

You do explicitly need to state ‘w’ mode in order to call truncate on the file.  However – as far as I can tell Truncate is redundant here and the author is testing us and no amount of research seems to prove to the contrary! I though that perhaps ‘w’ mode will only erase as far as you write or as far as the file pointer goes, so to test this I removed target.truncate(0) from the script and ran it with just .write in ‘w’ mode and wrote a long paragraph which saved to text.txt, then ran the script again with a very short line. Howver the file was completely erased so Truncate is not needed here!

Common Student Questions

Is the truncate() necessary with the ‘w’ parameter? (See Study drill 5)









Learn Ruby the Hard Way, Excercise 15: Reading Files

Here is the code for the excercise in it’s final form:

filename = ARGV.first

txt = open(filename)

puts "Here's your file #{filename}:"
print txt.read

print "Type the filename again:"
file_again =$stdin.gets.chomp

txt_again = open(file_again)

print txt_again.read

This excercise introduced opening and reading from files uses the .open and .read functions. I also learnt that open creates a file object which the author says is not the actual contents of the file! The script above will print out:


ex 15 consol

Study Drills

1. Above each line write out in English what it does 
- Done:
2. If you are not sure ask someone for help online.

– Yup – researched how gets & ARGV work together this way

3. I used the word commands here, but commands are also called functions and methods.

– That I did not know

4.Get rid of lines 8-13 where you use gets.,chomp and run the script again

– yup, it worked fine.

5. Use only gets and .chomp and try the script that way, why is one way of getting the filename better than the other?

– I tried this using lines 8-13 and deleting the rest of the scirpt. It worked fine but as far as I can see inputting from arguments from the consol is more efficient. Also you could name all the files you wanted to use up front.

6. Start irb to start the Ruby shell, and use open from the promt just like in this program.  Notice you can open files and run read on them from within irb?


7.Have your script also call close() on the txt and txt_again variables. It's important to close files when your are done with them.

I had not thought to do that and assumed this would automatically be done – I will have to research this later.