Escolar Documentos
Profissional Documentos
Cultura Documentos
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.
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.
'
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.
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.
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
+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.
+ou will robably see a *ery different rom t, Ruby information, and other stuff but this is the general idea.
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.
+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.
(%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.
>
- (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 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 -
$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.
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.
(%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.
$'
(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
(%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.
$(
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
(%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.
(%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.
(%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.
$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.
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
+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
(%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.
$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.
(%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.
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-&	-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.
$>
(%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.
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
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.
'$
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.
(%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.
''
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.
'(
=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.
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.
'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.
'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.
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.
'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.
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."
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.
(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.
($
*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.
(%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.
('
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.
(%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.
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."
(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#
?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.
(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
(%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
: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
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.
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
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.
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(
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.
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.
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.
(%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
,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*
(%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
B4
(%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.
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.
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.
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*
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
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*
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.
+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.
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
(%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
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.
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.
/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.
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
(%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".
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 $! $#
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
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.
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
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.
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.
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.
H$
3 bullsNonNpara*e.singN(eNaNsong@A
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.
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.
?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
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.
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.
.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.
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.
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.
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
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
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.
*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
4>
%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
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.
>'
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.
>(
?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.
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.
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.
>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.
?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.
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.
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#
/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.
.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.
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.
$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
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.
2y now you should be able to figure out what these do. )a!e sure you understand them.
$8B
$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.
+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.
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. .$...
$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*
: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 .
$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.
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.
$$$
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.
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
$$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.
$$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
-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.
$$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*
$$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.
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.
$'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.
$'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.
$'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