Você está na página 1de 128

Learn Ruby The Hard Way

Welcome to Learn Ruby the hard way. This is a translation of "Learn Python The Hard Way" to teach total beginners Ruby. It's in the same style, and the content is nearly the same, but it will teach you Ruby.

The Hard Way Is Easier


This sim le boo! is meant to get you started in rogramming. The title says it's the hard way to learn to write code" but it's actually not. It's only the "hard" way because it's the way eo le used to teach things. With the hel of this boo!, you will do the incredibly sim le things that all rogrammers need to do to learn a language# $. %o through each e&ercise. '. Ty e in each sam le e&actly. (. )a!e it run. That's it. This will be very difficult at first, but stic! with it. If you go through this boo!, and do each e&ercise for one or two hours a night, you will ha*e a good foundation for mo*ing onto another boo!. +ou might not really learn " rogramming" from this boo!, but you will learn the foundation s!ills you need to start learning the language. This boo!'s ,ob is to teach you the three most essential s!ills that a beginning rogrammer needs to !now# Reading and Writing, -ttention to .etail, / otting .ifferences.

Reading and Writing


It seems stu idly ob*ious, but, if you ha*e a roblem ty ing, you will ha*e a roblem learning to code. 0s ecially if you ha*e a roblem ty ing the fairly odd characters in source code. Without this sim le s!ill you will be unable to learn e*en the most basic things about how software wor!s. Ty ing the code sam les and getting them to run will hel you learn the names of the symbols, get familiar with ty ing them, and get you reading the language.

Attention to Detail
The one s!ill that se arates bad rogrammers from good rogrammers is attention to detail. In fact, it's what se arates the good from the bad in any rofession. Without aying attention to the tiniest details of your wor!, you will miss !ey elements of what you create. In rogramming, this is how you end u with bugs and difficult1to1use systems. 2y going through this boo!, and co ying each e&am le exactly, you will be training your brain to focus on the details of what you are doing, as you are doing it.

Spotting Differences
- *ery im ortant s!ill 11 that most rogrammers de*elo o*er time 11 is the ability to *isually notice differences between things. -n e& erienced rogrammer can ta!e two ieces of code that are slightly different and immediately start ointing out the differences. Programmers ha*e in*ented tools to ma!e this e*en easier, but we won't be using any of these. +ou first ha*e to train your brain the hard way, then you can use the tools. While you do these e&ercises, ty ing each one in, you will be ma!ing mista!es. It's ine*itable" e*en seasoned rogrammers would ma!e a few. +our ,ob is to com are what you ha*e written to what's re3uired, and fi& all the differences. 2y doing so, you will train yourself to notice mista!es, bugs, and other roblems.

Do Not Copy-Paste
+ou must type each of these e&ercises in, manually. If you co y and aste, you might as well ,ust not e*en do them. The oint of these e&ercises is to train your hands, your brain, and your mind in how to read, write, and see code. If you co y1 aste, you are cheating yourself out of the effecti*eness of the lessons.

A Note On Practice And Persistence


While you are studying rogramming, I'm studying how to lay guitar. I ractice it e*ery day for at least ' hours a day. I lay scales, chords, and ar eggios for an hour at least and then learn music theory, ear training, songs and anything else I can. /ome days I study guitar and music for 4 hours because I feel li!e it and it's fun. To me re etiti*e ractice is natural and ,ust how to learn something. I !now that to get good at anything you ha*e to ractice e*ery day, e*en if I suc! that day 5which is often6 or it's difficult. 7ee trying and e*entually it'll be easier and fun. -s you study this boo!, and continue with rogramming, remember that anything worth doing is difficult at first. )aybe you are the !ind of erson who is afraid of failure so you gi*e u at the first sign of difficulty. )aybe you ne*er learned self1disci line so you can't do anything that's "boring". )aybe you were told that you are "gifted" so you ne*er attem t anything that might ma!e you seem stu id or not a rodigy. )aybe you are com etiti*e and unfairly com are yourself to someone li!e me who's been rogramming for '89 years. Whate*er your reason for wanting to 3uit, !ee at it. :orce yourself. If you run into an 0&tra ;redit you can't do, or a lesson you ,ust do not understand, then s!i it and come bac! to it later. <ust !ee going because with rogramming there's this *ery odd thing that ha ens. -t first, you will not understand anything. It'll be weird, ,ust li!e with learning any human language. +ou will struggle with words, and not !now what symbols are what, and it'll all be *ery confusing. Then one day BANG your brain will sna and you will suddenly "get it". If you !ee doing the e&ercises and !ee trying to understand them, you will get it. +ou might not be a master coder, but you will at least understand how rogramming wor!s.

'

If you gi*e u , you won't e*er reach this oint. +ou will hit the first confusing thing 5which is e*erything at first6 and then sto . If you !ee trying, !ee ty ing it in, trying to understand it and reading about it, you will e*entually get it. 2ut, if you go through this whole boo!, and you still do not understand how to code, at least you ga*e it a shot. +ou can say you tried your best and a little more and it didn't wor! out, but at least you tried. +ou can be roud of that.

License
This boo! is ;o yright 5;6 '8$$ by =ed -. /haw. +ou are free to distribute this boo! to anyone you want, so long as you do not charge anything for it, and it is not altered. +ou must gi*e away the boo! in its entirety, or not at all. This means it's alright for you to teach a class using the boo!, so long as you aren't charging students for the book and you gi*e them the whole boo! unmodified.

Special Thanks
I'd li!e to than! a few eo le who hel ed with this edition of the boo!. :irst is my editor at Pretty Girl Editing Services who hel ed me edit the boo! and is ,ust lo*ely all by herself. Then there's Greg Newman, who did the co*er ,ac!et and artwor!, lus re*iewed co ies of the boo!. His artwor! made the boo! loo! li!e a real boo!, and didn't mind that I totally forgot to gi*e him credit in the first edition. I'd also li!e to than! Brian Shumate for doing the website landing age and other site design hel , which I need a lot of hel on. :inally, I'd li!e to than! the hundreds of thousands of eo le who read the first edition and es ecially the ones who submitted bug re orts and comments to im ro*e the boo!. It really made this edition solid and I couldn't ha*e done it without all of you. Than! you.

Exercise 0: The Setup


This e&ercise has no code. It is sim ly the e&ercise you com lete to get your com uter setu to run Ruby. +ou should follow these instructions as e&actly as ossible. This tutorial assumes that you are using Ruby *ersion $.>.(. +our system might already ha*e Ruby installed. ? en u a console and try running#
$ ruby -v ruby 1.9.3

If you don't already ha*e Ruby installed on your system, I highly recommend using Ruby @ersion )anager 5R@)6 to install it, regardless of which ?/ you are running.

Mac OS
To com lete this e&ercise, com lete the following tas!s#

$. %o to htt #AAwww.barebones.comA roductsAte&twranglerA with your browser, get the TextWrangler te&t editor, and install it. '. Put Te&tWrangler 5your editor6 in your .oc! so you can reach it easily. (. :ind your "Terminal" rogram. /earch for it. +ou will find it. B. Put your Terminal in your .oc! as well. C. Run your Terminal rogram. It won't loo! li!e much. D. In your Terminal rogram, run irb 5Interacti*e Ruby6. +ou run things in Terminal by ,ust ty ing their name and hitting R0TERF. $. If you run irb and it's not there 5irb is not recogniGed..6. Install it using Ruby @ersion )anager 5R@)6. H. Hit ;TRL1. 5^D6 and get out of irb. 4. +ou should be bac! at a rom t similar to what you had before you ty ed irb. If not find out why. >. Learn how to ma!e a directory in the Terminal. /earch online for hel . $8. Learn how to change into a directory in the Terminal. -gain search online. $$. Ese your editor to create a file in this directory. +ou will ma!e the file, "/a*e" or "/a*e -s...", and ic! this directory. $'. %o bac! to Terminal using ,ust the !eyboard to switch windows. Loo! it u if you can't figure it out. $(. 2ac! in Terminal, see if you can list the directory to see your newly created file. /earch online for how to list a directory.

OS ! What "o# Sho#ld See


Here's me doing the abo*e on my com uter in Terminal. +our com uter would be different, so see if you can figure out all the differences between what I did and what you should do.
Last login: Sat Apr ! "":#$:#! on ttys""1 % $ irb ruby-1.9. -p1&" :""1 ' ruby-1.9. -p1&" :"" ' ^D % $ ()*ir (ystu++ % $ ,* (ystu++ (ystu++ $ ls - ... .se TextWrangler /ere to e*it test.txt.... (ystu++ $ ls test.txt (ystu++ $

Windo$s
Fote ;ontributed by Ghmar!. $. %o to htt #AAnote ad1 lus1 lus.orgA with your browser, get the 0otepa*11 te&t editor, and install it. +ou do not need to be administrator to do this. '. )a!e sure you can get to Fote ad99 easily by utting it on your des!to andAor in Iuic! Launch. 2oth o tions are a*ailable during setu . (. :ind your "Terminal" rogram. It's called 2o((an* 3ro(pt. -lternati*ely ,ust run ,(*.

B. )a!e a shortcut to it on your des!to andAor 4ui,) Laun,/ for your con*enience. C. Run your Terminal rogram. It won't loo! li!e much. D. In your Terminal rogram, run irb 5Interacti*e Ruby6. +ou run things in Terminal by ,ust ty ing their name and hitting R0TERF. $. If you run irb and it's not there 5irb is not recogniGed..6. Install it using Ruby @ersion )anager 5R@)6. H. Hit ;TRL1= 5J=6, 0nter and get out of irb. 4. +ou should be bac! at a rom t similar to what you had before you ty ed irb. If not find out why. >. Learn how to ma!e a directory in the Terminal. /earch online for hel . $8. Learn how to change into a directory in the Terminal. -gain search online. $$. Ese your editor to create a file in this directory. )a!e the file, "/a*e" or "/a*e -s...", and ic! this directory. $'. %o bac! to Terminal using ,ust the !eyboard to switch windows. Loo! it u if you can't figure it out. $(. 2ac! in Terminal, see if you can list the directory to see your newly created file. /earch online for how to list a directory. Warning Windows is a big roblem for Ruby. /ometimes you install Ruby and one com uter will ha*e no roblems, and another com uter will be missing im ortant features. If you ha*e roblems, lease *isit# htt #AArubyinstaller.orgA

Windo$s! What "o# Sho#ld See


2:5Do,u(ents an* Settings5you'irb ruby-1.9. -p1&" :""1 ' ruby-1.9. -p1&" :""1 ' ^6 2:5Do,u(ents an* Settings5you'()*ir (ystu++ 2:5Do,u(ents an* Settings5you',* (ystu++ ... 7ere you 8oul* use 0otepa*11 to (a)e test.txt in (ystu++ ... 2:5Do,u(ents an* Settings5you5(ystu++' 9bun,/ o+ uni(portant errors i+ you istalle* it as non-a*(in - ignore t/e( - /it :nter' 2:5Do,u(ents an* Settings5you5(ystu++'*ir ;olu(e in *rive 2 is ;olu(e Serial 0u(ber is "&#2-<:" Dire,tory o+ 2:5Do,u(ents an* Settings5you5(ystu++ "!."#. "1" "!."#. "1" "!."#. "1" 3:3 9D=>' . 3:3 9D=>' .. 3:3 $ test.txt 1 ?ile@sA $ bytes Dir@sA 1! &"! $ 3 3$" bytes +ree

2:5Do,u(ents an* Settings5you5(ystu++'

+ou will robably see a *ery different rom t, Ruby information, and other stuff but this is the general idea. If your system is different let us !now and we'll fi& it.

Lin#%
Linu& is a *aried o erating system with a bunch of different ways to install software. I'm assuming if you are running Linu& then you !now how to install ac!ages so here are your instructions# $. Ese your Linu& ac!age manager and install the ge*it te&t editor. '. )a!e sure you can get to gedit easily by utting it in your window manager's menu. $. Run gedit so we can fi& some stu id defaults it has. '. ? en 3re+eren,es select the :*itor tab. (. ;hange Tab 8i*t/# to '. B. /elect 5ma!e sure a chec! mar! is in6 =nsert spa,es instea* o+ tabs. C. Turn on "-utomatic indentation" as well. D. ? en the ;ie8 tab turn on ".is lay line numbers". (. :ind your "Terminal" rogram. It could be called %F?)0 Terminal, 7onsole, or &term. B. Put your Terminal in your .oc! as well. C. Run your Terminal rogram. It won't loo! li!e much. D. In your Terminal rogram, run irb 5Interacti*e Ruby6. +ou run things in Terminal by ,ust ty ing their name and hitting R0TERF. $. If you run irb and it's not there 5irb is not recogniGed..6. Install it using Ruby @ersion )anager 5R@)6. H. Hit ;TRL1. 5^D6 and get out of irb. 4. +ou should be bac! at a rom t similar to what you had before you ty ed irb. If not find out why. >. Learn how to ma!e a directory in the Terminal. /earch online for hel . $8. Learn how to change into a directory in the Terminal. -gain search online. $$. Ese your editor to create a file in this directory. Ty ically you will ma!e the file, "/a*e" or "/a*e -s..", and ic! this directory. $'. %o bac! to Terminal using ,ust the !eyboard to switch windows. Loo! it u if you can't figure it out. $(. 2ac! in Terminal see if you can list the directory to see your newly created file. /earch online for how to list a directory.

Lin#%! What "o# Sho#ld See


$ irb ruby-1.9. -p1&" :""1 ' ruby-1.9. -p1&" :"" ' ^D $ ()*ir (ystu++ $ ,* (ystu++ - ... .se ge*it /ere to e*it test.txt ... $ ls test.txt $

+ou will robably see a *ery different rom t, Ruby information, and other stuff but this is the general idea.

Warnings &or 'eginners


+ou are done with this e&ercise. This e&ercise might be hard for you de ending on your familiarity with your com uter. If it is difficult, ta!e the time to read and study and get through it, because until you can do these *ery basic things you will find it difficult to get much rogramming done. If a rogrammer tells you to use vi( or e(a,s, tell them, "Fo." These editors are for when you are a better rogrammer. -ll you need right now is an editor that lets you ut te&t into a file. We will use ge*it, TextWraingler, or 0otepa*11 5from now on called "the te&t editor" or "a te&t editor"6 because it is sim le and the same on all com uters. Professional rogrammers use these te&t editors so it's good enough for you starting out. - rogrammer will e*entually tell you to use )ac ?/K or Linu&. If the rogrammer li!es fonts and ty ogra hy, they'll tell you to get a )ac ?/K com uter. If they li!e control and ha*e a huge beard, they'll tell you to install Linu&. -gain, use whate*er com uter you ha*e right now that wor!s. -ll you need is ge*it, a Terminal, and Ruby. :inally the ur ose of this setu is so you can do three things *ery reliably while you wor! on the e&ercises# $. Write e&ercises using ge*it. '. un the e&ercises you wrote. (. !ix them when they are bro!en. B. Re eat. -nything else will only confuse you, so stic! to the lan.

Exercise 1: A Good First ro!ra"


Remember, you should ha*e s ent a good amount of time in 0&ercise 8 learning how to install a te&t editor, run the te&t editor, run the Terminal, and wor! with both of them. If you ha*en't done that then do not go on. +ou will not ha*e a good time. This is the only time I'll start an e&ercise with a warning that you should not s!i or get ahead of yourself. Ty e the following into a single file named ex1.rb. This is im ortant as Ruby wor!s best with files ending in .rb.
1 puts puts 3 puts ! puts # puts $ puts < puts B7ello Worl*CB B7ello AgainB B= li)e typing t/is.B BT/is is +un.B DEayC 3rinting.D B=D* (u,/ rat/er you DnotD.B D= Bsai*B *o not tou,/ t/is.D

Then in Terminal run the file by ty ing#


ruby ex1.rb

If you did it right then you should see the same out ut I ha*e below. If not, you ha*e done something wrong. Fo, the com uter is not wrong.

What "o# Sho#ld See


$ ruby ex1.rb 7ello Worl*C 7ello Again = li)e typing t/is. T/is is +un. EayC 3rinting. =D* (u,/ rat/er you DnotD. = Bsai*B *o not tou,/ t/is. $

+ou may see the name of your directory before the $ which is fine, but if your out ut is not e&actly the same, find out why and fi& it. If you ha*e an error it will loo! li!e this#
ruby ex1.rb ex1.rb:!: syntax errorF unexpe,te* t2G0STA0TF expe,ting $en* puts BT/is is +un.B ^

It's im ortant that you can read these since you will be ma!ing many of these mista!es. 0*en I ma!e many of these mista!es. Let's loo! at this line1by1line. $. '. (. B. C. Here we ran our command in the terminal to run the e&$.rb scri t. Ruby then tells us that the file e&$.rb has an error on line B. It then rints this line for us. Then it uts a ^ 5caret6 character to oint at where the roblem is. :inally, it rints out a "synta& error" and tells us something about what might be the error. Esually these are *ery cry tic, but if you co y that te&t into a search engine, you will find someone else who's had that error and you can robably figure out how to fi& it.

(%tra Credit
+ou will also ha*e 0&tra ;redit. The 0&tra ;redit contains things you should try to do. If you can't, s!i it and come bac! later. :or this e&ercise, try these things# $. )a!e your scri t rint another line. '. )a!e your scri t rint only one of the lines. (. Put a - 5octothor e6 character at the beginning of a line. What did it doL Try to find out what this character does. B. :rom now on, I won't e& lain how each e&ercise wor!s unless an e&ercise is different.

Fote -n 'octothor e' is also called a ' ound', 'hash', 'mesh', or any number of names. Pic! the one that ma!es you chill out.

Exercise #: $o""ents And ound $haracters


;omments are *ery im ortant in your rograms. They are used to tell you what something does in 0nglish, and they also are used to disable arts of your rogram if you need to remo*e them tem orarily. Here's how you use comments in Ruby#
1 - A ,o((entF t/is is so you ,an rea* your progra( later. - Anyt/ing a+ter t/e - is ignore* by >uby. 3 ! puts B= ,oul* /ave ,o*e li)e t/is.B - an* t/e ,o((ent a+ter is ignore* # $ - Eou ,an also use a ,o((ent to B*isableB or ,o((ent out a pie,e o+ ,o*e: < - puts BT/is 8onDt run.B & 9 puts BT/is 8ill run.B

What "o# Sho#ld See


$ ruby ex .rb = ,oul* /ave ,o*e li)e t/is. T/is 8ill run. $

(%tra Credit
$. :ind out if you were right about what the - character does and ma!e sure you !now what it's called 5octothor e or ound character6. '. Ta!e your ex .rb file and re*iew each line going bac!wards. /tart at the last line, and chec! each word in re*erse against what you should ha*e ty ed. (. .id you find more mista!esL :i& them. B. Read what you ty ed abo*e out loud, including saying each character by its name. .id you find more mista!esL :i& them.

Exercise %: &u"bers And 'ath


0*ery rogramming language has some !ind of way of doing numbers and math. .o not worry, rogrammers lie fre3uently about being math geniuses when they really aren't. If they were math geniuses, they would be doing math, not writing ads and social networ! games to steal eo le's money. This e&ercise has lots of math symbols. Let's name them right away so you !now what they are called. -s you ty e this one in, say the names. When saying them feels boring you can sto saying them. Here are the names#
1 plus

>

- (inus H slas/ I asteris) J per,ent 9 less-t/an ' greater-t/an 9K less-t/an-eLual 'K greater-t/an-eLual

Fotice how the o erations are missingL -fter you ty e in the code for this e&ercise, go bac! and figure out what each of these does and com lete the table. :or e&am le, 1 does addition.
1 puts B= 8ill no8 ,ount (y ,/i,)ens:B 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 puts B7ensBF # 1 3" H $ puts B>oostersBF 1"" - # I 3 J ! puts B0o8 = 8ill ,ount t/e eggs:B puts 3 1 1 1 - # 1 ! J - 1 H ! 1 $ 9 # - <MB

puts B=s it true t/at 3 1 puts 3 1 9 # - <

puts BW/at is 3 1 MBF 3 1 puts BW/at is # - <MBF # - < puts BG/F t/atDs 8/y itDs +alse.B puts B7o8 about so(e (ore.B

puts B=s it greaterMBF # ' puts B=s it greater or eLualMBF # 'K 3 puts B=s it less or eLualMBF # 9K -

What "o# Sho#ld See


$ ruby ex3.rb = 8ill no8 ,ount (y ,/i,)ens: 7ens 3" >oosters 9< 0o8 = 8ill ,ount t/e eggs: < =s it true t/at 3 1 9 # - <M +alse W/at is 3 1 M # W/at is # - <M G/F t/atDs 8/y itDs +alse. 7o8 about so(e (ore. =s it greaterM true =s it greater or eLualM true =s it less or eLualM +alse

$8

(%tra Credit
$. -bo*e each line, use the - to write a comment to yourself e& laining what the line does. '. Remember in 0&ercise 8 when you started IR2L /tart IR2 this way again and using the abo*e characters and what you !now, use Ruby as a calculator. (. :ind something you need to calculate and write a new .rb file that does it. B. Fotice the math seems "wrong"L There are no fractions, only whole numbers. :ind out why by researching what a "floating oint" number is. C. Rewrite ex3.rb to use floating oint numbers so it's more accurate 5hint# '8.8 is floating oint6.

Exercise (: )ariab*es And &a"es


Fow you can rint things with puts and you can do math. The ne&t ste is to learn about *ariables. In rogramming a *ariable is nothing more than a name for something so you can use the name rather than the something as you code. Programmers use these *ariable names to ma!e their code read more li!e 0nglish, and because they ha*e lousy memories. If they didn't use good names for things in their software, they'd get lost when they tried to read their code again. If you get stuc! with this e&ercise, remember the tric!s you ha*e been taught so far of finding differences and focusing on details# $. Write a comment abo*e each line e& laining to yourself what it does in 0nglish. '. Read your .rb file bac!wards. (. Read your .rb file out loud saying e*en the characters.
1 ,ars K 1"" spa,eNinNaN,ar K !." 3 *rivers K 3" ! passengers K 9" # ,arsNnotN*riven K ,ars - *rivers $ ,arsN*riven K *rivers < ,arpoolN,apa,ity K ,arsN*riven I spa,eNinNaN,ar & averageNpassengersNperN,ar K passengers H ,arsN*riven 9 1" puts BT/ere are -O,arsP ,ars available.B 11 puts BT/ere are only -O*riversP *rivers available.B 1 puts BT/ere 8ill be -O,arsNnotN*rivenP e(pty ,ars to*ay.B 13 puts BWe ,an transport -O,arpoolN,apa,ityP people to*ay.B 1! puts BWe /ave -OpassengersP passengers to ,arpool to*ay.B 1# puts BWe nee* to put about -OaverageNpassengersNperN,arP in ea,/ ,ar.B

Fote

$$

The N in spa,eNinNaN,ar is called an underscore character. :ind out how to ty e it if you do not already !now. We use this character a lot to ut an imaginary s ace between words in *ariable names.

What "o# Sho#ld See


$ ruby ex!.rb T/ere are 1"" ,ars available. T/ere are only 3" *rivers available. T/ere 8ill be <" e(pty ,ars to*ay. We ,an transport 1 "." people to*ay. We /ave 9" passengers to ,arpool to*ay. We nee* to put about 3 in ea,/ ,ar. $

(%tra Credit
When I wrote this rogram the first time I had a mista!e, and Ruby told me about it li!e this#
ex!.rb:&:in Q9(ain'D: un*e+ine* lo,al variable or (et/o* Q,arNpoolN,apa,ityD +or (ain:GbRe,t @0a(e:rrorA

0& lain this error in your own words. )a!e sure you use line numbers and e& lain why.

)ere*s +ore e%tra credit!


$. '. (. B. C. D. I used B.8 for spa,eNinNaN,ar, but is that necessaryL What ha ens if it's ,ust BL Remember that B.8 is a "floating oint" number. :ind out what that means. Write comments abo*e each of the *ariable assignments. )a!e sure you !now what K is called 5e3uals6 and that it's ma!ing names for things. Remember N is an underscore character. Try running IR2 as a calculator li!e you did before and use *ariable names to do your calculations. Po ular *ariable names are also i, x, and R.

Exercise +: 'ore )ariab*es And rintin!


Fow we'll do e*en more ty ing of *ariables and rinting them out. This time we'll use something called a "format string". 0*ery time you ut B 5double13uotes6 around a iece of te&t you ha*e been ma!ing a string. - string is how you ma!e something that your rogram might gi*e to a human. +ou rint them, sa*e them to files, send them to web ser*ers, all sorts of things. /trings are really handy, so in this e&ercise you will learn how to ma!e strings that ha*e *ariables embedded in them. +ou embed *ariables inside a string by using s ecialiGed format se3uences and then utting the *ariables at the end with a s ecial synta& that tells Ruby, "Hey, this is a format string, ut these *ariables in there." -s usual, ,ust ty e this in e*en if you do not understand it and ma!e it e&actly the same.
1 (yNna(e K D6e* A. S/a8D (yNage K 3# - not a lie 3 (yN/eig/t K <! - in,/es

$'

! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1&

(yN8eig/t K 1&" - lbs (yNeyes K DSlueD (yNteet/ K DW/iteD (yN/air K DSro8nD puts puts puts puts puts puts BLetDs tal) about Js.B J (yNna(e B7eDs J* in,/es tall.B J (yN/eig/t B7eDs J* poun*s /eavy.B J (yN8eig/t BA,tually t/atDs not too /eavy.B B7eDs got Js eyes an* Js /air.B J T(yNeyesF (yN/airU B7is teet/ are usually Js *epen*ing on t/e ,o++ee.B J (yNteet/

- t/is line is tri,)yF try to get it exa,tly rig/t puts B=+ = a** J*F J*F an* J* = get J*.B J T (yNageF (yN/eig/tF (yN8eig/tF (yNage 1 (yN/eig/t 1 (yN8eig/tU

What "o# Sho#ld See


$ ruby ex#.rb LetDs tal) about 6e* A. S/a8. 7eDs <! in,/es tall. 7eDs 1&" poun*s /eavy. A,tually t/atDs not too /eavy. 7eDs got Slue eyes an* Sro8n /air. 7is teet/ are usually W/ite *epen*ing on t/e ,o++ee. =+ = a** 3#F <!F an* 1&" = get &9. $

(%tra Credit
$. ;hange all the *ariables so there isn't the (yN in front. )a!e sure you change the name e*erywhere, not ,ust where you used K to set them. '. Try more format se3uences. (. /earch online for all of the Ruby format se3uences. B. Try to write some *ariables that con*ert the inches and ounds to centimeters and !ilos. .o not ,ust ty e in the measurements. Wor! out the math in Ruby.

Exercise ,: Strin!s And Text


While you ha*e already been writing strings, you still do not !now what they do. In this e&ercise we create a bunch of *ariables with com le& strings so you can see what they are for. :irst an e& lanation of strings. - string is usually a bit of te&t you want to dis lay to someone, or "e& ort" out of the rogram you are writing. Ruby !nows you want something to be a string when you ut either B 5double13uotes6 or D 5single13uotes6 around the te&t. +ou saw this many times with your use of puts when you ut the te&t you want to go to the string inside B or D after the puts. Then Ruby dis lays it. /trings may contain the format characters you ha*e disco*ered so far. +ou sim ly ut the formatted *ariables in the string, and then a J 5 ercent6 character, followed by the *ariable. The only catch is that if you want multi le formats in your string to rint multi le *ariables, you need to ut them inside T U 5brac!ets6 se arated by F 5commas6. It's as if you were

$(

telling me to buy you a list of items from the store and you said, "I want mil!, eggs, bread, and sou ." ?nly as a rogrammer we say, "Mmil!, eggs, bread, sou N". -nother way of in,ecting *ariables into your strings is to use something called "string inter olation", which uses the -O P 5 ound and curly brace6 characters. /o, instead of using format strings#
na(e1 K BVoeB na(e K BWaryB puts B7ello JsF 8/ere is JsMB J Tna(e1F na(e U

We can ty e#
na(e1 K BVoeB na(e K BWaryB puts B7ello -Ona(e1PF 8/ere is -Ona(e PMB

We will now ty e in a whole bunch of strings, *ariables, formats, and rint them. +ou will also ractice using short abbre*iated *ariable names. Programmers lo*e sa*ing themsel*es time at your e& ense by using annoying cry tic *ariable names, so let's get you started being able to read and write them early on.
1 x K BT/ere are -O1"P types o+ people.B binary K BbinaryB 3 *oNnot K B*onDtB ! y K BT/ose 8/o )no8 -ObinaryP an* t/ose 8/o -O*oNnotP.B # $ puts x < puts y & 9 puts B= sai*: -OxP.B 1" puts B= also sai*: D-OyPD.B 11 1 /ilarious K +alse 13 Ro)eNevaluation K B=snDt t/at Ro)e so +unnyMC -O/ilariousPB 1! 1# puts Ro)eNevaluation 1$ 1< 8 K BT/is is t/e le+t si*e o+...B 1& e K Ba string 8it/ a rig/t si*e.B 19 " puts 8 1 e

What "o# Sho#ld See


T/ere are 1" types o+ people. T/ose 8/o )no8 binary an* t/ose 8/o *onDt. = sai*: T/ere are 1" types o+ people.. = also sai*: DT/ose 8/o )no8 binary an* t/ose 8/o *onDt.D. =snDt t/at Ro)e so +unnyMC +alse T/is is t/e le+t si*e o+...a string 8it/ a rig/t si*e.

(%tra Credit
$. %o through this rogram and write a comment abo*e each line e& laining it. '. :ind all the laces where a string is ut inside a string. There are four laces. (. -re you sure there's only four lacesL How do you !nowL )aybe I li!e lying.

$B

B. 0& lain why adding the two strings 8 and e with 1 ma!es a longer string.

Exercise -: 'ore rintin!


Fow we are going to do a bunch of e&ercises where you ,ust ty e code in and ma!e it run. I won't be e& laining much since it is ,ust more of the same. The ur ose is to build u your cho s. /ee you in a few e&ercises, and do not s!i O .o not asteO
1 puts BWary /a* a little la(b.B puts B=ts +lee,e 8as 8/ite as Js.B J Dsno8D 3 puts BAn* every8/ere t/at Wary 8ent.B ! puts B.B I 1" - 8/atD* t/at *oM # $ en*1 K B2B < en* K B/B & en*3 K BeB 9 en*! K BeB 1" en*# K BsB 11 en*$ K BeB 1 en*< K BSB 13 en*& K BuB 1! en*9 K BrB 1# en*1" K BgB 1$ en*11 K BeB 1< en*1 K BrB 1& 19 - noti,e /o8 8e are using print instea* o+ puts /ere. ,/ange it to puts " - an* see 8/at /appens. 1 print en*1 1 en* 1 en*3 1 en*! 1 en*# 1 en*$ print en*< 1 en*& 1 en*9 1 en*1" 1 en*11 1 en*1 3 ! - t/is Rust is polite use o+ t/e ter(inalF try re(oving it # puts

What "o# Sho#ld See


$ ruby ex<.rb Wary /a* a little la(b. =ts +lee,e 8as 8/ite as sno8. An* every8/ere t/at Wary 8ent. .......... 2/eeseSurger $

(%tra Credit
:or these ne&t few e&ercises, you will ha*e the e&act same e&tra credit. $. %o bac! through and write a comment on what each line does. '. Read each one bac!wards or out loud to find your errors. (. :rom now on, when you ma!e mista!es write down on a iece of a er what !ind of mista!e you made. B. When you go to the ne&t e&ercise, loo! at the last mista!es you made and try not to ma!e them in this new one.

$C

C. Remember that e*eryone ma!es mista!es. Programmers are li!e magicians who li!e e*eryone to thin! they are erfect and ne*er wrong, but it's all an act. They ma!e mista!es all the time.

Exercise .: rintin!/ rintin!


1 +or(atter K BJs Js Js JsB 3 ! # $ < & 9 1" 11 1 puts puts puts puts puts +or(atter J T1F F 3F !U +or(atter J TBoneBF Bt8oBF Bt/reeBF B+ourBU +or(atter J TtrueF +alseF +alseF trueU +or(atter J T+or(atterF +or(atterF +or(atterF +or(atterU +or(atter J T B= /a* t/is t/ing.BF BT/at you ,oul* type up rig/t.BF BSut it *i*nDt sing.BF BSo = sai* goo*nig/t.B

What "o# Sho#ld See


$ ruby ex&.rb 1 3 ! one t8o t/ree +our true +alse +alse true Js Js Js Js Js Js Js Js Js Js Js Js Js Js Js Js = /a* t/is t/ing. T/at you ,oul* type up rig/t. Sut it *i*nDt sing. So = sai* goo*nig/t. $

(%tra Credit
$. .o your chec!s of your wor!, write down your mista!es, try not to ma!e them on the ne&t e&ercise.

Exercise 0: rintin!/ rintin!/ rintin!


1 - 7ereDs so(e ne8 strange stu++F re(e(ber type it exa,tly. 3 ! # $ < & 9 1" 11 1 13 1! *ays K BWon Tue We* T/u ?ri Sat SunB (ont/s K BVan5n?eb5nWar5nApr5nWay5nVun5nVul5nAugB puts B7ere are t/e *ays: BF *ays puts B7ere are t/e (ont/s: BF (ont/s puts 993A>AX>A37 T/ereDs so(et/ing going on /ere. Wit/ t/e 3A>AX>A37 t/ing WeDll be able to type as (u,/ as 8e li)e. :ven ! lines i+ 8e 8antF or #F or $. 3A>AX>A37

What "o# Sho#ld See


$ ruby ex9.rb 7ere are t/e *ays: Won Tue We* T/u ?ri Sat Sun

$D

7ere are t/e (ont/s: Van ?eb War Apr Way Vun Vul Aug T/ereDs so(et/ing going on /ere. Wit/ t/e 3A>AX>A37 t/ing WeDll be able to type as (u,/ as 8e li)e. :ven ! lines i+ 8e 8antF or #F or $.

(%tra Credit
.o your chec!s of your wor!, write down your mista!es, try not to ma!e them on the ne&t e&ercise.

Exercise 10: What Was That1


In 0&ercise > I threw you some new stuff, ,ust to !ee you on your toes. I showed you two ways to ma!e a string that goes across multi le lines. In the first way, I ut the characters 5n 5bac!1slash n6 between the names of the months. What these two characters do is ut a new line character into the string at that oint. This use of the 5 5bac!1slash6 character is a way we can ut difficult1to1ty e characters into a string. There are lenty of these "esca e se3uences" a*ailable for different characters you might want to ut in, but there's a s ecial one, the double bac!1slash which is ,ust two of them 55. These two characters will rint ,ust one bac!1slash. We'll try a few of these se3uences so you can see what I mean. -nother im ortant esca e se3uence is to esca e a single13uote D or double13uote B. Imagine you ha*e a string that uses double13uotes and you want to ut a double13uote in for the out ut. If you do this B= Bun*erstan*B Roe.B then Ruby will get confused since it will thin! the B around Bun*erstan*B actually ends the string. +ou need a way to tell Ruby that the B inside the string isn't a real double13uote. To sol*e this roblem you esca e double13uotes and single13uotes so Ruby !nows to include in the string. Here's an e&am le#
B= a( $D 5B tall.B D= a( $5D B tall.D - es,ape *ouble-Luote insi*e string - es,ape single-Luote insi*e string

The second way is by using here document synta&, which uses 990AW: and wor!s li!e a string, but you also can ut as many lines of te&t you as want until you ty e 0AW: again. We'll also lay with these.
1 tabbyN,at K B5t=D( tabbe* in.B persianN,at K B=D( split5non a line.B 3 ba,)slas/N,at K B=D( 55 a 55 ,at.B !

$H

# $ < & 9 1" 11 1 13 1! 1#

+atN,at K 99WEN7:>:DG2 =Dll *o a list: 5tI 2at +oo* 5tI ?is/ies 5tI 2atnip5n5tI Xrass WEN7:>:DG2 puts puts puts puts tabbyN,at persianN,at ba,)slas/N,at +atN,at

What "o# Sho#ld See


Loo! for the tab characters that you made. In this e&ercise the s acing is im ortant to get right.
$ ruby ex1".rb =D( tabbe* in. =D( split on a line. =D( 5 a 5 ,at. =Dll *o a list: I 2at +oo* I ?is/ies I 2atnip I Xrass $

(%tra Credit
$. /earch online to see what other esca e se3uences are a*ailable. '. ;ombine esca e se3uences and format strings to create a more com le& format.

Exercise 11: As2in! 3uestions


Fow it is time to ic! u the ace. I ha*e got you doing a lot of rinting so that you get used to ty ing sim le things, but those sim le things are fairly boring. What we want to do now is get data into your rograms. This is a little tric!y because you ha*e learn to do two things that may not ma!e sense right away, but trust me and do it anyway. It will ma!e sense in a few e&ercises. )ost of what software does is the following# $. Ta!e some !ind of in ut from a erson. '. ;hange it. (. Print out something to show how it changed. /o far you ha*e only been rinting, but you ha*en't been able to get any in ut from a erson, or change it. +ou may not e*en !now what "in ut" means, so rather than tal! about it, let's ha*e you do some and see if you get it. Fe&t e&ercise we'll do more to e& lain it.
1 print B7o8 ol* are youM B

$4

3 ! # $ < &

age K gets.,/o(p@A print B7o8 tall are youM B /eig/t K gets.,/o(p@A print B7o8 (u,/ *o you 8eig/M B 8eig/t K gets.,/o(p@A puts BSoF youDre -OageP years ol*F -O/eig/tP tall an* -O8eig/tP /eavy.B

Fote Fotice that we are using print instead of puts to do the rom ting. print doesn't add a new line automatically, so your answer can go on the same line as the 3uestion. puts on the other hand, adds a newline automatically.

What "o# Sho#ld See


$ ruby ex11.rb 7o8 ol* are youM 3# 7o8 tall are youM $D B 7o8 (u,/ *o you 8eig/M 1&"lbs SoF youDre 3# ol*F $D B tall an* 1&"lbs /eavy. $

(%tra Credit
$. %o online and find out what Rubys gets and ,/o(p methods do. '. ;an you find other ways to use gets.,/o(pL Try some of the sam les you find. (. Write another "form" li!e this to as! some other 3uestions.

Exercise 1#: Libraries


Ta!e a loo! at this code#
1 reLuire Dopen-uriD

open@B/ttp:HH888.ruby-lang.orgHenBA *o Y+Y 3 +.ea,/Nline OYlineY p lineP ! puts +.baseNuri - 9.>=::7TT3:"x!"e$e+ .>L:/ttp:HH888.ruby# lang.orgHenH' $ puts +.,ontentNtype - BtextH/t(lB < puts +.,/arset - Biso-&&#9-1B & puts +.,ontentNen,o*ing - TU 9 puts +.lastN(o*i+ie* - T/u De, "# " :!#:" .T2 "" 1" en*

?n line $ we ha*e what's called a "re3uire". This is how you add features to your scri t from the Ruby feature set or other sources 5e.g., Ruby %ems, stuff you wrote yourself6. Rather than gi*e you all the features at once, Ruby as!s you to say what you lan to use. This !ee s your rograms small, but it also acts as documentation for other rogrammers who read your code later.

$>

)old ,p- &eat#res )a.e Another Na+e


I call them "features" here 5these little things you re3uire to ma!e your Ruby rogram do more6 but nobody else calls them features. I ,ust used that name because I needed to tric! you into learning what they are without ,argon. 2efore you can continue, you need to learn their real name# libraries. :rom now on we will be calling these "features" that we re3uire libraries. I'll say things li!e, "+ou want to re3uire the open-uri library." They are also called "modules" by other rogrammers, but let's ,ust stic! with libraries.

(%tra Credit
$. Research the difference between reLuire and in,lu*e. How are they differentL '. ;an you reLuire a scri t that doesn't contain a library s ecificallyL (. :igure out which directories on your system Ruby will loo! in to find the libraries you re3uire.

Exercise 1%: ara"eters/ 4npac2in!/ )ariab*es


In this e&ercise we will co*er one more in ut method you can use to ass *ariables to a scri t 5scri t being another name for your .rb files6. +ou !now how you ty e ruby ex13.rb to run the ex13.rb fileL Well the ex13.rb art of the command is called an "argument". What we'll do now is write a scri t that also acce ts arguments. Ty e this rogram and I'll e& lain it in detail#
1 +irstF se,on*F t/ir* K A>X; 3 ! # $ puts puts puts puts BT/e s,ript is ,alle*: -O$"PB BEour +irst variable is: -O+irstPB BEour se,on* variable is: -Ose,on*PB BEour t/ir* variable is: -Ot/ir*PB

The A>X; is the "argument *ariable", a *ery standard name in rogramming, that you will find used in many other languages. It's in all ca s because it's a constant, meaning you shouldn't change the *alue once it's been assigned. This *ariable holds the arguments you ass to your Ruby scri t when you run it. In the e&ercises you will get to lay with this more and see what ha ens. Line $ "un ac!s" A>X; so that, rather than holding all the arguments, it gets assigned to three *ariables you can wor! with# +irst, se,on*, and t/ir*. The name of the scri t itself is stored in a s ecial *ariable $", which we don't need to un ac!. This may loo! strange, but "un ac!" is robably the best word to describe what it does. It ,ust says, "Ta!e whate*er is in A>X;, un ac! it, and assign it to all of these *ariables on the left in order." -fter that we ,ust rint them out li!e normal.

'8

What "o# Sho#ld See


Run the rogram li!e this#
ruby ex13.rb +irst n* 3r*

This is what you should see when you do a few different runs with different arguments#
$ ruby ex13.rb +irst n* 3r* T/e s,ript is ,alle*: ex13.rb Eour +irst variable is: +irst Eour se,on* variable is: n* Eour t/ir* variable is: 3r* $ ruby ex13.rb ,/eese apples brea* T/e s,ript is ,alle*: ex13.rb Eour +irst variable is: ,/eese Eour se,on* variable is: apples Eour t/ir* variable is: brea* $ ruby ex13.rb 6e* A. S/a8 T/e s,ript is ,alle*: ex13.rb Eour +irst variable is: 6e* Eour se,on* variable is: A. Eour t/ir* variable is: S/a8

+ou can actually re lace "first", "'nd", and "(rd" with any three things. +ou do not ha*e to gi*e these arameters either, you can gi*e any ( strings you want#
ruby ex13.rb stu++ = li)e ruby ex13.rb anyt/ing $ <

(%tra Credit
$. Try gi*ing fewer than three arguments to your scri t. What *alues are used for the missing argumentsL '. Write a scri t that has fewer arguments and one that has more. )a!e sure you gi*e the un ac!ed *ariables good names. (. ;ombine STD=0.gets.,/o(p@A with A>X; to ma!e a scri t that gets more in ut from a user.

Exercise 1(: ro"ptin! And assin!


Let's do one e&ercise that uses A>X; and gets.,/o(p@A together to as! the user something s ecific. +ou will need this for the ne&t e&ercise where we learn to read and write files. In this e&ercise we'll rint a sim le ' rom t. This is similar to a game li!e =or! or -d*enture.
1 user K A>X;.+irst pro(pt K D' D 3 ! puts B7i -OuserPF =D( t/e -O$"P s,ript.B # puts B=D* li)e to as) you a +e8 Luestions.B $ puts BDo you li)e (e -OuserPMB < print pro(pt

'$

& 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1

li)es K STD=0.gets.,/o(p@A puts BW/ere *o you live -OuserPMB print pro(pt lives K STD=0.gets.,/o(p@A puts BW/at )in* o+ ,o(puter *o you /aveMB print pro(pt ,o(puter K STD=0.gets.,/o(p@A puts 99W:SSAX: Alrig/tF so you sai* -Oli)esP about li)ing (e. Eou live in -OlivesP. 0ot sure 8/ere t/at is. An* you /ave a -O,o(puterP ,o(puter. 0i,e. W:SSAX:

I"portant: -lso notice that we're using STD=0.gets instead of lain 'ol gets. That is because if there is stuff in A>X;, the default gets method tries to treat the first one as a file and read from that. To read from the user's in ut 5i.e., st*in6 in such a situation, you ha*e to use it STD=0.gets e& licitly.

What "o# Sho#ld See


When you run this, remember that you ha*e to gi*e the scri t your name for the A>X; arguments.
$ ruby ex1!.rb 6e* 7i 6e*F =D( t/e exHex1!.rb s,ript. =D* li)e to as) you a +e8 Luestions. Do you li)e (e 6e*M ' Ees W/ere *o you live 6e*M ' A(eri,a W/at )in* o+ ,o(puter *o you /aveM ' Tan*y Alrig/tF so you sai* Ees about li)ing (e. Eou live in A(eri,a. 0ot sure 8/ere t/at is. An* you /ave a Tan*y ,o(puter. 0i,e.

(%tra Credit
$. '. (. B. :ind out what =or! and -d*enture were. Try to find a co y and lay it. ;hange the pro(pt *ariable to something else entirely. -dd another argument and use it in your scri t. )a!e sure you understand how I combined a 99SGW:T7=0X style multi1line string with -O P string inter olation as the last rint.

Exercise 1+: Readin! Fi*es


0*erything you'*e learned about STD=0.gets and A>X; is so you can start reading files. +ou may ha*e to lay with this e&ercise the most to understand what's going on, so do it carefully and remember your chec!s. Wor!ing with files is an easy way to erase your wor! if you are not careful.

''

This e&ercise in*ol*es writing two files. ?ne is your usual ex1#.rb file that you will run, but the other is named ex1#Nsa(ple.txt. This second file isn't a scri t but a lain te&t file we'll be reading in our scri t. Here are the contents of that file#
T/is is stu++ = type* into a +ile. =t is really ,ool stu++. Lots an* lots o+ +un to /ave in /ere.

What we want to do is "o en" that file in our scri t and rint it out. Howe*er, we do not want to ,ust "hard code" the name ex1#Nsa(ple.txt into our scri t. "Hard coding" means utting some bit of information that should come from the user as a string right in our rogram. That's bad because we want it to load other files later. The solution is to use A>X; and STD=0.gets to as! the user what file they want instead of "hard coding" the file's name.
1 +ilena(e K A>X;.+irst 3 ! # $ < & 9 1" 11 1 13 1! 1# pro(pt K B' B txt K ?ile.open@+ilena(eA puts B7ereDs your +ile: -O+ilena(ePB puts txt.rea*@A puts B=Dll also as) you to type it again:B print pro(pt +ileNagain K STD=0.gets.,/o(p@A txtNagain K ?ile.open@+ileNagainA puts txtNagain.rea*@A

- few fancy things are going on in this file, so let's brea! it down real 3uic!# Line $1( should be a familiar use of A>X; to get a filename and setting u the rom t. Fe&t we ha*e line B where we use a new command ?ile.open. Right now, run ri ?ile.open from the command line and read the instructions. Fotice how li!e your own scri ts, it ta!es a arameter and returns a *alue you can set to your own *ariable. +ou ,ust o ened a file. Line D we rint a little line, but on line H we ha*e something *ery new and e&citing. We call a function on txt. What you got bac! from open is a +ile, and it's also got commands you can gi*e it. +ou gi*e a file a command by using the . 5dot or eriod6, the name of the command, and arameters. <ust li!e with ?ile.open. The difference is that when you say txt.rea*@A you are saying, "Hey t&tO .o your read command with no arametersO" The remainder of the file is more of the same, but we'll lea*e the analysis to you in the e&tra credit.

What "o# Sho#ld See


I made a file called "e&$CPsam le.t&t" and ran my scri t.
$ ruby ex1#.rb ex1#Nsa(ple.txt 7ereDs your +ile ex1#Nsa(ple.txt: T/is is stu++ = type* into a +ile.

'(

=t is really ,ool stu++. Lots an* lots o+ +un to /ave in /ere. =Dll also as) you to type it again: ' ex1#Nsa(ple.txt T/is is stu++ = type* into a +ile. =t is really ,ool stu++. Lots an* lots o+ +un to /ave in /ere. $

(%tra Credit
This is a big ,um so be sure you do this e&tra credit as best you can before mo*ing on. $. -bo*e each line write out in 0nglish what that line does. '. If you are not sure as! someone for hel or search online. )any times searching for "ruby THIF%" will find answers for what that THIF% does in Ruby. Try searching for "ruby file.o en". (. I used the name "commands" here, but they are also called "functions" and "methods". /earch around online to see what other eo le do to define these. .o not worry if they confuse you. It's normal for a rogrammer to confuse you with their *ast e&tensi*e !nowledge. B. %et rid of the art from line >1$C where you use STD=0.gets and try the scri t then. C. Ese only STD=0.gets and try the scri t that way. Thin! of why one way of getting the filename would be better than another. D. Run ri ?ile and scroll down until you see the rea*@A command 5methodAfunction6. /ee all the other ones you can useL Try some of the other commands. H. /tartu IR2 again and use ?ile.open from the rom t. Fotice how you can o en files and run read on them right thereL 4. Ha*e your scri t also do a ,lose@A on the txt and txtNagain *ariables. It's im ortant to close files when you are done with them.

Exercise 1,: Readin! And Writin! Fi*es


If you did the e&tra credit from the last e&ercise you should ha*e seen all sorts of commands 5methodsAfunctions6 you can gi*e to files. Here's the list of commands I want you to remember#

close 11 ;loses the file. Li!e ?ile-'Save.. in your editor. read 11 Reads the contents of the file, you can assign the result to a *ariable. readline 11 Reads ,ust one line of a te&t file. truncate 11 0m ties the file, watch out if you care about the file. write5stuff6 11 Writes stuff to the file.

:or now these are the im ortant commands you need to !now. /ome of them ta!e arameters, but we do not really care about that. +ou only need to remember that write ta!es a arameter of a string you want to write to the file. Let's use some of this to ma!e a sim le little te&t editor#

'B

1 +ilena(e K A>X;.+irst s,ript K $" 3 ! puts BWeDre going to erase -O+ilena(eP.B # puts B=+ you *onDt 8ant t/atF /it 2T>L-2 @^2A.B $ puts B=+ you *o 8ant t/atF /it >:T.>0.B < & print BM B 9 STD=0.gets 1" 11 puts BGpening t/e +ile...B 1 target K ?ile.open@+ilena(eF D8DA 13 1! puts BTrun,ating t/e +ile. Xoo*byeCB 1# target.trun,ate@target.siZeA 1$ 1< puts B0o8 =D( going to as) you +or t/ree lines.B 1& 19 print Bline 1: B[ line1 K STD=0.gets.,/o(p@A " print Bline : B[ line K STD=0.gets.,/o(p@A 1 print Bline 3: B[ line3 K STD=0.gets.,/o(p@A 3 ! # $ < & 9 3" 31 3 33 puts B=D( going to 8rite t/ese to t/e +ile.B target.8rite@line1A target.8rite@B5nBA target.8rite@line A target.8rite@B5nBA target.8rite@line3A target.8rite@B5nBA puts BAn* +inallyF 8e ,lose it.B target.,lose@A

Warnin! If you get errors in this scri t it is robably because you are using Ruby $.4 and the boo! assumes Ruby $.>. To see what *ersion you ha*e ty e# ruby -v If you need to install a newer *ersion then go bac! to the beginning of the boo! where 0&ercise 8 tells you how. That's a large file, robably the largest you ha*e ty ed in. /o go slow, do your chec!s, and ma!e it run. ?ne tric! is to get bits of it running at a time. %et lines $14 running, then C more, then a few more, etc., until it's all done and running.

What "o# Sho#ld See


There are actually two things you will see, first the out ut of your new scri t#
$ ruby ex1$.rb test.txt WeDre going to erase Dtest.txtD. =+ you *onDt 8ant t/atF /it 2T>L-2 @^2A. =+ you *o 8ant t/atF /it >:T.>0. M Gpening t/e +ile... Trun,ating t/e +ile. Xoo*byeC 0o8 =D( going to as) you +or t/ree lines. line 1: To all t/e people out t/ere.

'C

line : = say = *onDt li)e (y /air. line 3: = nee* to s/ave it o++. =D( going to 8rite t/ese to t/e +ile. An* +inallyF 8e ,lose it. $

Fow, o en u the file you made 5in my case test.t&t6 in your editor and chec! it out. Feat rightL

(%tra Credit
$. If you feel you do not understand this, go bac! through and use the comment tric! to get it s3uared away in your mind. ?ne sim le 0nglish comment abo*e each line will hel you understand, or at least let you !now what you need to research more. '. Write a scri t similar to the last e&ercise that uses read and arg* to read the file you ,ust created. (. There's too much re etition in this file. Ese strings, formats, and esca es to rint out line$, line', and line( with ,ust one target.8rite@A command instead of D. B. :ind out why we had to ass a D8D as an e&tra arameter to o en. Hint# o en tries to be safe by ma!ing you e& licitly say you want to write a file. C. If you o en the file with D8D mode, then do you really need the target.trun,ate@AL %o read the docs for Ruby's ?ile.open function and see if that's true.

Exercise 1-: 'ore Fi*es


Fow let's do a few more things with files. We're going to actually write a Ruby scri t to co y one file to another. It'll be *ery short but will gi*e you some ideas about other things you can do with files.
1 +ro(N+ileF toN+ile K A>X; s,ript K $" 3 ! puts B2opying +ro( -O+ro(N+ileP to -OtoN+ilePB # $ - 8e ,oul* *o t/ese t8o on one line tooF /o8M < input K ?ile.open@+ro(N+ileA & in*ata K input.rea*@A 9 1" puts BT/e input +ile is -Oin*ata.lengt/P bytes longB 11 1 puts BDoes t/e output +ile existM -O?ile.existsM toN+ilePB 13 puts B>ea*yF /it >:T.>0 to ,ontinueF 2T>L-2 to abort.B 1! STD=0.gets 1# 1$ output K ?ile.open@toN+ileF D8DA 1< output.8rite@in*ataA 1& 19 puts BAlrig/tF all *one.B " 1 output.,lose@A input.,lose@A

'D

Here we used a new method called ?ile.existsM. This returns true if a file e&ists, based on its name in a string as an argument. It returns 5a*se if not. We'll be using this function in the second half of this boo! to do lots of things.

What "o# Sho#ld See


<ust li!e your other scri ts, run this one with two arguments, the file to co y from and the file to co y it to. If we use your test.txt file from before we get this#
$ ruby ex1<.rb test.txt ,opie*.txt 2opying +ro( test.txt to ,opie*.txt T/e input +ile is &1 bytes long Does t/e output +ile existM ?alse >ea*yF /it >:T.>0 to ,ontinueF 2T>L-2 to abort. Alrig/tF all *one. $ ,at ,opie*.txt To all t/e people out t/ere. = say = *onDt li)e (y /air. = nee* to s/ave it o++. $

It should wor! with any file. Try a bunch more and see what ha ens. <ust be careful you do not blast an im ortant file. Warnin! .id you see that tric! I did with ,atL It only wor!s on Linu& or ?/K, on Windows use type to do the same thing.

(%tra Credit
$. %o read u on Ruby's reLuire statement, and start Ruby to try it out. Try im orting some things and see if you can get it right. It's alright if you do not. '. This scri t is really annoying. There's no need to as! you before doing the co y, and it rints too much out to the screen. Try to ma!e it more friendly to use by remo*ing features. (. /ee how short you can ma!e the scri t. I could ma!e this $ line long. B. Fotice at the end of the W+// I used something called ,atL It's an old command that "conQcatQenates" files together, but mostly it's ,ust an easy way to rint a file to the screen. Ty e (an ,at to read about it. C. Windows eo le, find the alternati*e to ,at that Linu&A?/K eo le ha*e. .o not worry about (an since there is nothing li!e that. D. :ind out why you had to do output.,lose@A in the code.

Exercise 1.: &a"es/ )ariab*es/ $ode/ Functions

'H

2ig title rightL I am about to introduce you to the functionO .um dum dahO 0*ery rogrammer will go on and on about functions and all the different ideas about how they wor! and what they do, but I will gi*e you the sim lest e& lanation you can use right now. :unctions do three things# $. They name ieces of code the way *ariables name strings and numbers. '. They ta!e arguments the way your scri ts ta!e A>X;. (. Esing R$ and R' they let you ma!e your own "mini scri ts" or "tiny commands". +ou can create a function 5also called "methods"6 by using the word *e+ in Ruby. I'm going to ha*e you ma!e four different functions that wor! li!e your scri ts, and then show you how each one is related.
1 - t/is one is li)e your s,ripts 8it/ argv *e+ putsNt8o@IargsA 3 arg1F arg K args ! puts Barg1: -Oarg1PF arg : -Oarg PB # en* $ < - o)F t/at Iargs is a,tually pointlessF 8e ,an Rust *o t/is & *e+ putsNt8oNagain@arg1F arg A 9 puts Barg1: -Oarg1PF arg : -Oarg PB 1" en* 11 1 - t/is Rust ta)es one argu(ent 13 *e+ putsNone@arg1A 1! puts Barg1: -Oarg1PB 1# en* 1$ 1< - t/is one ta)es no argu(ents 1& *e+ putsNnone@A 19 puts B= got not/inD.B " en* 1 putsNt8o@B6e*BFBS/a8BA 3 putsNt8oNagain@B6e*BFBS/a8BA ! putsNone@B?irstCBA # putsNnone@A

Let's brea! down the first function, putsNt8o which is the most similar to what you already !now from ma!ing scri ts# $. :irst we tell Ruby we want to ma!e a function using *e+ for "define". '. ?n the same line as *e+ we then gi*e the function a name, in this case we ,ust called it " utsPtwo" but it could be " eanuts" too. It doesn't matter, e&ce t that your function should ha*e a short name that says what it does. (. Then we tell it we want Iargs 5asteris! args6 which is a lot li!e your A>X; arameter but for functions. B. -fter the definition, all the lines that are indented ' s aces will become attached to this name, putsNt8o. ?ur first indented line is one that un ac!s the arguments the same as with your scri ts. C. To demonstrate how it wor!s we rint these arguments out, ,ust li!e we would in a scri t. Fow, the roblem with putsNt8o is that it's not the easiest way to ma!e a

'4

function. In Ruby we can s!i the whole un ac!ing args and ,ust use the names we want right inside @A. That's what putsNt8oNagain does. -fter that you ha*e an e&am le of how you ma!e a function that ta!es one argument in putsNone. :inally you ha*e a function that has no arguments in putsNnone. Warnin! This is *ery im ortant. .o not get discouraged right now if this doesn't 3uite ma!e sense. We're going to do a few e&ercises lin!ing functions to your scri ts and show you how to ma!e more. :or now ,ust !ee thin!ing "mini scri t" when I say "function" and !ee laying with them.

What "o# Sho#ld See


If you run the abo*e scri t you should see#
$ ruby ex1&.rb arg1: D6e*DF arg : DS/a8D arg1: D6e*DF arg : DS/a8D arg1: D?irstCD = got not/inD. $

Right away you can see how a function wor!s. Fotice that you used your functions the way you use things li!e ?ile.existsM, ?ile.open, and other "commands". In fact, I'*e been tric!ing you because in Ruby those "commands" are ,ust functions. This means you can ma!e your own commands and use them in your scri ts too.

(%tra Credit
Write out a function chec!list for later e&ercises. Write these on an inde& card and !ee it by you while you com lete the rest of these e&ercises or until you feel you do not need it# $. '. (. B. C. D. H. 4. .id you start your function definition with *e+L .oes your function name ha*e only characters and N 5underscore6 charactersL .id you ut an o en arenthesis @ right after the function nameL .id you ut your arguments after the arenthesis @ se arated by commasL .id you ma!e each argument uni3ue 5meaning no du licated names6. .id you ut a close arenthesis A after the argumentsL .id you indent all lines of code you want in the function ' s acesL .id you close your function body by ty ing "end"L

-nd when you run 5a!a "use" or "call"6 a function, chec! these things# $. .id you callAuseArun this function by ty ing its nameL '. .id you ut @ character after the name to run itL 5this isn't re3uired, but is idiomatic6 (. .id you ut the *alues you want into the arenthesis se arated by commasL

'>

B. .id you end the function call with a A character. Ese these two chec!lists on the remaining lessons until you do not need them anymore. :inally, re eat this a few times# "To 'run', 'call', or 'use' a function all mean the same thing."

Exercise 10: Functions And )ariab*es


:unctions may ha*e been a mind1blowing amount of information, but do not worry. <ust !ee doing these e&ercises and going through your chec!list from the last e&ercise and you will e*entually get it. There is one tiny oint though that you might not ha*e realiGed which we'll reinforce right now# The *ariables in your function are not connected to the *ariables in your scri t. Here's an e&ercise to get you thin!ing about this#
1 *e+ ,/eeseNan*N,ra,)ers@,/eeseN,ountF boxesNo+N,ra,)ersA puts BEou /ave -O,/eeseN,ountP ,/eesesCB 3 puts BEou /ave -OboxesNo+N,ra,)ersP boxes o+ ,ra,)ersCB ! puts BWan t/atDs enoug/ +or a partyCB # puts BXet a blan)et.B $ puts - a blan) line < en* & 9 puts BWe ,an Rust give t/e +un,tion nu(bers *ire,tly:B 1" ,/eeseNan*N,ra,)ers@ "F 3"A 11 1 puts BG>F 8e ,an use variables +ro( our s,ript:B 13 a(ountNo+N,/eese K 1" 1! a(ountNo+N,ra,)ers K #" 1# ,/eeseNan*N,ra,)ers@a(ountNo+N,/eeseF a(ountNo+N,ra,)ersA 1$ 1< puts BWe ,an even *o (at/ insi*e too:B 1& ,/eeseNan*N,ra,)ers@1" 1 "F # 1 $A 19 " puts BAn* 8e ,an ,o(bine t/e t8oF variables an* (at/:B 1 ,/eeseNan*N,ra,)ers@a(ountNo+N,/eese 1 1""F a(ountNo+N,ra,)ers 1 1"""A

This shows all different ways we're able to gi*e our function ,/eeseNan*N,ra,)ers the *alues it needs to rint them. We can gi*e it straight numbers. We can gi*e it *ariables. We can gi*e it math. We can e*en combine math and *ariables. In a way, the arguments to a function are !ind of li!e our K character when we ma!e a *ariable. In fact, if you can use K to name something, you can usually ass it to a function as an argument.

What "o# Sho#ld See


+ou should study the out ut of this scri t and com are it with what you thin! you should get for each of the e&am les in the scri t.

(8

$ ruby ex19.rb We ,an Rust give t/e +un,tion nu(bers *ire,tly: Eou /ave " ,/eesesC Eou /ave 3" boxes o+ ,ra,)ersC Wan t/atDs enoug/ +or a partyC Xet a blan)et. G>F Eou Eou Wan Xet 8e ,an use variables +ro( our s,ript: /ave 1" ,/eesesC /ave #" boxes o+ ,ra,)ersC t/atDs enoug/ +or a partyC a blan)et.

We ,an even *o (at/ insi*e too: Eou /ave 3" ,/eesesC Eou /ave 11 boxes o+ ,ra,)ersC Wan t/atDs enoug/ +or a partyC Xet a blan)et. An* Eou Eou Wan Xet $ 8e ,an ,o(bine t/e t8oF variables an* (at/: /ave 11" ,/eesesC /ave 1"#" boxes o+ ,ra,)ersC t/atDs enoug/ +or a partyC a blan)et.

(%tra Credit
$. %o bac! through the scri t and ty e a comment abo*e each line e& laining in 0nglish what it does. '. /tart at the bottom and read each line bac!wards, saying all the im ortant characters. (. Write at least one more function of your own design, and run it $8 different ways.

Exercise #0: Functions And Fi*es


Remember your chec!list for functions, then do this e&ercise aying close attention to how functions and files can wor! together to ma!e useful stuff.
1 inputN+ile K A>X;T"U 3 ! # $ < & 9 1" *e+ printNall@+A puts +.rea*@A en* *e+ re8in*@+A +.see)@"F =G::S::\NS:TA en*

($

11 1 13 1! 1# 1$ 1< 1& 19 " 1 3 ! # $ < & 9 3" 31 3 33 3! 3#

*e+ printNaNline@lineN,ountF +A puts B-OlineN,ountP -O+.rea*line@APB en* ,urrentN+ile K ?ile.open@inputN+ileA puts B?irst letDs print t/e 8/ole +ile:B puts - a blan) line printNall@,urrentN+ileA puts B0o8 letDs re8in*F )in* o+ li)e a tape.B re8in*@,urrentN+ileA puts BLetDs print t/ree lines:B ,urrentNline K 1 printNaNline@,urrentNlineF ,urrentN+ileA ,urrentNline K ,urrentNline 1 1 printNaNline@,urrentNlineF ,urrentN+ileA ,urrentNline K ,urrentNline 1 1 printNaNline@,urrentNlineF ,urrentN+ileA

Pay close attention to how we ass in the current line number each time we run printNaNline.

What "o# Sho#ld See


$ ruby ex ".rb test.txt ?irst letDs print t/e 8/ole +ile: To all t/e people out t/ere. = say = *onDt li)e (y /air. = nee* to s/ave it o++. 0o8 letDs re8in*F )in* o+ li)e a tape. LetDs print t/ree lines: 1 To all t/e people out t/ere. = say = *onDt li)e (y /air. 3 = nee* to s/ave it o++. $

(%tra Credit
$. %o through and write 0nglish comments for each line to understand what's going on. '. 0ach time printNaNline is run you are assing in a *ariable ,urrentNline. Write out what ,urrentNline is e3ual to on each function call, and trace how it becomes lineN,ount in printNaNline. (. :ind each lace a function is used, and go chec! its def to ma!e sure that you are gi*ing it the right arguments. B. Research online what the see) function for file does. Loo! at the r*o, documentation using the ri command and see if you can figure it out from there. C. Research the shorthand notation 1K and rewrite the scri t to use that.

('

Exercise #1: Functions $an Return So"ethin!


+ou ha*e been using the K character to name *ariables and set them to numbers or strings. We're now going to blow your mind again by showing you how to use K to set *ariables to be a *alue from a function. There will be one thing to ay close attention to, but first ty e this in#
1 *e+ a**@aF bA puts BADD=0X -OaP 1 -ObPB 3 a 1 b ! en* # $ *e+ subtra,t@aF bA < puts BS.ST>A2T=0X -OaP - -ObPB & a - b 9 en* 1" 11 *e+ (ultiply@aF bA 1 puts BW.LT=3LE=0X -OaP I -ObPB 13 a I b 1! en* 1# 1$ *e+ *ivi*e@aF bA 1< puts BD=;=D=0X -OaP H -ObPB 1& a H b 19 en* " 1 puts BLetDs *o so(e (at/ 8it/ Rust +un,tionsCB 3 ! # $ < & 9 3" 31 3 33 3! 3# age K a**@3"F #A /eig/t K subtra,t@<&F!A 8eig/t K (ultiply@9"F A iL K *ivi*e@1""F A puts BAge: -OagePF 7eig/t: -O/eig/tPF Weig/t: -O8eig/tPF =4: -OiLPB - A puZZle +or t/e extra ,re*itF type it in any8ay. puts B7ere is a puZZle.B 8/at K a**@ageF subtra,t@/eig/tF (ultiply@8eig/tF *ivi*e@iLF puts BT/at be,o(es: -O8/atP 2an you *o it by /an*MB AAAA

We are now doing our own math functions for a**, subtra,t, (ultiply, and *ivi*e. The im ortant thing to notice is the last line where we say a 1 b 5in a**6. What this does is the following# $. ?ur function is called with two arguments# a and b. '. We rint out what our function is doing, in this case "-..IF%". (. Then we tell Ruby to do something !ind of bac!ward# we return the addition of a 1 b. +ou might say this as, "I add a and b then return them." In Ruby, the last e*aluated statement in a method is its return *alue. +ou can be more e& licit if you want and ty e return a 1 b, but that is totally o tional.

((

B. Ruby adds the two numbers. Then when the function ends any line that runs it will be able to assign this a 9 b result to a *ariable. -s with many other things in this boo!, you should ta!e this real slow, brea! it down and try to trace what's going on. To hel there's e&tra credit to get you to sol*e a uGGle and learn something cool.

What "o# Sho#ld See


$ ruby ex 1.rb LetDs *o so(e (at/ 8it/ Rust +un,tionsC ADD=0X 3" 1 # S.ST>A2T=0X <& - ! W.LT=3LE=0X 9" I D=;=D=0X 1"" H Age: 3#F 7eig/t: <!F Weig/t: 1&"F =4: #" 7ere is a puZZle. D=;=D=0X #" H W.LT=3LE=0X 1&" I # S.ST>A2T=0X <! - !#"" ADD=0X 3# 1 -!! $ T/at be,o(es: -!391 2an you *o it by /an*M $

(%tra Credit
$. If you aren't really sure what return *alues are, try writing a few of your own functions and ha*e them return some *alues. +ou can return anything that you can ut to the right of an K. '. -t the end of the scri t is a uGGle. I'm ta!ing the return *alue of one function, and using it as the argument of another function. I'm doing this in a chain so that I'm !ind of creating a formula using the functions. It loo!s really weird, but if you run the scri t you can see the results. What you should do is try to figure out the normal formula that would recreate this same set of o erations. (. ?nce you ha*e the formula wor!ed out for the uGGle, get in there and see what ha ens when you modify the arts of the functions. Try to change it on ur ose to ma!e another *alue. B. :inally, do the in*erse. Write out a sim le formula and use the functions in the same way to calculate it. This e&ercise might really whac! your brain out, but ta!e it slow and easy and treat it li!e a little game. :iguring out uGGles li!e this is what ma!es rogramming fun, so I'll be gi*ing you more little roblems li!e this as we go.

Exercise ##: What 6o 7ou 8no9 So Far1


There won't be any code in this e&ercise or the ne&t one, so there's no W+// or 0&tra ;redit either. In fact, this e&ercise is li!e one giant 0&tra ;redit. I'm going to ha*e you do a form of re*iew what you ha*e learned so far. :irst, go bac! through e*ery e&ercise you ha*e done so far and write down e*ery word and symbol 5another name for 'character'6 that you ha*e used. )a!e sure your list of symbols is com lete. (B

Fe&t to each word or symbol, write its name and what it does. If you can't find a name for a symbol in this boo!, then loo! for it online. If you do not !now what a word or symbol does, then go read about it again and try using it in some code. +ou may run into a few things you ,ust can't find out or !now, so ,ust !ee those on the list and be ready to loo! them u when you find them. ?nce you ha*e your list, s end a few days rewriting the list and double chec!ing that it's correct. This may get boring but ush through and really nail it down. ?nce you ha*e memoriGed the list and what they do, then you should ste it u by writing out tables of symbols, their names, and what they do from memory. When you hit some you can't recall "rom memory, go bac! and memoriGe them again. Warnin! The most im ortant thing when doing this e&ercise is# "There is no failure, only trying."

What "o# are Learning


It's im ortant when you are doing a boring mindless memoriGation e&ercise li!e this to !now why. It hel s you focus on a goal and !now the ur ose of all your efforts. In this e&ercise you are learning the names of symbols so that you can read source code more easily. It's similar to learning the al habet and basic words of 0nglish, e&ce t that Ruby's al habet has e&tra symbols you might not !now. <ust ta!e it slow and do not hurt your brain. Ho efully by now these symbols are natural for you so this isn't a big effort. It's best to ta!e $C minutes at a time with your list and then ta!e a brea!. %i*ing your brain a rest will hel you learn faster with less frustration.

Exercise #%: Read So"e $ode


+ou should ha*e s ent last wee! getting your list of symbols straight and loc!ed in your mind. Fow you get to a ly this to another wee! reading code on the internet. This e&ercise will be daunting at first. I'm going to throw you in the dee end for a few days and ha*e you ,ust try your best to read and understand some source code from real ro,ects. The goal isn't to get you to understand code, but to teach you the following three s!ills# $. '. (. B. :inding Ruby source code for things you need. Reading through the code and loo!ing for files. Trying to understand code you find. -t your le*el you really do not ha*e the s!ills to e*aluate the things you find, but you can benefit from getting e& osure and seeing how things loo!.

(C

When you do this e&ercise, thin! of yourself as an anthro ologist, truc!ing through a new land with ,ust barely enough of the local language to get around and sur*i*e. 0&ce t, of course, that you will actually get out ali*e because the internet isn't a ,ungle. -nyway. Here's what you do# $. %o to github.com with your fa*orite web browser and search for "ruby". '. Pic! a random ro,ect and clic! on it. (. ;lic! on the /ource tab and browse through the list of files and directories until you find a .rb file. B. /tart at the to and read through it, ta!ing notes on what you thin! it does. C. If any symbols or strange words seem to interest you, write them down to research later. That's it. +our ,ob is to use what you !now so far and see if you can read the code and get a gras of what it does. Try s!imming the code first, and then read it in detail. )aybe also try ta!ing *ery difficult arts and reading each symbol you !now outloud. Fow try se*eral other sites#

hero!u.com rubygems.org bitbuc!et.org

?n each of these sites you may find weird files ending in .c so stic! to .rb files li!e the ones you ha*e written in this boo!. - final fun thing to do is use the abo*e four sources of Ruby code and ty e in to ics you are interested in instead of "ruby". /earch for ",ournalism", "coo!ing", " hysics", or anything you are curious about. ;hances are there's some code out there you could use right away.

Exercise #(: 'ore ractice


+ou are getting to the end of this section. +ou should ha*e enough Ruby "under your fingers" to mo*e onto learning about how rogramming really wor!s, but you should do some more ractice. This e&ercise is longer and all about building u stamina. The ne&t e&ercise will be similar. .o them, get them e&actly right, and do your chec!s.
1 puts BLetDs pra,ti,e everyt/ing.B puts BEou5D* nee* to )no8 5Dbout es,apes 8it/ 55 t/at *o 5n ne8lines an* 3 5t tabs.B ! # poe( K 99W.LT=NL=0:NST>=0X $ < 5tT/e lovely 8orl* & 8it/ logi, so +ir(ly plante* 9 ,annot *is,ern 5n t/e nee*s o+ love 1" nor ,o(pre/en* passion +ro( intuition 11 an* reLuires an explanation 1 5n5t5t8/ere t/ere is none. 13

(D

W.LT=NL=0:NST>=0X 1! 1# 1$ 1< 1& 19 " 1 3 ! # $ < & 9 3" 31 3 33 3! 3# 3$ 3< 3& puts B--------------B puts poe( puts B--------------B +ive K 1" 1 3 - $ puts BT/is s/oul* be +ive: -O+ivePB *e+ se,retN+or(ula@starte*A RellyNbeans K starte* I #"" Rars K RellyNbeans H 1""" ,rates K Rars H 1"" return RellyNbeansF RarsF ,rates en* startNpoint K 1"""" beansF RarsF ,rates K se,retN+or(ula@startNpointA puts BWit/ a starting point o+: -OstartNpointPB puts BWeD* /ave -ObeansP beansF -ORarsP RarsF an* -O,ratesP ,rates.B startNpoint K startNpoint H 1" puts BWe ,an also *o t/at t/is 8ay:B puts BWeD* /ave Js beansF Js RarsF an* Js ,rates.B J se,retN+or(ula@startNpointA

What "o# Sho#ld See


$ ruby ex !.rb LetDs pra,ti,e everyt/ing. EouD* nee* to )no8 Dbout es,apes 8it/ 5 t/at *o ne8lines an* tabs. -------------T/e lovely 8orl* 8it/ logi, so +ir(ly plante* ,annot *is,ern t/e nee*s o+ love nor ,o(pre/en* passion +ro( intuition an* reLuires an explanation 8/ere t/ere is none. -------------T/is s/oul* be +ive: # Wit/ a starting point o+: 1"""" WeD* /ave #"""""" beansF #""" RarsF an* #" ,rates. We ,an also *o t/at t/is 8ay: WeD* /ave #""""" beansF #"" RarsF an* # ,rates. $

(%tra Credit
$. )a!e sure to do your chec!s# read it bac!wards, read it out loud, ut comments abo*e confusing arts. '. 2rea! the file on ur ose, then run it to see what !inds of errors you get. )a!e sure you can fi& it.

(H

Exercise #+: E:en 'ore ractice


We're going to do some more ractice in*ol*ing functions and *ariables to ma!e sure you !now them well. This e&ercise should be straight forward for you to ty e in, brea! down, and understand. Howe*er, this e&ercise is a little different. +ou won't be running it. Instead you will im ort it into your Ruby inter reter and run the functions yourself.
1 (o*ule :x # *e+ sel+.brea)N8or*s@stu++A 3 - T/is +un,tion 8ill brea) up 8or*s +or us. ! 8or*s K stu++.split@D DA # 8or*s $ en* < & *e+ sel+.sortN8or*s@8or*sA 9 - Sorts t/e 8or*s. 1" 8or*s.sort@A 11 en* 1 13 *e+ sel+.printN+irstN8or*@8or*sA 1! - 3rints t/e +irst 8or* an* s/i+ts t/e ot/ers *o8n by one. 1# 8or* K 8or*s.s/i+t@A 1$ puts 8or* 1< en* 1& 19 *e+ sel+.printNlastN8or*@8or*sA " - 3rints t/e last 8or* a+ter popping it o++ t/e en*. 1 8or* K 8or*s.pop@A puts 8or* 3 en* ! # *e+ sel+.sortNsenten,e@senten,eA $ - Ta)es in a +ull senten,e an* returns t/e sorte* 8or*s. < 8or*s K brea)N8or*s@senten,eA & sortN8or*s@8or*sA 9 en* 3" 31 *e+ sel+.printN+irstNan*Nlast@senten,eA 3 - 3rints t/e +irst an* last 8or*s o+ t/e senten,e. 33 8or*s K brea)N8or*s@senten,eA 3! printN+irstN8or*@8or*sA 3# printNlastN8or*@8or*sA 3$ en* 3< 3& *e+ sel+.printN+irstNan*NlastNsorte*@senten,eA 39 - Sorts t/e 8or*s t/en prints t/e +irst an* last one. !" 8or*s K sortNsenten,e@senten,eA !1 printN+irstN8or*@8or*sA ! printNlastN8or*@8or*sA !3 en* !! en*

:irst, run this li!e normal with ruby ex #.rb to find any errors you ha*e made. ?nce you ha*e found all of the errors you can and fi&ed them, you will then want to follow the W+// section to com lete the e&ercise. (4

What "o# Sho#ld See


In this e&ercise we're going to interact with your .rb file inside the Ruby inter reter 5IR26 you used eriodically to do calculations. Here's what it loo!s li!e when I do it#
$ irb irb@(ainA:""1:"' reLuire D.Hex #D K' true irb@(ainA:"" :"' senten,e K BAll goo* t/ings ,o(e to t/ose 8/o 8ait.B K' BAll goo* t/ings ,o(e to t/ose 8/o 8ait.B irb@(ainA:""3:"' 8or*s K :x #.brea)N8or*s@senten,eA K' TBAllBF Bgoo*BF Bt/ingsBF B,o(eBF BtoBF Bt/oseBF B8/oBF B8ait.BU irb@(ainA:""!:"' sorte*N8or*s K :x #.sortN8or*s@8or*sA K' TBAllBF B,o(eBF Bgoo*BF Bt/ingsBF Bt/oseBF BtoBF B8ait.BF B8/oBU irb@(ainA:""#:"' :x #.printN+irstN8or*@8or*sA All K' nil irb@(ainA:""$:"' :x #.printNlastN8or*@8or*sA 8ait. K' nil irb@(ainA:""<:"' :x #.8ro*s 0oWet/o*:rror: un*e+ine* (et/o* Q8ro*sD +or :x #:Wo*ule +ro( @irbA:$ irb@(ainA:""&:"' 8or*s K' TBgoo*BF Bt/ingsBF B,o(eBF BtoBF Bt/oseBF B8/oBU irb@(ainA:""9:"' :x #.printN+irstN8or*@sorte*N8or*sA All K' nil irb@(ainA:"1":"' :x #.printNlastN8or*@sorte*N8or*sA 8/o K' nil irb@(ainA:"11:"' sorte*N8or*s K' TB,o(eBF Bgoo*BF Bt/ingsBF Bt/oseBF BtoBF B8ait.BU irb@(ainA:"1 :"' :x #.sortNsenten,e@senten,eA K' TBAllBF B,o(eBF Bgoo*BF Bt/ingsBF Bt/oseBF BtoBF B8ait.BF B8/oBU irb@(ainA:"13:"' :x #.printN+irstNan*Nlast@senten,eA All 8ait. K' nil irb@(ainA:"1!:"' :x #.printN+irstNan*NlastNsorte*@senten,eA All 8/o K' nil irb@(ainA:"1#:"' ^D $

Let's brea! this down line by line to ma!e sure you !now what's going on# $. Line ' you re3uire your .Hex #.rb Ruby file, ,ust li!e other re3uires you ha*e done. Fotice you do not need to ut the .rb at the end to re3uire it. When you do this you ma!e a (o*ule that has all your functions in it to use. '. Line B you made a senten,e to wor! with. (. Line D you use the :x # module and call your first function :x #.brea)N8or*s. The . 5dot, eriod6 symbol is how you tell Ruby, "Hey, inside :x # there's a function called brea)N8or*s and I want to run it." (>

B. Line 4 we do the same thing with :x #.sortN8or*s to get a sorted sentence. C. Lines $81$C we use :x #.printN+irstN8or* and :x #.printNlastN8or* to get the first and last word rinted out. D. Line $D is interesting. I made a mista!e and ty ed the 8or*s *ariable as 8ro*s so Ruby ga*e me an error on Lines $H1$4. H. Lines $>1'8 is where we rint the modified words list. Fotice that since we rinted the first and last one, those words are now missing. 4. The remaining lines are for you to figure out and analyGe in the e&tra credit.

(%tra Credit
$. Ta!e the remaining lines of the W+// out ut and figure out what they are doing. )a!e sure you understand how you are running your functions in the 0&'C module. '. The reason we ut our functions in a (o*ule is so they ha*e their own names ace. If someone else writes a function called brea)N8or*s, we won't collide. Howe*er, if ty ing :x #. is annoying, you can ty e in,lu*e :x # which is li!e saying, "Include e*erything from the 0&'C module in my current module." (. Try brea!ing your file and see what it loo!s li!e in Ruby when you use it. +ou will ha*e to 3uit IR2 with ;TRL1. to be able to reload it.

Exercise #,: $on!ratu*ations/ Ta2e A Test;


+ou are almost done with the first half of the boo!. The second half is where things get interesting. +ou will learn logic and be able to do useful things li!e ma!e decisions. 2efore you continue, I ha*e a 3uiG for you. This 3uiG will be *ery hard because it re3uires you to fi& someone else's code. When you are a rogrammer you often ha*e to deal with another rogrammer's code, and also with their arrogance. They will *ery fre3uently claim that their code is erfect. These rogrammers are stu id eo le who care little for others. - good rogrammer assumes, li!e a good scientist, that there's always some robability their code is wrong. %ood rogrammers start from the remise that their software is bro!en and then wor! to rule out all ossible ways it could be wrong before finally admitting that maybe it really is the other guy's code. In this e&ercise, you will ractice dealing with a bad rogrammer by fi&ing a bad rogrammer's code. I ha*e oorly co ied e&ercises 'B and 'C into a file and remo*ed random characters and added flaws. )ost of the errors are things Ruby will tell you, while some of them are math errors you should find. ?thers are formatting errors or s elling mista!es in the strings. -ll of these errors are *ery common mista!es all rogrammers ma!e. 0*en e& erienced ones. +our ,ob in this e&ercise is to correct this file. Ese all of your s!ills to ma!e this file better. -nalyGe it first, maybe rinting it out to edit it li!e you would a school term a er. :i& each flaw and !ee running it and fi&ing it until the scri t runs erfectly. Try not to get hel , and instead if you get stuc! ta!e a brea! and come bac! to it later.

B8

0*en if this ta!es days to do, bust through it and ma!e it right. :inally, the oint of this e&ercise isn't to ty e it in, but to fi& an e&isting file. To do that, you must go to# htt #AAruby.learncodethehardway.orgAboo!Ae&ercise'D.t&t ;o y1 aste the code into a file named ex $.rb. This is the only time you are allowed to co y1 aste.
- T/is +un,tion 8ill brea) up 8or*s +or us. *e+ brea)N8or*s@stu++A 8or*s K stu++.split@D DA return 8or*s en* - Sorts t/e 8or*s. *e+ sortN8or*s@8or*sA return sorte*@8or*sA en* - 3rints t/e +irst 8or* a+ter popping it o++. *e+ putsN+irstN8or*@8or*sA 8or* K 8or*s.poop@"A puts 8or* en* - 3rints t/e last 8or* a+ter popping it o++. *e+ putsNlastN8or*@8or*sA 8or* K 8or*s.pop@-1 puts 8or* en* - Ta)es in a +ull senten,e an* returns t/e sorte* 8or*s. *e+ sortNsenten,e@senten,eA 8or*s K brea)N8or*s@senten,eA return sortN8or*s@8or*sA en* - 3uts t/e +irst an* last 8or*s o+ t/e senten,e. *e+ putsN+irstNan*Nlast@senten,eA 8or*s K brea)N8or*s@senten,eA putsN+irstN8or*@8or*sA putsNlastN8or*@8or*sA en* - Sorts t/e 8or*s t/en prints t/e +irst an* last one. *e+ putsN+irstNan*NlastNsorte*@senten,eA 8or*s K sortNsenten,e@senten,eA putsN+irstN8or*@8or*sA putsNlastN8or*@8or*sA en* puts BLetDs pra,ti,e everyt/ing.B puts DEou5D* nee* to )no8 5Dbout es,apes 8it/ 55 t/at *o 5n ne8lines an* 5t tabs.D poe( K 993G:W

B$

5tT/e lovely 8orl* 8it/ logi, so +ir(ly plante* ,annot *is,ern 5n t/e nee*s o+ love nor ,o(pre/en* passion +ro( intuition an* reLuires an explantion 5n5t5t8/ere t/ere is none. 3G:W puts B--------------B puts poe( puts B--------------B +ive K 1" 1 3 - # puts BT/is s/oul* be +ive: JsB J +ive *e+ se,retN+or(ula@starte*A RellyNbeans K starte* I #"" Rars K RellyNbeans 5 1""" ,rates K Rars H 1"" return RellyNbeansF RarsF ,rates en* startNpoint K 1"""" beansF RarsF ,rates KK se,retN+or(ula@start-pointA puts BWit/ a starting point o+: J*B J startNpoint puts BWeD* /ave J* ReansF J* RarsF an* J* ,rates.B J @beansF RarsF ,ratesA startNpoint K startNpoint H 1" puts BWe ,an also *o t/at t/is 8ay:B puts BWeD* /ave J* beansF J* RarsF an* J* ,rabapples.B J se,retN+or(ula@startNpont senten,e K BAll go*5tt/ings ,o(e to t/ose 8/o 8eig/t.B 8or*s K ex #.brea)N8or*s@senten,eA sorte*N8or*s K ex #.sortN8or*s@8or*sA putsN+irstN8or*@8or*sA putsNlastN8or*@8or*sA .putsN+irstN8or*@sorte*N8or*sA putsNlastN8or*@sorte*N8or*sA sorte*N8or*s K ex #.sortNsenten,e@senten,eA prin sorte*N8or*s putsNirstNan*Nlast@senten,eA putsN+irstNaNlastNsorte*@senen,eA

Exercise #-: 'e"ori<in! Lo!ic


Today is the day you start learning about logic. E to this oint you ha*e done e*erything you ossibly can reading and writing files, to the terminal, and ha*e learned 3uite a lot of the math ca abilities of Ruby.

B'

:rom now on, you will be learning logic. +ou won't learn com le& theories that academics lo*e to study, but ,ust the sim le basic logic that ma!es real rograms wor! and that real rogrammers need e*ery day. Learning logic has to come after you do some memoriGation. I want you to do this e&ercise for an entire wee!. .o not falter. 0*en if you are bored out of your mind, !ee doing it. This e&ercise has a set of logic tables you must memoriGe to ma!e it easier for you to do the later e&ercises. I'm warning you this won't be fun at first. It will be downright boring and tedious but this is to teach you a *ery im ortant s!ill you will need as a rogrammer. +ou will need to be able to memoriGe im ortant conce ts as you go in your life. )ost of these conce ts will be e&citing once you get them. +ou will struggle with them, li!e wrestling a s3uid, then one day sna you will understand it. -ll that wor! memoriGing the basics ays off big later. Here's a ti on how to memoriGe something without going insane# .o a tiny bit at a time throughout the day and mar! down what you need to wor! on most. .o not try to sit down for two hours straight and memoriGe these tables. This won't wor!. +our brain will really only retain whate*er you studied in the first $C or (8 minutes anyway. Instead, what you should do is create a bunch of inde& cards with each column on the left on one side 5True or :alse6 and the column on the right on the bac!. +ou should then ull them out, see the "True or :alse" and be able to immediately say "TrueO" 7ee racticing until you can do this. ?nce you can do that, start writing out your own truth tables each night into a noteboo!. .o not ,ust co y them. Try to do them from memory, and when you get stuc! glance 3uic!ly at the ones I ha*e here to refresh your memory. .oing this will train your brain to remember the whole table. .o not s end more than one wee! on this, because you will be a lying it as you go.

The Tr#th Ter+s


In Ruby we ha*e the following terms 5characters and hrases6 for determining if something is "true" or "false". Logic on a com uter is all about seeing if some combination of these characters and some *ariables is True at that oint in the rogram.
an* or not CK 5not e3ual6 KK 5e3ual6 'K 5greater1than1e3ual6 9K 5less1than1e3ual6

true false

+ou actually ha*e run into these characters before, but maybe not the hrases. The hrases 5and, or, not6 actually wor! the way you e& ect them to, ,ust li!e in 0nglish. B(

The Tr#th Ta/les


We will now use these characters to ma!e the truth tables you need to memoriGe. &=T True1

not :alse True not True :alse =R True1 True or :alse True True or True True :alse or True True :alse or :alse :alse A&6 True1 True and :alse :alse True and True True :alse and True :alse :alse and :alse :alse &=T =R True1 not 5True or :alse6 :alse not 5True or True6 :alse not 5:alse or True6 :alse not 5:alse or :alse6 True &=T A&6 True1 not 5True and :alse6 True not 5True and True6 :alse not 5:alse and True6 True not 5:alse and :alse6 True ;> True1 $ OS 8 True $ OS $ :alse 8 OS $ True 8 OS 8 :alse >> True1 $ SS 8 :alse $ SS $ True 8 SS $ :alse 8 SS 8 True

BB

Fow use these tables to write u your own cards and s end the wee! memoriGing them. Remember though, there is no failing in this boo!, ,ust trying as hard as you can each day, and then a little bit more.

Exercise #.: ?oo*ean ractice


The logic combinations you learned from the last e&ercise are called "boolean" logic e& ressions. 2oolean logic is used e*erywhere in rogramming. They are essential fundamental arts of com utation and !nowing them *ery well is a!in to !nowing your scales in music. In this e&ercise you will be ta!ing the logic e&ercises you memoriGed and start trying them out in IR2. Ta!e each of these logic roblems, and write out what you thin! the answer will be. In each case it will be either true or false. ?nce you ha*e the answers written down, you will start IR2 in your terminal and ty e them in to confirm your answers.
1. true an* true . +alse an* true 3. 1 KK 1 an* KK 1 !. BtestB KK BtestB #. 1 KK 1 or CK 1 $. true an* 1 KK 1 <. +alse an* " CK " &. true or 1 KK 1 9. BtestB KK BtestingB 1". 1 CK " an* KK 1 11. BtestB CK BtestingB 1 . BtestB KK 1 13. not @true an* +alseA 1!. not @1 KK 1 an* " CK 1A 1#. not @1" KK 1 or 1""" KK 1"""A 1$. not @1 CK 1" or 3 KK !A 1<. not @BtestingB KK BtestingB an* B6e*B KK B2ool XuyBA 1&. 1 KK 1 an* not @BtestingB KK 1 or 1 KK "A 19. B,/un)yB KK Bba,onB an* not @3 KK ! or 3 KK 3A ". 3 KK 3 an* not @BtestingB KK BtestingB or B>ubyB KK B?unBA

I will also gi*e you a tric! to hel you figure out the more com licated ones toward the end. Whene*er you see these boolean logic statements, you can sol*e them easily by this sim le rocess# $. '. (. B. C. :ind e3uality test 5KK or CK6 and re lace it with its truth. :ind each andAor inside a arenthesis and sol*e those first. :ind each not and in*ert it. :ind any remaining andAor and sol*e it. When you are done you should ha*e true or false.

I will demonstrate with a *ariation on R'8#


3 CK ! an* not @BtestingB CK BtestB or B>ubyB KK B>ubyBA

BC

Here's me going through each of the ste s and showing you the translation until I'*e boiled it down to a single result# $. /ol*e each e3uality test# o 3 CK ! is True# true an* not @BtestingB CK BtestB or B>ubyB KK
B>ubyBA o BtestingB CK BtestB is True# true an* not @true or B>ubyB KK B>ubyBA o B>ubyB KK B>ubyB# true an* not @true or trueA :ind each andAor in arenthesis @A# o @true or trueA is True# true an* not @trueA ( :ind each not and in*ert

'.

it# is Fa*se# true an* +alse (. :ind any remaining andAor and sol*e them# o true an* +alse is Fa*se
o not @trueA

With that we're done and !now the result is false. Warnin! The more com licated ones may seem *ery hard at first. +ou should be able to gi*e a good first stab at sol*ing them, but do not get discouraged. I'm ,ust getting you rimed for more of these "logic gymnastics" so that later cool stuff is much easier. <ust stic! with it, and !ee trac! of what you get wrong, but do not worry that it's not getting in your head 3uite yet. It'll come.

What "o# Sho#ld See


-fter you ha*e tried to guess at these, this is what your session with IR2 might loo! li!e#
$ irb ruby-1.9. -p1&" :""1 ' true an* true K' true ruby-1.9. -p1&" :"" ' 1 KK 1 an* KK K' true

(%tra Credit
$. There are a lot of o erators in Ruby similar to CK and KK. Try to find out as many "e3uality o erators" as you can. They should be li!e# 9 or 9K. '. Write out the names of each of these e3uality o erators. :or e&am le, I call CK "not e3ual". (. Play with IR2 by ty ing out new boolean o erators, and before you hit enter try to shout out what it is. .o not thin! about it, ,ust the first thing that comes to mind. Write it down then hit enter, and !ee trac! of how many you get right and wrong. Throw away that iece of a er from R( away so you do not accidentally try to use it later.

BD

Exercise #0: What I5


Here is the ne&t scri t of Ruby you will enter, which introduces you to the i+-state(ent. Ty e this in, ma!e it run e&actly right, and then we'll try see if your ractice has aid off.
1 people K " ,ats K 3" 3 *ogs K 1# ! # i+ people 9 $ puts BToo < en* & 9 i+ people ' 1" puts B0ot 11 en* 1 13 i+ people 9 1! puts BT/e 1# en* 1$ 1< i+ people ' 1& puts BT/e 19 en* " 1 *ogs 1K # 3 ! # $ < & 9 3" 31 3 33

,ats (any ,atsC T/e 8orl* is *oo(e*CB ,ats (any ,atsC T/e 8orl* is save*CB *ogs 8orl* is *roole* onCB *ogs 8orl* is *ryCB

i+ people 'K *ogs puts B3eople are greater t/an or eLual to *ogs.B en* i+ people 9K *ogs puts B3eople are less t/an or eLual to *ogs.B en* i+ people KK *ogs puts B3eople are *ogs.B en*

What "o# Sho#ld See


$ ruby ex 9.rb Too (any ,atsC T/e 8orl* is *oo(e*C T/e 8orl* is *ryC 3eople are greater t/an or eLual to *ogs. 3eople are less t/an or eLual to *ogs. 3eople are *ogs. $

(%tra Credit
In this e&tra credit, try to guess what you thin! the i+-state(ent is and what it does. Try to answer these 3uestions in your own words before mo*ing onto the ne&t e&ercise# $. What do you thin! the i+ does to the code under itL '. ;an you ut other boolean e& ressions from 0&. 'H in the i+-state(entL Try it. (. What ha ens if you change the initial *ariables for eo le, cats, and dogsL BH

Exercise %0: E*se And I5


In the last e&ercise you wor!ed out some i+-state(ents, and then tried to guess what they are and how they wor!. 2efore you learn more I'll e& lain what e*erything is by answering the 3uestions you had from e&tra credit. +ou did the e&tra credit rightL $. What do you thin! the if does to the code under itL -n i+ statement creates what is called a "branch" in the code. It's !ind of li!e those choose your own ad*enture boo!s where you are as!ed to turn to one age if you ma!e one choice, and another if you go a different direction. The i+-state(ent tells your scri t, "If this boolean e& ression is True, then run the code under it, otherwise s!i it." '. ;an you ut other boolean e& ressions from 0&. 'H in the i+ statementL Try it. +es you can, and they can be as com le& as you li!e, although really com le& things generally are bad style. (. What ha ens if you change the initial *alues for eo le, cats, and dogsL 2ecause you are com aring numbers, if you change the numbers, different i+-state(ents will e*aluate to True and the bloc!s of code under them will run. %o bac! and ut different numbers in and see if you can figure out in your head what bloc!s of code will run. ;om are my answers to your answers, and ma!e sure you really understand the conce t of a "bloc!" of code. This is im ortant for when you do the ne&t e&ercise where you write all the arts of i+-state(ents that you can use. Ty e this one in and ma!e it wor! too.
1 people K 3" ,ars K !" 3 buses K 1# ! # i+ ,ars ' people $ puts BWe s/oul* ta)e t/e ,ars.B < elsi+ ,ars 9 people & puts BWe s/oul* not ta)e t/e ,ars.B 9 else 1" puts BWe ,anDt *e,i*e.B 11 en* 1 13 i+ buses ' ,ars 1! puts BT/atDs too (any buses.B 1# elsi+ buses 9 ,ars 1$ puts BWaybe 8e ,oul* ta)e t/e buses.B 1< else 1& puts BWe still ,anDt *e,i*e.B 19 en* " 1 i+ people ' buses puts BAlrig/tF letDs Rust ta)e t/e buses.B 3 else ! puts B?ineF letDs stay /o(e t/en.B # en*

B4

What "o# Sho#ld See


$ ruby ex3".rb We s/oul* ta)e t/e ,ars. Waybe 8e ,oul* ta)e t/e buses. Alrig/tF letDs Rust ta)e t/e buses. $

(%tra Credit
$. Try to guess what elsi+ and else are doing. '. ;hange the numbers of ,ars, people, and buses and then trace through each i+state(ent to see what will be rinted. (. Try some more com le& boolean e& ressions li!e ,ars ' people an* buses 9 ,ars. -bo*e each line write an 0nglish descri tion of what the line does.

Exercise %1: 'a2in! 6ecisions


In the first half of this boo! you mostly ,ust rinted out things and called functions, but e*erything was basically in a straight line. +our scri ts ran starting at the to , and went to the bottom where they ended. If you made a function you could run that function later, but it still didn't ha*e the !ind of branching you need to really ma!e decisions. Fow that you ha*e i+, else, and elsi+ you can start to ma!e scri ts that decide things. In the last scri t you wrote out a sim le set of tests as!ing some 3uestions. In this scri t you will as! the user 3uestions and ma!e decisions based on their answers. Write this scri t, and then lay with it 3uite a lot to figure it out.
1 *e+ pro(pt print B' B 3 en* ! # puts BEou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or $ *oor - MB < & pro(pt[ *oor K gets.,/o(p 9 1" i+ *oor KK B1B 11 puts BT/ereDs a giant bear /ere eating a ,/eese ,a)e. W/at *o you *oMB 1 puts B1. Ta)e t/e ,a)e.B 13 puts B . S,rea( at t/e bear.B 1! 1# pro(pt[ bear K gets.,/o(p 1$ 1< i+ bear KK B1B 1& puts BT/e bear eats your +a,e o++. Xoo* RobCB 19 elsi+ bear KK B B " puts BT/e bear eats your legs o++. Xoo* RobCB 1 else puts BWellF *oing -ObearP is probably better. Sear runs a8ay.B 3 en* ! # elsi+ *oor KK B B $ puts BEou stare into t/e en*less abyss at 2t/u/luDs retina.B < puts B1. Slueberries.B & puts B . Eello8 Ra,)et ,lot/espins.B

B>

puts B3. .n*erstan*ing revolvers yelling (elo*ies.B 9 3" pro(pt[ insanity K gets.,/o(p 31 3 i+ insanity KK B1B or insanity KK B B 33 puts BEour bo*y survives po8ere* by a (in* o+ Rello. Xoo* RobCB 3! else 3# puts BT/e insanity rots your eyes into a pool o+ (u,). Xoo* RobCB 3$ en* 3< 3& else 39 puts BEou stu(ble aroun* an* +all on a )ni+e an* *ie. Xoo* RobCB !" en*

- !ey oint here is that you are now utting the i+-state(ents inside i+-state(ents as code that can run. This is *ery owerful and can be used to create "nested" decisions, where one branch leads to another and another. )a!e sure you understand this conce t of i+-state(ents inside i+-state(ents. In fact, do the e&tra credit to really nail it.

What "o# Sho#ld See


Here is me laying this little ad*enture game. I do not do so well.
$ ruby ex31.rb Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' 1 T/ereDs a giant bear /ere eating a ,/eese ,a)e. W/at *o you *oM 1. Ta)e t/e ,a)e. . S,rea( at t/e bear. ' T/e bear eats your legs o++. Xoo* RobC $ ruby ex31.rb Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' 1 T/ereDs a giant bear /ere eating a ,/eese ,a)e. W/at *o you *oM 1. Ta)e t/e ,a)e. . S,rea( at t/e bear. ' 1 T/e bear eats your +a,e o++. Xoo* RobC $ ruby ex31.rb Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' Eou stare into t/e en*less abyss at 2t/u/luDs retina. 1. Slueberries. . Eello8 Ra,)et ,lot/espins. 3. .n*erstan*ing revolvers yelling (elo*ies. ' 1 Eour bo*y survives po8ere* by a (in* o+ Rello. Xoo* RobC $ ruby ex31.rb

C8

Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' Eou stare into t/e en*less abyss at 2t/u/luDs retina. 1. Slueberries. . Eello8 Ra,)et ,lot/espins. 3. .n*erstan*ing revolvers yelling (elo*ies. ' 3 T/e insanity rots your eyes into a pool o+ (u,). Xoo* RobC $ ruby ex31.rb Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' stu++ Eou stu(ble aroun* an* +all on a )ni+e an* *ie. Xoo* RobC $ ruby ex31.rb Eou enter a *ar) roo( 8it/ t8o *oors. Do you go t/roug/ *oor -1 or *oor - M ' 1 T/ereDs a giant bear /ere eating a ,/eese ,a)e. W/at *o you *oM 1. Ta)e t/e ,a)e. . S,rea( at t/e bear. ' apples WellF *oing apples is probably better. Sear runs a8ay.

(%tra Credit
)a!e new arts of the game and change what decisions eo le can ma!e. 0& and the game out as much as you can before it gets ridiculous.

Exercise %#: Loops And Arrays


+ou should now be able to do some rograms that are much more interesting. If you ha*e been !ee ing u , you should realiGe that now you can combine all the other things you ha*e learned with i+-state(ents and boolean e& ressions to ma!e your rograms do smart things. Howe*er, rograms also need to do re etiti*e things *ery 3uic!ly. We are going to use a +or-loop in this e&ercise to build and rint *arious arrays. When you do the e&ercise, you will start to figure out what they are. I won't tell you right now. +ou ha*e to figure it out. 2efore you can use a +or-loop, you need a way to store the results of loo s somewhere. The best way to do this is with an array. -n array is a container of things that are organiGed in order. It's not com licated" you ,ust ha*e to learn a new synta&. :irst, there's how you ma!e an array#
/airs K TDbro8nDF Dblon*DF Dre*DU eyes K TDbro8nDF DblueDF DgreenDU 8eig/ts K T1F F 3F !U

What you do is start the array with the T 5left1brac!et6 which "o ens" the array. Then you ut each item you want in the array se arated by commas, ,ust li!e when you did function

C$

arguments. Lastly you end the array with a U 5right1brac!et6 to indicate that it's o*er. Ruby then ta!es this array and all its contents, and assigns them to the *ariable. Warnin! This is where things get tric!y for eo le who can't rogram. +our brain has been taught that the world is flat. Remember in the last e&ercise where you ut i+-state(ents inside i+state(entsL That robably made your brain hurt because most eo le do not onder how to "nest" things inside things. In rogramming this is all o*er the lace. +ou will find functions that call other functions that ha*e i+-state(ents that ha*e arrays with arrays inside arrays. If you see a structure li!e this that you can't figure out, ta!e out encil and a er and brea! it down manually bit by bit until you understand it. We now will build some arrays using some loo s and rint them out#
1 t/eN,ount K T1F F 3F !F #U +ruits K TDapplesDF DorangesDF DpearsDF Dapri,otsDU 3 ,/ange K T1F DpenniesDF F D*i(esDF 3F DLuartersDU ! # - t/is +irst )in* o+ +or-loop goes t/roug/ an array $ +or nu(ber in t/eN,ount < puts BT/is is ,ount -Onu(berPB & en* 9 1" - sa(e as aboveF but using a blo,) instea* 11 +ruits.ea,/ *o Y+ruitY 1 puts BA +ruit o+ type: -O+ruitPB 13 en* 1! 1# - also 8e ,an go t/roug/ (ixe* arrays too 1$ +or i in ,/ange 1< puts B= got -OiPB 1& en* 19 " - 8e ,an also buil* arraysF +irst start 8it/ an e(pty one 1 ele(ents K TU 3 ! # $ < & 9 3" 31 3 33 - t/en use a range obRe,t to *o " to # ,ounts +or i in @"..#A puts BA**ing -OiP to t/e list.B - pus/ is a +un,tion t/at arrays un*erstan* ele(ents.pus/@iA en* - no8 8e ,an puts t/e( out too +or i in ele(ents puts B:le(ent 8as: -OiPB en*

What "o# Sho#ld See


$ ruby ex3 .rb T/is is ,ount 1 T/is is ,ount T/is is ,ount 3 T/is is ,ount ! T/is is ,ount # A +ruit o+ type: apples

C'

A +ruit o+ type: oranges A +ruit o+ type: pears A +ruit o+ type: apri,ots = got 1 = got DpenniesD = got = got D*i(esD = got 3 = got DLuartersD A**ing " to t/e list. A**ing 1 to t/e list. A**ing to t/e list. A**ing 3 to t/e list. A**ing ! to t/e list. A**ing # to t/e list. :le(ent 8as: " :le(ent 8as: 1 :le(ent 8as: :le(ent 8as: 3 :le(ent 8as: ! :le(ent 8as: # $

(%tra Credit
$. Ta!e a loo! at how you used the range @"..#A. Loo! u the >ange class to understand it. '. ;ould you ha*e a*oided that +or-loop entirely on line 'B and ,ust assigned @"..#A directly to ele(entsL (. :ind the Ruby documentation on arrays and read about them. What other o erations can you do to arrays besides pus/L

Exercise %%: Whi*e Loops


Fow to totally blow your mind with a new loo , the 8/ile-loop. - 8/ile-loop will !ee e&ecuting the code bloc! under it as long as a boolean e& ression is True. Wait, you ha*e been !ee ing u with the terminology rightL That if we write a statement such as i+ ite(s ' # or +or +ruit in +ruits we are starting a code bloc!. Then we indent the lines that follow, which are said to be within the bloc!, until we reach an en* statement, which closes the bloc!. This is all about structuring your rograms so that Ruby !nows what you mean. If you do not get that idea then go bac! and do some more wor! with i+-state(ents, functions, and the +or-loop until you get it. Later on we'll ha*e some e&ercises that will train your brain to read these structures, similar to how we burned boolean e& ressions into your brain. 2ac! to 8/ile-loops. What they do is sim ly do a test li!e an i+-state(ent, but instead of running the code bloc! once, they ,um bac! to the "to " where the 8/ile is, and re eat. It !ee s doing this until the e& ression is Fa*se.

C(

Here's the roblem with 8/ile-loops# sometimes they do not sto . This is great if your intention is to ,ust !ee loo ing until the end of the uni*erse. ?therwise you almost always want your loo s to end e*entually. To a*oid these roblems, there's some rules to follow# $. )a!e sure that you use 8/ile-loops s aringly. Esually a +or-loop is better. '. Re*iew your 8/ile statements and ma!e sure that the thing you are testing will become Fa*se at some oint. (. When in doubt, rint out your test *ariable at the to and bottom of the 8/ile-loop to see what it's doing. In this e&ercise, you will learn the 8/ile-loop by doing the abo*e three things#
1i K " nu(bers K TU 3 ! 8/ile i 9 $ # puts BAt t/e top i is -OiPB $ nu(bers.pus/@iA < & i K i 1 1 9 puts B0u(bers no8: -Onu(bersPB 1" puts BAt t/e botto( i is -OiPB 11 en* 1 13 puts BT/e nu(bers: B 1! 1# +or nu( in nu(bers 1$ puts nu( 1< en*

What "o# Sho#ld See


$ ruby ex33.rb At t/e top i is " 0u(bers no8: T"U At t/e botto( i is 1 At t/e top i is 1 0u(bers no8: T"F 1U At t/e botto( i is At t/e top i is 0u(bers no8: T"F 1F At t/e botto( i is 3 At t/e top i is 3 0u(bers no8: T"F 1F At t/e botto( i is ! At t/e top i is ! 0u(bers no8: T"F 1F At t/e botto( i is # At t/e top i is # 0u(bers no8: T"F 1F At t/e botto( i is $ T/e nu(bers: " 1 3

U F 3U F 3F !U F 3F !F #U

CB

! #

(%tra Credit
$. ;on*ert this 8/ile loo to a function that you can call, and re lace D in the test @i 9 $A with a *ariable. '. Fow use this function to rewrite the scri t to try different numbers. (. -dd another *ariable to the function arguments that you can ass in that lets you change the 1 1 on line 4 so you can change how much it increments by. B. Rewrite the scri t again to use this function to see what effect that has. C. Fow, write it to use +or-loops and ranges instead. .o you need the incrementor in the middle anymoreL What ha ens if you do not get rid of itL If at any time that you are doing this it goes craGy 5it robably will6, ,ust hold down ;TRL and hit c 5;TRL1c6 and the rogram will abort.

Exercise %(: Accessin! E*e"ents =5 Arrays


-rrays are retty useful, but unless you can get at the things in them they aren't all that great. +ou can already go through the elements of a list in order, but what if you want say, the Cth elementL +ou need to !now how to access the elements of an array. Here's how you would access the first element of an array#
ani(als K TDbearDF DtigerDF DpenguinDF DZebraDU bear K ani(alsT"U

+ou ta!e a list of animals, and then you get the first one using "LO How does that wor!L 2ecause of the way math wor!s, Ruby start its lists at 8 rather than $. It seems weird, but there's many ad*antages to this, e*en though it is mostly arbitrary. The best way to e& lain why is by showing you the difference between how you use numbers and how rogrammers use numbers. Imagine you are watching the four animals in our array abo*e 5TDbearDF DtigerDF DpenguinDF DZebraDU6 run in a race. They win in the order we ha*e them in this array. The race was really e&citing because the animals didn't eat each other and somehow managed to run a race. +our friend, howe*er, shows u late and wants to !now who won. .oes your friend say, "Hey, who came in GerothL" Fo, he says, "Hey, who came in firstL" This is because the order of the animals is im ortant. +ou can't ha*e the second animal without the first animal, and can't ha*e the third without the second. It's also im ossible to ha*e a "Geroth" animal since Gero means nothing. How can you ha*e a nothing win a raceL It ,ust doesn't ma!e sense. We call these !inds of numbers "ordinal" numbers, because they indicate an ordering of things. Programmers, howe*er, can't thin! this way because they can ic! any element out of a list at any oint. To a rogrammer, the abo*e list is more li!e a dec! of cards. If they want the tiger, they grab it. If they want the Gebra, they can ta!e it too. This need to ull elements out of lists at random means that they need a way to indicate elements consistently by an address, or an

CC

"inde&", and the best way to do that is to start the indices at 8. Trust me on this, the math is way easier for these !inds of accesses. This !ind of number is a "cardinal" number and means you can ic! at random, so there needs to be a 8 element. /o, how does this hel you wor! with arraysL /im le, e*ery time you say to yourself, "I want the (rd animal," you translate this "ordinal" number to a "cardinal" number by subtracting $. The "(rd" animal is at inde& ' and is the enguin. +ou ha*e to do this because you ha*e s ent your whole life using ordinal numbers, and now you ha*e to thin! in cardinal. <ust subtract $ and you will be good. Remember# ordinal SS ordered, $st" cardinal SS cards at random, 8. Let's ractice this. Ta!e this list of animals, and follow the e&ercises where I tell you to write down what animal you get for that ordinal or cardinal number. Remember if I say "first", "second", etc. then I'm using ordinal, so subtract $. If I gi*e you cardinal 58, $, '6 then use it directly.
ani(als K TDbearDF Dpyt/onDF Dpea,o,)DF D)angarooDF D8/aleDF DplatypusDU

The animal at $. The (rd animal. The $st animal. The animal at (. The Cth animal. The animal at '. The Dth animal. The animal at B. :or each of these, write out a full sentence of the form# "The $st animal is at 8 and is a bear." Then say it bac!wards, "The animal at 8 is the $st animal and is a bear." Ese your Ruby to chec! your answers. Hint: Ruby has also a few con*enience methods for accessing articular elements in an array# ani(als.+irst and ani(als.last

(%tra Credit
$. Read about ordinal and cardinal numbers online. '. With what you !now of the difference between these ty es of numbers, can you e& lain why this really is '8$$L 5Hint, you can't ic! years at random.6 (. Write some more arrays and wor! out similar inde&es until you can translate them. B. Ese Ruby to chec! your answers to this as well. Warnin! Programmers will tell you to read this guy named ".i,!stra" on this sub,ect. I recommend you a*oid his writings on this unless you en,oy being yelled at by someone who sto ed rogramming at the same time rogramming started.

Exercise %+: ?ranches and Functions


+ou ha*e learned to do i+-state(ents, functions, and arrays. Fow it's time to bend your mind. Ty e this in, and see if you can figure out what it's doing.

CD

1 *e+ pro(pt@A print B' B 3 en* ! # *e+ gol*Nroo(@A $ puts BT/is roo( is +ull o+ gol*. 7o8 (u,/ *o you ta)eMB < & pro(pt[ nextN(ove K gets.,/o(p 9 i+ nextN(ove.in,lu*eM B"B or nextN(ove.in,lu*eM B1B 1" /o8N(u,/ K nextN(ove.toNi@A 11 else 1 *ea*@BWanF learn to type a nu(ber.BA 13 en* 1! 1# i+ /o8N(u,/ 9 #" 1$ puts B0i,eF youDre not gree*yF you 8inCB 1< 3ro,ess.exit@"A 1& else 19 *ea*@BEou gree*y bastar*CBA " en* 1 en* 3 ! *e+ bearNroo(@A # puts BT/ere is a bear /ere.B $ puts BT/e bear /as a bun,/ o+ /oney.B < puts BT/e +at bear is in +ront o+ anot/er *oor.B & puts B7o8 are you going to (ove t/e bearMB 9 bearN(ove* K +alse 3" 31 8/ile true 3 pro(pt[ nextN(ove K gets.,/o(p 33 3! i+ nextN(ove KK Bta)e /oneyB 3# *ea*@BT/e bear loo)s at you t/en slaps your +a,e o++.BA 3$ elsi+ nextN(ove KK Btaunt bearB an* not bearN(ove* 3< puts BT/e bear /as (ove* +ro( t/e *oor. Eou ,an go t/roug/ it no8.B 3& bearN(ove* K true 39 elsi+ nextN(ove KK Btaunt bearB an* bearN(ove* !" *ea*@BT/e bear gets pisse* o++ an* ,/e8s your leg o++.BA !1 elsi+ nextN(ove KK Bopen *oorB an* bearN(ove* ! gol*Nroo(@A !3 else !! puts B= got no i*ea 8/at t/at (eans.B !# en* !$ en* !< en* !& !9 *e+ ,t/ul/uNroo(@A #" puts B7ere you see t/e great evil 2t/ul/u.B #1 puts B7eF itF 8/atever stares at you an* you go insane.B # puts BDo you +lee +or your li+e or eat your /ea*MB #3 #! pro(pt[ nextN(ove K gets.,/o(p ## #$ i+ nextN(ove.in,lu*eM B+leeB #< start@A #& elsi+ nextN(ove.in,lu*eM B/ea*B #9 *ea*@BWell t/at 8as tastyCBA $" else $1 ,t/ul/uNroo(@A

CH

$ $3 $! $# $$ $< $& $9 <" <1 < <3 <! <# <$ << <& <9 &" &1 & &3 &! &# &$

en* en* *e+ *ea*@8/yA puts B-O8/yP Xoo* RobCB 3ro,ess.exit@"A en* *e+ start@A puts BEou are in a *ar) roo(.B puts BT/ere is a *oor to your rig/t an* le+t.B puts BW/i,/ one *o you ta)eMB pro(pt[ nextN(ove K gets.,/o(p i+ nextN(ove KK Ble+tB bearNroo(@A elsi+ nextN(ove KK Brig/tB ,t/ul/uNroo(@A else *ea*@BEou stu(ble aroun* t/e roo( until you starve.BA en* en* start@A

What "o# Sho#ld See


Here's me laying the game#
$ ruby ex3#.rb Eou are in a *ar) roo(. T/ere is a *oor to your rig/t an* le+t. W/i,/ one *o you ta)eM ' le+t T/ere is a bear /ere. T/e bear /as a bun,/ o+ /oney. T/e +at bear is in +ront o+ anot/er *oor. 7o8 are you going to (ove t/e bearM ' taunt bear T/e bear /as (ove* +ro( t/e *oor. Eou ,an go t/roug/ it no8. ' open *oor T/is roo( is +ull o+ gol*. 7o8 (u,/ *o you ta)eM ' as+ WanF learn to type a nu(ber. Xoo* RobC $

(%tra Credit
$. .raw a ma of the game and how you flow through it. '. :i& all of your mista!es, including s elling mista!es. (. Write comments for the functions you do not understand. Remember R6oc commentsL B. -dd more to the game. What can you do to both sim lify and e& and it. C. The gol*Nroo( has a weird way of getting you to ty e a number. What are all the bugs in this way of doing itL ;an you ma!e it better than ,ust chec!ing if "$" or "8" are in the numberL Loo! at how toNi@A wor!s for clues.

C4

Exercise %,: 6esi!nin! and 6ebu!!in!


Fow that you !now i+-state(ents, I'm going to gi*e you some rules for +or-loops and 8/ile-loops that will !ee you out of trouble. I'm also going to gi*e you some ti s on debugging so that you can figure out roblems with your rogram. :inally, you are going to design a similar little game as in the last e&ercise but with a slight twist.

R#les &or 0f-State+ents


$. 0*ery i+-state(ent must ha*e an else. '. If this else should ne*er be run because it doesn't ma!e sense, then you must use a *ie function in the else that rints out an error message and dies, ,ust li!e we did in the last e&ercise. This will find many errors. (. Fe*er nest i+-state(ents more than ' dee and always try to do them $ dee . This means if you ut an i+ in an i+ then you should be loo!ing to mo*e that second i+ into another function. B. Treat i+-state(ents li!e aragra hs, where each i+,TTelsifTT,TTelseTT grou ing is li!e a set of sentences. Put blan! lines before and after. C. +our boolean tests should be sim le. If they are com le&, mo*e their calculations to *ariables earlier in your function and use a good name for the *ariable. If you follow these sim le rules, you will start writing better code than most rogrammers. %o bac! to the last e&ercise and see if I followed all of these rules. If not, fi& it. Warnin! Fe*er be a sla*e to the rules in real life. :or training ur oses you need to follow these rules to ma!e your mind strong, but in real life sometimes these rules are ,ust stu id. If you thin! a rule is stu id, try not using it.

R#les &or Loops


$. Ese a 8/ile-loop only to loo fore*er, and that means robably ne*er. This only a lies to Ruby, other languages are different. '. Ese a +or-loop for all other !inds of loo ing, es ecially if there is a fi&ed or limited number of things to loo o*er.

Tips &or De/#gging


$. .o not use a "debugger". - debugger is li!e doing a full1body scan on a sic! erson. +ou do not get any s ecific useful information, and you find a whole lot of information that doesn't hel and is ,ust confusing. '. The best way to debug a rogram is to use puts or p to rint out the *alues of *ariables at oints in the rogram to see where they go wrong. (. )a!e sure arts of your rograms wor! as you wor! on them. .o not write massi*e files of code before you try to run them. ;ode a little, run a little, fi& a little.

C>

)o+e$ork
Fow write a similar game to the one that I created in the last e&ercise. It can be any !ind of game you want in the same fla*or. / end a wee! on it ma!ing it as interesting as ossible. :or e&tra credit, use arrays, functions, and modules 5remember those from 0&. $(L6 as much as ossible, and find as many new ieces of Ruby as you can to ma!e the game wor!. There is one catch though, write u your idea for the game first. 2efore you start coding you must write u a ma for your game. ;reate the rooms, monsters, and tra s that the layer must go through on a er before you code. ?nce you ha*e your ma , try to code it u . If you find roblems with the ma then ad,ust it and ma!e the code match. ?ne final word of ad*ice# 0*ery rogrammer becomes aralyGed by irrational fear starting a new large ro,ect. They then use rocrastination to a*oid confronting this fear and end u not getting their rogram wor!ing or e*en started. I do this. 0*eryone does this. The best way to a*oid this is to ma!e a list of things you should do, and then do them one at a time. <ust start doing it, do a small *ersion, ma!e it bigger, !ee a list of things to do, and do them.

Exercise %-: Sy"bo* Re:ie9


It's time to re*iew the symbols and Ruby words you !now, and to try to ic! u a few more for the ne&t few lessons. What I'*e done here is written out all the Ruby symbols and !eywords that are im ortant to !now. In this lesson ta!e each !eyword, and first try to write out what it does from memory. Fe&t, search online for it and see what it really does. It may be hard because some of these are going to be im ossible to search for, but !ee trying. If you get one of these wrong from memory, write u an inde& card with the correct definition and try to "correct" your memory. If you ,ust didn't !now about it, write it down, and sa*e it for later. :inally, use each of these in a small Ruby rogram, or as many as you can get done. The !ey here is to find out what the symbol does, ma!e sure you got it right, correct it if you do not, then use it to loc! it in.

1ey$ords
alias an* S:X=0 begin brea)

D8

,ase ,lass *e+ *e+ine*M *o else elsi+ :0D en* ensure +alse +or i+ in (o*ule next nil not or re*o res,ue retry return sel+ super t/en true un*e+ unless until 8/en 8/ile yiel*

Data Types
:or data ty es, write out what ma!es u each one. :or e&am le, with strings write out how you create a string. :or numbers write out a few numbers.

true 5a*se ni*


,onstants strings nu(bers ranges arrays /as/es

/tring 0sca es /e3uences :or string esca e se3uences, use them in strings to ma!e sure they do what you thin! they do.

D$

55 5D 5B 5a 5b 5+ 5n 5r 5t 5v

? erators /ome of these may be unfamiliar to you, but loo! them u anyway. :ind out what they do, and if you still can't figure it out, sa*e it for later.
:: TU II -@unaryA 1@unaryA C % I H J 1 99 '' ] Y ' 'K 9 9K 9K' KK KKK CK K% C% ]] YY .. ...

/ end about a wee! on this, but if you finish faster that's great. The oint is to try to get co*erage on all these symbols and ma!e sure they are loc!ed in your head. What's also im ortant is to find out what you do not !now so you can fi& it later.

Exercise %.: 6oin! Thin!s To Lists


D'

Warnin! This is being rewritten based on the Python *ersion, there may be errors. +ou ha*e learned about lists. When you learned about 8/ile-loops you "a ended" numbers to the end of a list and rinted them out. There was also e&tra credit where you were su osed to find all the other things you can do to lists in the Ruby documentation. That was a while bac!, so go find in the boo! where you did that and re*iew if you do not !now what I'm tal!ing about. :ound itL Remember itL %ood. When you did this you had a list, and you "called" the function pus/ on it. Howe*er, you may not really understand what's going on so let's see what we can do to lists. When you ty e Ruby code that reads (ystu++.pus/@D/elloDA you are actually setting off a chain of e*ents inside Ruby to cause something to ha en to the (ystu++ list. Here's how it wor!s# $. Ruby sees you mentioned (ystu++ and loo!s u that *ariable. It might ha*e to loo! bac!wards to see if you created with K, loo! and see if it is a function argument, or maybe it's a global *ariable. 0ither way it has to find the (ystu++ first. '. ?nce it finds (ystu++ it then hits the . 5 eriod6 o erator and starts to loo! at variables that are a art of (ystu++. /ince (ystu++ is a list, it !nows that (ystu++ has a bunch of functions. (. It then hits pus/ and com ares the name " ush" to all the ones that (ystu++ says it owns. If ush is in there 5it is6 then it grabs that to use. B. Fe&t Ruby sees the @ 5 arenthesis6 and realiGes, "?h hey, this should be a function." -t this oint it calls 5a!a runs, e&ecutes6 the function ,ust li!e normally, but instead it calls the function with an extra argument. C. It then treats the pus/ as a function, gets it from (ystu++ and calls it with your arameter. That might be a lot to ta!e in, but we're going to s end a few e&ercises getting this conce t firm in your brain. To !ic! things off, here's an e&ercise that mi&es strings and lists for all !inds of fun.
1 tenNt/ings K BApples Granges 2ro8s Telep/one Lig/t SugarB 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< puts BWait t/ereDs not 1" t/ings in t/at listF letDs +ix t/at.B stu++ K tenNt/ings.split@D DA (oreNstu++ K J8@Day 0ig/t Song ?risbee 2orn Sanana Xirl SoyA 8/ile stu++.lengt/ CK 1" nextNone K (oreNstu++.pop@A puts BA**ing: -OnextNonePB stu++.pus/@nextNoneA puts BT/ereDs -Ostu++.lengt/P ite(s no8.B en* puts BT/ere 8e go: -Ostu++PB puts BLetDs *o so(e t/ings 8it/ stu++.B

D(

1& 19 puts stu++T1U " puts stu++T-1U - 8/oaC +an,y 1 puts stu++.pop@A puts stu++.Roin@D DA - 8/atM ,oolC 3 puts stu++.valuesNat@3F#A.Roin@D-DA - super stellarC

What "o# Sho#ld See


Wait t/ereDs not 1" t/ings in t/at listF letDs +ix t/at. A**ing: Soy T/ereDs < ite(s no8. A**ing: Xirl T/ereDs & ite(s no8. A**ing: Sanana T/ereDs 9 ite(s no8. A**ing: 2orn T/ereDs 1" ite(s no8. T/ere 8e go: ApplesGranges2ro8sTelep/oneLig/tSugarSoyXirlSanana2orn LetDs *o so(e t/ings 8it/ stu++. Granges 2orn 2orn Apples Granges 2ro8s Telep/one Lig/t Sugar Soy Xirl Sanana Telep/one-Sugar

(%tra Credit
$. Ta!e each function that is called, and go through the ste s outlined abo*e to translate them to what Ruby does. '. Translate these function calls into 0nglish sentences. :or e&am le (ystu++.pus/@D/elloDA would be, ":rom mystuff get the ush function and call it with 'hello'". (. %o read about "?b,ect ?riented Programming" online. ;onfusedL I was too. .o not worry. +ou will learn enough to be dangerous, and you can slowly learn more later. B. Read u on what a "class" is in Ruby. #o not read about how other languages use the word $class$% That will only mess you u . C. If you do not ha*e any idea what I'm tal!ing about do not worry. Programmers li!e to feel smart so they in*ented ?b,ect ?riented Programming, named it ??P, and then used it way too much. If you thin! that's hard, you should try to use "functional rogramming".

Exercise %0: Hashes/ =h Lo:e*y Hashes


Warnin! This is being rewritten based on the Python *ersion, there may be errors. Fow I ha*e to hurt you with another container you can use, because once you learn this container a massi*e world of ultra1cool will be yours. It is the most useful container e*er# the hash.

DB

Ruby calls them "hashes", other languages call them, ".ictionaries". I tend to use both names, but it doesn't matter. What does matter is what they do when com ared to -rrays. +ou see, a -rray lets you do this#
'' t/ings K TDaDFDbDFD,DFD*DU K' TBaBF BbBF B,BF B*BU '' puts t/ingsT1U b K' nil '' t/ingsT1U K DZD K' BZB '' puts t/ingsT1U Z K' nil '' puts t/ings.inspe,t TBaBF BbBF B,BF B*BU K' nil ''

+ou can use numbers to "inde&" into an -rray, meaning you can use numbers to find out what's in -rrays. +ou should !now this about -rrays by now, but ma!e sure you understand that you can only use numbers to get items out of a -rray. What a 7as/ does is let you use anything, not ,ust numbers. +es, a Hash associates one thing to another, no matter what it is. Ta!e a loo!#
'' stu++ K ODna(eD K' D6e*DF DageD K' 3$F D/eig/tD K' $I1 1 P K' OBna(eBK'B6e*BF B/eig/tBK'<!F BageBK'3$P '' puts stu++TDna(eDU 6e* K' nil '' puts stu++TDageDU 3$ K' nil '' puts stu++TD/eig/tDU <! K' nil '' stu++TD,ityDU K BSan ?ran,is,oB K' BSan ?ran,is,oB '' puts stu++TD,ityDU San ?ran,is,o K' nil ''

+ou will see that instead of ,ust numbers we're using strings to say what we want from the stu++ Hash. We can also ut new things into the Hash with strings. It doesn't ha*e to be strings though, we can also do this#
'' stu++T1U K BWo8B K' BWo8B '' stu++T U K B0eatoB K' B0eatoB '' puts stu++T1U Wo8 K' nil '' puts stu++T U 0eato

DC

K' nil '' puts stu++.inspe,t@A O1K'BWo8BF Bna(eBK'B6e*BF K'B0eatoBF B,ityBK'BSan ?ran,is,oBF B/eig/tBK'<!F BageBK'3$P K' nil ''

In this code I used numbers, and then you can see there's numbers and strings as !eys in the Hash when I rint it. I could use anything. Well almost but ,ust retend you can use anything for now. ?f course, a Hash that you can only ut things in is retty stu id, so here's how you delete things, with the *elete function#
'' stu++.*elete@D,ityDA K' BSan ?ran,is,oB '' stu++.*elete@1A K' BWo8B '' stu++.*elete@ A K' B0eatoB '' puts stu++.inspe,t OBna(eBK'B6e*BF B/eig/tBK'<!F BageBK'3$P K' nil ''

We'll now do an e&ercise that you must study *ery carefully. I want you to ty e this e&ercise in and try to understand what's going on. Ta!e note of when I ut things in a Hash, get from them, and all the o erations I use here.
1 - ,reate a (apping o+ state to abbreviation states K O 3 DGregonD K' DG>DF ! D?lori*aD K' D?LDF # D2ali+orniaD K' D2ADF $ D0e8 Eor)D K' D0EDF < DWi,/iganD K' DW=D &P 9 1" - ,reate a basi, set o+ states an* so(e ,ities in t/e( 11 ,ities K O 1 D2AD K' DSan ?ran,is,oDF 13 DW=D K' DDetroitDF 1! D?LD K' DVa,)sonvilleD 1# P 1$ 1< - a** so(e (ore ,ities 1& ,itiesTD0EDU K D0e8 Eor)D 19 ,itiesTDG>DU K D3ortlan*D " 1 - puts out so(e ,ities puts D-D I 1" 3 puts B0E State /as: BF ,itiesTD0EDU ! puts BG> State /as: BF ,itiesTDG>DU # $ - puts so(e states < puts D-D I 1" & puts BWi,/iganDs abbreviation is: BF statesTDWi,/iganDU 9 puts B?lori*aDs abbreviation is: BF statesTD?lori*aDU

DD

3" 31 3 33 3! 3# 3$ 3< 3& 39 !" !1 ! !3 !! !# !$ !< !& !9 #" #1 # #3 #! ## #$ #< #& #9 $" $1 $ $3 $! $#

- *o puts puts puts

it by using t/e state t/en ,ities *i,t D-D I 1" BWi,/igan /as: BF ,itiesTstatesTDWi,/iganDUU B?lori*a /as: BF ,itiesTstatesTD?lori*aDUU

- puts every state abbreviation puts D-D I 1" +or stateF abbrev in states puts BJs is abbreviate* JsB J TstateF abbrevU en* - puts every ,ity in state puts D-D I 1" +or abbrevF ,ity in ,ities puts BJs /as t/e ,ity JsB J TabbrevF ,ityU en* - no8 *o bot/ at t/e sa(e ti(e puts D-D I 1" +or stateF abbrev in states puts BJs state is abbreviate* Js an* /as ,ity JsB J T stateF abbrevF ,itiesTabbrevUU en* puts D-D I 1" - i+ itDs not t/ere you get nil state K statesTDTexasDU i+ not state puts BSorryF no Texas.B en* - get a ,ity 8it/ a *e+ault value ,ity K ,itiesTDT^DU YY DDoes 0ot :xistD puts BT/e ,ity +or t/e state DT^D is: JsB J ,ity

What "o# Sho#ld See


---------0E State /as: 0e8 Eor) G> State /as: 3ortlan* ---------Wi,/iganDs abbreviation is: W= ?lori*aDs abbreviation is: ?L ---------Wi,/igan /as: Detroit ?lori*a /as: Va,)sonville ---------Wi,/igan is abbreviate* W= 2ali+ornia is abbreviate* 2A 0e8 Eor) is abbreviate* 0E ?lori*a is abbreviate* ?L Gregon is abbreviate* G> ----------

DH

G> /as t/e ,ity 3ortlan* W= /as t/e ,ity Detroit ?L /as t/e ,ity Va,)sonville 0E /as t/e ,ity 0e8 Eor) 2A /as t/e ,ity San ?ran,is,o ---------Wi,/igan state is abbreviate* W= an* /as ,ity Detroit 2ali+ornia state is abbreviate* 2A an* /as ,ity San ?ran,is,o 0e8 Eor) state is abbreviate* 0E an* /as ,ity 0e8 Eor) ?lori*a state is abbreviate* ?L an* /as ,ity Va,)sonville Gregon state is abbreviate* G> an* /as ,ity 3ortlan* ---------SorryF no Texas. T/e ,ity +or t/e state DT^D is: Does 0ot :xist

(%tra Credit
$. .o this same !ind of ma ing with cities and statesAregions in your country, or or some other country. '. %o find the Ruby documentation for Hashes 5a.!.a. Hash6 and try to do e*en more things to them. (. :ind out what you can&t do with Hashes. - big one is that they do not ha*e order, so try laying with that.

Exercise (0: 'odu*es/ $*asses/ And =b@ects


Warnin! This is being rewritten based on the Python *ersion, there may be errors. Ruby is something called an "?b,ect ?riented Programming Language". What this means is there's a construct in Ruby called a class that lets you structure your software in a articular way. Esing classes you can add consistency to your rograms so that they can be used in a cleaner way, or at least that's the theory. I am now going to try to teach you the beginnings of ?b,ect ?riented Programming, classes, and ob,ects using what you already !now about hashes and modules. )y roblem though is that ?b,ect ?riented Programming 5a!a ??P6 is ,ust lain weird. +ou ha*e to sim ly struggle with this, try to understand what I say here, ty e in the code, and then in the ne&t e&ercise I'll hammer it in. Here we go.

Mod#les Are Like )ashes


+ou !now how a Hash is created and used, and that it is a way to ma one thing to another. That means if you ha*e a Hash with a !ey 'a le' and you want to get it then you do this#
(ystu++ K ODappleD K' B= AW A33L:SCBP puts (ystu++TDappleDU

D4

7ee this idea of "get K from +" in your head, and now thin! about modules. +ou'*e made a few so far, and used them, and you !now they are# $. - Ruby file with some functions or *ariables inside a Wo*ule. '. +ou then re3uire that file. (. -nd then you can access the functions or *ariables in that module with the '.' 5dot6 o erator. Imagine if I ha*e a module that I decide to name mystu""%rb and I ut a function in it called apple. Here's the module mystu""%rb#
- t/is goes in (ystu++.rb (o*ule WyStu++ *e+ WyStu++.apple@A puts B= AW A33L:SCB en* en*

?nce I ha*e that, I can use that module with re'uire and then access the apple function#
reLuire D(ystu++D WyStu++.apple@A

I could also ut a *ariable in it named tangerine li!e this#


(o*ule WyStu++ *e+ WyStu++.apple@A puts B= AW A33L:SCB en* - t/is is Rust a variable TA0X:>=0: K BLiving re+le,tion o+ a *rea(B en*

Then again I can access this *ariable using the (( 5double1colon6 o erator instead of the % 5dot6#
reLuire D(ystu++D WyStu++.apple@A puts WyStu++::TA0X:>=0:

%o refer bac! to the Hash, and you should start to see how this is similar to using a Hash, but the synta& is different. Let's com are#
(ystu++TDappleDU - get apple +ro( /as/ WyStu++.apple@A - get apple +ro( t/e (o*ule WyStu++::TA0X:>=0: - sa(e t/ingF itDs Rust a variable

This means we ha*e a very common attern in Ruby of this# $. Ta!e a !eyS*alue style container. '. %et something out of it by the !ey's name.

D>

In the case of the Hash, the !ey is a string and the synta& is )key*. In the case of the module, the !ey is an identifier, and the synta& is %key. ?ther than that they are nearly the same thing.

Classes Are Like Mod#les


- way to thin! about modules is they are a s ecialiGed Hash that can store Ruby code so you can get to it with the &%& o erator. Ruby also has another construct that ser*es a similar ur ose called a class. - class is a way to ta!e a grou ing of functions and data and lace them inside a container so you can access them with the &%& 5dot6 o erator. If I were to create a class ,ust li!e the +yStu"" module, I'd do something li!e this#
,lass WyStu++ *e+ initialiZe@A _tangerine K BAn* no8 a t/ousan* years bet8eenB en* attrNrea*er :tangerine *e+ apple@A puts B= AW 2LASSE A33L:SCB en*

en*

That loo!s com licated com ared to modules, and there is definitely a lot going on by com arison, but you should be able to ma!e out how this is li!e a "mini1module" with +yStu"" ha*ing an apple,- function in it. What is robably confusing with this is the initiali.e function and the use of /tangerine to set the *ariable. Here's why classes are used instead of modules# +ou can ta!e the abo*e class, and use it to craft many of them, millions at a time if you want, and they won't interfere with each other. With modules, when you re3uire there is only one for the entire rogram unless you do some monster hac!s. 2efore you can understand this though, you need to !now what an "ob,ect" is and how to wor! with +yStu"" ,ust li!e you do with the mystu""%rb module.

O/2ects Are Like Mini 0+ports


If a class is li!e a "mini1module", then there has to be a similar conce t to re'uire but for classes. That conce t is called "instantiate" which is ,ust a fancy obno&ious o*erly smart way to say "create". When you instantiate a class, what you get is called an ob0ect. The way you do this is you call the +yStu""%new,-, li!e this#
t/ing K WyStu++.ne8@A t/ing.apple@A puts t/ing.tangerine

H8

The first line is the "instantiate" o eration, and it's a s ecial function a*ailable on classes for ma!ing instances. Howe*er, when you call this there's a se3uence of e*ents that Ruby coordinates for you. I'll go through them using the abo*e code for +yStu""# $. Ruby loo!s for +yStu"" and sees that it is a class you'*e defined. '. Ruby crafts an em ty ob,ect with all the functions you'*e s ecified in the class using de". (. Ruby then loo!s to see if you made a "magic" initiali.e function, and if you ha*e it calls that function to initialiGe your newly created em ty ob,ect. B. In the +yStu"" function initiali.e I then get this e&tra *ariable sel" which is that em ty ob,ect Ruby made for me, and I can set *ariables on it ,ust li!e you would with a module, dict, or other ob,ect. C. In this case, I set /tangerine to a song lyric and then I'*e initialiGed this ob,ect. D. Fow Ruby can ta!e this newly minted ob,ect, and assign it to the thing *ariable for me to wor! with. That's the basics of how Ruby does this "mini1re3uire" when you call a %new,- on a class. Remember that this is not gi*ing you the class, but instead it is using the class as a blueprint for how to build a co y of that ty e of thing. 7ee in mind that I'm gi*ing you a slightly inaccurate idea for how these wor! so that you can start to build u an understanding of classes based on what you !now of modules. The truth is, classes and ob,ects suddenly di*erge from modules at this oint. If I were being totally honest, I'd say something more li!e this#

;lasses are li!e blue rints or definitions for creating new mini1modules. Instantiation is how you ma!e one of these mini1modules and re3uire it at the same time. The resulting created mini1module is called an ob0ect and you then assign it to a *ariable to wor! with it.

-fter this though classes and ob,ects become *ery different from modules and this should only ser*e as a way for you to bridge o*er to understanding classes.

3etting Things &ro+ Things


I now ha*e three ways to "get things from things"#
- /as/ style (ystu++TDapplesDU - (o*ule style (ystu++.apples@A puts (ystu++.tangerine - ,lass style t/ing K WyStu++.ne8@A t/ing.apples@A puts t/ing.tangerine

H$

A &irst Class (%a+ple


+ou should start seeing the similarities in these three !eyS*alue container ty es and robably ha*e a bunch of 3uestions. Hang on with the 3uestions, as the ne&t e&ercise is going to hammer home your "ob,ect oriented *ocabulary". In this e&ercise, I ,ust want you to ty e in this code and get it wor!ing so that you ha*e some e& erience before mo*ing on.
1 ,lass Song 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 *e+ initialiZe@lyri,sA _lyri,s K lyri,s en* *e+ singN(eNaNsong@A +or line in _lyri,s puts line en* en* en* /appyNb*ay K Song.ne8@TB7appy birt/*ay to youBF B= *onDt 8ant to get sue*BF BSo =Dll stop rig/t t/ereBUA bullsNonNpara*e K Song.ne8@TBT/ey rally aroun* t/e +a(ilyBF BWit/ po,)ets +ull o+ s/ellsBUA /appyNb*ay.singN(eNaNsong@A

3 bullsNonNpara*e.singN(eNaNsong@A

What You Should See


7appy birt/*ay to you = *onDt 8ant to get sue* So =Dll stop rig/t t/ere T/ey rally aroun* t/e +a(ily Wit/ po,)ets +ull o+ s/ells

Extra Credit
$. Write some more songs using this, ma!e sure you understand that you're assing a list of strings as the lyrics. '. Put the lyrics in a se arate *ariable, then ass that *ariable to the class to use instead. (. /ee if you can hac! on this and ma!e it do more things. .on't worry if you ha*e no idea how, ,ust gi*e it a try, see what ha ens. 2rea! it, trash it, thrash it, you can't hurt it. B. /earch online for "ob,ect oriented rogramming" and try to o*erflow your brain with what you read. .on't worry if it ma!es absolutely no sense to you. Half of that stuff ma!es no sense to me too.

Exercise (1: Learnin! To Spea2 =b@ect =riented


H'

Warnin! This is being rewritten based on the Python *ersion, there may be errors. In this e&ercise I'm going to teach you how to s ea! "ob,ect oriented". What I'll do is gi*e you a small set of words with definitions you need to !now. Then I'll gi*e you a set of sentences with holes in them that you'll ha*e to understand. :inally, I'm going to gi*e you a large set of e&ercises that you ha*e to com lete to ma!e these sentences solid in your *ocabulary.

Word Drills

class # Tell Ruby to ma!e a new !ind of thing. ob,ect # Two meanings# the most basic !ind of thing, and any instance of some thing. instance # What you get when you tell Ruby to create a class. def # How you define a function inside a class. U # Inside the functions in a class, U is an o erator for *ariables in the instanceAob,ect being accessed. inheritance # The conce t that one class can inherit traits from another class, much li!e you and your arents. com osition # The conce t that a class can be com osed of other classes as arts, much li!e how a car has wheels. attribute # - ro erty classes ha*e that are from com osition and are usually *ariables. is1a # - hrase to say that something inherits from another, as in a /almon is1a :ish. has1a # - hrase to say that something is com osed of other things or has a trait, as in a /almon has1a mouth.

-lright, ta!e some time to ma!e flash cards for those and memoriGe them. -s usual this won't ma!e too much sense until after you're done with this e&ercise, but you need to !now the base words first.

Phrase Drills
Fe&t I ha*e a list of Ruby code sni ets on the left, and the 0nglish sentences for them# $. '. (. B. C. D. class K5+6 # ")a!e a class named K that is1a +." class K5ob,ect6 def initialiGe5<6 # "class K has1a initialiGe that ta!es < arameters." class K5ob,ect6 def )5<6 # "class K has1a function named ) that ta!es < arameters." foo S K56 # "/et foo to an instance of class K." foo.)5<6 # ":rom foo get the ) function, and call it with arameters <." foo.7 S I # ":rom foo get the 7 attribute and set it to I."

In each of these where you see K, +, ), <, 7, I, and foo you can treat those li!e blan! s ots. :or e&am le I can also write these sentences as# $. '. (. B. ")a!e a class named LLL that is1a +." "class LLL has1a initialiGe that ta!es LLL arameters." "class LLL has1a function named LLL that ta!es LLL arameters." "/et foo to an instance of class LLL."

H(

C. ":rom foo get the LLL function, and call it with arameters LLL." D. ":rom foo get the LLL attribute and set it to LLL." -gain, write these on some flash cards and drill them. Put the Ruby code sni et on the front and the sentence on the bac!. +ou have to be able to say the sentence e&actly the same e*ery time whene*er you see that form. Fot sort of the same, but e&actly the same.

Co+/ined Drills
The final re aration for you is to combine the words drills with the hrase drills. What I want you to do for this drill is this# $. Ta!e a hrase card and drill it. '. :li it o*er and read the sentence, and for each word in the sentence that is in your words drills, get that card. (. .rill those words for that sentence. B. 7ee going until you are bored then ta!e a brea! and do it again.

A Reading Test
I now ha*e a little Ruby hac! that will drill you on these words you !now in an infinite manner. This is a sim le scri t you should be able to figure out, and the only thing it does is use a library called urllib to download a list of words I ha*e. Here's the scri t, which you should enter into oop1test%rb to wor! with it#
1 reLuire Dopen-uriD 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 WG>DN.>L K B/ttp:HHlearn,o*et/e/ar*8ay.orgH8or*s.txtB WG>DS K TU 37>AS:S K O B,lass --- 9 ---5nen*B K' BWa)e a ,lass na(e* --- t/at is-a ---.BF B,lass ---5n5t*e+ initialiZe@___A5n5ten*5nen*B K' B,lass --- /as-a initialiZe t/at ta)es ___ para(eters.BF B,lass ---5n5t*e+ III@___A5n5ten*5nen*B K' B,lass --- /as-a +un,tion na(e* III t/at ta)es ___ para(eters.BF BIII K ---.ne8@AB K' BSet III to an instan,e o+ ,lass ---.BF BIII.III@___AB K' B?ro( III get t/e III +un,tionF an* ,all it 8it/ para(eters ___.BF BIII.III K DIIIDB K' B?ro( III get t/e III attribute an* set it to DIIID.B P 37>AS:N?=>ST K A>X;T"U KK Benglis/B

open@WG>DN.>LA OY+Y +.ea,/Nline OY8or*Y WG>DS.pus/@8or*.,/o(pAP 3P ! # *e+ ,ra+tNna(es@ran*N8or*sF snippetF patternF ,apsK+alseA $ na(es K snippet.s,an@patternA.(ap *o < 8or* K ran*N8or*s.pop@A & ,aps M 8or*.,apitaliZe : 8or* 9 en* 3"

HB

31 3 33 3! 3# 3$ 3< 3& 39 !" !1 ! !3 !! !# !$ !< !& !9 #" #1 # #3 #! ## #$ #< #& #9 $" $1 $ $3 $! $# $$ $< $& $9 <" <1 < <3 <! <# <$ << <& <9 &" &1 &

return na(es I en* *e+ ,ra+tNpara(s@ran*N8or*sF snippetF patternA na(es K @"...snippet.s,an@patternA.lengt/A.(ap *o para(N,ount K ran*@3A 1 1 para(s K @"...para(N,ountA.(ap OYxY ran*N8or*s.pop@A P para(s.Roin@DF DA en* return na(es I en* *e+ ,onvert@snippetF p/raseA ran*N8or*s K WG>DS.sortNby Oran*P ,lassNna(es K ,ra+tNna(es@ran*N8or*sF snippetF H---HF ,apsKtrueA ot/erNna(es K ,ra+tNna(es@ran*N8or*sF snippetF H5I5I5IHA para(Nna(es K ,ra+tNpara(s@ran*N8or*sF snippetF H___HA results K TU +or senten,e in TsnippetF p/raseU - +a)e ,lass na(esF also ,opies senten,e result K senten,e.gsub@H---HA OYxY ,lassNna(es.pop P - +a)e ot/er na(es result.gsubC@H5I5I5IHA OYxY ot/erNna(es.pop P - +a)e para(eter lists result.gsubC@H___HA OYxY para(Nna(es.pop P results.pus/@resultA en* return results en* - )eep going until t/ey /it 2T>L-D loop *o snippets K 37>AS:S.)eys@A.sortNby Oran*P +or snippet in snippets p/rase K 37>AS:STsnippetU LuestionF ans8er K ,onvert@snippetF p/raseA i+ 37>AS:N?=>ST LuestionF ans8er K ans8erF Luestion en* print LuestionF B5n5n' B exit@"A unless STD=0.gets puts B5nA0SW:>: en* en* Js5n5nB J ans8er

Here's an e&am le of me running this and trying to answer the 3uestions as accurately as ossible. +ou can see that I ty e in the answer I thin! it is based on the hrases I'*e gi*en

HC

you, and then the scri t rints out the correct answer. +ou should get your answers as close as ossible.
$ ruby ex!1.rb ,lass Sran,/ *e+ initialiZe@bellF *egreeF ar(A en* en* ' ,lass Sran,/ /as-a initialiZe t/at ta)es bellF *egreeF an* ar( para(eters. A0SW:>: ,lass Sran,/ /as-a initialiZe t/at ta)es bellF *egreeF ar( para(eters. bat.,ollar@*eat/F arit/(eti,A ' ?ro( bat get t/e ,ollar +un,tion ,an ,all it 8it/ *eat/F arit/(eti, para(eters. A0SW:>: ?ro( bat get t/e ,ollar +un,tionF an* ,all it 8it/ para(eters *eat/F arit/(eti,. ,annon.,arpenter K D,ornD ' ?ro( ,annon get t/e ,arpenter attribute an* set it to D,ornD. A0SW:>: ?ro( ,annon get t/e ,arpenter attribute an* set it to D,ornD.

ani(al K Sor*er.ne8@A ' Set ani(al eLual to an instan,e o+ ,lass Sor*er. A0SW:>: Set ani(al to an instan,e o+ ,lass Sor*er.

,lass Sat 9 Srea)+ast en* ' ^D $

Practice (nglish To Code


Fe&t you should run the scri t with the "english" o tion so that you drill the in*erse o eration. %i*en an 0nglish hrase, write the code for it. Here's me doing that too#
ruby ex!1.rb englis/ Wa)e a ,lass na(e* Srot/er t/at is-a 2ra,)er. ' ,lass Srot/er 9 2ra,)er A0SW:>: en* ,lass Srot/er 9 2ra,)er

?ro( be/avior get t/e ,ent +un,tionF an* ,all it 8it/ para(eters *ressF boar*. ' be/avior.,ent@*erssF boar*A

HD

A0SW:>:

be/avior.,ent@*ressF boar*A

Set bas)et to an instan,e o+ ,lass 2oug/. ' ^D $

Remember that these hrases are using nonsense words. Part of learning to read code well is to sto lacing so much meaning on the names used for *ariables and classes. Too often eo le will read a word li!e ";or!" and suddenly get derailed because that word will confuse them about the meaning. In the abo*e e&am le, ";or!" is ,ust an arbitrary name chosen for a class. .on't ut any other meaning into it, and instead treat it li!e the atterns I'*e gi*en you.

Reading More Code


+ou are now to go on a new 3uest to read e*en more code and this time, to read the hrases you ,ust learned in the code you read. +ou will loo! for all the files with classes, and then do the following# $. '. (. B. :or each class gi*e its name and what other classes it inherits from. Ender that, list e*ery function it has, and the arameters they ta!e. List all of the attributes it uses on self. :or each attribute, gi*e the class it is.

The goal is to go through real code and start learning to " attern match" the hrases you ,ust learned against how they're used. If you drill this enough you should start to see these atterns shout at you in the code whereas before they ,ust seemed li!e *ague blan! s ots you didn't !now.

Exercise (#: IsAA/ HasAA/ =b@ects/ and $*asses


Warnin! This is being rewritten based on the Python *ersion, there may be errors. -n im ortant conce t that you ha*e to understand is the difference between a 2lass and an GbRe,t. The roblem is, there is no real "difference" between a class and an ob,ect. They are actually the same thing at different oints in time. I will demonstrate by a =en !oan#
W/at is t/e *i++eren,e bet8een a ?is/ an* a Sal(onM

.id that 3uestion sort of confuse youL Really sit down and thin! about it for a minute. I mean, a :ish and a /almon are different but, wait, they are the same thing rightL - /almon is a kind of :ish, so I mean it's not different. 2ut at the same time, becase a /almon is a articular type of :ish and so it's actually different from all other :ish. That's what ma!es it a /almon and not a Halibut. /o a /almon and a :ish are the same but different. Weird.

HH

This 3uestion is confusing because most eo le do not thin! about real things this way, but they intuiti*ely understand them. +ou do not need to thin! about the difference between a :ish and a /almon because you know how they are related. +ou !now a /almon is a kind of :ish and that there are other !inds of :ish without ha*ing to understand that. Let's ta!e it one ste further, let's say you ha*e a buc!et full of ( /almon and because you are a nice erson, you ha*e decided to name them :ran!, <oe, and )ary. Fow, thin! about this 3uestion#
W/at is t/e *i++eren,e bet8een Wary an* a Sal(onM

-gain this is a weird 3uestion, but it's a bit easier than the :ish *s. /almon 3uestion. +ou !now that )ary is a /almon, and so she's not really different. /he's ,ust a s ecific "instance" of a /almon. <oe and :ran! are also instances of /almon. 2ut, what do I mean when I say instanceL I mean they were created from some other /almon and now re resent a real thing that has /almon1li!e attributes. Fow for the mind bending idea# :ish is a 2lass, and /almon is a 2lass, and )ary is an GbRe,t. Thin! about that for a second. -lright let's brea! it down real slow and see if you get it. - :ish is a 2lass, meaning it's not a real thing, but rather a word we attach to instances of things with similar attributes. %ot finsL %ot gillsL Li*es in waterL -lright it's robably a :ish. /omeone with a Ph... then comes along and says, "Fo my young friend, this :ish is actually Salmo salar, affectionately !nown as a /almon." This rofessor has ,ust clarified the :ish further and made a new 2lass called "/almon" that has more s ecific attributes. Longer nose, reddish flesh, big, li*es in the ocean or fresh water, tastyL ?!, robably a /almon. :inally, a coo! comes along and tells the Ph..., "Fo, you see this /almon right here, I'll call her )ary and I'm going to ma!e a tasty fillet out of her with a nice sauce." Fow you ha*e this instance of a /almon 5which also is an instance of a :ish6 named )ary turned into something real that is filling your belly. It has become an GbRe,t. There you ha*e it# )ary is a !ind of /almon that is a !ind of :ish. GbRe,t is a 2lass is a 2lass.

)o$ This Looks 0n Code


This is a weird conce t, but to be *ery honest you only ha*e to worry about it when you ma!e new classes, and when you use a class. I will show you two tric!s to hel you figure out whether something is a 2lass or GbRe,t. :irst, you need to learn two catch hrases "is1a" and "has1a". +ou use the hrase is1a when you tal! about ob,ects and classes being related to each other by a class relationshi . +ou use has1a when you tal! about ob,ects and classes that are related only because they re"erence each other. Fow, go through this iece of code and re lace each --MM comment with a re lacement comment that says whether the ne&t line re resents an is-a or a /as-a relationshi , and what H4

that relationshi is. In the beginning of the code, I'*e laid out a few e&am les, so you ,ust ha*e to write the remaining ones. Remember, is1a is the relationshi between :ish and /almon, while has1a is the relationshi between /almon and %ills.
1 -- Ani(al is-a obRe,t loo) at t/e extra ,re*it ,lass Ani(al 3 en* ! # -- MM $ ,lass Dog 9 Ani(al < & *e+ initialiZe@na(eA 9 -- MM 1" _na(e K na(e 11 en* 1 en* 13 1! -- MM 1# ,lass 2at 9 Ani(al 1$ 1< *e+ initialiZe@na(eA 1& -- MM 19 _na(e K na(e " en* 1 en* 3 ! # $ < & 9 3" 31 3 33 3! 3# 3$ 3< 3& 39 !" !1 ! !3 !! !# !$ !< !& !9 #" #1 # #3 #! -- MM ,lass 3erson *e+ initialiZe@na(eA -- MM _na(e K na(e -- 3erson /as-a pet o+ so(e )in* _pet K nil en* en* attrNa,,essor :pet

-- MM ,lass :(ployee 9 3erson *e+ initialiZe@na(eF salaryA -- MM /(( 8/at is t/is strange (agi,M super@na(eA -- MM _salary K salary en* en* -- MM ,lass ?is/ en* -- MM ,lass Sal(on 9 ?is/

H>

## #$ #< #& #9 $" $1 $ $3 $! $# $$ $< $& $9 <" <1 < <3 <! <# <$ << <& <9 &" &1 & &3 &! &# &$ &<

en* -- MM ,lass 7alibut 9 ?is/ en* -- rover is-a Dog rover K Dog.ne8@B>overBA -- MM satan K 2at.ne8@BSatanBA -- MM (ary K 3erson.ne8@BWaryBA -- MM (ary.pet K satan -- MM +ran) K :(ployee.ne8@B?ran)BF 1 """"A -- MM +ran).pet K rover -- MM +lipper K ?is/.ne8@A -- MM ,rouse K Sal(on.ne8@A -- MM /arry K 7alibut.ne8@A

Extra Credit
$. Is it ossible to use a 2lass li!e it's an GbRe,tL '. :ill out the animals, fish, and eo le in this e&ercise with functions that ma!e them do things. /ee what ha ens when functions are in a "base class" li!e -nimal *s. in say .og. (. :ind other eo le's code and wor! out all the is1a and has1a relationshi s. B. )a!e some new relationshi s that are lists and dicts so you can also ha*e "has1many" relationshi s. C. .o you thin! there's a such thing as a "is1many" relationshi L Read about "multi le inheritance", then a*oid it if you can.

Exercise (%: Gothons Fro" *anet erca* B#+


Warnin! This is being rewritten based on the Python *ersion, there may be errors. Here is a new game, using what you'*e learned so far and some new tric!s.

48

1 ,lass Xa(e 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 3 ! # $ < & 9 3" 31 3 33 3! 3# 3$ 3< 3& 39 !" !1 ! !3 !! !# !$ !< !& !9 #" #1 # #3 #! ## #$ #< #& #9 $" $1 *e+ initialiZe@startA _Luips K T BEou *ie*. Eou )in*a su,) at t/is.BF B0i,e RobF you *ie* ...Ra,)ass.BF BSu,/ a luser.BF B= /ave a s(all puppy t/atDs better at t/is.B U _start K start en* *e+ pro(pt@A print B' B en* *e+ play@A nextNroo( K _start 8/ile true puts B5n--------B roo( K (et/o*@nextNroo(A nextNroo( K roo(.,all@A en* en* *e+ *eat/@A puts _LuipsTran*@_Luips.lengt/@AAU 3ro,ess.exit@1A en* *e+ ,entralN,orri*or@A puts BT/e Xot/ons o+ 3lanet 3er,al - # /ave inva*e* your s/ip an* *estroye*B puts Byour entire ,re8. Eou are t/e last surviving (e(ber an* your lastB puts B(ission is to get t/e neutron *estru,t bo(b +ro( t/e Weapons Ar(oryFB puts Bput it in t/e bri*geF an* blo8 t/e s/ip up a+ter getting into an B puts Bes,ape po*.B puts B5nB puts BEouDre running *o8n t/e ,entral ,orri*or to t/e Weapons Ar(ory 8/enB puts Ba Xot/on Ru(ps outF re* s,aly s)inF *ar) gri(y teet/F an* evil ,lo8n ,ostu(eB puts B+lo8ing aroun* /is /ate +ille* bo*y. 7eDs blo,)ing t/e *oor to t/eB puts BAr(ory an* about to pull a 8eapon to blast you.B pro(pt@A a,tion K gets.,/o(p@A i+ a,tion KK Bs/ootCB puts B4ui,) on t/e *ra8 you yan) out your blaster an* +ire it at t/e Xot/on.B puts B7is ,lo8n ,ostu(e is +lo8ing an* (oving aroun* /is bo*yF 8/i,/ t/ro8sB puts Bo++ your ai(. Eour laser /its /is ,ostu(e but (isses /i( entirely. T/isB puts B,o(pletely ruins /is bran* ne8 ,ostu(e /is (ot/er boug/t

4$

$ $3 $! $# $$ $< $& $9 <" <1 < <3 <! <# <$ << <& <9 &" &1 & &3 &! &# &$ &< && &9 9" 91 9 93 9! 9# 9$ 9< 9& 99 1"" 1"1 1" 1"3 1"! 1"# 1"$ 1"< 1"& 1"9 11" 111 11 113 11! 11# 11$ 11< 11& 119 1 " 1 1 1

/i(F 8/i,/B puts B(a)es /i( +ly into an insane rage an* blast you repeate*ly in t/e +a,e untilB puts Byou are *ea*. T/en /e eats you.B return :*eat/ elsi+ a,tion KK B*o*geCB puts BLi)e a 8orl* ,lass boxer you *o*geF 8eaveF slip an* sli*e rig/tB puts Bas t/e Xot/onDs blaster ,ran)s a laser past your /ea*.B puts B=n t/e (i**le o+ your art+ul *o*ge your +oot slips an* youB puts Bbang your /ea* on t/e (etal 8all an* pass out.B puts BEou 8a)e up s/ortly a+ter only to *ie as t/e Xot/on sto(ps onB puts Byour /ea* an* eats you.B return :*eat/ elsi+ a,tion KK Btell a Ro)eB puts BLu,)y +or you t/ey (a*e you learn Xot/on insults in t/e a,a*e(y.B puts BEou tell t/e one Xot/on Ro)e you )no8:B puts BLb/e Zbgure v+ +b sngF Rura +ur +vg+ neb/aL gur ub/+rF +ur +vg+ neb/aL gur ub/+r.B puts BT/e Xot/on stopsF tries not to laug/F t/en busts out laug/ing an* ,anDt (ove.B puts BW/ile /eDs laug/ing you run up an* s/oot /i( sLuare in t/e /ea*B puts Bputting /i( *o8nF t/en Ru(p t/roug/ t/e Weapon Ar(ory *oor.B return :laserN8eaponNar(ory else puts BDG:S 0GT 2GW3.T:CB return :,entralN,orri*or en* en* *e+ laserN8eaponNar(ory@A puts BEou *o a *ive roll into t/e Weapon Ar(oryF ,rou,/ an* s,an t/e roo(B puts B+or (ore Xot/ons t/at (ig/t be /i*ing. =tDs *ea* LuietF too Luiet.B puts BEou stan* up an* run to t/e +ar si*e o+ t/e roo( an* +in* t/eB puts Bneutron bo(b in its ,ontainer. T/ereDs a )eypa* lo,) on t/e boxB puts Ban* you nee* t/e ,o*e to get t/e bo(b out. =+ you get t/e ,o*eB puts B8rong 1" ti(es t/en t/e lo,) ,loses +orever an* you ,anDtB puts Bget t/e bo(b. T/e ,o*e is 3 *igits.B ,o*e K BJsJsJsB J Tran*@9A11F ran*@9A11F ran*@9A11U print BT)eypa*U' B guess K gets.,/o(p@A guesses K " 8/ile guess CK ,o*e an* guesses 9 1" puts BS6666:DDDCB guesses 1K 1 print BT)eypa*U' B guess K gets.,/o(p@A en*

4'

1 3 i+ guess KK ,o*e 1 ! puts BT/e ,ontainer ,li,)s open an* t/e seal brea)sF letting gas 1 # out.B 1 $ puts BEou grab t/e neutron bo(b an* run as +ast as you ,an to t/eB 1 < puts Bbri*ge 8/ere you (ust pla,e it in t/e rig/t spot.B 1 & return :t/eNbri*ge 1 9 else 13" puts BT/e lo,) buZZes one last ti(e an* t/en you /ear a si,)eningB 131 puts B(elting soun* as t/e (e,/anis( is +use* toget/er.B 13 puts BEou *e,i*e to sit t/ereF an* +inally t/e Xot/ons blo8 up 133 t/eB 13! puts Bs/ip +ro( t/eir s/ip an* you *ie.B 13# return :*eat/ 13$ en* 13< en* 13& 139 *e+ t/eNbri*ge@A 1!" puts BEou burst onto t/e Sri*ge 8it/ t/e neutron *estru,t bo(bB 1!1 puts Bun*er your ar( an* surprise # Xot/ons 8/o are trying toB 1! puts Bta)e ,ontrol o+ t/e s/ip. :a,/ o+ t/e( /as an even uglierB 1!3 puts B,lo8n ,ostu(e t/an t/e last. T/ey /avenDt pulle* t/eirB 1!! puts B8eapons out yetF as t/ey see t/e a,tive bo(b un*er yourB 1!# puts Bar( an* *onDt 8ant to set it o++.B 1!$ 1!< pro(pt@A 1!& a,tion K gets.,/o(p@A 1!9 1#" i+ a,tion KK Bt/ro8 t/e bo(bB 1#1 puts B=n a pani, you t/ro8 t/e bo(b at t/e group o+ Xot/onsB 1# puts Ban* (a)e a leap +or t/e *oor. >ig/t as you *rop it aB 1#3 puts BXot/on s/oots you rig/t in t/e ba,) )illing you.B 1#! puts BAs you *ie you see anot/er Xot/on +ranti,ally try to *isar(B 1## puts Bt/e bo(b. Eou *ie )no8ing t/ey 8ill probably blo8 up 8/enB 1#$ puts Bit goes o++.B 1#< return :*eat/ 1#& 1#9 elsi+ a,tion KK Bslo8ly pla,e t/e bo(bB 1$" puts BEou point your blaster at t/e bo(b un*er your ar(B 1$1 puts Ban* t/e Xot/ons put t/eir /an*s up an* start to s8eat.B 1$ puts BEou in,/ ba,)8ar* to t/e *oorF open itF an* t/en ,are+ullyB 1$3 puts Bpla,e t/e bo(b on t/e +loorF pointing your blaster at it.B 1$! puts BEou t/en Ru(p ba,) t/roug/ t/e *oorF pun,/ t/e ,lose buttonB 1$# puts Ban* blast t/e lo,) so t/e Xot/ons ,anDt get out.B 1$$ puts B0o8 t/at t/e bo(b is pla,e* you run to t/e es,ape po* toB 1$< puts Bget o++ t/is tin ,an.B 1$& return :es,apeNpo* 1$9 else 1<" puts BDG:S 0GT 2GW3.T:CB 1<1 return :t/eNbri*ge 1< en* 1<3 en* 1<! 1<# *e+ es,apeNpo*@A 1<$ puts BEou rus/ t/roug/ t/e s/ip *esperately trying to (a)e it toB 1<< puts Bt/e es,ape po* be+ore t/e 8/ole s/ip explo*es. =t see(s li)eB 1<& puts B/ar*ly any Xot/ons are on t/e s/ipF so your run is ,lear o+B 1<9 puts Binter+eren,e. Eou get to t/e ,/a(ber 8it/ t/e es,ape po*sF 1&" an*B 1&1 puts Bno8 nee* to pi,) one to ta)e. So(e o+ t/e( ,oul* be *a(age*B 1& puts Bbut you *onDt /ave ti(e to loo). T/ereDs # po*sF 8/i,/ oneB 1&3 puts B*o you ta)eMB

4(

goo*Npo* K ran*@#A11 print BTpo* -U'B guess K gets.,/o(p@A i+ guess.toNi CK goo*Npo* puts BEou Ru(p into po* Js an* /it t/e eRe,t button.B J guess puts BT/e po* es,apes out into t/e voi* o+ spa,eF t/enB puts Bi(plo*es as t/e /ull rupturesF ,rus/ing your bo*yB puts Binto Ra( Relly.B return :*eat/ else puts BEou Ru(p into po* Js an* /it t/e eRe,t button.B J guess puts BT/e po* easily sli*es out into spa,e /ea*ing toB puts Bt/e planet belo8. As it +lies to t/e planetF you loo)B puts Bba,) an* see your s/ip i(plo*e t/en explo*e li)e aB puts Bbrig/t starF ta)ing out t/e Xot/on s/ip at t/e sa(eB puts Bti(e. Eou 8onCB 3ro,ess.exit@"A en* en* en* aNga(e K Xa(e.ne8@:,entralN,orri*orA aNga(e.play@A

It's a lot of code, but go through it, ma!e sure it wor!s, lay it.

What "o# Sho#ld See


Here's me laying the game.
$ ruby exHex!3.rb -------T/e Xot/ons o+ 3lanet 3er,al - # /ave inva*e* your s/ip an* *estroye* your entire ,re8. Eou are t/e last surviving (e(ber an* your last (ission is to get t/e neutron *estru,t bo(b +ro( t/e Weapons Ar(oryF put it in t/e bri*geF an* blo8 t/e s/ip up a+ter getting into an es,ape po*. EouDre running *o8n t/e ,entral ,orri*or to t/e Weapons Ar(ory 8/en a Xot/on Ru(ps outF re* s,aly s)inF *ar) gri(y teet/F an* evil ,lo8n ,ostu(e +lo8ing aroun* /is /ate +ille* bo*y. 7eDs blo,)ing t/e *oor to t/e Ar(ory an* about to pull a 8eapon to blast you. ' tell a Ro)e Lu,)y +or you t/ey (a*e you learn Xot/on insults in t/e a,a*e(y. Eou tell t/e one Xot/on Ro)e you )no8: Lb/e Zbgure v+ +b sngF Rura +ur +vg+ neb/aL gur ub/+rF +ur +vg+ neb/aL gur ub/+r. T/e Xot/on stopsF tries not to laug/F t/en busts out laug/ing an* ,anDt (ove. W/ile /eDs laug/ing you run up an* s/oot /i( sLuare in t/e /ea* putting /i( *o8nF t/en Ru(p t/roug/ t/e Weapon Ar(ory *oor. -------Eou *o a *ive roll into t/e Weapon Ar(oryF ,rou,/ an* s,an t/e roo( +or (ore Xot/ons t/at (ig/t be /i*ing. =tDs *ea* LuietF too Luiet. Eou stan* up an* run to t/e +ar si*e o+ t/e roo( an* +in* t/e

4B

neutron bo(b in its ,ontainer. T/ereDs a )eypa* lo,) on t/e box an* you nee* t/e ,o*e to get t/e bo(b out. =+ you get t/e ,o*e 8rong 1" ti(es t/en t/e lo,) ,loses +orever an* you ,anDt get t/e bo(b. T/e ,o*e is 3 *igits. T)eypa*U' S6666:DDDC T)eypa*U' !#$ S6666:DDDC T)eypa*U' 39# T/e ,ontainer ,li,)s open an* t/e seal brea)sF letting gas out. Eou grab t/e neutron bo(b an* run as +ast as you ,an to t/e bri*ge 8/ere you (ust pla,e it in t/e rig/t spot. -------Eou burst onto t/e Sri*ge 8it/ t/e neutron *estru,t bo(b un*er your ar( an* surprise # Xot/ons 8/o are trying to ta)e ,ontrol o+ t/e s/ip. :a,/ o+ t/e( /as an even uglier ,lo8n ,ostu(e t/an t/e last. T/ey /avenDt pulle* t/eir 8eapons out yetF as t/ey see t/e a,tive bo(b un*er your ar( an* *onDt 8ant to set it o++. ' t/ro8 t/e bo(b =n a pani, you t/ro8 t/e bo(b at t/e group o+ Xot/ons an* (a)e a leap +or t/e *oor. >ig/t as you *rop it a Xot/on s/oots you rig/t in t/e ba,) )illing you. As you *ie you see anot/er Xot/on +ranti,ally try to *isar( t/e bo(b. Eou *ie )no8ing t/ey 8ill probably blo8 up 8/en it goes o++. -------= /ave a s(all puppy t/atDs better at t/is.

(%tra Credit
$. 0& lain how returning the ne&t room wor!s. '. -dd cheat codes to the game so you can get ast the more difficult rooms. I can do this with two words on one line. (. Instead of ha*ing each function rint itself, learn about "doc string" style comments. Write the room descri tion as doc comments, and change the runner to rint them. B. ?nce you ha*e doc comments as the room descri tion, do you need to ha*e the function rom t e*enL Ha*e the runner rom t the user, and ass that in to each function. +our functions should ,ust be if1statements rinting the result and returning the ne&t room. C. This is actually a small *ersion of something called a "finite state machine". Read about them. They might not ma!e sense but try anyway. D. I ha*e a bug in this code. Why is the door loc! guessing $$ timesL

Exercise ((: Inheritance )sC $o"position


Warning This is being rewritten based on the Python *ersion, there may be errors. In the fairy tales about heroes defeating e*il *illains there's always a dar! forest of some !ind. It could be a ca*e, a forest, another lanet, ,ust some lace that e*eryone !nows the hero shouldn't go. ?f course, shortly after the *illain is introduced you find out, yes, the hero has

4C

to go to that stu id forest to !ill the bad guy. It seems the hero ,ust !ee s getting into situations that re3uire him to ris! his life in this e*il forest. +ou rarely read fairy tales about the heroes who are smart enough to ,ust a*oid the whole situation entirely. +ou ne*er hear a hero say, "Wait a minute, if I lea*e to ma!e my fortunes on the high seas lea*ing 2uttercu behind I could die and then she'd ha*e to marry some ugly rince named Hum erdin!. Hum erdin!O I thin! I'll stay here and start a :arm 2oy :or Rent business." If he did that there'd be no fire swam , dying, reanimation, sword fights, giants, or any !ind of story really. 2ecause of this, the forest in these stories seems to e&ist li!e a blac! hole that drags the hero in no matter what they do. In ob,ect oriented rogramming, Inheritance is the e*il forest. 0& erienced rogrammers !now to a*oid this e*il because they !now that dee inside the .ar! :orest Inheritance is the 0*il Iueen )eta1Programming. /he li!es to eat software and rogrammers with her massi*e com le&ity teeth, chewing on the flesh of the fallen. 2ut, the forest is so owerful and so tem ting that nearly e*ery rogrammer has to go into it, and try to ma!e it out ali*e with the 0*il Iueen's head before they can call themsel*es real rogrammers. +ou ,ust can't resist the Inheritance :orest's ull, so you go in. -fter the ad*enture you learn to ,ust stay out of that stu id forest and bring and army if you are e*er forced to go in again. This is basically a funny way to say that I'm going to teach you something you should a*oid called Inheritance. Programmers who are currently in the forest battling the Iueen will robably tell you that you ha*e to go in. They say this because they need your hel since what they'*e created is robably too much for them to handle. 2ut, you should always remember this# )ost of the uses of inheritance can be sim lified or re laced with com osition, and meta1 rogramming should be used s aringly.

What 0s 0nheritance4
Inheritance is used to indicate that one class will get most or all of its features from a arent class. This ha ens im licitly whene*er you write ,lass ?oo 9 Sar which says ")a!e a class :oo that inherits from 2ar." When you do this, the language ma!es any action that you do on instances of !oo also wor! as if they were done to an instance of Bar. .oing this lets you ut common functionality in the Bar class, then s ecialiGe that functionality in the !oo class as needed. When you are doing this !ind of s ecialiGation, there's three ways that the arent and child classes can interact# $. -ctions on the child im ly an action on the arent. '. -ctions on the child o*erride the action on the arent. (. -ctions on the child alter the action on the arent. I will now demonstrate each of these in order and show you code for them.

4D

Implicit Inheritance
:irst I will show you the im licit actions that ha en when you define a function in the arent, but not in the child.
1 ,lass 3arent 3 ! # $ < & 9 1" 11 1 13 1! 1# *e+ i(pli,it@A puts B3A>:0T i(pli,it@AB en* en* ,lass 2/il* 9 3arent en* *a* K 3arent.ne8@A son K 2/il*.ne8@A *a*.i(pli,it@A son.i(pli,it@A

This creates a class named 2hild but says that there's nothing new to define in it. Instead it will inherit all of its beha*ior from Parent. When you run this code you get the following#
3A>:0T i(pli,it@A 3A>:0T i(pli,it@A

Fotice how e*en though I'm calling son.i(pli,it@A on line $D, and e*en though 2hild does not ha*e a implicit function defined, it still wor!s and it calls the one defined in Parent. This shows you that, if you ut functions in a base class 5i.e. Parent6 then all subclasses 5i.e. 2hild6 will automatically get those features. @ery handy for re etiti*e code you need in many classes.

Override Explicitly
The roblem with im licitly ha*ing functions called is sometimes you want the child to beha*e differently. In this case you want to o*erride the function in the child, effecti*ely re lacing the functionality. To do this ,ust define a function with the same name in 2hild. Here's an e&am le#
1 ,lass 3arent 3 ! # $ < & 9 1" 11 1 13 1! 1# *e+ overri*e@A puts B3A>:0T overri*e@AB en*

en*

,lass 2/il* 9 3arent *e+ overri*e@A puts B27=LD overri*e@AB en* en* *a* K 3arent.ne8@A

4H

1$ son K 2/il*.ne8@A 1< 1& *a*.overri*e@A 19 son.overri*e@A

In this e&am le e&am le I ha*e a function named override in both classes, so let's see what ha ens when you run it.
3A>:0T overri*e@A 27=LD overri*e@A

-s you can see, when line $B runs, it runs the Parent%override function because that *ariabe 5dad6 is a Parent. 2ut, when line $C runs it rints out the 2hild%override messages because son is an instance of 2hild and child o*errides that function by defining it's own *ersion. Ta!e a brea! right now and try laying with these two conce ts before continuing.

Alter Before Or After


The third way to use inheritance is a s ecial case of o*erriding where you want to alter the beha*ior before or after you the arent class's *ersion runs. +ou first o*erride the function ,ust li!e in the last e&am le, but then you use a Ruby built1in function named super to get the Parent *ersion to call. Here's the e&am le of doing that so you can ma!e sense of this descri tion#
1 ,lass 3arent 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 *e+ altere*@A puts B3A>:0T altere*@AB en* en* ,lass 2/il* 9 3arent *e+ altere*@A puts B27=LDF S:?G>: 3A>:0T altere*@AB super@A puts B27=LDF A?T:> 3A>:0T altere*@AB en* en* *a* K 3arent.ne8@A son K 2/il*.ne8@A

*a*.altere*@A 3 son.altere*@A

The im ortant lines here are >1$$, where in the child I do the following when son.altere*@A is called# $. 2ecause I'*e o*erridden Parent%altered the 2hild%altered *ersion runs, and line > e&ecutes li!e you'd e& ect.

44

'. In this case I want to do a before and after so after line >, I want to use super to get the Parent%altered *ersion. (. ?n line $8 I call super@A, which rea eats this function call on the arent class. B. -t this oint, the Parent%altered *ersion of the function runs, and that rints out the arent message. C. :inally, this returns from the Parent%altered and the 2hild%altered function continues to rint out the after message. If you then run this you should see this#
3A>:0T 27=LDF 3A>:0T 27=LDF altere*@A S:?G>: 3A>:0T altere*@A altere*@A A?T:> 3A>:0T altere*@A

All Three Combined


To demonstrate all of these, I ha*e a final *ersion that shows each !ind of interaction from inheritance in one file#
1 ,lass 3arent 3 *e+ overri*e@A ! puts B3A>:0T overri*e@AB # en* $ < *e+ i(pli,it@A & puts B3A>:0T i(pli,it@AB 9 en* 1" 11 *e+ altere*@A 1 puts B3A>:0T altere*@AB 13 en* 1! en* 1# 1$ ,lass 2/il* 9 3arent 1< 1& *e+ overri*e@A 19 puts B27=LD overri*e@AB " en* 1 *e+ altere*@A 3 puts B27=LDF S:?G>: 3A>:0T altere*@AB ! super@A # puts B27=LDF A?T:> 3A>:0T altere*@AB $ en* < en* & 9 *a* K 3arent.ne8@A 3" son K 2/il*.ne8@A 31 3 *a*.i(pli,it@A 33 son.i(pli,it@A 3! 3# *a*.overri*e@A 3$ son.overri*e@A 3<

4>

3& *a*.altere*@A 39 son.altere*@A

%o through each line of this code, and write a comment e& laining what that line does and whether it's an o*erride or not. Then, run it and see that you get what you e& ected#
3A>:0T i(pli,it@A 3A>:0T i(pli,it@A 3A>:0T overri*e@A 27=LD overri*e@A 3A>:0T altere*@A 27=LDF S:?G>: 3A>:0T altere*@A 3A>:0T altere*@A 27=LDF A?T:> 3A>:0T altere*@A

The Reason &or s#per56


In the 2hild%altered,- function I used a s ecial function named super,-. This isn't a function you define, but instead one Ruby gi*es you. This function figures out how to call the same function, but in a arent class. The reason you need a s ecial function is that what is "the arent class" is a bit com le&. It relies on Ruby !nowing the full inheritance structure of the current class, and any ossible modules you'*e added to it with mi&ins 5which I'll show you soon6. 2y using super,- you don't need to worry about figuring this out and can ,ust let Ruby do it. +ou use super,- by assing it the right number of arguments for the arent class's argument count. In the e&am le abo*e, neither *ersion of altered,- had arguments, so I ,ust called super,-. If the class Parent had arguments, then I'd add them to the super,- call.

U in! uper"# With initiali$e


The most common use of super,- is actually in initiali.e functions in base classes. This is usually the only lace where you need to do some things in a child, then com lete the initialiGation in the arent. Here's a 3uic! e&am le of doing that in the 2hild from these e&am les#
,lass 2/il* 9 3arent *e+ initialiZe@sel+F stu++A: sel+.stu++ K stu++ super@A en* en*

This is retty much the same as the 2hild%altered e&am le abo*e, e&ce t I'm setting some *ariables in the initiali.e before ha*ing the Parent initialiGe with its Parent%initiali.e.

Co+position
Inheritance is useful, but another way to do the e&act same thing is ,ust to use other classes and modules, rather than rely on im licit inheritance. If you loo! at the three ways to e& loit inheritance, two of the three in*ol*e writing new code to re lace or alter functionality. This

>8

can easily be re licated by ,ust calling functions on another class or from a module. Here's an e&am le of doing this#
1 ,lass Gt/er 3 *e+ overri*e@A ! puts BGT7:> overri*e@AB # en* $ < *e+ i(pli,it@A & puts BGT7:> i(pli,it@AB 9 en* 1" 11 *e+ altere*@A 1 puts BGT7:> altere*@AB 13 en* 1! en* 1# 1$ ,lass 2/il* 1< 1& *e+ initialiZe@A 19 _ot/er K Gt/er.ne8@A " en* 1 *e+ i(pli,it@A 3 _ot/er.i(pli,it@A ! en* # $ *e+ overri*e@A < puts B27=LD overri*e@AB & en* 9 3" *e+ altere*@A 31 puts B27=LDF S:?G>: GT7:> altere*@AB 3 _ot/er.altere*@A 33 puts B27=LDF A?T:> GT7:> altere*@AB 3! en* 3# en* 3$ 3< son K 2/il*.ne8@A 3& 39 son.i(pli,it@A !" son.overri*e@A !1 son.altere*@A

In this code I'm not using the name Parent, since there is not a arent1child is1a relationshi . This is a has1a relationshi , where 2hild has1a 3ther that it uses to get its wor! done. When I run this I get the following out ut#
GT7:> i(pli,it@A 27=LD overri*e@A 27=LDF S:?G>: GT7:> altere*@A GT7:> altere*@A 27=LDF A?T:> GT7:> altere*@A

+ou can see that most of the code in 2hild and 3ther is the same to accom lish the same thing. The only difference is that I had to define a 2hild%implicit function to do that one

>$

action. I could then as! myself if I need this 3ther to be a class, and could I ,ust ma!e it into a module named 3ther. I totally could ma!e this into a module instead#
1 (o*ule Gt/er 3 *e+ Gt/er.overri*e@A ! puts BGT7:> overri*e@AB # en* $ < *e+ Gt/er.i(pli,it@A & puts BGT7:> i(pli,it@AB 9 en* 1" 11 *e+ Gt/er.altere*@A 1 puts BGT7:> altere*@AB 13 en* 1! en* 1# 1$ ,lass 2/il* 1< 1& *e+ i(pli,it@A 19 Gt/er.i(pli,it@A " en* 1 *e+ overri*e@A 3 puts B27=LD overri*e@AB ! en* # $ *e+ altere*@A < puts B27=LDF S:?G>: GT7:> altere*@AB & Gt/er.altere*@A 9 puts B27=LDF A?T:> GT7:> altere*@AB 3" en* 31 en* 3 33 son K 2/il*.ne8@A 3! 3# son.i(pli,it@A 3$ son.overri*e@A 3< son.altere*@A

Fearly the e&act same thing ,ust using a module. The choice of which is better in the abo*e code 5class 3ther *s. module 3ther6 de ends on if you need to maintain state in each function call in 3ther. If each function can stand on its own, and they're mostly utilities then use a module. If howe*er the set of functions ma!e u a cohesi*e "thing" that !ee s state then use a class.

When To ,se 0nheritance Or Co+position


The 3uestion of "inheritance *s. com osition" comes down to an attem t to sol*e the roblem of reusable code. +ou don't want to ha*e du licated code all o*er your code, since that's not clean and efficient. Inheritance sol*es this roblem by creating a mechanism for you to ha*e im lied features in base classes. ;om osition sol*es this by gi*ing you modules and the ability to sim ly call functions in other classes.

>'

If both solutions sol*e the roblem of reuse, then which one is a ro riate in which situationsL The answer is incredibly sub,ecti*e, but I'll gi*e you my three guidelines for when to do which# $. -*oid meta1 rogramming at all costs, as it's too com le& to be useful reliably. If you're stuc! with it, then be re ared to s end time finding where e*erything is coming from. '. Ese com osition to ac!age u code into modules that is used in many different unrelated laces and situations. (. Ese inheritance only when there are clearly related reusable ieces of code that fit under a single common conce t, or if you ha*e to because of something you're using. Howe*er, do not be a sla*e to these rules. The thing to remember about ob,ect oriented rogramming is that it is entirely a social con*ention rogrammers ha*e created to ac!age and share code. 2ecause it's a social con*ention, but one that's codified in Ruby, you may be forced to a*oid these rules because of the eo le you wor! with. In that case, find out how they use things and then ,ust ada t to the situation.

(%tra Credit
There is only one e&tra credit for this e&ercise because it is a big e&ercise. %o and read this htt s#AAgithub.comAstyleguideAruby and start trying to use it in your code. +ou'll notice that some of it is different from what you'*e been learning in this boo!, but now you should be able to understand their recommendations and use them in your own code. The rest of the code in this boo! may or may not follow these guidelines de ending on if it ma!es the code more confusing. I suggest you also do this, as com rehension is more im ortant than im ressing e*eryone with you !nowledge of esoteric style rules.

Exercise (+: 7ou 'a2e A Ga"e


+ou need to start learning to feed yourself. Ho efully as you ha*e wor!ed through this boo!, you ha*e learned that all the information you need is on the internet, you ,ust ha*e to go search for it. The only thing you ha*e been missing are the right words and what to loo! for when you search. Fow you should ha*e a sense of it, so it's about time you struggled through a big ro,ect and tried to get it wor!ing. Here are your re3uirements# $. )a!e a different game from the one I made. '. Ese more than one file, and use reLuire to use them. )a!e sure you !now what that is. (. Ese one class er room and gi*e the classes names that fit their ur ose. Li!e Xol*>oo(, \oi3on*>oo(. B. +our runner will need to !now about these rooms, so ma!e a class that runs them and !nows about them. There's lenty of ways to do this, but consider ha*ing each room return what room is ne&t or setting a *ariable of what room is ne&t.

>(

?ther than that I lea*e it to you. / end a whole wee! on this and ma!e it the best game you can. Ese classes, functions, dicts, lists anything you can to ma!e it nice. The ur ose of this lesson is to teach you how to structure classes that need other classes inside other files. Remember, I'm not telling you e&actly how to do this because you ha*e to do this yourself. %o figure it out. Programming is roblem sol*ing, and that means trying things, e& erimenting, failing, scra ing your wor!, and trying again. When you get stuc!, as! for hel and show eo le your code. If they are mean to you, ignore them, focus on the eo le who are not mean and offer to hel . 7ee wor!ing it and cleaning it until it's good, then show it some more. %ood luc!, and see you in a wee! with your game.

Exercise (,: A ro@ect S2e*eton


This will be where you start learning how to setu a good ro,ect "s!eleton" directory. This s!eleton directory will ha*e all the basics you need to get a new ro,ect u and running. It will ha*e your ro,ect layout, automated tests, modules, and install scri ts.

Skeleton Contents! Lin#%7OS


:irst, create the structure of your s!eleton directory with these commands#
$ $ $ $ $ ()*ir -p proRe,ts ,* proRe,tsH ()*ir s)eleton ,* s)eleton ()*ir bin lib libH0AW: test

I use a directory named ro,ects to store all the *arious things I'm wor!ing on. Inside that directory I ha*e my s!eleton directory that I ut the basis of my ro,ects into. The directory F-)0 will be renamed to whate*er you are calling your ro,ect's main module when you use the s!eleton. Fe&t we need to setu some initial files#
$ tou,/ libH0AW:.rb $ tou,/ libH0AW:Hversion.rb

Then we can create a 0AW:.ge(spe, file in our ro,ect's root directory which we can use to install our ro,ect later if we want#
1 - -I- en,o*ing: ut+-& -I$:.pus/ ?ile.expan*Npat/@B..HlibBF NN?=L:NNA 3 reLuire B0AW:HversionB ! # Xe(::Spe,i+i,ation.ne8 *o YsY $ s.na(e K B0AW:B < s.version K 0AW:::;:>S=G0 & s.aut/ors K TB>ob SobersBU 9 s.e(ail K TBrsobers_g(ail.,o(BU 1" s./o(epage K BB

>B

s.su((ary K JLOTGDG: Write a ge( su((aryP 11 s.*es,ription K JLOTGDG: Write a ge( *es,riptionP 1 13 s.ruby+orgeNproRe,t K B0AW:B 1! 1# s.+iles K Qgit ls-+ilesQ.split@B5nBA 1$ s.testN+iles K Qgit ls-+iles -- OtestFspe,F+eaturesPHIQ.split@B5nBA 1< s.exe,utables K Qgit ls-+iles -- binHIQ.split@B5nBA.(apO Y+Y 1& ?ile.basena(e@+A P 19 s.reLuireNpat/s K TBlibBU " en*

0dit this file so that it has your contact information and is ready to go for when you co y it. :inally you will want a sim le s!eleton file for unit tests 5which will tal! about more in the ne&t lesson6 named testHtestN0AW:.rb#
1 reLuire DtestHunitD 3 ,lass Wy.nitTests 9 Test::.nit::Test2ase ! # *e+ setup $ puts BsetupCB < en* & 9 *e+ tear*o8n 1" puts Btear*o8nCB 11 en* 1 13 *e+ testNbasi, 1! puts B= >A0CB 1# en* 1$ 1< en*

0nstalling 3e+s
%ems are ac!ages of Ruby code that hel you get things done, so you will need to !now how to install them and use them. Here's the roblem though. +ou are at a oint where it's difficult for me to hel you do that and !ee this boo! sane and clean. There are so many ways to install software on so many com uters that I'd ha*e to s end $8 ages wal!ing you through e*ery ste , and let me tell you I am a laGy guy. Rather than tell you how to do it e&actly, I'm going to tell you what you should install, and then tell you to figure it out and get it wor!ing. This will be really good for you since it will o en a whole world of software you can use that other eo le ha*e released to the world. Fe&t, install the following software ac!ages#

git 1 htt #AAgit1scm.comA ra!e 1 htt #AAra!e.rubyforge.orgA r*m 1 htt s#AAr*m.beginrescueend.comA rubygems 1 htt #AArubygems.orgA agesAdownload bundler 1 htt #AAgembundler.comA

>C

.o not ,ust download these ac!ages and install them by hand. Instead see how other eo le recommend you install these ac!ages and use them for your articular system. The rocess will be different for most *ersions of Linu&, ?/K, and definitely different for Windows. I am warning you, this will be frustrating. In the business we call this "ya! sha*ing". +a! sha*ing is any acti*ity that is mind numblingly irritatingly boring and tedious that you ha*e to do before you can do something else that's more fun. +ou want to create cool Ruby ro,ects, but you can't do that until you setu a s!eleton directory, but you can't setu a s!eleton directory until you install some ac!ages, but you can't install ac!ages until you install ac!age installers, and you can't install ac!age installers until you figure out how your system installs software in general, and so on. /truggle through this anyway. ;onsider it your trial1by1annoyance to get into the rogrammer club. 0*ery rogrammer has to do these annoying tedious tas!s before they can do something cool.

,sing The Skeleton


+ou are now done with most of your ya! sha*ing. Whene*er you want to start a new ro,ect, ,ust do this# $. '. (. B. C. )a!e a co y of your s!eleton directory. Fame it after your new ro,ect. Rename 5mo*e6 the F-)0 directory and 0AW:.rb file to be the name of your ro,ect. 0dit your 0AW:.ge(spe, file to ha*e all the information for your ro,ect. Rename testHtestN0AW:.rb to also ha*e your ro,ect name. /tart coding.

Re8#ired 9#i:
This e&ercise doesn't ha*e e&tra credit but a 3uiG you should com lete# $. '. (. B. Read about how to use all of the things you installed. Read about the 0AW:.ge(spe, file and all it has to offer. )a!e a ro,ect and start writing some code in the 0AW:.rb scri t. Put a scri t in the bin directory that you can run. Read about how you can ma!e a Ruby scri t that's runnable for your system. C. )a!e sure the bin scri t you created is referenced in your 0AW:.ge(spe, so that it gets installed. D. Ese your 0AW:.ge(spe, and ge( buil* ge( install to install your own library and ma!e sure it wor!s, then use ge( uninstall to uninstall it. H. :igure out how you can use 2undler to generate a s!eleton directory automatically.

Exercise (-: Auto"ated Testin!


Ha*ing to ty e commands into your game o*er and o*er to ma!e sure it's wor!ing is annoying. Wouldn't it be better to write little ieces of code that test your codeL Then when you ma!e a change, or add a new thing to your rogram, you ,ust "run your tests" and the

>D

tests ma!e sure things are still wor!ing. These automated tests won't catch all your bugs, but they will cut down on the time you s end re eatedly ty ing and running your code. 0*ery e&ercise after this one will not ha*e a W/at Eou S/oul* See se,tion, but instead it will ha*e a W/at Eou S/oul* Test se,tion. +ou will be writing automated tests for all of your code starting now, and this will ho efully ma!e you an e*en better rogrammer. I won't try to e& lain why you should write automated tests. I will only say that, you are trying to be a rogrammer, and rogrammers automate boring and tedious tas!s. Testing a iece of software is definitely boring and tedious, so you might as well write a little bit of code to do it for you. That should be all the e& lanation you need because your reason for writing unit tests is to ma!e your brain stronger. +ou ha*e gone through this boo! writing code to do things. Fow you are going to ta!e the ne&t lea and write code that !nows about other code you ha*e written. This rocess of writing a test that runs some code you ha*e written forces you to understand clearly what you ha*e ,ust written. It solidifies in your brain e&actly what it does and why it wor!s and gi*es you a new le*el of attention to detail.

Writing A Test Case


We're going to ta!e a *ery sim le iece of code and write one sim le test. We're going to base this little test on a new ro,ect from your ro,ect s!eleton. :irst, ma!e a ex!< ro,ect from your ro,ect s!eleton. )a!e sure you do it right and rename the library and get that first ex!<HtestHtestNex!<.rb test file going right. Fe&t, create a sim le file ex!<HlibHex!<.rb where you can ut the code to test. This will be a *ery silly little class that we want to test with this code in it#
1 ,lass >oo( 3 attrNa,,essor :na(eF :*es,riptionF :pat/s ! # *e+ initialiZe@na(eF *es,riptionA $ _na(e K na(e < _*es,ription K *es,ription & _pat/s K OP 9 en* 1" 11 *e+ go@*ire,tionA 1 _pat/sT*ire,tionU 13 en* 1! 1# *e+ a**Npat/s@pat/sA 1$ _pat/s.up*ate@pat/sA 1< en* 1& 19 en*

?nce you ha*e that file, change unit test s!eleton to this#
1 reLuire DtestHunitD

>H

reLuireNrelative D..HlibHex!<D 3 ! ,lass Wy.nitTests 9 Test::.nit::Test2ase # $ *e+ testNroo(@A < gol* K >oo(.ne8@BXol*>oo(BF & BBBT/is roo( /as gol* in it you ,an grab. T/ereDs a 9 *oor to t/e nort/.BBBA 1" assertNeLual@gol*.na(eF BXol*>oo(BA 11 assertNeLual@gol*.pat/sF OPA 1 en* 13 1! *e+ testNroo(Npat/s@A 1# ,enter K >oo(.ne8@B2enterBF BTest roo( in t/e ,enter.BA 1$ nort/ K >oo(.ne8@B0ort/BF BTest roo( in t/e nort/.BA 1< sout/ K >oo(.ne8@BSout/BF BTest roo( in t/e sout/.BA 1& 19 ,enter.a**Npat/s@O:nort/ K' nort/F :sout/ K' sout/PA " assertNeLual@,enter.go@:nort/AF nort/A 1 assertNeLual@,enter.go@:sout/AF sout/A en* 3 ! *e+ testN(ap@A # start K >oo(.ne8@BStartBF BEou ,an go 8est an* *o8n a /ole.BA $ 8est K >oo(.ne8@BTreesBF BT/ere are trees /ereF you ,an go east.BA < *o8n K >oo(.ne8@BDungeonBF B=tDs *ar) *o8n /ereF you ,an go up.BA & 9 start.a**Npat/s@O:8est K' 8estF :*o8n K' *o8nPA 3" 8est.a**Npat/s@O:east K' startPA 31 *o8n.a**Npat/s@O:up K' startPA 3 33 assertNeLual@start.go@:8estAF 8estA 3! assertNeLual@start.go@:8estA.go@:eastAF startA 3# assertNeLual@start.go@:*o8nA.go@:upAF startA 3$ en* 3< 3& en*

This file re3uires the >oo( class you made in the libHex!<.rb file so that you can do tests on it. There are then a set of tests that are functions starting with testN. Inside each test case there's a bit of code that ma!es a >oo( or a set of >oo(s, and then ma!es sure the rooms wor! the way you e& ect them to wor!. It tests out the basic room features, then the aths, then tries out a whole ma . The im ortant functions here are assertNeLual which ma!es sure that *ariables you ha*e set or aths you ha*e built in a >oo( are actually what you thin! they are. If you get the wrong result, then Ruby's Test::.nit module will rint out an error message so you can go figure it out.

Testing 3#idelines
:ollow these general loose set of guidelines when ma!ing your tests# $. Test files go in testH and are named testN0AW:.rb. This !ee s your tests from clashing with your other code. '. Write one test file for each module or class you ma!e.

>4

(. 7ee your test cases 5functions6 short, but do not worry if they are a bit messy. Test cases are usually !ind of messy. B. 0*en though test cases are messy, try to !ee them clean and remo*e any re etiti*e code you can. ;reate hel er functions that get rid of du licate code. +ou will than! me later when you ma!e a change and then ha*e to change your tests. .u licated code will ma!e changing your tests more difficult. C. :inally, do not get too attached to your tests. /ometimes, the best way to redesign something is to ,ust delete it, the tests, and start o*er.

What "o# Sho#ld See


$ ruby testNex!<.rb Loa*e* suite testNex!< Starte* ... ?inis/e* in "."""3#3 se,on*s. 3 testsF < assertionsF " +ailuresF " errorsF " s)ips Test run options: --see* $3#3<

That's what you should see if e*erything is wor!ing right. Try causing an error to see what that loo!s li!e and then fi& it.

(%tra Credit
$. %o read about Test::.nit more, and also read about alternati*es. '. Learn about >spe, and see if you li!e it better. (. )a!e your Room more ad*anced, and then use it to rebuild your game yet again but this time, unit test as you go.

Exercise (.: Ad:anced 4ser Input


+our game robably was coming along great, but I bet how you handled what the user ty ed was becoming tedious. 0ach room needed its own *ery e&act set of hrases that only wor!ed if your layer ty ed them erfectly. What you'd rather ha*e is a de*ice that lets users ty e hrases in *arious ways. :or e&am le, we'd li!e to ha*e all of these hrases wor! the same#

o en door o en the door go THR?E%H the door unch bear Punch The 2ear in the :-;0

It should be alright for a user to write something a lot li!e 0nglish for your game, and ha*e your game figure out what it means. To do this, we're going to write a library that does ,ust that. This module will ha*e a few classes that wor! together to handle use in ut and con*ert it into something your game can wor! with reliably. In a sim le *ersion of 0nglish the following elements#

Words se arated by s aces. >>

/entences com osed of the words. %rammar that structures the sentences into meaning.

That means the best lace to start is figuring out how to get words from the user and what !inds of words those are.

O#r 3a+e Le%icon


In our game we ha*e to create a Le&icon of words#

.irection words# north, south, east, west, down, u , left, right, bac!. @erbs# go, sto , !ill, eat. /to words# the, in, of, from, at, it Founs# door, bear, rincess, cabinet. Fumbers# any string of 8 through > characters.

When we get to nouns, we ha*e a slight roblem since each room could ha*e a different set of Founs, but let's ,ust ic! this small set to wor! with for now and im ro*e it later.

'reaking ,p A Sentence
?nce we ha*e our le&icon of words we need a way to brea! u sentences so that we can figure out what they are. In our case, we'*e defined a sentence as "words se arated by s aces", so we really ,ust need to do this#
stu++ K gets.,/o(p@A 8or*s K stu++.split@A

That's really all we'll worry about for now, but this will wor! really well for 3uite a while.

Le%icon Str#cts
?nce we !now how to brea! u a sentence into words, we ,ust ha*e to go through the list of words and figure out what "ty e" they are. To do that we're going to use a handy little Ruby structure called a "struct". - struct is a con*enient way to bundle a number of attributes together, using accessor methods, without ha*ing to write an e& licit class. It's created li!e this#
3air K Stru,t.ne8@:to)enF :8or*A +irstN8or* K 3air.ne8@B*ire,tionBF Bnort/BA se,on*N8or* K 3air.ne8@BverbBF BgoBA senten,e K T+irstN8or*F se,on*N8or*U

This creates a air of 5T?70F, W?R.6 that lets you loo! at the word and do things with it. This is ,ust an e&am le, but that's basically the end result. +ou want to ta!e in ut from the user, car*e it into words with s lit, then analyGe those words to identify their ty e, and finally ma!e a sentence out of them.

$88

Scanning 0np#t
Fow you are ready to write your scanner. This scanner will ta!e a string of in ut from a user and return a sentence that's com osed of a list of structs with the 5T?70F, W?R.6 airings. If a word isn't art of the le&icon then it should still return the W?R., but set the T?70F to an error to!en. These error to!ens will tell the user they messed u . Here's where it gets fun. I'm not going to tell you how to do this. Instead I'm going to write a unit test und you are going to write the scanner so that the unit test wor!s.

(%ceptions And N#+/ers


There is one tiny thing I will hel you with first, and that's con*erting numbers. In order to do this though, we're going to cheat and use e&ce tions. -n e&ce tion is an error that you get from some function you may ha*e run. What ha ens is your function "raises" an e&ce tion when it encounters an error, then you ha*e to handle that e&ce tion. :or e&am le, if you ty e this into IR2#
ruby-1.9. -p1&" :""1 ' =nteger@B/ellBA Argu(ent:rror: invali* value +or =nteger@A: B/ellB +ro( @irbA:1:in Q=ntegerD +ro( @irbA:1 +ro( H/o(eHrobH.rv(HrubiesHruby-1.9. -p1&"HbinHirb:1$:in Q9(ain'D

That Argu(ent:rror is an e&ce tion that the =nteger@A function threw because what you handed =nteger@A is not a number. The =nteger@A function could ha*e returned a *alue to tell you it had an error, but since it only returns numbers, it'd ha*e a hard time doing that. It can't return 1$ since that's a number. Instead of trying to figure out what to return when there's an error, the =nteger@A function raises the Type:rror e&ce tion and you deal with it. +ou deal with an e&ce tion by using the begin and res,ue !eywords#
*e+ ,onvertNnu(ber@sA begin =nteger@sA res,ue Argu(ent:rror nil en* en*

+ou ut the code you want to "begin" inside the begin bloc!, and then you ut the code to run for the error inside the res,ue. In this case, we want to call =nteger@A on something that might be a number. If that has an error, then we "rescue" it and return nil instead. In your scanner that you write, you should use this function to test if something is a number. +ou should also do it as the last thing you chec! for before declaring that word an error word.

What "o# Sho#ld Test


Here are the files testHtestNlexi,on.rb that you should use#

$8$

reLuire DtestHunitD 1 reLuireNrelative B..HlibHlexi,onB 3 ,lass Lexi,onTests 9 Test::.nit::Test2ase ! # 3air K Lexi,on::3air $ __lexi,on K Lexi,on.ne8@A < & *e+ testN*ire,tions@A 9 assertNeLual@T3air.ne8@:*ire,tionF Dnort/DAUF 1" __lexi,on.s,an@Bnort/BAA 11 result K __lexi,on.s,an@Bnort/ sout/ eastBA 1 assertNeLual@resultF T3air.ne8@:*ire,tionF Dnort/DAF 13 3air.ne8@:*ire,tionF Dsout/DAF 1! 3air.ne8@:*ire,tionF DeastDAUA 1# en* 1$ 1< *e+ testNverbs@A 1& assertNeLual@__lexi,on.s,an@BgoBAF T3air.ne8@:verbF DgoDAUA 19 result K __lexi,on.s,an@Bgo )ill eatBA " assertNeLual@resultF T3air.ne8@:verbF DgoDAF 1 3air.ne8@:verbF D)illDAF 3air.ne8@:verbF DeatDAUA 3 en* ! # *e+ testNstops@A $ assertNeLual@__lexi,on.s,an@Bt/eBAF T3air.ne8@:stopF Dt/eDAUA < result K __lexi,on.s,an@Bt/e in o+BA & assertNeLual@resultF T3air.ne8@:stopF Dt/eDAF 9 3air.ne8@:stopF DinDAF 3" 3air.ne8@:stopF Do+DAUA 31 en* 3 33 *e+ testNnouns@A 3! assertNeLual@__lexi,on.s,an@BbearBAF T3air.ne8@:nounF DbearDAUA 3# result K __lexi,on.s,an@Bbear prin,essBA 3$ assertNeLual@resultF T3air.ne8@:nounF DbearDAF 3< 3air.ne8@:nounF Dprin,essDAUA 3& en* 39 !" *e+ testNnu(bers@A !1 assertNeLual@__lexi,on.s,an@B1 3!BAF T3air.ne8@:nu(berF 1 3!AUA ! result K __lexi,on.s,an@B3 91 3!BA !3 assertNeLual@resultF T3air.ne8@:nu(berF 3AF !! 3air.ne8@:nu(berF 91 3!AUA !# en* !$ !< *e+ testNerrors@A !& assertNeLual@__lexi,on.s,an@BASD?AD?ASD?BAF T3air.ne8@:errorF !9 DASD?AD?ASD?DAUA #" result K __lexi,on.s,an@Bbear =AS prin,essBA #1 assertNeLual@resultF T3air.ne8@:nounF DbearDAF # 3air.ne8@:errorF D=ASDAF #3 3air.ne8@:nounF Dprin,essDAUA #! en* ## en*

$8'

Remember that you will want to ma!e a new ro,ect with your s!eleton, ty e in this test case 5do not co y1 asteO6 and write your scanner so that the test runs. :ocus on the details and ma!e sure e*erything wor!s right.

Design )ints
:ocus on getting one test wor!ing at a time. 7ee this sim le and ,ust ut all the words in your le&icon in lists that are in your lexi,on.rb file. .o not modify the in ut list of words, but instead ma!e your own new list with your le&icon airs in it. -lso, use the in,lu*eM method with these le&icon arrays to chec! if a word is in the le&icon.

(%tra Credit
$. Im ro*e the unit test to ma!e sure you co*er more of the le&icon. '. -dd to the le&icon and then u date the unit test. (. )a!e your scanner handles user in ut in any ca italiGation and case. E date the test to ma!e sure this actually wor!s. B. :ind another way to con*ert the number. C. )y solution was (H lines long. Is yours longerL /horterL

Exercise (0: 'a2in! Sentences


What we should be able to get from our little game le&icon scanner is a list that loo!s li!e this 5yours will be formatted differently6#
ruby-1.9. -p1&" :""3 ' print Lexi,on.s,an@Bgo nort/BA T-9stru,t Lexi,on::3air to)enK:verbF 8or*KBgoB'F -9stru,t Lexi,on::3air to)enK:*ire,tionF 8or*KBnort/B'U K' nil ruby-1.9. -p1&" :""! ' print Lexi,on.s,an@B)ill t/e prin,essBA T-9stru,t Lexi,on::3air to)enK:verbF 8or*KB)illB'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBt/eB'F -9stru,t Lexi,on::3air to)enK:nounF 8or*KBprin,essB'U K' nil ruby-1.9. -p1&" :""# ' print Lexi,on.s,an@Beat t/e bearBA T-9stru,t Lexi,on::3air to)enK:verbF 8or*KBeatB'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBt/eB'F -9stru,t Lexi,on::3air to)enK:nounF 8or*KBbearB'U K' nil ruby-1.9. -p1&" :""$ ' print Lexi,on.s,an@Bopen t/e *oor an* s(a,) t/e bear in t/e noseBA T-9stru,t Lexi,on::3air to)enK:errorF 8or*KBopenB'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBt/eB'F -9stru,t Lexi,on::3air to)enK:nounF 8or*KB*oorB'F -9stru,t Lexi,on::3air to)enK:errorF 8or*KBan*B'F -9stru,t Lexi,on::3air to)enK:errorF 8or*KBs(a,)B'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBt/eB'F -9stru,t Lexi,on::3air to)enK:nounF 8or*KBbearB'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBinB'F -9stru,t Lexi,on::3air to)enK:stopF 8or*KBt/eB'F -9stru,t Lexi,on::3air to)enK:errorF 8or*KBnoseB'U K' nil ruby-1.9. -p1&" :""< '

Fow let us turn this into something the game can wor! with, which would be some !ind of /entence class. If you remember grade school, a sentence can be a sim le structure li!e# $8(

/ub,ect @erb ?b,ect ?b*iously it gets more com le& than that, and you robably did many days of annoying sentence gra hs for 0nglish class. What we want is to turn the abo*e lists of structs into a nice /entence ob,ect that has sub,ect, *erb, and ob,ect.

Match And Peek


To do this we need four tools# $. - way to loo through the list of structs. That's easy. '. - way to "match" different ty es of structs that we e& ect in our /ub,ect @erb ?b,ect setu . (. - way to " ee!" at a otential struct so we can ma!e some decisions. B. - way to "s!i " things we do not care about, li!e sto words. C. We use the ee! function to say loo! at the ne&t element in our struct array, and then match to ta!e one off and wor! with it. Let's ta!e a loo! at a first ee! function#
*e+ pee)@8or*NlistA begin 8or*Nlist.+irst.to)en res,ue nil en* en*

@ery easy. Fow for the match function#


*e+ (at,/@8or*NlistF expe,tingA begin 8or* K 8or*Nlist.s/i+t i+ 8or*.to)en KK expe,ting 8or* else nil en* res,ue nil en* en*

-gain, *ery easy, and finally our s!i function#


*e+ s)ip@8or*NlistF 8or*NtypeA 8/ile pee)@8or*NlistA KK 8or*Ntype (at,/@8or*NlistF 8or*NtypeA en* en*

2y now you should be able to figure out what these do. )a!e sure you understand them.

$8B

The Sentence 3ra++ar


With our tools we can now begin to build /entence ob,ects from our array of structs. What we do is a rocess of# $. Identify the ne&t word with pee). '. If that word fits in our grammar, we call a function to handle that art of the grammar, say parseNsubRe,t. (. If it doesn't, we raise an error, which you will learn about in this lesson. B. When we're all done, we should ha*e a /entence ob,ect to wor! with in our game. The best way to demonstrate this is to gi*e you the code to read, but here's where this e&ercise is different from the re*ious one# +ou will write the test for the arser code I gi*e you. Rather than gi*ing you the test so you can write the code, I will gi*e you the code, and you ha*e to write the test. Here's the code that I wrote for arsing sim le sentences using the ex!& Le&icon class#
1 ,lass 3arser:rror 9 :x,eption 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 1& 19 " 1 3 ! # $ < & 9 3" 31 3 33 3! 3# 3$ 3< 3& 39 en* ,lass Senten,e *e+ initialiZe@subRe,tF verbF obRe,tA - re(e(ber 8e ta)e 3air.ne8@:nounF Bprin,essBA stru,ts an* ,onvert t/e( _subRe,t K subRe,t.8or* _verb K verb.8or* _obRe,t K obRe,t.8or* en* en* (o*ule 3arser *e+ sel+.pee)@8or*NlistA begin 8or*Nlist.+irst.to)en res,ue nil en* en* *e+ sel+.(at,/@8or*NlistF expe,tingA begin 8or* K 8or*Nlist.s/i+t i+ 8or*.to)en KK expe,ting 8or* else nil en* res,ue nil en* en*

$8C

*e+ sel+.s)ip@8or*NlistF to)enA !" 8/ile pee)@8or*NlistA KK to)en !1 (at,/@8or*NlistF to)enA ! en* !3 en* !! !# *e+ sel+.parseNverb@8or*NlistA !$ s)ip@8or*NlistF :stopA !< !& i+ pee)@8or*NlistA KK :verb !9 return (at,/@8or*NlistF :verbA #" else #1 raise 3arser:rror.ne8@B:xpe,te* a verb next.BA # en* #3 en* #! ## *e+ sel+.parseNobRe,t@8or*NlistA #$ s)ip@8or*NlistF :stopA #< nextN8or* K pee)@8or*NlistA #& #9 i+ nextN8or* KK :noun $" return (at,/@8or*NlistF :nounA $1 en* $ i+ nextN8or* KK :*ire,tion $3 return (at,/@8or*NlistF :*ire,tionA $! else $# raise 3arser:rror.ne8@B:xpe,te* a noun or *ire,tion next.BA $$ en* $< en* $& $9 *e+ sel+.parseNsubRe,t@8or*NlistF subRA <" verb K parseNverb@8or*NlistA <1 obR K parseNobRe,t@8or*NlistA < <3 return Senten,e.ne8@subRF verbF obRA <! en* <# <$ *e+ sel+.parseNsenten,e@8or*NlistA << s)ip@8or*NlistF :stopA <& <9 start K pee)@8or*NlistA &" &1 i+ start KK :noun & subR K (at,/@8or*NlistF :nounA &3 return parseNsubRe,t@8or*NlistF subRA &! elsi+ start KK :verb &# - assu(e t/e subRe,t is t/e player t/en &$ return parseNsubRe,t@8or*NlistF 3air.ne8@:nounF BplayerBAA &< else && raise 3arser:rror.ne8@BWust start 8it/ subRe,tF obRe,tF or verb &9 not: -OstartPBA 9" en* 91 en* 9 en*

A Word On Mod#les
This code uses something in Ruby called a "module" named 3arser. - module 5created with (o*ule 3arser6 is a way to ac!age u the functions so that they don't conflict with other $8D

arts of Ruby. In Ruby $.> there was a change to the testing system that created a s)ip method which conflicted with the 3arser.s)ip method. The solution was to do what you see here and wra all the functions in this module. +ou use a module by sim ly calling functions on it with the . o erator, similar to an ob,ect you'*e made. In this case if you wanted to call the parseNverb@A function you'd write 3arser.parseNverb@A. +ou'll see a demonstration of this when I gi*e you a sam le unit test.

A Word On (%ceptions
+ou briefly learned about e&ce tions, but not how to raise them. This code demonstrates how to do that with the 3arser:rror at the to . Fotice that it uses classes to gi*e it the ty e of :x,eption. -lso notice the use of raise !eyword to raise the e&ce tion. In your tests, you will want to wor! with these e&ce tions, which I'll show you how to do.

What "o# Sho#ld Test


:or 0&ercise B> is write a com lete test that confirms e*erything in this code is wor!ing. That includes ma!ing e&ce tions ha en by gi*ing it bad sentences. Here is a starter sam le so you can see how you would call a function in a module#
1 reLuire DtestHunitD reLuireNrelative D..HlibHex!9D 3 ! ,lass 3arserTests 9 Test::.nit::Test2ase # $ *e+ testNparseNverb@A < - WA>0=0X: T7=S ?A=LS G0 3.>3GS: S:: T7: SGG\ & 3arser.parseNverb@T+alseUA 9 en* 1" 11 en*

+ou can see I ma!e the basic test class, then create a testNparseNverb to test out the 3arser.parseNverb function. I don't want to do the wor! for you, so I'*e made this fail on purpose. This shows you how to use the 3arser module and call functions on it, and you should wor! on ma!ing this test actually test all the code. ;hec! for an e&ce tion by using the function assertNraise from the Test##Enit documentation. Learn how to use this so you can write a test that is e& ected to fail, which is *ery im ortant in testing. Learn about this function 5and others6 by reading the Test##Enit documentation. When you are done, you should !now how this bit of code wor!s, and how to write a test for other eo le's code e*en if they do not want you to. Trust me, it's a *ery handy s!ill to ha*e.

(%tra Credit
$. ;hange the parseN methods and try to ut them into a class rather than be ,ust methods. Which design do you li!e betterL $8H

'. )a!e the arser more error resistant so that you can a*oid annoying your users if they ty e words your le&icon doesn't understand. (. Im ro*e the grammar by handling more things li!e numbers. B. Thin! about how you might use this /entence class in your game to do more fun things with a user's in ut.

Exercise +0: 7our First Website


These final three e&ercises will be *ery hard and you should ta!e your time with them. In this first one you'll build a sim le web *ersion of one of your games. 2efore you attem t this e&ercise you must ha*e com leted 0&ercise BD successfully and ha*e a wor!ing RubyGe"s installed such that you can install ac!ages and !now how to ma!e a s!eleton ro,ect directory. If you don't remember how to do this, go bac! to 0&ercise BD and do it all o*er again.

0nstalling Sinatra
2efore creating your first web a lication, you'll first need to install the "web framewor!" called Sinatra. The term "framewor!" generally means "some ac!age that ma!es it easier for me to do something". In the world of web a lications, eo le create "web framewor!s" to com ensate for the difficult roblems they'*e encountered when ma!ing their own sites. They share these common solutions in the form of a ac!age you can download to bootstra your own ro,ects. In our case, we'll be using the /inatra framewor!, but there are many, many, many others you can choose from. :or now, learn /inatra then branch out to another one when you're ready 5or ,ust !ee using /inatra since it's good enough6. Esing ge( install /inatra#
$ ge( install sinatra ?et,/ing: tilt-1.3. .ge( @1""JA ?et,/ing: sinatra-1. .$.ge( @1""JA Su,,ess+ully installe* tilt-1.3. Su,,ess+ully installe* sinatra-1. .$ ge(s installe* =nstalling ri *o,u(entation +or tilt-1.3. ... =nstalling ri *o,u(entation +or sinatra-1. .$... =nstalling >Do, *o,u(entation +or tilt-1.3. ... =nstalling >Do, *o,u(entation +or sinatra-1. .$...

Make A Si+ple ;)ello World; Pro2ect


Fow you're going to ma!e an initial *ery sim le "Hello World" web a lication and ro,ect directory using /inatra. :irst, ma!e your ro,ect directory#
$ ,* proRe,ts $ bun*le ge( got/on8eb

$84

+ou'll be ta!ing the game from 0&ercise B' and ma!ing it into a web a lication, so that's why you're calling it got/on8eb. 2efore you do that, we need to create the most basic /inatra a lication ossible. Put the following code into libHgot/on8eb.rb#
1 reLuireNrelative Bgot/on8ebHversionB reLuire BsinatraB 3 ! (o*ule Xot/on8eb # get DHD *o $ greeting K B7elloF Worl*CB < return greeting & en* 9 en*

Then run the a lication li!e this#


$ ruby libHgot/on8eb.rb KK SinatraH1. .$ /as ta)en t/e stage on !#$< +or *evelop(ent 8it/ ba,)up +ro( W:Sri,) T "11-"<-1& 11: <:"<U =0?G W:Sri,) 1.3.1 T "11-"<-1& 11: <:"<U =0?G ruby 1.9. @ "11-" -1&A Tx&$N$!-linuxU T "11-"<-1& 11: <:"<U =0?G W:Sri,)::7TT3Server-start: pi*K$#99 portK!#$<

:inally, use your web browser and go to the ERL /ttp:HHlo,al/ost:!#$<H and you should see two things. :irst, in your browser you'll see 7elloF Worl*C. /econd, you'll see your terminal with new out ut li!e this#
1 <.".".1 - - T1&HVulH lo,al/ost - - T1&HVulH - -' H 1 <.".".1 - - T1&HVulH "."""& lo,al/ost - - T1&HVulH !!< - -' H+avi,on.i,o "11 11: 9:1"U BX:T H 7TT3H1.1B "" 1 ".""1# "11:11: 9:1" :DTU BX:T H 7TT3H1.1B "" 1 "11 11: 9:1"U BX:T H+avi,on.i,o 7TT3H1.1B !"! !!< "11:11: 9:1" :DTU BX:T H+avi,on.i,o 7TT3H1.1B !"!

Those are log messages that /inatra rints out so you can see that the ser*er is wor!ing, and what the browser is doing behind the scenes. The log messages hel you debug and figure out when you ha*e roblems. :or e&am le, it's saying that your browser tried to get H+avi,on.i,o but that file didn't e&ist so it returned !"! 0ot ?oun* status code. I ha*en't e& lained the way any of this web stuff wor!s yet, because I want to get you setu and ready to roll so that I can e& lain it better in the ne&t two e&ercises. To accom lish this, I'll ha*e you brea! your /inatra a lication in *arious ways and then restructure it so that you !now how it's setu .

What*s 3oing On4


Here's what's ha ening when your browser hits your a lication# $. +our browser ma!es a networ! connection to your own com uter, which is called lo,al/ost and is a standard way of saying "whate*er my own com uter is called on the networ!". It also uses port !#$<.

$8>

'. ?nce it connects, it ma!es an HTTP re3uest to the libHgot/on8eb.rb a lication and as!s for the H ERL, which is commonly the first ERL on any website. (. Inside libHgot/on8eb.rb you'*e got bloc!s of code that ma to ERLs. The only one we ha*e is the DHD ma ing. This means that whene*er someone goes to H with a browser, /inatra will find the code bloc! to handle the re3uest. B. /inatra calls the matching bloc!, which sim ly returns a string for what /inatra should send to the browser. C. :inally, /inatra has handled the re3uest and sends this res onse to the browser which is what you are seeing. )a!e sure you really understand this. .raw u a diagram of how this information flows from your browser, to /inatra, then to the H bloc! and bac! to your browser.

&i%ing (rrors
:irst, delete line D where you assign the greeting *ariable, then hit refresh in your browser. +ou should see an error age now that gi*es you lots of information on how your a lication ,ust e& loded. +ou !now that the *ariable greeting is now missing, but /inatra gi*es you this nice error age to trac! down e&actly where. .o each of the following with this age# $. Loo! at the sinatra.error *ariable. '. Loo! at the >:4.:STN *ariables and see if they match anything you're already familiar with. This is information that your web browser is sending to your gothonweb a lication. +ou normally don't e*en !now that it's sending this stuff, so now you get to see what it does.

Create 'asic Te+plates


+ou can brea! your /inatra a lication, but did you notice that "Hello World" isn't a *ery good HT)L ageL This is a web a lication, and as such it needs a ro er HT)L res onse. To do that you will create a sim le tem late that says "Hello World" in a big green font. The first ste is to create a libHvie8sHin*ex.erb file that loo!s li!e this#
9/t(l' 9/ea*' 9title'Xot/ons G+ 3lanet 3er,al - #9Htitle' 3 9H/ea*' ! 9bo*y' # $ 9J i+ greeting J' < 9p'= Rust 8ante* to say 9e( styleKB,olor: green[ +ont-siZe: & JK greeting J'9He('. 9 9J else J' 1" 9e('7ello9He('F 8orl*C 11 9J en* J' 1 13 9Hbo*y' 1! 9H/t(l' 1

e([B'9

What is a .erb fileL 0R2 stands for 0mbedded Ruby. .erb files are HT)L with bits of Ruby code embedded within. If you !now what HT)L is then this should loo! fairly familiar. If $$8

not, research HT)L and try writing a few web ages by hand so you !now how it wor!s. /ince this is an erb tem late, /inatra will fill in "holes" in the te&t de ending on *ariables you ass in to the tem late. 0*ery lace you see 9JK greeting J' will be a *ariable you'll ass to the tem late that alters its contents. To ma!e your libHgot/on8eb.rb scri t do this, you need to add some code to tell /inatra where to load the tem late and to render it. Ta!e that file and change it li!e this#
1 reLuireNrelative Bgot/on8ebHversionB reLuire BsinatraB 3 reLuire BerbB ! # (o*ule Xot/on8eb $ get DHD *o < greeting K B7elloF Worl*CB & erb :in*exF :lo,als K' O:greeting K' greetingP 9 en* 1" en*

Pay close attention to how I changed the last line of the H bloc! so it calls erb assing in your greeting *ariable. ?nce you ha*e that in lace, reload the web age in your browser and you should see a different message in green. +ou should also be able to do a @iew /ource on the age in your browser to see that it is *alid HT)L. This may ha*e flown by you *ery fast, so let me e& lain how a tem late wor!s# $. In your libHgot/on8eb.rb you'*e added a new erb method call. '. The erb method !nows how to load .erb files out of the libHvie8sH directory. It !nows which file to grab 5in*ex.erb in this case6 because you ass it as a arameter 5erb :in*ex ...6. (. Fow, when the browser hits H and libHgot/on8eb.rb matches and e&ecutes the get DHD *o bloc!, instead of ,ust returning the string greeting, it calls erb and ass greeting to it as a *ariable. B. :inally, you ha*e the HT)L in libHvie8sHin*ex.erb that contains a bit of Ruby code that tests the greeting variable, and if it's there, rints one message using the greeting, or a default message. To get dee er into this, change the greeting *ariable and the HT)L to see what effect it has. -lso create another tem late named libHvie8sH+oo.lib and render that using erb :+oo instead of erb :in*ex li!e before. This will show you how the first arameter you ass to erb is ,ust matched to a .erb file in libHvie8sH.

(%tra Credit
$. '. (. B. Read the documentation at htt #AAwww.sinatrarb.com. 0& eriment with e*erything you can find there, including their e&am le code. Read about HT)LC and ;//( and ma!e some ./t(l and .,ss files for ractice. If you ha*e a friend who !nows Rai*s and is willing to hel you, then consider doing 0& C8, C$, and C' in Rails instead to see what that's li!e.

$$$

Exercise +1: Gettin! Input Fro" A ?ro9ser


While it's e&citing to see the browser dis lay "Hello World", it's e*en more e&citing to let the user submit te&t to your a lication from a form. In this e&ercise we'll im ro*e our starter web a lication using forms and figure out how to do automated testing for a web a lication.

)o$ The We/ Works


Time for some boring stuff. +ou need to understand a bit more about how the web wor!s before you can ma!e a form. This descri tion isn't com lete, but it's accurate and will hel you figure out what might be going wrong with your a lication. -lso, creating forms will be easier if you !now what they do. I'll start with a sim le diagram that shows you the different arts of a web re3uest and how the information flows#

htt re3uest diagram I'*e labeled the lines with letters so I can wal! you through a regular re3uest rocess# $. +ou ty e in the url htt #AAlearn ythonthehardway.orgA into your browser and it sends the re3uest out on line @AA to your com uter's networ! interface. '. +our re3uest goes out o*er the internet on line @SA and then to the remote com uter on line @2A where my ser*er acce ts the re3uest. (. ?nce my com uter acce ts it, my web a lication gets it on line @DA, and my web a lication code runs the H 5inde&6 handler. B. The res onse comes out of my web ser*er when I return it, and goes bac! to your browser o*er line @DA again. C. The ser*er running this site ta!es the res onse off line @DA then sends it bac! o*er the internet on line @2A. D. The res onse from the ser*er then comes off the internet on line @SA, and your com uter's networ! interface hands it to your browser on line @AA. H. :inally, your browser then dis lays the res onse. In this descri tion there are a few terms you should !now so that you ha*e a common *ocabulary to wor! with when tal!ing about your web a lication#

$$'

Bro% er
The software that you're robably using e*ery day. )ost eo le don't !now what it really does, they ,ust call it "the internet". Its ,ob is to ta!e addresses 5li!e htt #AAlearn ythonthehardway.org6 you ty e into the ERL bar, then use that information to ma!e re3uests to the ser*er at that address.

Addre
This is normally a ERL 5Eniform Resource Locator6 li!e htt #AAlearn ythonthehardway.orgA and indicates where a browser should go. The first art /ttp indicates the rotocol you want to use, in this case "Hy er1Te&t Trans ort Protocol". +ou can also try ft #AAibiblio.orgA to see how ":ile Trans ort Protocol" wor!s. The learnpyt/ont/e/ar*8ay.org art is the "hostname", or a human readable address you can remember and which ma s to a number called an IP address, similar to a tele hone number for a com uter on the Internet. :inally, ERLs can ha*e a trailing pat/ li!e the Hboo)H art of htt #AAlearn ythonthehardway.orgAboo!A which indicates a file or some resource on the ser*er to retrie*e with a re3uest. There are many other arts, but those are the main ones.

Connection
?nce a browser !nows what rotocol you want to use 5htt 6, what ser*er you want to tal! to 5learn ythonthehardway.org6, and what resource on that ser*er to get, it must ma!e a connection. The browser sim ly as!s your ? erating /ystem 5?/6 to o en a " ort" to the com uter, usually ort 48. When it wor!s the ?/ hands bac! to your rogram something that wor!s li!e a file, but is actually sending and recei*ing bytes o*er the networ! wires between your com uter and the other com uter at "learn ythonthehardway.org". This is also the same thing that ha ens with htt #AAlocalhost#4848A but in this case you're telling the browser to connect to your own com uter 5localhost6 and use ort BCDH rather than the default of 48. +ou could also do htt #AAlearn ythonthehardway.org#48A and get the same result, e&ce t you're e& licitly saying to use ort 48 instead of letting it be that by default.

&e'ue t
+our browser is connected using the address you ga*e. Fow it needs to as! for the resource it wants 5or you want6 on the remote ser*er. If you ga*e Hboo)H at the end of the ERL, then you want the file 5resource6 at Hboo)H, and most ser*ers will use the real file Hboo)Hin*ex./t(l but retend it doesn't e&ist. What the browser does to get this resource is send a re3uest to the ser*er. I won't get into e&actly how it does this, but ,ust understand that it has to send something to 3uery the ser*er for the re3uest. The interesting thing is that these "resources" don't ha*e to be files. :or instance, when the browser in your a lication as!s for something, the ser*er is returning something your code generated.

Server
The ser*er is the com uter at the end of a browser's connection that !nows how to answer your browser's re3uests for filesAresources. )ost web ser*ers ,ust send files, and that's actually the ma,ority of traffic. 2ut you're actually building a ser*er in Ruby that !nows how to ta!e re3uests for resources, and then return strings that you craft using Ruby. When you do

$$(

this crafting, you are retending to be a file to the browser, but really it's ,ust code. -s you can see from 0&. C8, it also doesn't ta!e much code to create a res onse.

&e pon e
This is the HT)L 5css, ,a*ascri t, or images6 your ser*er wants to send bac! to the browser as the answer to the browser's re3uest. In the case of files, it ,ust reads them off the dis! and sends them to the browser, but it wra s the contents of the dis! in a s ecial "header" so the browser !nows what it's getting. In the case of your a lication, you're still sending the same thing, including the header, but you generate that data on the fly with your Ruby code. That is the fastest crash course in how a web browser accesses information on ser*ers on the internet. It should wor! well enough for you to understand this e&ercise, but if not, read about it as much as you can until you get it. - really good way to do that is to ta!e the diagram, and brea! different arts of the web a lication you did in 0&ercise C8. If you can brea! your web a lication in redictable ways using the diagram, you'll start to understand how it wor!s.

)o$ &or+s Work


The best way to lay with forms is to write some code that acce ts form data, and then see what you can do. Ta!e your libHgot/on8eb.rb file and ma!e it loo! li!e this#
1 reLuireNrelative Bgot/on8ebHversionB reLuire BsinatraB 3 reLuire BerbB ! # (o*ule Xot/on8eb $ get DHD *o < greeting K B7elloF Worl*CB & erb :in*exF :lo,als K' O:greeting K' greetingP 9 en* 1" 11 get DH/elloD *o 1 na(e K para(sT:na(eU YY B0obo*yB 13 greeting K B7elloF -Ona(ePB 1! erb :in*exF :lo,als K' O:greeting K' greetingP 1# en* 1$ en*

Restart /inatra 5hit ;TRL1; and then run it again6 to ma!e sure it loads again, then with your browser go to /ttp:HHlo,al/ost:!#$<H/ello which should dis lay, "I ,ust wanted to say Hello, Fobody." Fe&t, change the ERL in your browser to /ttp:HHlo,al/ost:!#$<H/elloMna(eK?ran) and you'll see it say "Hello, :ran!." :inally, change the na(eK?ran) art to be your name. Fow it's saying hello to you. Let's brea! down the changes I made to your scri t. $. Instead of ,ust a string for greeting I'm now using the para(s hash to get data from the browser. /inatra ta!es all of the !eyA*alue airs after the M art of the ERL and adds them to the para(s hash for you to wor! with. '. I then construct the greeting from the na(e *alue we e&tracted *ia the para(sT:na(eU hash loo!u , which should be *ery familiar to you by now.

$$B

(. 0*erything else about the file is the same as before. +ou're also not restricted to ,ust one arameter on the ERL. ;hange this e&am le to gi*e two *ariables li!e this# /ttp:HHlo,al/ost:!#$<H/elloMna(eK?ran)]greetK7ola. Then change the code to get para(sT:na(eU and para(sT:greetU li!e this#
greeting K B-OgreetPF -Ona(ePB

Creating )TML &or+s


Passing the arameters on the ERL wor!s, but it's !ind of ugly and not easy to use for regular eo le. What you really want is a "P?/T form", which is a s ecial HT)L file that has a 9+or(' tag in it. This form will collect information from the user, then send it to your web a lication ,ust li!e you did abo*e. Let's ma!e a 3uic! one so you can see how it wor!s. Here's the new HT)L file you need to create, in libHvie8sH/elloN+or(.erb#
1 9/t(l' 9/ea*' 3 9title'Sa(ple Web ?or(9Htitle' ! 9H/ea*' # 9bo*y' $ < 9/1'?ill Gut T/is ?or(9H/1' & 9 9+or( a,tionKBH/elloB (et/o*KB3GSTB' 1" A Xreeting: 9input typeKBtextB na(eKBgreetB' 11 9brH' 1 Eour 0a(e: 9input typeKBtextB na(eKBna(eB' 13 9brH' 1! 9input typeKBsub(itB' 1# 9H+or(' 1$ 1< 9Hbo*y' 1& 9H/t(l'

+ou should then change libHgot/on8eb.rb to loo! li!e this#


1 reLuireNrelative Bgot/on8ebHversionB reLuire BsinatraB 3 reLuire BerbB ! # (o*ule Xot/on8eb $ < get DHD *o & greeting K B7elloF Worl*CB 9 erb :in*exF :lo,als K' O:greeting K' greetingP 1" en* 11 1 get DH/elloD *o 13 erb :/elloN+or( 1! en* 1# 1$ post DH/elloD *o 1< greeting K B-Opara(sT:greetU YY B7elloBPF -Opara(sT:na(eU YY

$$C

1& 19 " 1

B0obo*yBPB erb :in*exF :lo,als K' O:greeting K' greetingP en* en*

?nce you'*e got those written u , sim ly restart the web a lication again and hit it with your browser li!e before. This time you'll get a form as!ing you for "- %reeting" and "+our Fame". When you hit the /ubmit button on the form, it will gi*e you the same greeting you normally get, but this time loo! at the ERL in your browser. /ee how it's /ttp:HHlo,al/ost:!#$<H/ello e*en though you sent in arameters. The art of the /elloN+or(.erb file that ma!es this wor! is the line with 9+or( a,tionKBH/elloB (et/o*KB3GSTB'. This tells your browser to# $. ;ollect data from the user using the form fields inside the form. '. /end them to the ser*er using a P?/T ty e of re3uest, which is ,ust another browser re3uest that "hides" the form fields. (. /end that to the H/ello ERL 5as shown in the a,tionKBH/elloB art6. B. +ou can then see how the two 9input' tags match the names of the *ariables in your new code. -lso notice that instead of ,ust a %0T method inside class inde&, I ha*e another method P?/T. How this new a lication wor!s is# $. The browser first hits the web a lication at H/ello but it sends a %0T, so our get DH/elloHD bloc! runs and returns the /elloN+or(. '. +ou fill out the form in the browser, and the browser does what the 9+or(' says and sends the data as a P?/T. (. The web a lication then runs the post DH/elloD bloc! rather than the get DH/elloD bloc! to handle this re3uest. B. This post DH/elloD bloc! then does what it normally does to send bac! the /ello age li!e before. There's really nothing new in here, it's ,ust mo*ed into a new bloc!. -s an e&ercise, go into the libHvie8sHin*ex.erb file and add a lin! bac! to ,ust H/ello so that you can !ee filling out the form and seeing the results. )a!e sure you can e& lain how this lin! wor!s and how it's letting you cycle between libHvie8sHin*ex.erb and libHvie8sH/elloN+or(.erb and what's being run inside this latest Ruby code.

Creating A Layo#t Te+plate


When you wor! on your game in the ne&t 0&ercise, you'll need to ma!e a bunch of little HT)L ages. Writing a full web age each time will 3uic!ly become tedious. Luc!ily you can create a "layout" tem late, or a !ind of shell that will wra all your other ages with common headers and footers. %ood rogrammers try to reduce re etition, so layouts are essential for being a good rogrammer. ;hange libHvie8sHin*ex.erb to be li!e this#

$$D

9J i+ greeting J' 9p'= Rust 8ante* to say 9e( styleKB,olor: green[ +ont-siZe: greeting J'9He('. 3 9J else J' ! 9e('7ello9He('F 8orl*C # 9J en* J'' 1

e([B'9JK

;hange libHvie8sH/elloN+or(.erb to be li!e this#


1 9/1'?ill Gut T/is ?or(9H/1' 3 9+or( a,tionKBH/elloB (et/o*KB3GSTB' ! A Xreeting: 9input typeKBtextB na(eKBgreetB' # 9brH' $ Eour 0a(e: 9input typeKBtextB na(eKBna(eB' < 9brH' & 9input typeKBsub(itB' 9 9H+or('

-ll we're doing is stri ing out the "boiler late" at the to and the bottom which is always on e*ery age. We'll ut that bac! into a single libHvie8sHlayout.erb file that handles it for us from now on. ?nce you ha*e those changes, create a libHvie8sHlayout.erb file with this in it#
1 9/t(l' 9/ea*' 3 9title'Xot/ons ?ro( 3lanet 3er,al - #9Htitle' ! 9H/ea*' # 9bo*y' $ 9JK yiel* J' < 9Hbo*y' & 9H/t(l'

/inatra automatically loo!s for a layout tem late called layout by default to use as the base tem late for all other tem lates. +ou can customiGe which tem late is used as the base for any gi*en age, too. Restart your a lication and then try to change the layout in interesting ways, but without changing the other tem lates.

Writing A#to+ated Tests &or &or+s


It's easy to test a web a lication with your browser by ,ust hitting refresh, but come on, we're rogrammers here. Why do some re etiti*e tas! when we can write some code to test our a licationL What you're going to do ne&t is write a little test for your web a lication form based on what you learned in 0&ercise BH. If you don't remember 0&ercise BH, read it again. I'*e created a sim le little function for that lets you assert things about your web a lication's res onse, a tly named assertNresponse. ;reate the file testHtestNgot/on8eb.rb with these contents#
1 reLuireNrelative D..HlibHgot/on8eb.rbD reLuire DtestHunitD 3 reLuire Dra,)HtestD

$$H

:0;TD>A2\N:0;DU K DtestD ! # ,lass Xot/on8ebTest 9 Test::.nit::Test2ase $ in,lu*e >a,)::Test::Wet/o*s < & *e+ app 9 Sinatra::Appli,ation 1" en* 11 1 *e+ assertNresponse@respF ,ontainsKnilF (at,/esKnilF /ea*ersKnilF 13 statusK ""A 1! assertNeLual@resp.statusF statusF B:xpe,te* response -OstatusP not in 1# -OrespPBA 1$ 1< i+ status KK "" 1& assert@resp.bo*yF B>esponse *ata is e(pty.BA 19 en* " 1 i+ ,ontains assert@@resp.bo*y.in,lu*eM ,ontainsAF B>esponse *oes not ,ontain 3 -O,ontainsPBA ! en* # $ i+ (at,/es < reg K >egexp.ne8@(at,/esA & assert reg.(at,/@,ontainsAF B>esponse *oes not (at,/ -O(at,/esPB 9 en* 3" 31 i+ /ea*ers 3 assertNeLual@resp./ea*ersF /ea*ersA 33 en* 3! en* 3# 3$ *e+ testNin*ex 3< - ,/e,) t/at 8e get a !"! on t/e H .>L 3& get@BH+ooBA 39 assertNresponse@lastNresponseF nilF nilF nilF !"!A !" !1 - test our +irst X:T reLuest to H/ello ! get@BH/elloBA !3 assertNresponse@lastNresponseA !! !# - (a)e sure *e+ault values 8or) +or t/e +or( !$ post@BH/elloBA !< assertNresponse@lastNresponseF B0obo*yBA !& !9 - test t/at 8e get expe,te* values #" post@BH/elloBF :na(e K' D6e*DF :greet K' D7olaDA #1 assertNresponse@lastNresponseF B6e*BA # assertNresponse@lastNresponseF B7olaBA #3 en* en*

:inally, run testHtestNgot/on8eb.rb to test your web a lication#


$ ruby testHtestNgot/on8eb.rb Loa*e* suite testHtestNgot/on8eb Starte* .

$$4

?inis/e* in "." 3&39 se,on*s. 1 testsF 9 assertionsF " +ailuresF " errorsF " s)ips Test run options: --see* #<!1!

What I'm doing here is I'm actually im orting the whole a lication from the libHgot/on8eb.rb library, then running it manually. The ra,)Htest library we ha*e included has a *ery sim le -PI for rocessing re3uests. Its get, put, post, *elete, and /ea* methods simulate the res ecti*e ty e of re3uest on the a lication. -ll moc! re3uest methods ha*e the same argument signature#
get DHpat/DF para(sKOPF ra,)NenvKOP Hpat/ is the re3uest ath and may o tionally include a 3uery string. para(s is a Hash of 3ueryA ost arameters, a /tring re3uest body, or nil. ra,)Nenv is a Hash of Rac! en*ironment *alues. This can be used to set re3uest

headers and other re3uest related information, such as session data. This wor!s without running an actual web ser*er so you can do tests with automated tests and also use your browser to test a running ser*er. To *alidate res onses from this function, use the assertNresponse function from testHtestNgot/on8eb.rb which has#
assertNresponse@respF ,ontainsKnilF (at,/esKnilF /ea*ersKnilF statusK ""A

Pass in the res onse you get from calling get or post then add things you want chec!ed. Ese the ,ontains arameter to ma!e sure that the res onse contains certain *alues. Ese the status arameter to chec! for certain res onses. There's actually 3uite a lot of information in this little function so it would be good for you to study it. In the testHtestNgot/on8eb.rb automated test I'm first ma!ing sure the H+oo ERL returns a "B8B Fot :ound" res onse, since it actually doesn't e&ist. Then I'm chec!ing that H/ello wor!s with both a %0T and P?/T form. :ollowing the test should be fairly sim le, e*en if you might not totally !now what's going on. Ta!e some time studying this latest a lication, es ecially how the automated testing wor!s.

(%tra Credit
$. Read e*en more about HT)L, and gi*e the sim le form a better layout. It hel s to draw what you want to do on a er and then im lement it with HT)L. '. This one is hard, but try to figure out how you'd do a file u load form so that you can u load an image and sa*e it to the dis!. (. This is e*en more mind1numbing, but go find the HTTP R:; 5which is the document that describes how HTTP wor!s6 and read as much of it as you can. It is really boring, but comes in handy once in a while.

$$>

B. This will also be really difficult, but see if you can find someone to hel you setu a web ser*er li!e - ache, Fgin&, or thtt d. Try to ser*e a cou le of your .html and .css files with it ,ust to see if you can. .on't worry if you can't, web ser*ers !ind of suc!. C. Ta!e a brea! after this and ,ust try ma!ing as many different web a lications as you can. +ou should definitely read about sessions in /inatra so you can understand how to !ee state for a user.

Exercise +#: The Start =5 7our Web Ga"e


We're coming to the end of the boo!, and in this e&ercise I'm going to really challenge you. When you're done, you'll be a reasonably com etent Ruby beginner. +ou'll still need to go through a few more boo!s and write a cou le more ro,ects, but you'll ha*e the s!ills to com lete them. The only thing in your way will be time, moti*ation, and resources. In this e&ercise, we won't ma!e a com lete game, but instead we'll ma!e an "engine" that can run the game from 0&ercise B' in the browser. This will in*ol*e refactoring 0&ercise B', mi&ing in the structure from 0&ercise BH, adding automated tests, and finally creating a web engine that can run the games. This e&ercise will be huge, and I redict you could s end anywhere from a wee! to months on it before mo*ing on. It's best to attac! it in little chun!s and do a bit a night, ta!ing your time to ma!e e*erything wor! before mo*ing on.

Refactoring The (%ercise <= 3a+e


+ou'*e been altering the got/on8eb ro,ect for two e&ercises and you'll do it one more time in this e&ercise. The s!ill you're learning is called "refactoring", or as I li!e to call it, "fi&ing stuff". Refactoring is a term rogrammers use to describe the rocess of ta!ing old code, and changing it to ha*e new features or ,ust to clean it u . +ou'*e been doing this without e*en !nowing it, as it's second nature to building software. What you'll do in this art is ta!e the ideas from 0&ercise BH of a testable "ma " of Rooms, and the game from 0&ercise B', and combine them together to create a new game structure. It will ha*e the same content, ,ust "refactored" to ha*e a better structure. :irst ste is to grab the code from ex!<.rb and co y it to got/on8ebHlibH(ap.rb and co y ex!<Ntests.rb file to got/on8ebHtestHtestN(ap.rb and run the test suite again to ma!e sure it !ee s wor!ing. Fote :rom now on I won't show you the out ut of a test run, ,ust assume that you should be doing it and it'll loo! li!e the abo*e unless you ha*e an error. ?nce you ha*e the code from 0&ercise BH co ied o*er, it's time to refactor it to ha*e the 0&ercise B' ma in it. I'm going to start off by laying down the basic structure, and then you'll ha*e an assignment to ma!e the (ap.rb file and the (apNtests.rb file com lete. :irst thing to do is lay out the basic structure of the ma using the >oo( class as it is now# $'8

1 ,lass >oo( 3 attrNa,,essor :na(eF :*es,riptionF :pat/s ! # *e+ initialiZe@na(eF *es,riptionA $ _na(e K na(e < _*es,ription K *es,ription & _pat/s K OP 9 en* 1" 11 *e+ go@*ire,tionA 1 _pat/sT*ire,tionU 13 en* 1! 1# *e+ a**Npat/s@pat/sA 1$ _pat/s.up*ate@pat/sA 1< en* 1& 19 en* " 1 ,entralN,orri*or K >oo(.ne8@B2entral 2orri*orBF JLO 3 T/e Xot/ons o+ 3lanet 3er,al - # /ave inva*e* your s/ip an* *estroye* ! your entire ,re8. Eou are t/e last surviving (e(ber an* your last # (ission is to get t/e neutron *estru,t bo(b +ro( t/e Weapons Ar(oryF $ put it in t/e bri*geF an* blo8 t/e s/ip up a+ter getting into an < es,ape po*. & 9 EouDre running *o8n t/e ,entral ,orri*or to t/e Weapons Ar(ory 8/en 3" a Xot/on Ru(ps outF re* s,aly s)inF *ar) gri(y teet/F an* evil ,lo8n 31 ,ostu(e 3 +lo8ing aroun* /is /ate +ille* bo*y. 7eDs blo,)ing t/e *oor to t/e 33 Ar(ory an* about to pull a 8eapon to blast you. 3! PA 3# 3$ 3< laserN8eaponNar(ory K >oo(.ne8@BLaser Weapon Ar(oryBF 3& JLO 39 Lu,)y +or you t/ey (a*e you learn Xot/on insults in t/e a,a*e(y. !" Eou tell t/e one Xot/on Ro)e you )no8: !1 Lb/e Zbgure v+ +b sngF Rura +ur +vg+ neb/aL gur ub/+rF +ur +vg+ neb/aL ! gur ub/+r. !3 T/e Xot/on stopsF tries not to laug/F t/en busts out laug/ing an* ,anDt !! (ove. !# W/ile /eDs laug/ing you run up an* s/oot /i( sLuare in t/e /ea* !$ putting /i( *o8nF t/en Ru(p t/roug/ t/e Weapon Ar(ory *oor. !< !& Eou *o a *ive roll into t/e Weapon Ar(oryF ,rou,/ an* s,an t/e roo( !9 +or (ore Xot/ons t/at (ig/t be /i*ing. =tDs *ea* LuietF too Luiet. #" Eou stan* up an* run to t/e +ar si*e o+ t/e roo( an* +in* t/e #1 neutron bo(b in its ,ontainer. T/ereDs a )eypa* lo,) on t/e box # an* you nee* t/e ,o*e to get t/e bo(b out. =+ you get t/e ,o*e #3 8rong 1" ti(es t/en t/e lo,) ,loses +orever an* you ,anDt #! get t/e bo(b. T/e ,o*e is 3 *igits. ## PA #$ #< #& t/eNbri*ge K >oo(.ne8@BT/e Sri*geBF #9 JLO $" T/e ,ontainer ,li,)s open an* t/e seal brea)sF letting gas out. $1 Eou grab t/e neutron bo(b an* run as +ast as you ,an to t/e

$'$

$ $3 $! $# $$ $< $& $9 <" <1 < <3 <! <# <$ << <& <9 &" &1 & &3 &! &# &$ &< && &9 9" 91 9 93 9! 9# 9$ 9< 9& 99 1"" 1"1 1" 1"3 1"! 1"# 1"$ 1"< 1"& 1"9 11" 111 11 113 11! 11# 11$ 11< 11& 119 1 " 1 1 1

bri*ge 8/ere you (ust pla,e it in t/e rig/t spot. Eou burst onto t/e Sri*ge 8it/ t/e netron *estru,t bo(b un*er your ar( an* surprise # Xot/ons 8/o are trying to ta)e ,ontrol o+ t/e s/ip. :a,/ o+ t/e( /as an even uglier ,lo8n ,ostu(e t/an t/e last. T/ey /avenDt pulle* t/eir 8eapons out yetF as t/ey see t/e a,tive bo(b un*er your ar( an* *onDt 8ant to set it o++. PA es,apeNpo* K >oo(.ne8@B:s,ape 3o*BF JLO Eou point your blaster at t/e bo(b un*er your ar( an* t/e Xot/ons put t/eir /an*s up an* start to s8eat. Eou in,/ ba,)8ar* to t/e *oorF open itF an* t/en ,are+ully pla,e t/e bo(b on t/e +loorF pointing your blaster at it. Eou t/en Ru(p ba,) t/roug/ t/e *oorF pun,/ t/e ,lose button an* blast t/e lo,) so t/e Xot/ons ,anDt get out. 0o8 t/at t/e bo(b is pla,e* you run to t/e es,ape po* to get o++ t/is tin ,an. Eou rus/ t/roug/ t/e s/ip *esperately trying to (a)e it to t/e es,ape po* be+ore t/e 8/ole s/ip explo*es. =t see(s li)e /ar*ly any Xot/ons are on t/e s/ipF so your run is ,lear o+ inter+eren,e. Eou get to t/e ,/a(ber 8it/ t/e es,ape po*sF an* no8 nee* to pi,) one to ta)e. So(e o+ t/e( ,oul* be *a(age* but you *onDt /ave ti(e to loo). T/ereDs # po*sF 8/i,/ one *o you ta)eM PA t/eNen*N8inner K >oo(.ne8@BT/e :n*BF JLO Eou Ru(p into po* an* /it t/e eRe,t button. T/e po* easily sli*es out into spa,e /ea*ing to t/e planet belo8. As it +lies to t/e planetF you loo) ba,) an* see your s/ip i(plo*e t/en explo*e li)e a brig/t starF ta)ing out t/e Xot/on s/ip at t/e sa(e ti(e. Eou 8onC PA t/eNen*Nloser K JLO Eou Ru(p into a T/e po* es,apes i(plo*es as t/e into Ra( Relly. PA >oo(.ne8@BT/e :n*BF ran*o( po* an* /it t/e eRe,t button. out into t/e voi* o+ spa,eF t/en /ull rupturesF ,rus/ing your bo*y

es,apeNpo*.a**Npat/s@O D D K' t/eNen*N8innerF DID K' t/eNen*Nloser PA generi,N*eat/ K >oo(.ne8@B*eat/BF BEou *ie*.BA t/eNbri*ge.a**Npat/s@O Dt/ro8 t/e bo(bD K' generi,N*eat/F Dslo8ly pla,e t/e bo(bD K' es,apeNpo*

$''

PA 1 3 1 ! 1 # 1 $ 1 < 1 & 1 9 13" 131 13 133 laserN8eaponNar(ory.a**Npat/s@O D"13 D K' t/eNbri*geF DID K' generi,N*eat/ PA ,entralN,orri*or.a**Npat/s@O Ds/ootCD K' generi,N*eat/F D*o*geCDK' generi,N*eat/F Dtell a Ro)eD K' laserN8eaponNar(ory PA STA>T K ,entralN,orri*or

+ou'll notice that there are a cou le of roblems with our Room class and this ma # $. We ha*e to ut the te&t that was in the i+-else clauses that got rinted before entering a room as art of each room. This means you can't shuffle the ma around which would be nice. +ou'll be fi&ing that u in this e&ercise. '. There are arts in the original game where we ran code that determined things li!e the bomb's !ey ad code, or the right od. In this game we ,ust ic! some defaults and go with it, but later you'll be gi*en e&tra credit to ma!e this wor! again. (. I'*e ,ust made a generi,N*eat/ ending for all of the bad decisions, which you'll ha*e to finish for me. +ou'll need to go bac! through and add in all the original endings and ma!e sure they wor!. B. I'*e got a new !ind of transition labeled BIB that will be used for a "catch1all" action in the engine. ?nce you'*e got that basically written out, here's the new automated test testHtestN(ap.rb that you should ha*e to get yourself started#
1 reLuire DtestHunitD reLuireNrelative D..HlibH(apD 3 ! ,lass WapTests 9 Test::.nit::Test2ase # $ *e+ testNroo(@A < gol* K >oo(.ne8@BXol*>oo(BF & JLOT/is roo( /as gol* in it you ,an grab. T/ereDs a 9 *oor to t/e nort/.PA 1" assertNeLual@gol*.na(eF BXol*>oo(BA 11 assertNeLual@gol*.pat/sF OPA 1 en* 13 1! *e+ testNroo(Npat/s@A 1# ,enter K >oo(.ne8@B2enterBF BTest roo( in t/e ,enter.BA 1$ nort/ K >oo(.ne8@B0ort/BF BTest roo( in t/e nort/.BA 1< sout/ K >oo(.ne8@BSout/BF BTest roo( in t/e sout/.BA 1& 19 ,enter.a**Npat/s@ODnort/D K' nort/F Dsout/D K' sout/PA " assertNeLual@,enter.go@Dnort/DAF nort/A 1 assertNeLual@,enter.go@Dsout/DAF sout/A en* 3 ! *e+ testN(ap@A # start K >oo(.ne8@BStartBF BEou ,an go 8est an* *o8n a /ole.BA

$'(

$ 8est K >oo(.ne8@BTreesBF BT/ere are trees /ereF you ,an go east.BA < *o8n K >oo(.ne8@BDungeonBF B=tDs *ar) *o8n /ereF you ,an go up.BA & 9 start.a**Npat/s@OD8estD K' 8estF D*o8nD K' *o8nPA 3" 8est.a**Npat/s@ODeastD K' startPA 31 *o8n.a**Npat/s@ODupD K' startPA 3 33 assertNeLual@start.go@D8estDAF 8estA 3! assertNeLual@start.go@D8estDA.go@DeastDAF startA 3# assertNeLual@start.go@D*o8nDA.go@DupDAF startA 3$ en* 3< 3& *e+ testNgot/onNga(eN(ap@A 39 assertNeLual@STA>T.go@Ds/ootCDAF generi,N*eat/A !" assertNeLual@STA>T.go@D*o*geCDAF generi,N*eat/A !1 ! roo( K STA>T.go@Dtell a Ro)eDA !3 assertNeLual@roo(F laserN8eaponNar(oryA !! en* !# !$ en*

+our tas! in this art of the e&ercise is to com lete the ma , and ma!e the automated test com letely *alidate the whole ma . This includes fi&ing all the generi,N*eat/ ob,ects to be real endings. )a!e sure this wor!s really well and that your test is as com lete as ossible because we'll be changing this ma later and you'll use the tests to ma!e sure it !ee s wor!ing.

Sessions And Tracking ,sers


-t a certain oint in your web a lication you'll need to !ee trac! of some information and associate it with the user's browser. The web 5because of HTTP6 is what we li!e to call "stateless", which means each re3uest you ma!e is inde endent of any other re3uests being made. If you re3uest age -, ut in some data, and clic! a lin! to age 2, all the data you sent to age - ,ust disa ears. The solution to this is to create a little data store 5usually in a database, on dis!, or in coo!ies6 that uses a number uni3ue to each browser to !ee trac! of what that browser was doing. In /inatra it's fairly easy, and here's an e&am le showing how it's done using Rac! middleware#
reLuire Drubyge(sD reLuire DsinatraD use >a,)::Session::3ool get DH,ountD *o sessionT:,ountU YYK " sessionT:,ountU 1K1 B2ount: -OsessionT:,ountUPB en* get DHresetD *o session.,lear B2ount reset to ".B en*

$'B

Creating An (ngine
+ou should ha*e your game ma wor!ing and a good unit test for it. I now want to ma!e a sim le little game engine that will run the rooms, collect in ut from the layer, and !ee trac! of where a lay is in the game. We'll be using the sessions you ,ust learned to ma!e a sim le game engine that will# $. '. (. B. C. /tart a new game for new users. Present the room to the user. Ta!e in ut from the user. Run their in ut through the game. .is lay the results and !ee going until they die.

To do this, you're going to ta!e the trusty libHgot/on8eb.rb you'*e been hac!ing on and create a fully wor!ing, session based, game engine. The catch is I'm going to ma!e a *ery sim le one with basic HT)L files, and it'll be u to you to com lete it. Here's the base engine#
1 reLuireNrelative Bgot/on8ebHversionB reLuireNrelative B(apB 3 reLuire BsinatraB ! reLuire BerbB # $ (o*ule Xot/on8eb < & use >a,)::Session::3ool 9 1" get DHD *o 11 - t/is is use* to BsetupB t/e session 8it/ starting values 1 p STA>T 13 sessionT:roo(U K STA>T 1! re*ire,t@BHga(eBA 1# en* 1$ 1< get DHga(eD *o 1& i+ sessionT:roo(U 19 erb :s/o8Nroo(F :lo,als K' O:roo( K' sessionT:roo(UP " else 1 - 8/y is t/is /ereM *o you nee* itM erb :youN*ie* 3 en* ! en* # $ post DHga(eD *o < a,tion K B-Opara(sT:a,tionU YY nilPB & - t/ere is a bug /ereF ,an you +ix itM 9 i+ sessionT:roo(U 3" sessionT:roo(U K sessionT:roo(U.go@para(sT:a,tionUA 31 en* 3 re*ire,t@BHga(eBA 33 en* 3! 3# en*

$'C

+ou should ne&t delete libHvie8sH/elloN+or(.erb and libHvie8sHin*ex.erb and create the two tem lates mentioned in the abo*e code. Here's a *ery sim le libHvie8sHs/o8Nroo(.erb#
1 9/1'9JK roo(.na(e J'9H/1' 3 ! # $ < & 9 1" 11 1 13 1! 1# 1$ 1< 9pre' 9JK roo(.*es,ription J' 9Hpre' 9J i+ roo(.na(e KK B*eat/B J' 9p' 9a /re+KBHB'3lay AgainM9Ha' 9Hp' 9J else J' 9p' 9+or( a,tionKBHga(eB (et/o*KB3GSTB' - 9input typeKBtextB na(eKBa,tionB' 9input typeKBS.SW=TB' 9H+or(' 9Hp' 9J en* J'

That is the tem late to show a room as you tra*el through the game. Fe&t you need one to tell someone they died in the case that they got to the end of the ma on accident, which is libHvie8sHyouN*ie*.erb#
1 9/1'Eou Die*C9H/1' 3 9p'Loo)s li)e you bit t/e *ust.9Hp' ! 9p'9a /re+KBHB'3lay Again9Ha'9Hp'

With those in lace, you should now be able to do the following# $. %et the test testHtestNgot/on8eb.rb wor!ing again so that you are testing the game. +ou won't be able to do much more than a few clic!s in the game because of sessions, but you should be able to do some basics. '. Run the libHgot/on8eb.rb scri t and test out the game. (. +ou should be able to refresh and fi& the game li!e normal, and wor! with the game HT)L and engine until it does all the things you want it to do.

"o#r &inal (%a+


.o you feel li!e this was a huge amount of information thrown at you all at onceL %ood, I want you to ha*e something to tin!er with while you build your s!ills. To com lete this e&ercise, I'm going to gi*e you a final set of e&ercises for you to com lete on your own. +ou'll notice that what you'*e written so far isn't *ery well built, it is ,ust a first *ersion of the code. +our tas! now is to ma!e the game more com lete by doing these things# $. :i& all the bugs I mention in the code, and any that I didn't mention. If you find new bugs, let me !now. '. Im ro*e all of the automated tests so that you test more of the a lication and get to a oint where you use a test rather than your browser to chec! the a lication while you wor!.

$'D

(. )a!e the HT)L loo! better. B. Research logins and create a signu system for the a lication, so eo le can ha*e logins and high scores. C. ;om lete the game ma , ma!ing it as large and feature com lete as ossible. D. %i*e eo le a "hel " system that lets them as! what they can do at each room in the game. H. -dd any other features you can thin! of to the game. 4. ;reate se*eral "ma s" and let eo le choose a game they want to run. +our libHgot/on8eb.rb engine should be able to run any ma of rooms you gi*e it, so you can su ort multi le games. >. :inally, use what you learned in 0&ercises B4 and B> to create a better in ut rocessor. +ou ha*e most of the code necessary, you ,ust need to im ro*e the grammar and hoo! it u to your in ut form and the %ame0ngine. %ood luc!O

&ext Steps
+ou're not a rogrammer 3uite yet. I li!e to thin! of this boo! as gi*ing you your " rogramming brown belt". +ou !now enough to start another boo! on rogramming and handle it ,ust fine. This boo! should ha*e gi*en you the mental tools and attitude you need to go through most Ruby boo!s and actually learn something. It might e*en ma!e it easy. Rob says: :or fun, I recommend you chec! out Why's 5Poignant6 %uide to Ruby# htt #AAmisla*.uni3 ath.comA oignant1guide )ost of the actual rogramming content will be re*iew by now, but Why is a brilliant mind and his boo! is a wor! of art. ;hec! out some of his o en source ro,ects, which are still floating around. +ou can learn a lot by reading his code. +ou could robably start hac!ing away at some rograms right now, and if you ha*e that itch, go ahead. <ust understand anything you write will robably suc!. That's alright though, I suc! at e*ery rogramming language I first start using. Fobody writes ure erfect gold when they're a beginner, and anyone who tells you they did is a huge liar. :inally, remember that this is something you ha*e to do at least a cou le hours a night for a while before you can get good. If it hel s, while you're struggling to learn Ruby e*ery night, I'm hard at wor! learning to lay guitar. I wor! at it about ' or B hours a day and still ractice scales. 0*eryone is a beginner at something.

Ad:ice Fro" An =*d ro!ra""er


+ou'*e finished this boo! and ha*e decided to continue with rogramming. )aybe it will be a career for you, or maybe it will be a hobby. +ou'll need some ad*ice to ma!e sure you continue on the right ath, and get the most en,oyment out of your newly chosen acti*ity.

$'H

I'*e been rogramming for a *ery long time. /o long that it's incredibly boring to me. -t the time that I wrote this boo!, I !new about '8 rogramming languages and could learn new ones in about a day to a wee! de ending on how weird they were. 0*entually though this ,ust became boring and couldn't hold my interest anymore. This doesn't mean I thin! rogramming is boring, or that you will thin! it's boring, only that I find it uninteresting at this oint in my ,ourney. What I disco*ered after this ,ourney of learning is that it's not the languages that matter but what you do with them. -ctually, I always !new that, but I'd get distracted by the languages and forget it eriodically. Fow I ne*er forget it, and neither should you. Which rogramming language you learn and use doesn't matter. .o not get suc!ed into the religion surrounding rogramming languages as that will only blind you to their true ur ose of being your tool for doing interesting things. Programming as an intellectual acti*ity is the only art form that allows you to create interacti*e art. +ou can create ro,ects that other eo le can lay with, and you can tal! to them indirectly. Fo other art form is 3uite this interacti*e. )o*ies flow to the audience in one direction. Paintings do not mo*e. ;ode goes both ways. Programming as a rofession is only moderately interesting. It can be a good ,ob, but you could ma!e about the same money and be ha ier running a fast food ,oint. +ou're much better off using code as your secret wea on in another rofession. Peo le who can code in the world of technology com anies are a dime a doGen and get no res ect. Peo le who can code in biology, medicine, go*ernment, sociology, hysics, history, and mathematics are res ected and can do amaGing things to ad*ance those disci lines. ?f course, all of this ad*ice is ointless. If you li!ed learning to write software with this boo!, you should try to use it to im ro*e your life any way you can. %o out and e& lore this weird wonderful new intellectual ursuit that barely anyone in the last C8 years has been able to e& lore. )ight as well en,oy it while you can. :inally, I'll say that learning to create software changes you and ma!es you different. Fot better or worse, ,ust different. +ou may find that eo le treat you harshly because you can create software, maybe using words li!e "nerd". )aybe you'll find that because you can dissect their logic that they hate arguing with you. +ou may e*en find that sim ly !nowing how a com uter wor!s ma!es you annoying and weird to them. To this I ha*e ,ust one iece of ad*ice# they can go to hell. The world needs more weird eo le who !now how things wor! and who lo*e to figure it all out. When they treat you li!e this, ,ust remember that this is your ,ourney, not theirs. 2eing different is not a crime, and eo le who tell you it is are ,ust ,ealous that you'*e ic!ed u a s!ill they ne*er in their wildest dreams could ac3uire. +ou can code. They cannot. That is retty damn cool.

$'4

Você também pode gostar