Você está na página 1de 61

0.

I N I C I A N D O
Quando voc programa um computador, voc tem que "falar" em uma lngua que o seu computador entenda: uma linguagem de programao. Existem muitas e muitas linguagens por a, e muitas so excelentes. Neste tutorial eu escolhi usar a minha favorita, Ruby. Alm de ser a minha favorita, Ruby tambm a linguagem mais fcil que eu j vi (e eu j vi uma boa quantidade delas). Alis, esta a verdadeira razo pela qual estou escrevendo este tutorial: Eu no decidi escrever este tutorial e a escolhi Ruby por ser minha favorita; ao invs disso, eu descobri que o Ruby era to fcil que eu decidi que deveria haver um bom tutorial que a usasse voltado para iniciantes. Foi a simplicidade do Ruby que inspirou este tutorial, no o fato dela ser minha favorita. (Escrever um tutorial similar usando outra linguagem, C++ ou Java, teria tomado centenas e centenas de pginas.) Mas no pense que Ruby uma linguagem para iniciantes s porque fcil! Ela uma linguagem poderosa, de nvel profissional como poucas. Quando voc escreve algo em uma linguagem humana, o que escrito chamado de texto. Quando voc escreve algo em uma linguagem de computador, o que escrito chamado de cdigo. Eu inclu vrios exemplos de cdigo Ruby por todo este tutorial, a maioria deles programas completos que voc pode rodar no seu prprio computador. Para deixar o cdigo mais legvel, eu colori partes dele com cores diferentes. (Por exemplo, nmeros esto sempre em verde.) Qualquer coisa que voc tiver que digitar estar sempre numa caixa branca , e qualquer coisa que o programa imprimir estar em uma caixa azul . Se voc encontrar algo que no entende, ou se voc tiver uma pergunta que no foi respondida, tome nota e continue a ler! bem possvel que a resposta venha em um captulo mais adiante. Porm, se sua pergunta no for respondida at o ltimo captulo, eu lhe mostrarei onde voc pode ir para perguntar. Existem muitas pessoas maravilhosas por a mais que dispostas a ajudar; voc s precisa saber onde elas esto. Mas primeiro ns precisamos baixar e instalar o Ruby no nosso computador.

I NS T A L A O

NO

W INDO W S

A instalao do Ruby no Windows muito fcil. Primeiro, voc precisa baixar o Instalador Ruby. Pode haver mais de verso para escolher; este tutorial usa a verso 1.8.7, ento assegure-se de que o que voc baixar seja ao menos to recente quanto ela. (Eu pegaria a ltima verso disponvel.) Ento simplesmente rode o programa de instalao. Ele perguntar onde voc gostaria de instalar o Ruby. A no ser que voc tenha uma boa razo para no fazer isso, eu instalaria no lugar recomendado. Para programar, voc precisa poder escrever programas e rod-los. Para fazer isso, voc vai precisar de um editor de texto e uma linha de comando. O instalador do Ruby vem com um editor de texto adorvel chamado SciTE (the Scintilla Text Editor). Voc pode rodar o SciTE selecionando-o no menu Iniciar. Se voc quiser que o seu cdigo seja colorido como os exemplos deste tutorial, baixe estes arquivos e coloque-os na sua pasta SciTE ( c:/ruby/scite se voc escolher o local recomendado).
Propriedades Globais Propriedades do Ruby

Seria tambm uma boa idia criar um diretrio em algum lugar para manter todos os seus programas.

Tenha certeza que, quando voc salvar um programa, esteja salvando neste diretrio. Para ir para sua linha de comando, selecione Prompt de Comando na pasta Acessrios do seu menu Iniciar. Voc vai querer navegar para o diretrio onde voc mantm seus programas. Digitar cd .. levar voc para o diretrio anterior, e cd nome_do_diretorio colocar voc dentro do diretrio chamado nome_do_diretorio. Para ver todos seus diretrios dentro do diretrio atual, digite dir /ad . E isto! Voc est pronto para aprender a programar.

I NS T A L A O

P A RA

M A C INT O S H

Se voc tiver um Mac OS X 10.2 (Jaguar), ento voc j tem Ruby no seu sistema! O que poderia ser mais fcil? Infelizmente, eu no acho que voc possa usar Ruby no Mac OS X 10.1 e verses anteriores. Para programar, voc precisa ser capaz de escrever programas e execut-los. Para fazer isto, voc precisar de um editor de textos e uma linha de comando. Sua linha de comando est acessvel atravs da aplicao Terminal (encontrada em Aplicaes/Utilitrios). Para um editor de textos, voc pode usar qualquer um com que voc esteja familiarizado ou se sinta confortvel usando. Se voc usa TextEdit, entretanto, tenha certeza que voc est salvando seus programas como somente-texto! Caso contrrio seus programas no funcionaro. Outras opes para programar so emacs, vi, e pico, que esto todos acessveis via linha de comando. E isto! Voc est pronto para aprender a programar.

I NS T A L A O

EM

L INU X

Primeiro, vale a pena checar se voc j tem Ruby instalado. Digite which ruby . Se este comando responder algo como /usr/bin/which: no ruby in (...) , ento voc precisa fazer o download do Ruby, caso contrrio veja que verso do Ruby voc possui com ruby -v . Se for mais velha do que a ltima verso estvel na pgina de download acima, pode ser bom atualiz-lo. Se voc for o usurio root, ento voc provavelmente no precisa de qualquer instruo para instalar o Ruby. Se no for, voc poderia pedir ao seu administrador de sistema para instal-lo para voc. (Desta forma todos neste sistema poderiam usar Ruby.) Caso contrrio, voc pode apenas instal-lo de forma que apenas voc possa us-lo. Mova o arquivo baixado para um diretrio temporrio, como $HOME/tmp. Se o nome do arquivo for ruby-1.6.7.tar.gz, voc pode abri-lo com tar zxvf ruby-1.6.7.tar.gz . Mude do diretrio atual para o diretrio que acabou de ser criado (neste exemplo, cd ruby-1.6.7 ). Configure sua instalao digitando ./configure --prefix=$HOME ). Depois digite make , que construir seu interpretador Ruby. Isto pode levar alguns minutos. Aps isto ter terminado, digite make install para instal-lo. Em seguida, voc vai querer adicionar $HOME/bin para seu caminho de busca de comandos varivel de ambiente PATH, editando seu arquivo $HOME/.bashrc. (Voc pode ter que se deslogar e logar novamente para que isto surta efeito.) Aps ter feito isto, teste sua instalao: ruby -v . Se mostrar a voc qual a verso do Ruby que voc tem, voc pode agora remover os arquivos em $HOME/tmp (ou onde quer que voc os colocou). E isto! Voc est pronto para aprender a programar.

2003-2011 Chris Pine

1. N M ER OS
Agora que voc j arranjou tudo, vamos escrever um programa! Abra seu editor de texto favorito e digite o seguinte:
puts 1+2

Salve seu programa (sim, isso um programa!) como calc.rb (o .rb o que normalmente colocamos no final de programas escritos em Ruby). Agora rode o seu programa digitando ruby calc.rb na linha de comando. Ele deve ter posto 3 na sua tela. Viu como programar no to difcil?

I NT RO DU O

A O PUTS

O que ento que est acontecendo no programa? Tenho certeza que voc capaz de adivinhar o qu 1+2 faz; nosso programa praticamente a mesma coisa que:
puts 3

puts simplesmente escreve na tela tudo que vem depois dele.

I NT E IRO

FLOAT

Na maioria das linguagens de programao (e no diferente no Ruby) nmeros sem pontos decimais so chamados de inteiros, e nmeros com pontos decimais normalmente so chamados de nmeros de ponto-flutuante, ou mais singelamente, floats. Eis alguns inteiros:
5 -205 9999999999999999999999999 0

E aqui esto alguns floats:


54.321 0.001 -205.3884 0.0

Na prtica, a maioria dos programas no usa floats; apenas inteiros. (Afinal, ningum quer ler 7.4 emails, ou navegar 1.8 pginas, ou ouvir 5.24 msicas favoritas) Floats so usados mais freqentemente para fins acadmicos (experimentos de fsica e afins) e para grficos 3D. Mesmo a maioria dos programas que lidam com dinheiro usam inteiros; eles s ficam contando as moedinhas!

A RIT M T IC A S IMP L E S
At agora, temos tudo que necessrio para uma calculadora simples. (Calculadoras sempre usam floats, ento se voc quer que seu computador aja como uma calculadora, voc tambm deve usar floats.) Para adio e subtrao, usamos + e -, como vimos. Para multiplicao, usamos *, e para diviso usamos /. A maioria dos teclados possui essas teclas no teclado numrico. Se voc tem teclado menor ou um laptop, voc pode usar Shift 8 e / (fica na mesma tecla que ?). Vamos tentar expandir um pouco nosso calc.rb. Digite o seguinte e depois rode.
puts puts puts puts 1.0 2.0 5.0 9.0 + * / 2.0 3.0 8.0 2.0

Isto o que o programa retorna:


3.0 6.0 -3.0 4.5

(Os espaos no programa no so importantes; eles s deixam o cdigo mais legvel.) Bom, no foi l muito surpreendente. Vamos tentar agora com inteiros.
puts puts puts puts 1+2 2*3 5-8 9/2

Basicamente a mesma coisa, no ?


3 6 -3 4

Ahn... tirando aquele ltimo ali! Quando voc faz aritmtica com inteiros, voc recebe respostas em inteiros. Quando seu computador no sabe dar a resposta "certa", ele sempre arredonda para baixo. (Claro, 4 a resposta certa em aritmtica de inteiros para 9/2; s pode no ser o que voc estava esperando.) Talvez voc esteja se perguntado para que diviso de inteiros serve. Bem, vamos dizer que voc vai ao cinema, mas s tem $ 9. Aqui em Portland, voc pode ver um filme no Bagdad por 2 pilas. A quantos filmes voc pode assistir l? 9/2... 4 filmes. 4.5 no a resposta certa neste caso; eles no vo deixar voc ver metade de um filme, ou metade de voc ver um filme inteiro... algumas coisas no so divisveis. Agora experimente com alguns programas seus! Se voc quiser escrever expresses mais complexas, voc pode usar parnteses. Por exemplo:
puts 5 * (12-8) + -15 puts 98 + (59872 / (13*8)) * -52

5 -29802

U MA S C O IS INHA S P A RA T E NT A R

Escreva um programa que lhe d:


quantas horas h em um ano? quantos minutos h em uma dcada? qual a sua idade em segundos? quantos chocolates voc pretende comer na vida? Aviso: Esta parte do programa pode demorar um pouco para computar!

Eis uma pergunta mais difcil:


Se minha idade de 1109 milhes de segundos, qual minha idade em anos?

Quando voc cansar de brincar com nmeros, vamos dar uma olhada em algumas letras.

2003-2011 Chris Pine

2. L ETR A S
Ento, ns j aprendemos tudo sobre nmeros, mas e as letras? Palavras? Textos? Ns nos referimos a grupos de letras em um programa como strings (Voc pode pensar em letras impressas juntas ao longo de um banner). Para ficar mais fcil de entender quais partes do cdigo so strings, Eu vou colorir as strings em vermelho. Aqui tem alguns exemplos de strings:
'Ol.' 'Ruby rocks.' '5 meu nmero favorito... qual o seu?' 'Snoopy diz #%^?&*@! quando algum pisa no seu p.' ' ' ''

Como voc pode ver, strings podem ter pontuao, dgitos, smbolos e espaos... muito mais do que apenas letras. A ltima string no tem nada: ns a chamamos de string vazia. Ns estvamos usando puts para imprimir os nmeros; vamos tentar ele de novo com algumas strings:
puts 'Ol, mundo!' puts '' puts 'At logo.'

Ol, mundo! At logo.

Isso funcionou bem. Agora, tente umas strings voc mesmo.

A RIT IM T IC A

DA S

S T RING

Assim como voc pode fazer aritimtica com nmeros, voc tambm pode fazer aritimtica com strings! Bem, uma parte dela... voc pode adicionar strings, de qualquer forma. Vamos tentar adicionar duas strings e ver o que o puts faz.
puts 'Eu gosto de' + 'torta de ma.'

Eu gosto detorta de ma.

Ops! Eu esqueci de adicionar um espao entre 'Eu gosto de' e 'torta de ma.'. Espaos no fazem importncia normalmente, mas eles fazem sentido dentro de strings. ( verdade o que dizem: computadores no fazem o que voc quer que eles faam, apenas o que voc manda eles fazerem). Vamos tentar de novo:
puts 'Eu gosto de ' + 'torta de ma.'

puts 'Eu gosto de' + ' torta de ma.'

Eu gosto de torta de ma. Eu gosto de torta de ma.

(Como voc pode ver, no importa em qual string eu adicione o espao.) Ento voc pode somar strings. Mas voc pode, tambm, multiplic-las! (Por um nmero, de qualquer forma). Veja isso:
puts 'piscar ' * 4

piscando os olhos dela

(Estou brincando... ele na verdade faz isso:)


piscar piscar piscar piscar

Se voc parar para pensar, isso realmente faz sentido. Afinal, 7*3 realmente quer dizer 7+7+7, ento 'moo'*3 apenas significa 'moo'+'moo'+'moo'.

12

VS

'12'

Antes de irmos mais longe, ns devemos ter certeza de que entendemos a diferena entre nmeros e dgitos. 12 um nmero, mas '12' uma string de dois dgitos. Vamos brincar com isso um pouco:
puts 12 + 12 puts '12' + '12' puts '12 + 12'

24 1212 12 +

12

Que tal isso?


puts 2 * puts '2' * puts '2 * 5 5 5'

10 22222 2 * 5

Esses exemplos foram muito diretos. De qualquer forma, se voc no for muito cauteloso quando misturar strings e nmeros, voc pode cair em...

P RO BL E MA S
Nesse ponto, voc j deve ter tentado algumas coisas que no funcionaram. Se no, aqui tem algumas:

puts '12' + 12 puts '2' * '5'

#<TypeError: can't convert Fixnum into String>

Hmmm... Uma mensagem de erro. O problema que voc no pode, realmente, adicionar um nmero a uma string, ou multiplicar uma string por outra string. Isso no faz muito sentido como isso:
puts 'Betty' + 12 puts 'Fred' * 'John'

Uma coisa que voc deve saber: voc pode escrever 'porco'*5 em um programa, j que isso apenas quer dizer 5 conjuntos da string 'porco', todas adicionadas entre si. Entretanto, voc no pode escrever 5*'porco', j que isso significa 'porco' conjuntos do nmero 5, o que um pouco insano. Finalmente, e que tal um programa que imprima Isso um apstrofo: ' ? Ns podemos tentar isso:
puts 'Isso um apstrofo: ''

Bem, aquilo no vai funcionar; Eu nem vou tentar executar aquilo. O computador me disse que ns terminamos com uma string. ( por isso que bom ter um editor de texto que tenha realador de sintaxe para voc). Ento, como podemos fazer com que o computador saiba que ns queremos continuar dentro da string? Ns temos que escapar o apstrofo, assim:
puts 'Isso um apstrofo: \''

Isso um apstrofo: '

A barra invertida um caractere de escape. Em outras palavras, se voc tem uma barra invertida seguida de um caractere, isso pode ser, algumas vezes, traduzido em um novo caractere. As nicas coisas que uma barra invertida escapa, porm, so o apstrofo e a prpria barra invertida (Se voc pensar a respeito, caracteres de escape devem sempre escapar a si mesmos).) Acho que uns exemplos so bons agora:
puts puts puts puts 'Isso um apstrofo: \'' 'uma barra invertida no fim da string: 'acima\\embaixo' 'acima\embaixo'

\\'

Isso um apstrofo: ' uma barra invertida no fim da string: acima\embaixo acima\embaixo

Uma vez que a barra invertida no escapa'e', mas escapa a si mesma, as ltimas duas strings so idnticas. Elas no se parecem no cdigo, mas no seu computador elas so as mesmas. Se voc tiver outra dvida, apenas continue lendo! Eu no posso responder a todas as questes nesta pgina.

2003-2011 Chris Pine

3. V A R I V EI S

A TR I B U I ES

At agora, sempre que usamos puts numa string ou nmero, o que imprimimos some. O que eu quero dizer , se quisssemos imprimir algo duas vezes, teramos que digitar duas vezes:
puts '...voc pode dizer aquilo de novo...' puts '...voc pode dizer aquilo de novo...'

...voc pode dizer aquilo de novo... ...voc pode dizer aquilo de novo...

Seria legal se pudssemos digit-lo uma nica vez e mant-lo por perto... guard-lo em algum lugar. Bom, ns podemos, clarocaso contrrio eu no teria tocado no assunto! Para guardar a string na memria de seu computador, precisamos dar um nome a ela. Normalmente os programadores chamam esse processo de atribuio, e chamam os nomes de variveis. A varivel pode ser praticamente qualquer seqncia de letras e nmeros, mas o primeiro caracter tem de ser uma letra minscula. Vamos rodar o ltimo programa de novo, mas desta vez eu darei string o nome de minhaString (ainda que eu pudesse t-la chamado de str ou minhaStringzinha ou pedroPrimeiro).
minhaString = '...voc pode dizer aquilo de novo...' puts minhaString puts minhaString

...voc pode dizer aquilo de novo... ...voc pode dizer aquilo de novo...

Sempre que voc tentou fazer algo com minhaString, o programa fez com '...voc pode dizer aquilo de novo' no lugar. Voc pode pensar na varivel minhaString como "apontando para" a string '...voc pode dizer aquilo de novo...'. Eis um exemplo um pouquinho mais interessante:
nome = 'Patricia Rosanna Jessica Mildred Oppenheimer' puts 'Meu nome ' + nome + '.' puts 'Nossa! ' + nome + ' um nome bem longo!'

Meu nome Patricia Rosanna Jessica Mildred Oppenheimer. Nossa! Patricia Rosanna Jessica Mildred Oppenheimer um nome bem longo!

Assim como podemos atribuir um objeto a uma varivel, podemos reatribuir um objeto diferente mesma varivel (e por isso que ns as chamamos de variveis: porque a coisa para a qual apontam pode variar).
compositor = 'Mozart' puts compositor + ' era "sensa", na sua poca.'

compositor = 'Beethoven' puts 'Mas eu, pessoalmente, prefiro ' + compositor + '.'

Mozart era "sensa", na sua poca. Mas eu, pessoalmente, prefiro Beethoven.

Variveis podem, claro, apontar para qualquer tipo de objeto, no s strings:


var = 's mais uma ' + 'string' puts var var = 5 * (1+2) puts var

s mais uma string 15

Na verdade, variveis podem apontar para qualquer coisa... que no outras variveis. Ento o que acontece se tentarmos?
var1 var2 puts puts = 8 = var1 var1 var2

puts '' var1 = 'oito' puts var1 puts var2

8 8 oito 8

Primeiro, quando tentamos apontar var2 para var1, var2 apontou para 8 (exatamente como var1 apontava). A fizemos var1 apontar para 'oito', mas como var2 nunca apontou de verdade para var1, ela se mantm apontando para 8. Agora que temos variveis, nmeros e strings, vamos aprender como misturar todos eles!

2003-2011 Chris Pine

4. M I S TU R A N D O

TU D O

Ns vimos alguns tipos diferentes de objetos (nmeros e letras), e ns fizemos variveis para apontar para elas; a coisa que queremos fazer a seguir fazer com que todas se encaixem. Ns vimos que se desejssemos que um programa imprimisse 25 , o cdigo a seguir no funcionaria, porque voc no pode somar nmeros e strings:
var1 = 2 var2 = '5' puts var1 + var2

Parte do problema que seu computador no sabe se voc est querendo 7 (2 + 5) ou 25 ('2' + '5'). Antes que possamos somar os dois, precisamos de alguma maneira de obter a verso em string de var1, ou ento de obter a verso inteira de var2.

C O NV E RS IO NS
Para obter a verso string de um objeto, simplesmente escrevemos .to_s depois dele:
var1 = 2 var2 = '5' puts var1.to_s + var2

25

Similarmente, to_i fornece a verso inteira de um objeto, e to_f d a verso float. Vejamos o que esses trs mtodo fazem (e no fazem) com mais detalhe:
var1 = 2 var2 = '5' puts var1.to_s + var2 puts var1 + var2.to_i

25 7

Note que, mesmo depois que obtivemos a verso string de var1 por meio de to_s, var1 sempre apontou para 2, e nunca para '2'. A no ser que reatribuamos var1 explicitamente (o que requer um sinal de =), ela vai apontar para 2 enquanto o programa estiver rodando. Agora vamos tentar algumas converses mais interessantes (e alguma apenas esquisitas):

puts puts puts puts puts puts puts puts puts puts

'15'.to_f '99.999'.to_f '99.999'.to_i '' '5 meu nmero favorito!'.to_i 'Quem foi que te perguntou sobre o 5?'.to_i 'Sua me.'.to_f '' 'stringuelingue'.to_s 3.to_i

15.0 99.999 99 5 0 0.0 stringuelingue 3

provvel que tenha havido surpresas. A primeira bem padro e d 15 . Depois disso, convertemos a string '99.999' para um float e para um inteiro. O float ficou como espervamos; o inteiro, como sempre, foi arredondado para baixo. Em seguida temos alguns exemplos de strings... atpicas convertidas em nmeros. to_i ignora a primeira coisa que ela no entende, e o resto da string daquele ponto em diante. Ento a primeira string foi convertida para 5, mas as outras, j que comeavam com letras, foram ignoradas por completo... ento o computador s escolhe zero. Por fim, vimos que nossas duas ltimas conversas no fizeram nada, exatamente como espervamos.

U MA O U T RA O L HA DE L A

EM PUTS

H alguma coisa estranha no nosso mtodo favorito... D uma olhadinha:


puts 20 puts 20.to_s puts '20'

20 20 20

Por que que essas trs imprimem a mesma coisa? Tudo bem, as duas ltimas deveriam mesmo, j que 20.to_s '20'. Mas e a primeira, o inteiro 20? Falando nisso, faz algum sentido escrever o inteiro 20? Quando voc escreve um 2 e depois um 0 num papel, voc est escrevendo uma string, no um inteiro. O inteiro 20 o nmero de dedos que eu possuo, e no um 2 seguido de um 0. O nosso amigo puts carrega um grande segredo: antes de tentar escrever um objeto, puts usa to_s para obter a verso string do mesmo. Na verdade, o s em puts est l representando string; puts na verdade significa put string (colocar string). Isso pode no parecer muito animador agora, mas h muitos, muitos tipos de objetos em Ruby (voc vai at aprender a fazer o seu prprio!), e bom saber o que vai acontecer se voc tentar usar puts num objeto muito estranho, como uma foto da sua av, ou um arquivo de msica ou algo assim. Mas isso vem depois... At l, ns temos mais alguns mtodos para voc, e eles permitem que escrevamos um bando de programas divertidos...

O S M T O DO S

GETS E CHOMP

Se puts significa colocar string (N.T.: put significa "colocar"), acho que voc pode adivinhar o que gets quer dizer (N.T.: get, em ingls, entre vrias acepes, significa pegar, obter). E assim como puts sempre cospe strings, gets vai apenas obter strings. E de onde ele as pega? De voc! Tudo bem, do seu teclado. J que seu teclado s produz strings, isso funciona muito bem. O que acontece, na verdade, que gets fica l esperando, lendo o que voc digita at que voc pressione Enter. Vamos experimentar:
puts gets

Tem um eco aqui?


Tem um eco aqui?

Claro, tudo que voc digitar vai ser repetido para voc. Rode algumas vezes e tente digitar coisas diferentes. Agora podemos fazer programas interativos! Neste, digite o seu nome para que ele lhe saude:
puts name puts puts 'Ol, qual o seu nome?' = gets 'Seu nome ' + name + '? Que nome bonito!' 'Prazer em conhec-lo, ' + name + '. :)'

Eca! Eu acabei de rod-loescrevi meu nomee aconteceu isto:


Ol, qual o seu nome?

Chris
Seu nome Chris ? Que nome bonito! Prazer em conhec-lo, Chris . :)

Hmmm... parece que quando eu digitei as letras C, h, r, i, s, e pressionei Enter, gets obteve todas as letras do meu nome e o Enter! Felizmente, existe um mtodo exatamente pra esse tipo de coisa: chomp. Ele retira qualquer Enter que esteja l de bobeira no fim da sua string. Vamos testar aquele programa de novo, mas com chomp para ajudar:
puts name puts puts 'Ol, qual o seu nome?' = gets.chomp 'Seu nome ' + name + '? Que nome bonito!' 'Prazer em conhec-lo, ' + name + '. :)'

Ol, qual o seu nome?

Chris
Seu nome Chris? Que nome bonito! Prazer em conhec-lo, Chris. :)

Muito melhor! Perceba que j que name aponta para gets.chomp, no temos que dizer name.chomp; name j foi mastigado (N.T.: chomp, em Ingls "mastigar").

U MA S C O IS INHA S P A RA T E NT A R
Escreva um programa que pea o nome de uma pessoa, depois o sobrenome. Por fim, faa com que

ele cumprimente a pessoa usando seu nome completo. Escreva um programa que pergunte pelo nmero favorito de uma pessoa. Some um ao nmero, e sugira o resultado como um nmero favorito muito melhor (tenha tato ao faz-lo). Assim que voc terminar esses dois programas (e quaisquer outros que voc queira tentar), aprenderemos mais mtodos (e mais coisas sobre eles).

2003-2011 Chris Pine

5. M A I S S OB R E M TOD OS
At agora ns vimos uma poro de mtodos diferentes, puts e gets dentre outros (Teste Surpresa: Liste todos os mtodos que vimos at agora! Foram dez deles; a resposta est mais embaixo.), mas ns no conversamos realmente sobre o que so mtodos. Ns sabemos o que eles fazem, mas no sabemos o que eles so. Mas, na verdade, isso o que eles so: coisas que fazem coisas. Se objetos (como strings, inteiros e floats) so os substantivos na linguagem Ruby, os mtodos so como os verbos. E, ao contrrio do Portugus (em que h sujeitos indefinidos e outras construes esotricas), voc no pode ter um verbo sem um substantivo para executar o verbo. Mas mesmo o Portugus trata a ausncia de um substantivo como exceo: por exemplo, contar o tempo no algo que simplesmente acontece; um relgio (ou cronmetro, ou algo parecido) deve faz-lo. Em Portugus diramos: "O relgio conta o tempo". Em Ruby dizemos relogio.tiquetaque (presumindo que relogio um objeto Ruby, claro). Programadores podem dizer que estamos "chamando o mtodo tiquetaque do relogio," ou que "chamamos tiquetaque no relogio." E ento, voc respondeu o quiz? timo. Bem, tenho certeza que voc lembrou dos mtodos puts, gets e chomp, que acabamos de ver. Voc tambm provavelmente lembrou dos mtodos de converso, to_i, to_f e to_s. No entanto, voc descobriu os outros quatro? Pois no eram ningum menos que nossos velhos amigos da matemtica, +, -, * e /! Como eu estava dizendo, todo mtodo precisa de um objeto. Geralmente fcil dizer qual objeto est executando o mtodo: aquilo que vem logo antes do ponto, como no nosso exemplo do relogio.tiquetaque, ou em 101.to_s. s vezes, no entanto, isso no to bvio; como com os mtodos aritmticos. A bem da verdade, 5 + 5 realmente apenas um atalho para se escrever 5.+ 5. Por exemplo:
puts 'ol '.+ 'mundo' puts (10.* 9).+ 9

ol mundo 99

No muito bonito, ento ns nunca mais vamos escrever desse jeito; no entanto, importante entender o que realmente est acontecendo. (Na minha mquina, isso tambm me d um aviso: warning: parenthesize argument(s) for future version . O cdigo ainda rodou sem problemas, mas ele est me dizendo que est com problemas para descobrir o que eu quis dizer, e pedindo para usar mais parnteses no futuro). Isso tambm nos d um entendimento mais profundo sobre por que podemos fazer 'porco'*5 mas no 5*'porco': 'porco'*5 est dizendo ao 'porco' para se multiplicar, mas 5*'porco' est pedindo ao 5 que se multiplique. 'porco' sabe como fazer 5 cpias de si mesmo e junt-las; no entanto, 5 vai ter muito mais dificuldade para fazer 'porco' cpias de si mesmo e junt-las. E, claro, ns ainda temos o puts e o gets para explicar. Onde esto seus objetos? Em Portugus, voc pode s vezes omitir o substantivo; por exemplo, se um vilo grita "Morra!", o substantivo implcito a pessoa com quem ele est gritando. Em Ruby, se dissermos puts 'ser ou no ser', o que eu realmente estou dizendo self.puts 'ser ou no ser'. Ento o que self? uma varivel especial que aponta para o objeto onde voc est. Ns nem sabemos como estar em um objeto ainda,

mas at descobrirmos, ns estaremos sempre em um grande objeto que ... o programa inteiro! E para nossa sorte, o programa tem alguns mtodos prprios, como puts e gets. Preste ateno:
naoAcreditoQueFizUmNomeDeVariavelTaoGrandeApenasParaGuardarUm3 = 3 puts naoAcreditoQueFizUmNomeDeVariavelTaoGrandeApenasParaGuardarUm3 self.puts naoAcreditoQueFizUmNomeDeVariavelTaoGrandeApenasParaGuardarUm3

3 3

Se voc no acompanhou tudo o que aconteceu, no tem problema. A coisa importante para aprender disso tudo que cada mtodos est sendo executado pelo mesmo objeto, mesmo que ele no esteja na sua frente. Se voc entender isso, ento est preparado.

M T O DO S E L E G A NT E S

DA

S T RING

Vamos aprender alguns mtodos divertidos da string. Voc no precisa memorizar todos eles; voc pode apenas olhar esta pgina novamente se esquec-los. Eu s quero mostrar uma pequena parte do que as strings podem fazer. Na verdade, eu mesmo no lembro da metade dos mtodos da stringmas no tem problema, pois existem timas referncias na internet com todos os mtodos da string listados e explicados. (Vou mostrar onde encontr-los no final deste tutorial.) Pra falar a verdade, eu nem quero saber todos os mtodos da string; como saber todas as palavras do dicionrio. Eu posso falar Portugus muito bem sem saber todas as palavras do dicionrio... e esse no exatamente o seu propsito? Para que voc no precise saber tudo que est nele? Ento, nosso primeiro mtodo da string o reverse, que nos d uma verso ao contrrio da string:
var1 = 'pare' var2 = 'radar' var3 = 'Voce consegue pronunciar esta frase ao contrario?' puts puts puts puts puts puts var1.reverse var2.reverse var3.reverse var1 var2 var3

erap radar ?oirartnoc oa esarf atse raicnunorp eugesnoc ecoV pare radar Voce consegue pronunciar esta frase ao contrario?

Como voc pode ver, reverse no inverte a string original; ela apenas faz uma nova verso ao contrrio dela. por isso que var1 ainda 'pare' mesmo aps a chamada a reverse em var1. Outro mtodo da string length, que nos diz o nmero de caracteres (incluindo espaos) na string:
puts 'Qual o seu nome completo?' nome = gets.chomp puts 'Voc sabia que seu nome possui ' + nome.length + ' caracteres, ' + nome + '?'

Qual o seu nome completo?

Christopher David Pine


#<TypeError: can't convert Fixnum into String>

Uh-oh! Algo deu errado, e parece que isso aconteceu aps a linha nome = gets.chomp... Voc enxerga o problema? Veja se consegue descobrir. O problema est em length: ele lhe d um nmero, mas queremos uma string. Fcil, vamos colocar um to_s (e cruzar os dedos):
puts 'Qual o seu nome completo?' nome = gets.chomp puts 'Voc sabia que seu nome possui ' + nome.length.to_s + ' caracteres, ' + nome + '?'

Qual o seu nome completo?

Christopher David Pine


Voc sabia que seu nome possui 22 caracteres, Christopher David Pine?

No, eu no sabia disso. Nota: este o nmero de caracteres no meu nome, no o nmero de letras (conte-as). Eu acho que conseguimos escrever um programa que pergunta seu primeiro nome, nome do meio e sobrenome individualmente e some todos os tamanhos... Ei, por que voc no faz isso? V em frente, eu espero. Pronto? Bom! um programa legal, no ? Depois de mais uns captulos, entretanto, voc vai ficar maravilhado com o que conseguir fazer. Existem alguns mtodos da string que conseguem mudar a caixa (maisculas e minsculas) da sua string. upcase muda todas as letras minsculas para maisculas, e downcase muda todas as letras maisculas para minsculas. swapcase troca a caixa de todas as letras da string e, finalmente, capitalize parecido com downcase, exceto que ele troca o primeiro caractere para maisculo (se for uma letra).
letras = 'aAbBcCdDeE' puts letras.upcase puts letras.downcase puts letras.swapcase puts letras.capitalize puts ' a'.capitalize puts letras

AABBCCDDEE aabbccddee AaBbCcDdEe Aabbccddee a aAbBcCdDeE

Coisas bem simples. Como voc pode ver na linha puts ' a'.capitalize, o mtodo capitalize apenas deixa em maisculo o primeiro caractere, no a primeira letra. Tambm, como vimos anteriormente, durante todas essas chamadas de mtodos, letras continuou inalterada. Eu no quero me alongar nesse ponto, mas importante entender. Existem alguns mtodos que mudam o objeto associado, mas ainda no vimos nenhum, e nem iremos ver durante algum tempo. O ltimo mtodo elegante da string que iremos ver para formatao visual. O primeiro, center, adiciona espaos no comeo e no fim da string para torn-la centralizada. No entanto, assim como voc precisa dizer ao puts o que quer que seja impresso, e ao + o que quer que seja adicionado, voc precisa dizer ao center a largura total da string a ser centralizada. Ento se eu quiser centralizar as linhas de um poema, eu faria assim:
larguraDaLinha = 50 puts( 'Old Mother Hubbard'.center(larguraDaLinha)) puts( 'Sat in her cupboard'.center(larguraDaLinha)) puts( 'Eating her curds an whey,'.center(larguraDaLinha)) puts( 'When along came a spider'.center(larguraDaLinha)) puts( 'Which sat down beside her'.center(larguraDaLinha)) ('A d d h h d ' (l D Li h ))

puts('And scared her poor shoe dog away.'.center(larguraDaLinha))

Old Mother Hubbard Sat in her cupboard Eating her curds an whey, When along came a spider Which sat down beside her And scared her poor shoe dog away.

Hum... Eu no acho que essa rima assim, mas sou muito preguioso para procurar. (Tambm, eu queria alinhar a parte do .center larguraDaLinha, por isso acrescentei espaos extra antes das strings. Isso s por que acho que fica mais bonito assim. Programadores geralmente tm opinies fortes sobre o que bonito num programa, e eles geralmente discordam sobre o assunto. Quanto mais voc programar, mais vai descobrir seu prprio estilo). Falando em ser preguioso, a preguia nem sempre algo ruim na programao. Por exemplo, viu como eu guardei a largura do poema numa varivel larguraDaLinha? Fiz isso pois se quiser tornar o poema mais largo mais tarde, s precisarei mudar a primeira linha do programa, ao invs de todas as linhas que so centralizadas. Com um poema muito longo, isso poderia me poupar um bom tempo. Esse tipo de preguia na verdade uma virtude na programao. Ento, em relao centralizao... voc deve ter percebido que no est to bonito quanto um processador de texto teria feito. Se voc realmente quer centralizao perfeita (e talvez uma fonte melhor), ento voc deveria apenas usar um processador de texto! Ruby uma ferramenta maravilhosa, mas nenhuma ferramenta a ferramenta certa para qualquer trabalho. Os outros dois mtodos de formatao da string so ljust e rjust, que fazem o texto justificado esquerda e justificado direita. Eles so parecidos com o center, exceto que eliminam os espaos em branco da string do lado direito e esquerdo, respectivamente. Vamos ver os trs em ao:
larguraDaLinha = 40 str = '--> text <--' puts str.ljust larguraDaLinha puts str.center larguraDaLinha puts str.rjust larguraDaLinha puts str.ljust (larguraDaLinha/2) + str.rjust (larguraDaLinha/2)

--> text <---> text <--

--> text <--

--> text <---> text <--

U MA S C O IS INHA S P A RA T E NT A R
Escreva um programa do Chefe Zangado. Ele deve perguntar o que voc quer de forma rude. Qualquer que seja a sua resposta, o Chefe Zangado vai gritar de volta para voc, e ento despedi-lo. Por exemplo, se voc digitar Eu quero um aumento. , ele deve gritar de volta O QUE VOC QUER DIZER COM "EU QUERO UM AUMENTO."?!? VOC EST DESPEDIDO!! Eis aqui algo para voc fazer para brincar um pouco mais com center, ljust e rjust: Escreva um programa que ir mostrar um ndice de forma que fique parecido com:
Tabela de Contedo Captulo 1: Captulo 2: Captulo 3: Nmeros Letras Variveis pgina 1 pgina 72 pgina 118

M A T E M T IC A A V A N A DA
(E l i l El ld h i i S

(Esta seo totalmente opcional. Ela assume um certo nvel de conhecimento matemtico. Se voc no estiver interessado, voc pode ir direto para o Controle de Fluxo sem nenhum problema. No entanto, uma breve passada pela seo de Nmeros Aleatrios pode ser til.) No h tantos mtodos nos nmeros quanto nas strings (apesar de eu ainda no ter decorado todos). Aqui, iremos olhar o resto dos mtodos de aritmtica, um gerador de nmeros aleatrios e o objeto Math, com seus mtodos trigonomtricos e transcendentais.

M A IS A RIT IM T IC A
Os outros dois mtodos aritmticos so ** (exponenciao) e % (mdulo). Ento se voc quisesse dizer "cinco ao quadrado" em Ruby, voc escreveria 5**2. Voc tambm pode usar floats para seu expoente, ento se voc quiser a raiz quadrada de 5, voc pode escrever 5**0.5. O mtodo mdulo lhe d o resto da diviso por um nmero. Ento, por exemplo, se eu divido 7 por 3, eu tenho 2 com resto 1. Vamos vlos em ao num programa:
puts puts puts puts puts 5**2 5**0.5 7/3 7%3 365%7

25 2.23606797749979 2 1 1

Pela ltima linha, aprendemos que um ano (no-bissexto) tem um certo nmero de semanas, mais um dia. Ento se seu aniversrio caiu numa tera-feira este ano, ele ser numa quarta-feira no ano que vem. Voc tambm pode usar floats com o mtodo mdulo. Basicamente, ele funciona da nica maneira razovel que consegue... Mas eu vou deixar voc brincar um pouco com isso. Tem um ltimo mtodo para ser mencionado antes de vermos o gerador de nmeros aleatrios: abs. Ele simplesmente pega o valor absoluto de um nmero:
puts((5-2).abs) puts((2-5).abs)

3 3

N ME RO S A L E A T RIO S
Ruby vem com um gerador de nmeros aleatrios bem legal. O mtodo que escolhe aleatoriamente um nmero o rand. Se voc chamar rand simplesmente assim, voc vai ter um float maior ou igual a 0.0 e menor que 1.0. Se voc der um inteiro (5 por exemplo) para o rand, ele vai te dar um inteiro maior ou igual a 0 e menor que 5 (ento so cinco nmeros possveis, de 0 at 4). Vamos ver o rand em ao. (Se voc recarregar esta pgina, estes nmeros vo mudar a cada vez. Voc sabia que eu estou realmente rodando estes programas, no sabia?)
puts rand puts rand puts rand puts(rand(100)) puts(rand(100)) puts(rand(100)) t ( d(1))

puts(rand(1)) puts(rand(1)) puts(rand(1)) puts(rand(99999999999999999999999999999999999999999999999999999999999)) puts('O homem do tempo disse que existe '+rand(101).to_s+'% de chance de chover,') puts('mas voc no pode nunca confiar num homem do tempo.')

0.250155999601107 0.999297688708222 0.127660371461191 72 99 71 0 0 0 2306971306222446870665292874293651659816757282565833710354 O homem do tempo disse que existe 70% de chance de chover, mas voc no pode nunca confiar num homem do tempo.

Perceba que eu usei rand(101) para conseguir os nmeros de 0 at 100, e que rand(1) sempre retorna 0. No entender o intervalo dos possveis valores retornados o maior erro que eu vejo as pessoas cometerem ao usar rand; mesmo programadores profissionais; mesmo em produtos terminados que voc pode comprar na loja. Eu inclusive tive um tocador de CD que, se configurado para "Tocar Aleatoriamente", iria tocar todas as msicas menos a ltima... (Eu imagino o que aconteceria se eu colocasse um CD com apenas uma msica nele?) As vezes voc pode querer que rand retorne os mesmos nmeros aleatrios na mesma sequncia em duas execues diferentes do seu programa. (Por exemplo, uma vez eu estava usando nmeros aleatrios gerados para criar um mundo gerado aleatoriamente num jogo de computador. Se eu encontrasse um mundo que eu realmente gostasse, talvez eu quisesse jogar nele novamente, ou mand-lo para um amigo). Para isso, voc precisa configurar a semente, que voc consegue fazer com srand. Desta forma:
srand 1776 puts(rand(100)) puts(rand(100)) puts(rand(100)) puts(rand(100)) puts(rand(100)) puts '' srand 1776 puts(rand(100)) puts(rand(100)) puts(rand(100)) puts(rand(100)) puts(rand(100))

24 35 36 58 70 24 35 36 58 70

Ele far a mesma coisa sempre que voc aliment-lo com a mesma semente. Se voc quer voltar a ter nmeros diferentes (como acontece quando voc nunca usa srand), ento apenas chame srand 0. Isso alimenta o gerador com um nmero realmente estranho, usando (dentre outras coisas) a hora atual do seu computador, com preciso de milisegundos.

O O BJE T O M A T H
Finalmente, vamos olhar para o objeto Math. Vamos comear de uma vez:
puts(Math::PI) puts(Math::E) puts(Math.cos(Math::PI/3)) puts(Math.tan(Math::PI/4)) puts(Math.log(Math::E**2)) puts((1 + Math.sqrt(5))/2)

3.14159265358979 2.71828182845905 0.5 1.0 2.0 1.61803398874989

A primeira coisa que voc percebeu foi provavelmente a notao do ::. Explicar o operador de escopo (que o que ele ) est um pouco alm do, uh... escopo deste tutorial. No nenhum trocadilho. Eu juro. Basta dizer que voc pode usar Math::PI exatamente da forma como voc espera. Como voc pode ver, Math tem todas as coisas que voc esperaria que uma calculadora cientfica decente tivesse. E, como sempre, os floats esto realmente perto de serem as respostas certas. Ento vamos entrar no fluxo!

2003-2011 Chris Pine

6. C ON TR OLE

DE

F LU X O

Ahhhh, controle de fluxo. aqui que tudo se junta. Ainda que este captulo seja mais curto e fcil que o captulo sobre mtodos, ele vai abrir um mundo de possibilidades de programao. Aps este captulo, poderemos escrever programas realmente interativos; antes fizemos programas que dizem coisas diferentes dependendo do que voc escreve, mas aps este captulo eles faro coisas diferentes, tambm. Todavia, temos que poder comparar objetos no nosso programa. Precisamos de...

M T O DO S

DE

C O MP A RA O

Vamos ser rpidos por aqui para chegar at as ramificaes, que onde as coisas legais comeam a acontecer. Para ver se um objeto maior ou menor que outro, usamos os mtodos > e <, assim:
puts 1 > 2 puts 1 < 2

false true

Tudo em ordem. Do mesmo modo, podemos descobrir se um objeto maior-ou-igual-que (ou menorou-igual-que) outro com os mtodos >= e <=.
puts 5 >= 5 puts 5 <= 4

true false

Por fim, podemos descobrir se dois objetos so iguais ou no usando == (que significa "estes objetos so iguais?") e != (que significa "estes objetos so diferentes?"). importante no confundir = com ==. = serve para dizer a uma varivel que aponte para um objeto (atribuio), e == para fazer a pergunta: "Estes dois objetos so iguais?".
puts 1 == 1 puts 2 != 1

true true

E claro que tambm podemos comparar strings. Quando strings so comparadas, leva-se em conta seus ordenamentos lexicogrficos, que, trocando em midos, significa a ordem delas no dicionrio. cachorro vem antes de gato no dicionrio, ento:
puts 'cachorro' < 'gato'

true

H um porm: os computadores costumam ordenar letras maisculas antes de minsculas, como se viessem antes ( assim que guardam as letras em fontes, por exemplo: todas as letras maisculas primeiro, seguidas das minsculas). Isso significa que o computador vai pensar que 'Zoolgico' vem antes de 'abelha', ento se voc quiser descobrir qual palavra viria primeiro num dicionrio de verdade, use downcase (ou upcase ou capitalize) em ambas as palavras antes de tentar comparlas. Uma ltima observao antes de Ramificaes: os mtodos de comparao no esto nos dando as strings 'true' e 'false'; elas esto nos dando os objetos especiais true e false (claro, true.to_s nos d 'true', que como puts imprimiu 'true'). true e false so usados o tempo todo em...

R A MIF IC A E S (B RA NC HING )
"Ramificao" um conceito simples, mas poderoso. Na verdade, to simples que aposto que nem tenho que explic-lo; deixa eu mostrar para voc:
puts 'Ol, qual o seu nome?' nome = gets.chomp puts 'Ol, ' + nome + '.' if nome == 'Chris' puts 'Que nome bonito!' end

Ol, qual o seu nome?

Chris
Ol, Chris. Que nome bonito!

Mas se colocarmos um nome diferente...


Ol, qual o seu nome?

Chewbacca
Ol, Chewbacca.

E isso ramificar. Se o que vem depois de if (N.T.se) true, ns executamos o cdigo entre if e end. Se o que vem depois de if false, no executamos nada. Claro e simples. Eu indentei o cdigo entre if e end porque acho que fica mais fcil acompanhar as ramificaes assim. Quase todos os programadores fazem isso, independente da linguagem em que estejam trabalhando. Pode no parecer muito til neste exemplo pequeno, mas quando as coisas ficam mais complexas, faz uma baita diferena. Muitas vezes gostaramos que um programa fizesse uma coisa se uma expresso for true, e outra se for false. para isso que serve else:
puts 'Eu sou um vidente. Diga-me seu nome:' nome = gets.chomp if nome == 'Chris' puts 'Vejo coisas maravilhosas no seu futuro.' else puts 'Seu futuro ... , Deus! Olha a hora!' puts 'Eu tenho que ir, mil perdes!' end

Eu sou um vidente. Diga-me seu nome:

Chris
Vejo coisas maravilhosas no seu futuro.

Agora vamos tentar um nome diferente...


Eu sou um vidente. Diga-me seu nome:

Ringo
Seu futuro ... , Deus! Olha a hora! Eu tenho que ir, mil perdes!

Ramificar como deparar com uma bifurcao no cdigo: tomamos o caminho para as pessoas com o nome == 'Chris' ou else, tomamos o outro caminho? E como os galhos de uma rvore, voc pode ter ramificaes que contm suas prprias ramificaes:
puts 'Ol, e bem-vindo aula de Portugus.' puts 'Meu nome professora Hlia. Seu nome ...?' nome = gets.chomp if nome == nome.capitalize puts 'Por favor, sente-se, ' + nome + '.' else puts nome + '? Voc quer dizer ' + nome.capitalize + ', no ?' puts 'Voc no sabe nem escrever seu nome??' resposta = gets.chomp if resposta.downcase == 'sim' puts 'Hunf! V, sente-se!' else puts 'FORA!!!' end end

Ol, e bem-vindo aula de Portugus. Meu nome professora Hlia. Seu nome ...?

chris
chris? Voc quer dizer Chris, no ? Voc no sabe nem escrever seu nome??

sim
Hunf! V, sente-se!

Est bem, vou capitalizar...


Ol, e bem-vindo aula de Portugus. Meu nome professora Hlia. Seu nome ...?

Chris
Por favor, sente-se, Chris.

s vezes pode ficar confuso entender onde colocar os ifs, elses e ends. O que eu fao escrever o end ao mesmo tempo que escrevo o if. Ento enquanto eu estava escrevendo o programa acima, ele estava primeiro assim:
puts 'Ol, e bem-vindo aula de Portugus.' puts 'Meu nome professora Hlia. Seu nome ...?' nome = gets.chomp if nome == nome.capitalize else end

A eu preenchi com comentrios, coisas no cdigo que o computador ir ignorar:

puts 'Ol, e bem-vindo aula de Portugus.' puts 'Meu nome professora Hlia. Seu nome ...?' nome = gets.chomp if nome == nome.capitalize # Ela cordial. else # Ela fica brava. end

Qualquer coisa aps um # considerado um comentrio (a no ser, claro, que voc esteja em uma string). Depois de preencher com comentrios, substitu-os por cdigo funcional. Algumas pessoas gostam de deix-los no arquivo; particularmente, creio que cdigo bem-escrito fala por si. Eu costumava escrever mais comentrios, mas quanto mais "fluente" fico em Ruby, menos fao uso deles. Eles me distraem boa parte do tempo. uma escolha individual; voc vai encontrar o seu estilo (normalmente em constante evoluo). Ento meu prximo passo ficou assim:
puts 'Ol, e bem-vindo aula de Portugus.' puts 'Meu nome professora Hlia. Seu nome ...?' nome = gets.chomp if nome == nome.capitalize puts 'Por favor, sente-se, ' + nome + '.' else puts nome + '? Voc quer dizer ' + nome.capitalize + ', no ?' puts 'Voc no sabe nem escrever seu nome??' resposta = gets.chomp if resposta.downcase == 'sim' else end end

Mais uma vez escrevi if, else e end ao mesmo tempo. Realmente me ajuda a saber "onde estou" no cdigo. Tambm faz com que o trabalho parea mais fcil porque posso me concentrar em uma parte pequena, como preencher o cdigo entre if e else. Uma outra vantagem de faz-lo desta maneira que o computador pode entender o programa em qualquer estgio. Qualquer uma das verses inacabadas do programa que eu lhe mostrei rodariam. Elas no estavam terminadas, mas eram programas funcionais. Desta maneira eu pude testar enquanto escrevia, o que me ajudou a ver como o programa progredia e o que precisava ser melhorado. Quando ele passou em todos os testes, eu soube que estava pronto! Essas dicas vo ajud-lo a escrever programas que se ramificam, mas tambm ajudam com outro tipo central de controle de fluxo:

R E P E T I O (L O O P ING )
Voc vai querer com alguma freqncia que o computador faa a mesma coisa vrias e vrias vezes afinal, nisso que os computadores, em teoria, so bons. Quando voc manda o seu computador ficar repetindo algo, voc tambm precisa diz-lo quando parar. Computadores nunca se entediam, ento se voc no mandar o seu parar, ele no parar. Garantimos que isso no acontea ao dizermos que ele deve repetir certas partes de um programa while (N.T. enquanto) uma condio especificada for verdadeira. O funcionamento bem parecido com o do if:
comando = '' while comando != 'tchau' puts comando comando = gets.chomp end puts 'Volte logo!'

Ol?
Ol?

Oi!
Oi!

Muito prazer em conhec-lo.


Muito prazer em conhec-lo.

Ah... que amor!


Ah... que amor!

tchau
Volte logo!

E isso um loop (voc deve ter notado a linha em branco no comeo da sada; ela vem do primeiro puts, antes do primeiro gets. Como voc modificaria o programa para se livrar dessa primeira linha? Teste! Funcionou exatamente como o programa acima, fora aquela primeira linha em branco?). Loops, ou repeties, permitem que voc faa vrias coisas interessantes, como sei que voc pode imaginar. Mas tambm podem causar problemas se voc cometer algum erro. E se o computador ficar preso num loop infinito? Se voc acha que isso pode ter acontecido, s segurar a tecla Ctrl e pressionar C. Antes de comearmos a brincar com loops, vamos aprender algumas coisinhas para facilitar nossa vida.

UM P OUC O

DE

L G IC A

Vamos dar uma olhada no nosso primeiro programa com ramificaes. E se minha esposa chegasse em casa, visse o programa, tentasse us-lo e ele no dissesse que nome bonito ela tem? Eu no gostaria de mago-la (ou de dormir no sof), ento vamos reescrev-lo:
puts 'Ol, qual o seu nome?' nome = gets.chomp puts 'Ol, ' + nome + '.' if nome == 'Chris' puts 'Que nome bonito!' else if nome == 'Katy' puts 'Que nome bonito!' end end

Ol, qual o seu nome?

Katy
Ol, Katy. Que nome bonito!

Bom, funciona... mas no l um programa muito bonito. E por qu? A melhor regra que eu aprendi sobre programao foi a regra DRY: Don't Repeat Yourself (N.T.No Se Repita). Eu poderia escrever um livro s sobre o quo boa ela . No nosso caso, repetimos a linha Que nome bonito!. Por que que isso um problema? Bem, e se eu cometi um erro de digitao quando eu reescrevi? E se eu quisesse mudar de bonito para gracioso em ambas as linhas? Eu sou preguioso, lembra? Basicamente, se eu quero que meu programa faa a mesma coisa quando receber Chris ou Katy, ento ele realmente deve fazer a mesma coisa:
puts 'Ol, qual o seu nome?' nome = gets.chomp puts 'Ol, ' + nome + '.' if (nome == 'Chris' or nome == 'Katy') puts 'Que nome bonito!' end

Ol, qual o seu nome?

Katy
Ol, Katy. Que nome bonito!

Muito melhor. Para que funcionasse, usei or. Os outros operadores lgicos so and e not. sempre bom usar parnteses ao trabalhar com eles. Vamos ver como funcionam:
euSouChris = true euSouRoxo = false euAmoComida = true euComoPedras = false puts puts puts puts puts puts puts puts puts puts puts puts (euSouChris and euAmoComida) (euAmoComida and euComoPedras) (euSouRoxo and euAmoComida) (euSouRoxo and euComoPedras) (euSouChris or euAmoComida) (euAmoComida or euComoPedras) (euSouRoxo or euAmoComida) (euSouRoxo or euComoPedras) (not euSouRoxo) (not euSouChris)

true false false false true true true false true false

O nico deles que pode engan-lo or (N.T.ou). Em portugus, usa-se "ou" para dizer "um ou outro, mas no os dois". Por exemplo, sua me pode lhe dizer: "Para sobremesa voc pode escolher torta ou bolo". Ela no deu a opo de escolher os dois! Um computador, por outro lado, entende or como "ou um ou outro, ou os dois" (outro jeito de colocar "ao menos um destes verdadeiro"). por isso que computadores so mais legais que mes.

U MA S C O IS INHA S P A RA T E NT A R
"Um elefante incomoda muita gente..." Escreva um programa que imprima a letra para o clssico das viagens de carro, com um limite de 100 elefantes. Escreva um programa Velha Surda. O que quer que voc diga velha (o que quer que voc digite), ela tem que responder com QUE?! FALA MAIS ALTO! , a no ser que voc grite (digite tudo em maisculas). Se voc gritar, ela pode lhe ouvir (ou ao menos pensa que pode), e sempre responde NO, NO DESDE 1938! Para fazer seu programa ser realmente verossmil, faa a velha gritar um nmero diferente a cada vez; talvez qualquer ano aleatrio entre 1930 e 1950 (a ltima parte opcional, e ficaria muito mais fcil se voc lesse a seo sobre o gerador de nmeros randmicos do Ruby no captulo sobre mtodos). Voc no pode parar de falar com a velha enquanto no gritar TCHAU . Dica: No esquea do chomp ! 'TCHAU' com um enter no a mesma coisa que 'TCHAU' sem! Dica 2: Tente pensar em que partes do programa as coisas acontecem repetidamente. Todas elas devem estar no seu loop while. Melhore o seu programa Velha Surda: e se a velha no quiser que voc v embora? Quando voc gritar TCHAU , ela pode fingir que no lhe ouve. Mude seu programa anterior para que voc tenha que gritar TCHAU trs vezes em seqncia. Teste bem o seu programa: se voc gritar TCHAU trs vezes, mas no em seqncia, voc tem que continuar falando com a velha. A bi t E t i i i l fi l i i

Anos bissextos. Escreva um programa que pergunte um ano inicial e um ano final, e imprima com puts todos os anos bissextos entre eles (e os incluindo, se eles tambm forem bissextos). Anos bissextos so sempre divisveis por quatro (como 1984 e 2004). Contudo, anos divisveis por 100 no so bissextos (como 1800 e 1900) a no ser que sejam divisveis por 400 (como 1600 e 2000, que foram de fato anos bissextos). (Sim, bem confuso, mas no to confuso como ter dezembro no meio do inverno, que o que aconteceria no fim). Quando voc termin-las, descanse um pouco! Voc j aprendeu muitas coisas. Parabns. Voc est surpreso com a quantidade de coisas que se pode mandar o computador fazer? Mais alguns captulos e voc vai poder programar praticamente tudo. Srio mesmo! Veja s tudo que voc pode fazer que no podia antes de aprender sobre loops e ramificaes. Agora vamos aprender sobre um novo tipo de objeto, que controla listas de outros objetos: arrays.

2003-2011 Chris Pine

7. A R R A Y S

I TER A D OR ES

Vamos escrever um programa que nos permita entrar com quantas palavras quisermos (uma por linha, at pressionarmos Enter em uma linha vazia), e depois mostre as palavras em ordem alfabtica. Ok? Ento... primeiro ns iremos.. bem.. hum... Bom, poderamos.. rsrsrs.. Certo, no sei se podemos fazer isso. Precisamos de uma forma de armazenar um nmero qualquer de palavras, e de podermos acess-las sem que se misturem com as outras variveis. Precisamos coloclas num tipo de lista. Precisamos dos arrays. Um array apenas uma lista em seu computador. Cada item da lista se comporta como uma varivel: voc pode ver qual objeto um item est apontando, e voc pode faz-lo apontar para um outro objeto. Vamos dar uma olhada em alguns arrays:
[] [5] ['Ol', 'Tchau'] sabor = 'baunilha' [89.9, sabor, [true, false]] # # isto no um array, claro... ...mas isto .

Primeiro ns temos um array vazio, ento um array contendo um nico nmero, ento um array contendo duas strings. Depois, temos uma atribuio simples; e a um array contendo trs objetos, sendo que o ltimo um outro array [true, false]. Lembre-se, variveis no so objetos, ento, nosso ltimo array est realmente apontando a para um float, uma string e um array. Mesmo que ns mudssemos o valor de sabor, isso no mudaria o array. Para nos ajudar a encontrar um objeto qualquer num array, cada item tem um nmero de indexao. Programadores (e, alis, a maioria dos matemticos) iniciam contando do zero, ento, o primeiro item do array o item zero. Veja como podemos referenciar os objetos em um array:
nomes = ['Ana', 'Maria', 'Cris'] puts puts puts puts puts nomes nomes[0] nomes[1] nomes[2] nomes[3]

Isto est fora do intervalo

Ana Maria Cris Ana Maria Cris nil

Vemos ento, que puts nomes imprime cada nome do array nomes. Ento usamos puts nomes[0] para imprimir o "primeiro" nome do array e puts nomes[1] para imprimir o "segundo"... Tenho certeza que parece confuso, mas voc deve se acostumar com isso. Voc deve realmente comear a acreditar que contar inicia do zero e parar de usar palavras como "primeiro" e "segundo". Se voc for num rodzio

de pizza, no fale sobre o "primeiro" pedao; fale sobre o pedao zero (e na sua cabea pense pedaco[0]). Voc tem 5 dedos na sua mo e seus nmeros so 0, 1, 2, 3 e 4. Minha esposa e eu somos malabariastas. Quando fazemos malabares com 6 pinos, estamos equilibrando os pinos 0 a 5. Felizmente, em alguns meses, estaremos equilibrando o pino 6 (e portanto, equilibrando 7 pinos). Voc saber que conseguiu quando comear a usar o termo "zersimo" :-) Sim, uma palavra real.. Pergunte a um programador ou matemtico.. Finalmente, ns tentamos puts nomes[3], apenas veja o que aconteceria. Voc estava esperando um erro? Algumas vezes quando voc faz uma pergunta, sua pergunta no faz sentido (pelo menos para seu computador); quando obtm um erro. Algumas vezes, entretanto, voc pode fazer uma pergunta e a resposta nada. O que est na posio trs? Nada. O que nomes[3]? nil: A maneira Ruby de dizer "nada". nil um objeto especial que basicamente significa "no qualquer outro objeto." Se toda esta numerao divertida de posies de array est confundindo voc, no tema! Freqentemente, ns podemos evit-la completamente usando vrios mtodos de array, como este:

O M T O DO

EACH

each nos permite fazer algo (o que quer que ns desejemos) para each (cada em portugus) objeto pertencente ao array. Assim, se ns quisssemos dizer algo bom sobre cada linguagem no array abaixo, ns faramos isto:
linguagens = ['Portugus', 'Ingls', 'Ruby'] linguagens.each do |ling| puts 'Eu adoro ' + ling + '!' puts 'Voc no?' end puts 'E vamos ouv-lo sobre C++!' puts '...'

Eu adoro Portugus! Voc no? Eu adoro Ingls! Voc no? Eu adoro Ruby! Voc no? E vamos ouv-lo sobre C++! ...

Ento, o que aconteceu? Bem, ns fomos capazes de passar por todos os objetos no array sem usar nenhum nmero, e isto muito bom. Traduzindo para o portugus, o programa acima seria algo como: Para cada objeto em linguagens, aponte a varivel ling para o objeto e ento faa (do em ingls) tudo que eu disser, at que voc chegue ao fim (end em ingls). (Como voc sabe, C++ uma outra linguagem de programao. muito mais difcil de aprender do que Ruby; normalmente, um programa C++ ser muitas vezes maior do que um programa Ruby que faz a mesma coisa.) Vocs poderiam estar pensando consigo mesmos, "Isto muito parecido com os laos de repetio (loops) que ns aprendemos anteriormente." Sim, similar. Uma diferena importante que o mtodo each apenas: um mtodo. while e end (como do, if, else, e todas as outras palavras em azul) no so mtodos. Elas so parte fundamental da linguagem Ruby, como = e os parnteses; como os sinais de pontuaes no portugus. Mas no each; each um apenas um outro mtodo do array. Mtodos como each que "atuam como" loops so freqentemente chamados iteradores. Uma coisa para notar sobre iteradores que eles so sempre seguidos por do...end. while e if nunca tm um do perto deles; ns apenas usamos do com iteradores. Aqui est um outro atraente iteradorzinho, mas no um mtodo de array... um mtodo de inteiros!

3.times do puts 'Hip-Hip-Urra!' end

Hip-Hip-Urra! Hip-Hip-Urra! Hip-Hip-Urra!

M A IS M T O DO S

DE

A RRA Y

Ento ns aprendemos each, mas existem muitos outros mtodos de array... quase tantos quantos existem mtodos de string! Na verdade, alguns deles (como length, reverse, +, e *) funcionam da mesma forma que funcionam para strings, exceto que eles operam em posies de array ao invs de em letras de string. Outros, como last e join, so especficos para arrays. Ainda outros, como push e pop, na verdade modificam o array. E assim como com os mtodos de string, voc no tem que se lembrar de todos estes, desde que voc possa se lembrar onde achar informaes sobre eles (bem aqui). Primeiro, vamos dar uma olhada em to_s e join. join funciona de forma semelhante a to_s, exceto que ele adiciona uma string entre os objetos do array. Vamos dar uma olhada:
comidas = ['feijoada', 'tapioca', 'bolo de fub'] puts puts puts puts puts puts puts comidas comidas.to_s comidas.join(', ') comidas.join(' :) ') + ' 8)'

200.times do puts [] end

feijoada tapioca bolo de fub feijoadatapiocabolo de fub feijoada, tapioca, bolo de fub feijoada :) tapioca :) bolo de fub 8)

Como voc pode ver, puts trata os arrays diferentemente de outros objetos: ele apenas chama puts em cada um dos objetos no array. por isso que chamar puts para um um array vazio 200 vezes no faz nada; o array no aponta para nada, assim no h nada para o puts mostrar (Fazer nada 200 vezes ainda fazer nada). Tente chamar puts para um array contendo outros arrays; fez o que voc esperava? Voc tambm notou que eu deixei uma string vazia quando eu quis mostrar uma linha em branco? Isto faz a mesma coisa. Agora vamos dar uma olhada em push, pop, e last. Os mtodos push e pop so de alguma forma opostos, assim como + e - so. push adiciona um objeto no fim do seu array, e pop remove o ltimo objeto do array (e diz para voc qual era este objeto). last similar a pop em dizer para voc o que est no fim do array, exceto que o last deixa o array em paz. Novamente, push e pop realmente modificam o array:
favoritos = [] f i h ' l b '

favoritos.push 'azul e branco' favoritos.push 'verde e amarelo' puts favoritos[0] puts favoritos.last puts favoritos.length puts favoritos.pop puts favoritos puts favoritos.length

azul e branco verde e amarelo 2 verde e amarelo azul e branco 1

A L G U MA S C O IS A S

P A RA

T E NT A R

Escreva o programa que ns comentamos no incio deste captulo. Dica: Existe um adorvel mtodo de array que dar a voc uma verso ordenada de um array: sort. Use-o! Tente escrever o programa acima sem usar o mtodo sort. Uma grande parte da programao resolver problemas, assim pratique o mximo que voc puder! Re-escreva seu programa de Tabela de Contedos (do captulo mtodos). Inicie o programa com um array que mantm todas as informaes sobre sua Tabela de Contedos (nomes de captulos, nmeros de pginas, etc.). Ento imprima na tela a informao do array em uma Tabela de Contedos, formatada de forma bem bonita. At o momento aprendemos bastante sobre um nmero de mtodos diferentes. Agora hora de aprender como fazer seus prprios mtodos.

2003-2011 Chris Pine

8. E S CR EV EN D O

S EU S

P R P R I OS M TOD OS

Como vimos, repeties e iteradores nos permitem fazer a mesma coisa (rodar o mesmo cdigo) vrias e vrias vezes. Porm, algumas vezes queremos fazer a mesma coisa um monte de vezes, mas de lugares diferentes do programa. Por exemplo, vamos supor que estejamos escrevendo um programa de questionrio para um estudante de psicologia. Levando em conta os estudantes de psicologia que eu conheo e os questionrios que eles me forneceram, seria algo parecido com isto:
puts puts puts puts puts puts puts puts # 'Ol, e obrigado pelo seu tempo para me ajudar' 'com essa pesquisa. Minha pesquisa sobre' 'como as pessoas se sentem com comida' 'mexicana. Apenas pense sobre comida mexicana' 'e tente responder, honestamente, cada questo' 'com "sim" ou "no". Minha pesquisa no tem' 'nada a ver com quem molha a cama.'

Ns fazemos as perguntas, mas ignoramos as respostas.

boaResposta = false while (not boaResposta) puts 'Voc gosta de comer tacos?' resposta = gets.chomp.downcase if (resposta == 'sim' or resposta == 'no') boaResposta = true else puts 'Por favor, responda com "sim" ou "no".' end end boaResposta = false while (not boaResposta) puts 'Voc gosta de comer burritos?' resposta = gets.chomp.downcase if (resposta == 'sim' or resposta == 'no') boaResposta = true else puts 'Por favor, responda com "sim" ou "no".' end end # Porm, ns prestamos ateno *nesta* questo. boaResposta = false while (not boaResposta) puts 'Voc faz xixi na cama?' resposta = gets.chomp.downcase if (resposta == 'sim' or resposta == 'no') boaResposta = true if resposta == 'sim' molhaCama = true else molhaCama = false end else puts 'Por favor, responda com "sim" ou "no".' end end boaResposta = false while (not boaResposta) puts 'Voc gosta de comer chimichangas?'

resposta = gets.chomp.downcase if (resposta == 'sim' or resposta == 'no') boaResposta = true else puts 'Por favor, responda com "sim" ou "no".' end end puts 'Apenas mais algumas perguntas...' boaResposta = false while (not boaResposta) puts 'Voc gosta de comer sopapillas?' resposta = gets.chomp.downcase if (resposta == 'sim' or resposta == 'no') boaResposta = true else puts 'Por favor, responda com "sim" ou "no".' end end # # Faa mais um monte de perguntas sobre comida mexicana. 'QUESTIONRIO:' 'Obrigado por dispender seu tempo ao nos ajudar' 'com nossa pesquisa. Na verdade, essa pesquisa' 'no tem nada a ver com comida mexicana.' 'Mas uma pesquisa sobre quem molha a cama.' 'As comidas mexicanas estavam l apenas para' 'baixar sua guarda na esperana de fazer voc' 'responder mais honestamente. Obrigado novamente.' molhaCama

puts puts puts puts puts puts puts puts puts puts puts

Ol, e obrigado pelo seu tempo para me ajudar com essa pesquisa. Minha pesquisa sobre como as pessoas se sentem com comida mexicana. Apenas pense sobre comida mexicana e tente responder, honestamente, cada questo com "sim" ou "no". Minha pesquisa no tem nada a ver com quem molha a cama. Voc gosta de comer tacos?

sim
Voc gosta de comer burritos?

sim
Voc faz xixi na cama?

de jeito nenhum!
Por favor, responda com "sim" ou "no". Voc faz xixi na cama?

NO
Por favor, responda com "sim" ou "no". Voc faz xixi na cama?

sim
Voc gosta de comer chimichangas?

sim
Apenas mais algumas perguntas... Voc gosta de comer sopapillas?

sim
QUESTIONRIO: Obrigado por dispender seu tempo ao nos ajudar com nossa pesquisa. Na verdade, essa pesquisa no tem nada a ver com comida mexicana. Mas uma pesquisa sobre quem molha a cama. As comidas mexicanas estavam l apenas para baixar sua guarda na esperana de fazer voc responder mais honestamente. Obrigado novamente. true

Um programa lindo e longo, com um monte de repetio. (Todas as sees de cdigo que giram em torno de questes sobre comida mexicana so idnticas, e a questo sobre xixi na cama ligeiramente diferente.) Repetio uma coisa ruim. Mas ns no podemos fazer um grande iterador, porque algumas vezes ns queremos fazer alguma coisa entre as questes. Em situaes como essa, melhor escrever um mtodo. Veja como:
def digaMoo puts 'mooooooo...' end

Ahn... Nosso programa no disse mooooooo... . Por que no? Porque ns no o mandamos fazer isso. Ns apenas dissemos como fazer para dizer mooooooo... , mas ns nunca o mandamos fazer isso. Vamos l, outra tentativa:
def digaMoo puts 'mooooooo...' end digaMoo digaMoo puts 'coin-coin' digaMoo digaMoo

mooooooo... mooooooo... coin-coin mooooooo... mooooooo...

Ah! Muito melhor. (Para o caso de voc no falar francs, havia um pato francs no meio do programa. Na Frana, os patos fazem "coin-coin"). Ento, ns definimos o mtodo digaMoo (Nomes de mtodo, assim como nomes de variveis, comeam com uma letra minscula. H excees, como + ou ==). Mas mtodos no tm de sempre estar associados com objetos? Bem, sim, eles tm. E nesse caso (assim como com o puts e o gets), o mtodo est associado apenas com o objeto representando o programa como um todo. No prximo captulo ns vamos ver como adicionar mtodos a outros objetos. Mas primeiro...

P A R ME T RO S

DE

M T O DO S

Voc deve ter notado que se podemos chamar alguns mtodos (como o gets, ou o to_s, ou o reverse...) apenas como um objeto. Porm, outros mtodos (como o +, o -, o puts...) recebem parmetros para dizer ao objeto o que fazer com o mtodo. Por exemplo, voc no diz apenas 5+, certo? Voc est dizendo ao 5 para adicionar, mas voc no est dizendo o que adicionar. Para adicionar um parmetro ao digaMoo (o nmero de mugidos, por exemplo), ns podemos fazer o seguinte:
def digaMoo numeroDeMoos puts 'mooooooo...'*numeroDeMoos end digaMoo 3 puts 'oink-oink' digaMoo # Isso vai dar erro porque no foi passado nenhum parmetro.

mooooooo...mooooooo...mooooooo... i k i k

oink-oink #<ArgumentError: wrong number of arguments (0 for 1)>

numeroDeMoos uma varivel que aponta para o parmetro que foi passado. Vou dizer mais uma vez, mas um pouco confuso: numeroDeMoos uma varivel que aponta para o parmetro que foi passado. Ento, se eu digitar digaMoo 3, o parmetro o 3, e a varivel numeroDeMoos aponta para 3. Como voc pode ver, agora o parmetro necessrio. Afinal, o que o digaMoo deve fazer multiplicar 'mooooooo' por um nmero. Mas por quanto, se voc no disse? Seu computador no tem a menor idia. Se compararmos os objetos em Ruby aos substantivos em portugus, os mtodos podem, da mesma forma, ser comparados aos verbos. Assim, voc pode imaginar os parmetros como advrbios (assim como em digaMoo, onde o parmetro nos diz como a digaMoo agir) ou algumas vezes como objetos diretos (como em puts, onde o parmetro o que o puts ir imprimir).

V A RI V E IS L O C A IS
No programa a seguir, h duas variveis:
def dobreEste num numVezes2 = num*2 puts 'O dobro de '+num.to_s+' '+numVezes2.to_s end dobreEste 44

O dobro de 44 88

As variveis so num e numVezes2. Ambas esto localizadas dentro do mtodo dobreEste. Estas (e todas as outras variveis que voc viu at agora) so variveis locais. Isso significa que elas vivem dentro do mtodo e no podem sair. Se voc tentar, voc ter um erro:
def dobreEste num numVezes2 = num*2 puts 'O dobro de '+num.to_s+' '+numVezes2.to_s end dobreEste 44 puts numVezes2.to_s

O dobro de 44 88 #<NameError: undefined local variable or method `numVezes2' for #<StringIO:0x7f1910512270>>

Varivel local no definida... Na verdade, ns definimos aquela varivel local, mas ela no local em relao ao local onde tentamos us-la; ela local ao mtodo. Isso pode parecer inconveniente, mas muito bom. Enquanto voc no tiver acesso a variveis de dentro dos mtodos, isso tambm quer dizer que ningum tem acesso s suas variveis, e isso quer dizer que ningum pode fazer algo como isso:
def pequenaPeste var var = nil puts 'HAHA! Eu acabei com a sua varivel!' end var = 'Voc no pode tocar na minha varivel!' pequenaPeste var puts var

HAHA! Eu acabei com a sua varivel! Voc no pode tocar na minha varivel!

H, atualmente, duas variveis naquele pequeno programa chamadas var: uma dentro do mtodo pequenaPeste e uma fora dele. Quando voc chamou pequenaPeste var, ns realmente passamos a string que estava em var para a outra, ento as mesmas estavam apontando para a mesma string. Ento, o mtodo pequenaPeste apontou a sua var local para nil, mas isso no fez nada com a var de fora do mtodo.

R E T O RNA NDO V A L O RE S
Voc deve ter notado que alguns mtodos devolvem alguma coisa quando voc os chama. Por exemplo, o mtodo gets retorna uma string (a string que voc digitou), e o mtodo + em 5+3, (que , na verdade 5.+(3)) retorna 8. Os mtodos aritmticos para nmeros retornam nmeros, e os mtodos aritmticos para strings retornam strings. importante entender a diferena entre mtodos retornando um valor para onde ele foi chamado, e o seu programa gerando uma sada para a sua tela, como o puts faz. Note que 5+3 retorna 8; ele no imprime 8 na tela. Ento, o que o puts retorna? Ns nunca nos importamos antes, mas vamos dar uma olhadinha agora:
valorRetorno = puts 'Este puts retornou:' puts valorRetorno

Este puts retornou: nil

O primeiro puts retornou nil. Apesar de no termos testado o segundo puts, ele fez a mesma coisa; puts sempre retorna um nil. Todo mtodo tem que retornar alguma coisa, mesmo que seja apenas um nil. Faa uma pausa e escreva um programa que encontre o que o mtodo digaMoo retornou. Voc est surpreso? Bem, as coisas funcionam assim: o valor de retorno de um mtodo simplesmente a ltima linha avaliada do mtodo. No caso do mtodo digaMoo, isso quer dizer que ele retornou 'puts mooooooo...'*numeroDeMoos, que um simples nil, j que puts sempre retorna um nil. Se ns quisermos que todos os nossos mtodos retornem a string 'yellow submarine', ns apenas temos que colocar ela no fim deles:
def digaMoo numeroDeMoos puts 'mooooooo...'*numeroDeMoos 'yellow submarine' end x = digaMoo 2 puts x

mooooooo...mooooooo... yellow submarine

Agora vamos tentar aquela pesquisa de psicologia de novo, mas desta vez vamos escrever um mtodo que faa a pergunta para ns. Ele vai precisar pegar a questo como um parmetro e retornar true se a resposta foi sim e false se a resposta foi no (Mesmo que ns ignoremos a resposta na maioria das vezes, uma boa idia fazer o mtodo retornar a resposta. Assim ns podemos usar isso para a questo sobre molhar a cama). Eu tambm vou dar uma resumida na saudao e no final, apenas para ficar mais fcil de ler:

def pergunte pergunta boaResposta = false while (not boaResposta) puts pergunta replica = gets.chomp.downcase if (replica == 'sim' or replica == 'no') boaResposta = true if replica == 'sim' resposta = true else resposta = false end else puts 'Por favor, responda com "sim" ou "no".' end end resposta # end isso o que ser retornado (true ou false).

puts 'Ol e obrigado por...' puts pergunte 'Voc gosta de comer tacos?' pergunte 'Voc gosta de comer burritos?' molhaCama = pergunte 'Voc faz xixi na cama?' pergunte 'Voc gosta de comer chimichangas?' pergunte 'Voc gosta de comer sopapillas?' pergunte 'Voc gosta de comer tamales?' puts 'Apenas mais algumas perguntas...' pergunte 'Voc gosta de beber horchata?' pergunte 'Voc gosta de comer flautas?' puts puts 'QUESTIONRIO:' puts 'Obrigado por...' puts puts molhaCama # # Ns ignoramos o valor de retorno desse mtodo. Ns salvamos o retorno desse.

Ol e obrigado por... Voc gosta de comer tacos?

sim
Voc gosta de comer burritos?

sim
Voc faz xixi na cama?

de jeito nenhum!
Por favor, responda com "sim" ou "no". Voc faz xixi na cama?

NO
Por favor, responda com "sim" ou "no". Voc faz xixi na cama?

sim
Voc gosta de comer chimichangas?

sim
Voc gosta de comer sopapillas?

sim
Voc gosta de comer tamales?

sim
Apenas mais algumas perguntas... Voc gosta de beber horchata?

sim
Voc gosta de comer flautas?

sim
QUESTIONRIO: Obrigado por... true

N d

l h i ? N

di i

di i

f il

Nada mal, hein? Ns podemos adicionar mais perguntas (e adicionar mais perguntas fcil agora), mas nosso programa continuar pequeno! Isso um grande progresso o sonho de todo programador preguioso.

M A IS

UM

G RA NDE E XE MP L O

Eu acho que outro exemplo de mtodo seria muito til aqui. Vamos chamar esse de numeroPortugues. Esse mtodo vai pegar um nmero, como o 22, e retorn-lo por extenso (nesse caso, a string vinte e dois). Por enquanto, vamos faz-lo trabalhar apenas com inteiros entre 0 e 100. (NOTA: Esse mtodo usa um novo truque para retornar a partir de um mtodo antes do fim usando a palavra-chave return, e introduz um novo conceito: elsif. Isso deve ficar mais claro no contexto, mostrando como as coisas funcionam).
def numeroPortugues numero # Ns apenas queremos nmeros entre 0 e 100. if numero < 0 return 'Por favor, entre com um nmero maior ou igual a zero.' end if numero > 100 return 'Por favor, entre com um nmero menor ou igual a 100.' end numExtenso = '' # Esta a string que vamos retornar.

# "falta" quanto do nmero ainda falta para escrevermos. # "escrevendo" a parte que estamos escrevendo agora. falta = numero escrevendo = falta/100 # Quantas centenas faltam escrever? falta = falta - escrevendo*100 # Subtraia essas centenas. if escrevendo > 0 return 'cem' end escrevendo = falta/10 falta = falta - escrevendo*10 # # Quantas dezenas faltam escrever? Subtraia essas dezenas.

if escrevendo > 0 if escrevendo == 1 # Oh-oh... # J que no podemos escrever "dez e dois", # vamos fazer algo especial aqui if falta == 0 numExtenso = numExtenso + 'dez' elsif falta == 1 numExtenso = numExtenso + 'onze' elsif falta == 2 numExtenso = numExtenso + 'doze' elsif falta == 3 numExtenso = numExtenso + 'treze' elsif falta == 4 numExtenso = numExtenso + 'catorze' elsif falta == 5 numExtenso = numExtenso + 'quinze' elsif falta == 6 numExtenso = numExtenso + 'dezesseis' elsif falta == 7 numExtenso = numExtenso + 'dezessete' elsif falta == 8 numExtenso = numExtenso + 'dezoito' elsif falta == 9 numExtenso = numExtenso + 'dezenove' end # J que j cuidamos das unidades, # no temos mais nada a escrever. falta = 0 elsif escrevendo == 2 numExtenso = numExtenso + 'vinte' elsif escrevendo == 3 numExtenso = numExtenso + 'trinta' elsif escrevendo == 4 numExtenso = numExtenso + 'quarenta' elsif escrevendo == 5

elsif escrevendo == 5 numExtenso = numExtenso elsif escrevendo == 6 numExtenso = numExtenso elsif escrevendo == 7 numExtenso = numExtenso elsif escrevendo == 8 numExtenso = numExtenso elsif escrevendo == 9 numExtenso = numExtenso end

+ 'cinqenta' + 'sessenta' + 'setenta' + 'oitenta' + 'noventa'

if falta > 0 numExtenso = numExtenso + ' e ' end end escrevendo = falta falta = 0 # # Quantos ainda faltam a escrever? Subtraia esses.

if escrevendo > 0 if escrevendo == 1 numExtenso = numExtenso elsif escrevendo == 2 numExtenso = numExtenso elsif escrevendo == 3 numExtenso = numExtenso elsif escrevendo == 4 numExtenso = numExtenso elsif escrevendo == 5 numExtenso = numExtenso elsif escrevendo == 6 numExtenso = numExtenso elsif escrevendo == 7 numExtenso = numExtenso elsif escrevendo == 8 numExtenso = numExtenso elsif escrevendo == 9 numExtenso = numExtenso end end

+ 'um' + 'dois' + 'trs' + 'quatro' + 'cinco' + 'seis' + 'sete' + 'oito' + 'nove'

if numExtenso == '' # A nica forma de "numExtenso" estar vazia # se o "numero" for 0 return 'zero' end # Se chemagmos aqui, ento temos um # nmero entre 0 e 100, ento precisamos # apenas retornar o "numExtenso" numExtenso end puts puts puts puts puts puts puts puts puts numeroPortugues( 0) numeroPortugues( 9) numeroPortugues( 10) numeroPortugues( 11) numeroPortugues( 17) numeroPortugues( 32) numeroPortugues( 88) numeroPortugues( 99) numeroPortugues(100)

zero nove dez onze dezessete trinta e dois oitenta e oito noventa e nove cem

Bem ainda h algumas coisas nesse programa que eu no gostei Primeiro: h muita repetio

Bem, ainda h algumas coisas nesse programa que eu no gostei. Primeiro: h muita repetio. Segundo: esse programa no consegue lidar com nmeros maiores do que 100. Terceiro: h muitos casos especiais, muitos retornos (return). Vamos usar alguns vetores e tentar dar uma limpada:
def numeroPortugues numero if numero < 0 # Nada de nmeros negativos. return 'Por favor, digite um nmero positivo.' end if numero == 0 return 'zero' end # Nada de casos especiais! Nada de retornos! # Esta a string que vamos retornar.

numExtenso = '' unidades dezenas especiais =

= ['um' , 'dois', 'tres', 'quatro', 'cinco', 'seis', 'sete', 'oito', 'nove'] = ['dez' , 'vinte' , 'trinta' , 'quarenta', 'cinqenta', 'sessenta', 'sessenta', 'oitenta', 'noventa'] ['onze' , 'doze' , 'treze' , 'catorze', 'quinze', 'dezesseis', 'dezesete', 'dezoito', 'dezenove']

# "falta" quanto do nmero ainda falta escrever. # "escrevendo" a parte que estamos escrevendo agora. falta = numero escrevendo = falta/100 # Quantas centenas ainda faltam escrever? falta = falta - escrevendo*100 # Subtraia essas centenas. if escrevendo > 0 # Aqui est o truque sujo: centenas = numeroPortugues escrevendo numExtenso = numExtenso + centenas + ' centos' # Isso chamado "recurso". O que ns fizemos? # Eu disse para o mtodo chamar a si mesmo, mas # passando "escrevendo" como parmetro, ao invs # de "numero". Lembre-se de que "escrevendo" # (agora) o nmero de dezenas que ns estamos escrevendo. # Depois de adicionarmos as "centenas" a "numExtenso", # ns adicionamos a string " centos". Ento, se ns # chamamos numeroPortugues com 1999 (numero = 1999), # agora escrevendo ser 19, e "falta" deve ser 99. # A coisa mais preguiosa que fazemos aqui # mandar o mtodo numeroPortugues escrever o nmero # 19 por extenso, e ento adicionando "centos" ao # fim e escrevendo "noventa e nove" ao que falta. # Ficando, portanto, "dezenove centos e noventa e nove". if falta > 0 # Ns no escrevemos dois centosecinqenta e um'... numExtenso = numExtenso + ' e ' end end escrevendo = falta/10 falta = falta - escrevendo*10 # # Quantas dezenas faltam escrever? Subtraia dessas dezenas.

if escrevendo > 0 if ((escrevendo == 1) and (falta > 0)) # No podemos escrever "dez e dois", temos que escrever "doze", # ento vamos fazer uma exceo. numExtenso = numExtenso + especiais[falta-1] # O "-1" aqui porque especiais[3] 'catorze', e no 'treze'. # J que cuidamos do dgito das unidades, # no falta mais nada falta = 0 else numExtenso = numExtenso + dezenas[escrevendo-1] # E o "-1" aqui porque dezenas[3] 'quarenta', e no 'trinta'. end if falta > 0 # Como ns no escrevemos "sessentaequatro"... numExtenso = numExtenso + ' e ' end end

end escrevendo = falta falta = 0 # # Quantas unidades faltam ser escritas? Subtraia elas.

if escrevendo > 0 numExtenso = numExtenso + unidades[escrevendo-1] # Novamente: O "-1" aqui porque unidades[3] 'quatro', e no 'trs'. end # Agora podemos, simplesmente, retornar o nosso "numExtenso"... numExtenso end puts puts puts puts puts puts puts puts puts puts puts puts puts puts numeroPortugues( 0) numeroPortugues( 9) numeroPortugues( 10) numeroPortugues( 11) numeroPortugues( 17) numeroPortugues( 32) numeroPortugues( 88) numeroPortugues( 99) numeroPortugues(100) numeroPortugues(101) numeroPortugues(234) numeroPortugues(3211) numeroPortugues(999999) numeroPortugues(1000000000000)

zero nove dez onze dezesete trinta e dois oitenta e oito noventa e nove um centos um centos e um dois centos e trinta e quatro trinta e dois centos e onze noventa e nove centos e noventa e nove centos e noventa e nove um centos centos centos centos centos centos

Ahhhh.... Agora est muito melhor. O programa est um pouco maante, mas porque eu enchi de comentrios. Agora ele funciona para nmeros grandes... embora no de uma maneira muito elegante. Por exemplo, eu acho que 'um trilho' seria muito mais elegante para o ltimo nmero, ou mesmo 'um milho milho' (muito embora todas as trs estejam corretas). Na verdade, voc pode fazer isso agora...

A L G U MA S C O IS INHA S

P A RA

T E NT A R

Melhore o mtodo numeroPortugues. Primeiro, coloque os milhares. Ou seja, ele deve retornar 'um mil' ao inves de 'dez centos' e 'dez mil' ao invs de 'um centos centos'. Seria interessante retornar 'cem', 'duzentos' e etc. ao invs de 'um centos', 'dois centos' e etc. (muito embora ambas as formas estejam corretas). Melhore o mtodo numeroPortugues um pouquinho mais. Coloque milhes agora, assim voc conseguir coisas como 'um milho' ao invs de 'um mil mil'. Depois tente adicionar bilhes e trilhes. Quo longe voc consegue ir? "Um elefante incomoda muita gente..." Usando o mtodo numeroPortugues, escreva esse clssico corretamente agora. Coloque seu computador de castigo: faa ele contar 9999 elefantes (No exagere nos elefantes, porm. Escrever todos esses elefantes na sua tela vai demorar um pouco. Se voc pensar em um milho de elefantes, voc vai acabar se colocando de castigo!). Parabns! Agora voc j um verdadeiro programador! Voc aprendeu tudo o que voc precisava para escrever grandes programas do zero Se voc tiver idias de programas que voc gostaria de escrever

escrever grandes programas do zero. Se voc tiver idias de programas que voc gostaria de escrever para voc mesmo, tente agora! Claro que escrever tudo do zero pode ser um processo muito lento. Por que gastar tempo e energia escrevendo um cdigo que algum j escreveu? Voc quer um programa que mande alguns e-mails? Voc gostaria de salvar e carregar arquivos em seu computador? Que tal gerar pginas da web para um tutorial onde os exemplos de cdigo sejam executados cada vez que a pgina carregada? :) Ruby tem muitos tipos diferentes de objetos que podemos usar para nos ajudar a escrever programas mais rapidamente.

2003-2011 Chris Pine

9. C LA S S ES
At agora, ns vimos muitos tipos diferentes de objetos, ou classes: strings, inteiros, ponto flutuante, vetores e alguns objetos especiais (true, false e nil), que vamos voltar a falar mais tarde. Em Ruby, todas essas classes sempre comeam com maisculas: String, Integer (Inteiros), Float (Ponto Flutuante), Array (Vetores) e etc. Geralmente, se queremos criar um novo objeto de uma certa classe, ns usamos o new:
a = Array.new + [12345] # Adio de Vetores. b = String.new + 'ol' # Adio com Strings. c = Time.new puts 'a = '+a.to_s puts 'b = '+b.to_s puts 'c = '+c.to_s

a = 12345 b = ol c = Fri Sep 30 19:31:06 -0700 2011

Como ns podemos criar vetores e strings usando [...] e '...', respectivamente, ns raramente usamos o new para isso (De qualquer forma, no est muito claro, no exemplo anterior, que String.new cria uma string vazia e que Array.new cria um vetor vazio). Nmeros, porm, so uma exceo: voc no pode criar um inteiro usando Integer.new. Voc apenas tem que digitar o nmero.

C LASSE

TIME

Est bem, e a classe Time? Objetos Time representam momentos de tempo. Voc pode adicionar (ou subtrair) nmeros para (ou de) tempos para conseguir novos instantes: adicionando 1.5 a um instante, retorna um novo instante de um segundo e meio depois:
tempo = Time.new tempo2 = tempo + 60 puts tempo puts tempo2 # # O instante em que voc carrega esta pgina. Um minuto depois.

Fri Sep 30 19:31:06 -0700 2011 Fri Sep 30 19:32:06 -0700 2011

Voc pode, tambm, fazer um tempo para um momento especfico usando Time.mktime:
puts Time.mktime(2000, 1, 1) puts Time.mktime(1976, 8, 3, 10, 11) # # Ano 2000. Ano em que nasci.

Sat Jan 01 00:00:00 -0800 2000 Tue Aug 03 10:11:00 -0700 1976

Nota: quando eu nasci, estava em uso o Horrio de Vero do Pacfico (PDT, em Ingls). Quanto o ano 2000 chegou, porm, estava em uso o Horrio Padro do Pacfico (PST, em Ingls), pelo menos para ns, da costa Oeste. Os parnteses servem para agrupar os parmetros para o mktime. Quanto mais parmetros voc adicionar, mais preciso o seu instante se tornar. Voc pode comparar dois tempos utilizando os mtodos de comparao (um tempo anterior menor que

A L G U MA S C O IS INHA S P A RA T E NT A R
Um bilho de segundos... Encontre o segundo exato do seu nascimento (se voc puder). Descubra quando voc far (ou quando voc fez?) um bilho de segundos de idade. Ento v marcar na sua folhinha. Feliz Aniversrio! Pergunte o ano de nascimento em que uma pessoa nasceu. Ento pergunte o ms e, finalmente, o dia. Ento descubra a idade dessa pessoa e lhe d um PUXO DE ORELHA! para cada aniverario que ela fez.

A C L A SSE HASH
Outra classe muito til a classe Hash. Hashes so muito parecidos com vetores: eles tm um monte de espaos que podem conter vrios objetos. Porm, em um vetor, os espaos so dispostos em uma linha, e cada um numerado (iniciando pelo zero). Em um Hash, porm, os espaos no esto dispostos em uma linha (eles esto apenas juntos), e voc pode usar qualquer objeto para se referir a um espao, no apenas um nmero. bom usar hashes quando voc tem uma poro de coisas que voc quer armazenar, mas que no tm, realmente, uma ordem. Por exemplo, as cores que eu uso em diversas partes desse tutorial:
colorArray = [] colorHash = {} # # o mesmo que Array.new o mesmo que Hash.new = = = = = = 'vermelho' 'verde' 'azul' 'vermelho' 'verde' 'azul'

colorArray[0] colorArray[1] colorArray[2] colorHash['strings'] colorHash['numbers'] colorHash['keywords']

colorArray.each do |color| puts color end colorHash.each do |codeType, color| puts codeType + ': ' + color end

vermelho verde azul strings: vermelho keywords: azul numbers: verde

Se eu usar um vetor, eu tenho que me lembrar que o espao 0 para strings, o slot 1 para nmeros e etc. Mas se eu usar um Hash, fica fcil! O espao 'strings' armazena a cor das strings, claro. Nada para lembrar. Voc deve ter notado que quando eu usei o each, os objetos no hash no vieram na mesma ordem que eu os coloquei (Pelo menos no quando eu escrevi isso. Talvez agora esteja em ordem... voc nunca sabe a ordem com os hashes). Vetores servem para colocar as coisas em ordem, os Hashes no. Apesar das pessosas normalmente usarem strings para nomear os espaos em um hash, voc pode

usar qualquer tipo de objeto, at mesmo vetores e outros hashes (apesar de eu no conseguir achar uma razo para voc fazer isso...):
hashBizarro = Hash.new hashBizarro[12] = 'macacos' hashBizarro[[]] = 'totalmente vazio' hashBizarro[Time.new] = 'nada melhor que o Presente'

Hashes e vetores so bons para coisas diferentes: a escolha sobre qual resolve o seu problema melhor sua, e diferente para todos os problemas que voc tiver.

E XP A NDINDO C L A S S E S
No fim do ltimo captulo, voc escreveu um mtodo para retornar um nmero por extenso. Porm, esse no era um mtodo de inteiros: era um mtodo genrico do programa. No seria mais legal se voc pudesse escrever 22.ext ao invs de porExtenso 22? Olha s como voc pode fazer isso:
class Integer def ext if self == 5 porExtenso = 'cinco' else porExtenso = 'cinqenta e oito' end porExtenso end end # Eu prefiro testar sempre em duplas... puts 5.ext puts 58.ext

cinco cinqenta e oito

Bem, eu testei; e nada explodiu. :) Ns definimos um mtodo inteiro apenas "pulando" dentro da classe Integer, definindo o mtodo l dentro e caindo fora. Agora todos os inteiros tem esse sensacional (incompleto) mtodo. Na verdade, se voc no gostar da forma como o mtodo nativo to_s faz as coisas, voc pode simplesmente redefini-lo da mesma forma... mas eu no recomendo isso! melhor deixar os mtodos antigos quietos em seu canto e fazer novos quando voc precisar de uma coisa nova. Confuso ainda? Deixe-me voltar at o ltimo programa mais um pouco. At agora, quando ns executamos qualquer cdigo ou definido um mtodo, ns o fizemos no objeto "programa" padro. No nosso ltimo programa, ns samos daquele objeto pela primeira vez e fomos para dentro da classe Integer. Ns definimos um mtodo l (o que o tornou um mtodo inteiro) e todos os inteiros podem usar ele. Dentro daquele mtodos, ns usamos o self para nos referir ao objeto (o inteiro) que estiver usando o mtodo.

C RIA NDO C L A S S E S
Ns j vimos um monte de objetos de classes diferentes. Porm, fcil criar tipos de objeto que o Ruby no tenha. Por sorte, criar uma classe nova to fcil como expandir uma classe j existente. Vamos supor que eu queira rodar alguns dados no Ruby. Olhe como podemos fazer uma classe chamada Dado:

class Dado def rolar 1 + rand(6) end end # Vamos fazer dois dados... dados = [Dado.new, Dado.new] # ...e rolar cada um deles. dados.each do |dado| puts dado.rolar end

5 3

(Se voc pulou a parte que falava sobre nmeros aleatrios, rand(6) apenas devolve um nmero aleatrio entre 0 e 5). S isso! Objetos de nossa prpria autoria. Role os dados algumas vezes (utilizando o boto de "Atualizar" do seu navegador) e veja o que acontece. Ns podemos definir todo o tipo de mtodos para os nossos objetos... mas tem alguma coisa errada. Trabalhando com esses objetos no mudou grande coisa desde que aprendemos a mexer com variveis. Olhe o nosso dado, por exemplo. Cada vez que rolamos ele, ns temos um nmero diferente. Mas se ns quisermos salvar aquele nmero, ns temos que criar uma varivel e apontar para aquele nmero. E qualquer dado que preste deve ter um nmero, e rolando o dado deve mudar o nmero. Se ns armazenarmos o dado, ns no temos como saber qual nmero ele est mostrando. Porm, se ns tentarmos armazenar o nmero que ns tirmaos no dado em uma varivel (local) dentro de rolar, o valor ser perdido assim que o rolar acabar. Ns precisamos salvar esse nmero em um tipo diferente de varivel:

V A RI V E IS

DE

I NS T NC IA

Normalmente quando falamos sobre strings, ns apenas nos referimos a elas como strings. Porm, ns poderamos cham-las de Objetos do tipo String. Algumas vezes, alguns programadores podem chamlas de instncias da classe String, mas essa uma forma exagerada (e muito longa) de dizer string. Uma instncia de uma classe apenas um objeto daquela classe. Portanto, variveis de instncia so como variveis de objeto. Uma varivel local de um mtodo ficam vivas at que o mtodo termine. Uma varivel de instncia de um objeto, por outro lado, ficar viva enquanto o objeto estiver vivo. Para diferenciar variveis de instncia de variveis locais, elas tm uma @ na frente dos seus nomes:
class Dado def rolar @numeroMostrado = 1 + rand(6) end def mostrado @numeroMostrado end end dado = Dado.new dado.rolar puts dado.mostrado puts dado.mostrado dado.rolar t d d t d

puts dado.mostrado puts dado.mostrado

6 6 3 3

Muito legal! Agora o rolar rola o dado e o mostrado nos diz qual o nmero que saiu. Mas e se quisermos ver qual nmero saiu antes de rolar o dado (antes de termos definido @numeroMostrado)?
class Dado def rolar @numeroMostrado = 1 + rand(6) end def mostrado @numeroMostrado end end # J que eu no vou mais usar esse dado, # eu no preciso salv-lo em uma varivel. puts Dado.new.mostrado

nil

Hum... Bem, pelo menos no deu erro. Espera a, no faz muito sentido um dado "no-rolado" ou o que quer que nil signifique aqui. Seria muito mais bacana se ns pudessemos rolar o dado assim que ele for criado. isso que o initialize faz:
class Dado def initialize # Eu vou apenas rolar o dado, apesar de # podermos fazer qualquer coisa que # queiramos fazer, como colocar a face '6' # para cima rolar end def rolar @numeroMostrado = 1 + rand(6) end def mostrado @numeroMostrado end end puts Dado.new.mostrado

Quando um objeto criado, o mtodo initialize (se foi definido) sempre chamado. Nosso dado est quase perfeito. A nica coisa que falta uma maneira de arrumar qual nmero est sendo mostrado... Por que voc no escreve o mtodo trapaca que faa isso? Volte quando tiver terminado (e quando voc testar e funcionar, lgico). Apenas tenha certeza de que ningum pode fazer com o que o dado mostre um 7! F i it l l fi t M f i b i d i i D i

Foi muito legal o que fizemos at agora. Mas foi apenas uma brincadeira, mesmo assim. Deixe-me mostrar um exemplo mais interessante. Vamos fazer um bichinho virtual, um drago beb. Assim como todos os bebs, ele deve conseguir comer, dormir e "atender natureza", o que significa que vamos ter que ter como aliment-lo, coloc-lo pra dormir e levar ele at o quintal. Internamente, o nosso drago precisa saber se est com fome, cansado ou se precisa ir l fora, mas ns no poderemos ver isso enquanto estivermos interagindo com ele, assim como voc no pode perguntar a um beb "voc est com fome?". Ento ns vamos adicionar algumas maneiras legais para interagir com nosso drago beb, e quando ele nascer ns vamos dar um nome para ele (Qualquer coisa que voc passe como parmetro para o mtodo new ser passado para o mtodo initialize para voc). Certo, vamos tentar:
class Dragao def initialize nome @nome = nome @dormindo = false @comidaEstomago = 10 # @comidaIntestino = 0 # puts @nome + ' nasceu.' end def alimentar puts 'Voc alimentou o ' + @nome + '.' @comidaEstomago = 10 passagemDeTempo end def quintal puts 'Voc levou o ' + @nome + ' at o quintal.' @comidaIntestino = 0 passagemDeTempo end def colocarNaCama puts 'Voc colocou o ' + @nome + ' na cama.' @dormindo = true 3.times do if @dormindo passagemDeTempo end if @dormindo puts @nome + ' est roncando e enchendo o quarto de fumaa.' end end if @dormindo @dormindo = false puts @nome + ' est acordando.' end end def jogar puts 'Voc joga o ' + @nome + ' no ar.' puts 'Ele d uma risadinha e queima suas sobrancelhas.' passagemDeTempo end def balancar puts 'Voc balana o ' + @nome + ' gentilmente.' @dormindo = true puts 'Ele comea a cochilar...' passagemDeTempo if @dormindo @dormindo = false puts '...mas acorda quando voc pra.' end end private # # # # "private" significa que os mtodos definidos aqui so mtodos internos do objeto. (Voc pode aliment-lo, mas voc no pode perguntar se ele est com fome.)

Ele est cheio Ele no precisa ir ao quintal

def comFome?

def comFome? # Nomes de mtodos podem acabar com "?". # Normalmente, ns fazemos isso apenas # se o mtodos retorna verdadeiro ou falso, # como esse: @comidaEstomago <= 2 end def precisaSair? @comidaIntestino >= 8 end def passagemDeTempo if @comidaEstomago > 0 # Mover a comida do estmago para o intestino. @comidaEstomago = @comidaEstomago - 1 @comidaIntestino = @comidaIntestino + 1 else # Nosso drago est faminto! if @dormindo @dormindo = false puts 'Ele est acordando!' end puts @nome + ' est faminto! Em desespero, ele comeu VOC!' exit # Isso sai do programa. end if @comidaIntestino >= 10 @comidaIntestino = 0 puts 'Ops! ' + @nome + ' teve um acidente...' end if comFome? if @dormindo @dormindo = false puts 'Ele est acordando!' end puts 'O estmago do ' + @nome + ' est roncando...' end if precisaSair? if @dormindo @dormindo = false puts 'Ele est acordando!' end puts @nome + ' faz a dana para ir ao quintal...' end end end bichinho = Dragao.new 'Norbert' bichinho.alimentar bichinho.jogar bichinho.quintal bichinho.colocarNaCama bichinho.balancar bichinho.colocarNaCama bichinho.colocarNaCama bichinho.colocarNaCama bichinho.colocarNaCama

UAU! Claro que seria muito mais legal se esse fosse um programa interativo, mas voc pode fazer essa parte depois. Eu apenas estava tentando mostrar as partes relacionadas diretamente a criar uma nova classe do tipo Drago. Ns dissemos um monte de coisas novas nesse exemplo. A primeira simples: exit termina o programa onde estiver. A segunda a palavra private, que ns colocamos bem no meio da nossa classe. Eu podia ter deixado ela de fora, mas eu apenas quis reforar a idia de que certos mtodos voc podia fazer com um drago, enquanto que outros aconteciam com o drago. Voc pode pensar nisso como "coisas por trs dos panos": a no ser que voc seja um mecnico de automveis, tudo o que voc precisa saber sobre carros o acelerador, o freio e a direo. Um programador chama isso de interface pblica

interface pblica Agora, para um exemplo mais concreto nessa linha de raciocnio, vamos falar um pouco sobre como voc representaria um carro em um jogo (o que a minha linha de trabalho). Primeiro, voc precisa decidir como ir se parecer sua interface pblica; em outras palavras, quais mtodos as pessoas podem chamar do seus objetos do tipo carro? Bem, eles devem podem acelerar e freiar, mas eles precisam, tambm, poder definir a fora que esto aplicando no pedal (H uma grande diferena entre tocar o acelerador e afundar o p). Eles vo precisar tambm guiar, e novamente, e dizer que fora esto aplicando na direo. Eu acho que voc pode ir ainda mais longe e adicionar uma embreagem, piscas, lanador de foguetes, incinerador traseiro, um condensador de fluxo e etc... depende do tipo de jogo que voc est fazendo. Os objetos internos a um carro, porm, so mais complexos: outras coisas que um carro precisa so a velocidade, a direo e a posio (ficando no bsico). Esses atributos sero modificados pressionando o pedal do acelerador ou o de freio e girando o volante, claro, mas o usurio no deve poder alterar essas informaes diretamente (o que seria uma distoro). Voc pode querer checar a derrapagem ou o dano, a resistncia do ar e por a vai. Tudo isso diz respeito apenas ao carro. Tudo isso interno ao carro.

A L G U MA S C O IS INHA S P A RA T E NT A R
Faa uma classe de ArvoreDeLaranja. Ela deve ter um mtodo altura que retorne sua altura, um mtodo chamado passar_um_ano que, quando chamado, faz a rvore completar mais um ano de vida. Cada ano, a rvore cresce mais magra (no importa o quo grande voc ache que uma rvore de laranja possa crescer em um ano), e depois de alguns anos (novamente, voc faz as chamadas) a rvore deve morrer. Nos primeiros anos, ela no deve produzir frutos, mas depois de um tempo ela deve, e eu acho que as rvores mais velhas produzem muito mais frutos do que uma mais jovem com o passar dos anos... ou o que voc achar mais lgico. E, claro, voc deve poder contar_as_laranjas (o nmero de laranjas na rvore), e pegar_uma_laranja (que ir reduzir o @numero_de_laranjas em um e retornar uma string dizendo quo deliciosa a laranja estava, ou ento ir dizer que no h mais laranjas esse ano). Lembre-se de que as laranjas que voc no pegar esse ano devem cair antes do prximo ano. Escreva um programa para que voc possa interagir com o seu filhote de drago. Voc deve ser capaz de inserir comandos como alimentar e quintal , e esses mtodos devem ser chamados no seu drago. Logicamente que, como toda a entrada ser por strings, voc deve ter uma forma de repassar os mtodos, onde seu programa deve validar a string digitada e chamar o mtodo apropriado. E isso tudo! Mas espere um pouco... Eu no disse nada a voc sobre classes para fazer coisas como mandar um e-mail, ou salvar e carregar arquivos do seu computador, ou como criar janelas e botes, ou mundos em 3D ou qualquer coisa! Bem, h apenas muitas classes que voc pode usar, e isso torna impossvel que eu mostre todas para voc; mesmo eu no conheo todas elas. O que eu posso dizer para voc onde encontrar mais sobre elas, assim voc pode aprender mais sobre as que voc quiser usar. Mas antes de mandar voc embora, h mais um recurso do Ruby que voc deveria saber, algo que a maioria das outras linguagens no tem, mas que eu simplesmente no posso viver sem: blocos e procs.

2003-2011 Chris Pine

10. B LOCOS

P R OCS

Este , definitivamente, um dos recursos mais legais de Ruby. Algumas outras linguagens tm esse recurso, porm elas podem chamar isso de formas diferentes (como closures), mas muitas das mais populares no, o que uma pena. Ento o que essa nova coisa legal? a habilidade de pegar um bloco de cdigo (cdigo entre do e end), amarrar tudo em um objeto (chamado de proc), armazenar isso em uma varivel e passar isso para um mtodo, e rodar o cdigo do bloco quando voc quiser (mais de uma vez, se voc quiser). Ento, como se fosse um mtodo, exceto pelo fato de que isso no est em um objeto (isso um objeto), e voc pode armazen-lo ou pass-lo adiante, como com qualquer outro objeto. Acho que hora de um exemplo:
saudacao = Proc.new do puts 'Ol!' end saudacao.call saudacao.call saudacao.call

Ol! Ol! Ol!

Eu criei uma proc (eu acho que abreviatura para "procedimento", mas o que importa que rima com "block") que tem um bloco de cdigo, ento eu chamei (call) a proc trs vezes. Como voc pode ver, parece, em muito, com um mtodo. Atualmente, muito mais parecido com um mtodo do que eu mostrei para voc, porque blocos podem receber parmetros:
VoceGostade = Proc.new do |umaBoaCoisa| puts 'Eu *realmente* gosto de '+umaBoaCoisa+'!' end VoceGostade.call 'chocolate' VoceGostade.call 'ruby'

Eu *realmente* gosto de chocolate! Eu *realmente* gosto de ruby!

Certo, ento ns vimos o que blocos e procs so e como os usar, mas e da? Por que no usar apenas mtodos? Bem, isso porque existem algumas coisas que voc no pode fazer com mtodos. Particularmente, voc no pode passar mtodos para outros mtodos (mas voc pode passar procs para mtodos), e mtodos no podem retornar outros mtodos (mas podem retornar procs). apenas por isso que procs so objetos; mtodos no. (De qualquer forma, isso parece familiar? Sim, voc j viu blocos antes... quando voc aprendeu sobre iteradores. Mas vamos voltar a falar disso daqui a pouco.)

M T O DO S

QUE

R E C E BE M P RO C S

Quando passamos uma proc em um mtodo, ns podemos controlar como, se ou quantas vezes ns vamos chamar a proc. Por exemplo, posso dizer que h uma coisa que ns queremos fazer antes e depois que um cdigo executado:
def FacaUmaCoisaImportante umaProc puts 'Todo mundo apenas ESPERE! Eu tenho uma coisa a fazer...' umaProc.call puts 'Certo pessoal, Eu terminei. Voltem a fazer o que estavam fazendo.' end digaOla = Proc.new do puts 'ol' end digaTchau = Proc.new do puts 'tchau' end FacaUmaCoisaImportante digaOla FacaUmaCoisaImportante digaTchau

Todo mundo apenas ol Certo pessoal, Eu Todo mundo apenas tchau Certo pessoal, Eu

ESPERE! Eu tenho uma coisa a fazer... terminei. Voltem a fazer o que estavam fazendo. ESPERE! Eu tenho uma coisa a fazer... terminei. Voltem a fazer o que estavam fazendo.

Talvez isso no parea to fabuloso... mas . :-) muito comum em programao que alguns requesitos crticos sejam executados. Se voc grava um arquivo, por exemplo, voc deve abrir o arquivo, escrever o que quiser l dentro e ento fechar o arquivo. Se voc se esquecer de fechar o arquivo, Coisas Ruins(tm) podem acontecer. Mas toda a vez que voc quiser salvar ou carregar um arquivo, voc deve fazer a mesma coisa: abrir o arquivo, fazer o que voc realmente quiser com ele e ento fechar o arquivo. Isso entediante e fcil de esquecer. Em Ruby, salvar (ou carregar) arquivos funciona similarmente com o cdigo anterior, ento voc no precisa se preocupar com nada alm de o que voc quer salvar (ou carregar) (No prximo captulo eu vou lhe mostrar como fazer coisas como salvar e carregar arquivos). Voc pode tambm escrever mtodos que vo determinar quantas vezes, ou mesmo se uma proc ser chamada. Aqui est um mtodo que ir chamar uma proc metade do tempo, e outra que ir chamar a proc duas vezes.
def talvezFaca umaProc if rand(2) == 0 umaProc.call end end def FacaDuasVezes umaProc umaProc.call umaProc.call end piscar = Proc.new do puts '<piscada>' end olhandofixamente = Proc.new do puts '<olhando fixamente>' end talvezFaca piscar talvezFaca olhandofixamente FacaDuasVezes piscar FacaDuasVezes olhandofixamente

<piscada> <olhando fixamente> <piscada> <piscada> <olhando fixamente> <olhando fixamente>

(Se voc recarregar essa pgina algumas vezes, voc ver que a sada muda) Esses so alguns dos usos mais comuns de procs, que nos possibilita fazer coisas que ns simplesmente no poderamos fazer usando apenas mtodos. Claro, voc pode escrever um mtodo que "pisque" duas vezes, mas voc no pode escrever um que apenas faa qualquer coisa duas vezes! Antes de seguirmos adiante, vamos olhar um ltimo exemplo. At agora, as procs que ns usamos foram muito similares umas s outras. Agora, elas sero um pouco diferentes, assim voc poder ver como um mtodo depende das procs que lhe so passadas. Nosso mtodo ir receber um objeto e uma proc e ir chamar essa proc naquele objeto. Se a proc retornar falso, ns samos; caso contrrio, ns chamamos a proc com o objeto retornado. Ns vamos continuar fazendo isso at que a proc retorne falso (o que o melhor a fazer eventualmente, ou o program ir travar). O mtodo ir retornar o ltimo valor no falso retornado pela proc.
def facaAteFalso primeiraEntrada, umaProc entrada = primeiraEntrada saida = primeiraEntrada while saida entrada = saida saida = umaProc.call entrada end entrada end construindoVetorDeQuadrados = Proc.new do |vetor| ultimoNumero = vetor.last if ultimoNumero <= 0 false else vetor.pop # Jogue fora o ltimo nmero... vetor.push ultimoNumero*ultimoNumero # ... e o substitua com esse quadrado... vetor.push ultimoNumero-1 # ... seguido pelo nmero imediatamente anterior. end end sempreFalso = Proc.new do |apenasIgnoreme| false end puts facaAteFalso([5], construindoVetorDeQuadrados).inspect puts facaAteFalso('Estou escrevendo isso s 3:00; algum me derrube!', sempreFalso)

[25, 16, 9, 4, 1, 0] Estou escrevendo isso s 3:00; algum me derrube!

Certo, esse foi um exemplo estranho, eu admito. Mas isso mostra como nosso mtodo age diferentemente quando recebe diferentes procs. O mtodo inspect muito parecido com o to_s, exceto pelo fato de que a string retornada tenta mostrar para voc o cdigo em ruby que est construindo o objeto que voc passou. Aqui ele nos mostra todo o vetor retornado pela nossa primeira chamada a facaAteFalso. Voc tambm deve ter notado que ns nunca elevamos aquele 0 ao quadrado, no fim do vetor. J que 0 elevado ao quadrado continua apenas 0, ns no precisamos fazer isso. E j que sempreFalso foi, voc sabe, sempre falso, facaAteFalso no fez nada na segunda vez que a chamamos; apenas retornou o que lhe foi passada.

M T O DO S

QUE

R E T O RNA M P RO C S

Uma das outras coisas legais que voc pode fazer com procs cri-las em mtodos e retorn-las. Isso permite toda uma variedade de poderes de programao malucos (coisas com nomes impressionantes, como avaliao preguiosa, estrutura de dados infinita, e temperando com curry), mas o fato de que eu nunca fao isso na prtica e eu no me lembro de ter visto ningum fazendo isso. Eu acho que isso o tipo de coisa que voc acaba no fazendo em Ruby, ou talvez Ruby apenas encoraje-o a achar outras solues: eu no sei. De qualquer forma, eu vou tocar no assunto apenas brevemente. Nesse exemplo, compor recebe duas procs e retorna uma nova proc que, quando chamada, chama uma terceira proc e passa seu resultado para a segunda proc.
def compor proc1, proc2 Proc.new do |x| proc2.call(proc1.call(x)) end end quadrado = Proc.new do |x| x * x end dobre = Proc.new do |x| x + x end dobreeEleve = compor dobre, quadrado eleveeDobre = compor quadrado, dobre puts dobreeEleve.call(5) puts eleveeDobre.call(5)

100 50

Note que a chamada para proc1 deve ser inserida entre parenteses dentro de proc2, para que seja executada primeiro.

P A S S A NDO B L O C O S (E N O P RO C S )

P A RA

M T O DO S

Certo, isso foi muito interessante academicamente, mas de pouca utilidade prtica. Uma poro desse problema que h trs passos que voc deve seguir (definir o mtodo, construir a proc e chamar o mtodo com a proc), quando eles podem ser resumidos em apenas dois (definir o mtodo e passar o bloco diretamente ao mtodo, sem usar uma proc), uma vez que na maior parte das vezes voc no vai querer usar a proc ou o bloco depois que o passar para um mtodo. Bem, voc no sabe, mas Ruby tem isso para ns! Na verdade, voc j estava fazendo isso todas as vezes que usou iteradores. Eu vou mostrar a voc um exemplo rpido, ento ns vamos falar sobre isso.
class Array def cadaComparacao(&eraUmBloco_agoraUmaProc) eIgual = true # Ns comeamos com "verdadeiro" porque vetores comeam com 0, mesmo se iguais. self.each do |objeto| if eIgual eraUmBloco_agoraUmaProc.call objeto end eIgual = (not eIgual) end end end # Comutando entre igual para diferente, ou de diferente para igual.

['ma', 'ma podre', 'cereja', 'mamona'].cadaComparacao do |fruta| puts 'Hum! Eu adoro tortas de '+fruta+', voc no?' end # Lembre-se, ns estamos pegando os mesmos elementos numerados # do array, todos que se relacionam com os outros nmeros, # apenas porque gosto de causar esse tipo de problema. [1, 2, 3, 4, 5].cadaComparacao do |bola_estranha| puts bola_estranha.to_s+' no um nmero!' end

Hum! Eu Hum! Eu 1 no 3 no 5 no

adoro tortas de ma, voc no? adoro tortas de cereja, voc no? um nmero! um nmero! um nmero!

Para passar um bloco para cadaComparacao, tudo o que temos que fazer anexar o bloco aps o mtodo. Voc pode passar um bloco para qualquer mtodo dessa maneira, apesar de que muitos mtodos vo apenas ignorar o bloco. Para fazer seu mtodo no ignorar o bloco, mas peg-lo e transform-lo em uma proc, ponha o nome da proc no comeo da lista dos parmetros do seu mtodo, precedido por um 'e' comercial (&). Essa parte um pequeno truque, mas no to ruim, e voc apenas precisa fazer isso uma vez (quando voc define o mtodo). Ento voc pode usar o mtodo de novo, e de novo e de novo, assim como os mtodos da linguagem que aceitam blocos, como o each e o times (Lembra-se do 5.times do...?). Se voc estiver confuso, apenas lembre-se do que supostamente o mtodo cadaComparacao faz: chama o bloco passado como parmetro para cada elemento no vetor. Depois que voc o escrever e ele estiver funcionando, voc no vai precisar pensar sobre o que est acontecendo realmente por baixo dos panos ("qual bloco chamado quando??"); na verdade, exatamente por isso que escrevemos mtodos assim: ns nunca mais vamos precisar pensar sobre como eles funcionam novamente. Ns vamos apenas usar-los. Eu lembro que uma vez eu quis cronometrar quanto tempo cada seo do meu cdigo estava demorando (Isso algo conhecido como sumarizar o cdigo). Ento, eu escrevi um mtodo que pegava o tempo antes de executar o cdigo, o executava e ento fazia uma nova medio do tempo e me retornava a diferena. Eu no estou conseguindo achar o cdigo agora, mas eu no preciso disso: provavelmente um cdigo parecido com esse:
def sumario descricaoDoBloco, &bloco tempoInicial = Time.now bloco.call duracao = Time.now - tempoInicial puts descricaoDoBloco+': '+duracao.to_s+' segundos' end sumario 'dobrando 25000 vezes' do numero = 1 25000.times do numero = numero + numero end puts numero.to_s.length.to_s+' dgitos' end sumario 'contando at um milho' do numero = 0 1000000.times do numero = numero + 1 end end # isso mesmo: o nmero de dgitos nesse nmero ENORME.

7526 dgitos dobrando 25000 vezes: 0.135415 segundos contando at um milho: 0.160568 segundos

Que simplicidade! Que elegncia! Com aquele pequeno mtodo eu posso, agora, facilmente cronometrar qualquer seo, de qualquer programa, que eu queira, eu apenas preciso jogar o cdigo para um bloco e enviar ele para o sumario. O que poderia ser mais simples? Em muitas linguagens, eu teria que adicionar explicitamente o cdigo de cronometragem (tudo o que est em sumario) em volta de qualquer seo que eu queira medir. Em Ruby, porm, eu deixo tudo em um s lugar, e (o mais importante) fora do meu caminho!

A L G U MA S C O IS INHA S P A RA T E NT A R
Relgio Cuco. Escreva um mtodo que pegue um bloco e o chame de hora em hora. Assim, se eu passar o bloco do puts 'DONG!' end, ele deve tocar como um relgio cuco. Teste seu mtodo com diferentes blocos (inclusive o que eu mostrei para voc). Dica: Voc pode usar Time.now.hour para pegar a hora atual. Porm, isso retorna um nmero entre 0 e 23, ento voc deve alterar esses nmeros para os nmeros de um relgio normal, entre (1 e 12). Logger do programa. Escreva um mtodo chamado log, que pegue uma string como descrio de um bloco e, claro, um bloco. Similarmente ao FacaUmaCoisaImportante, essa deve retornar (puts) uma string dizendo que o bloco foi iniciado e outra string ao fim, dizendo que o fim da execuo do bloco, e tambm dizendo o que o bloco retornou. Teste seu mtodo enviando um bloco de cdigo. Dentro do bloco, coloque outra chamada para log, passando outro bloco para o mesmo (isto chamado de nesting). Em outras palavras, sua sada deve se parecer com isso:
Comeando "bloco externo"... Comeando "um bloco um pouco menor"... ..."um bloco um pouco menor" terminou retornando: 5 Comeando "um outro bloco"... ..."um outro bloco" terminou retornando: Eu gosto de comida tailandesa! ..."bloco externo" terminou retornando: false

Um Logger aperfeioado. A sada do ltimo logger muito difcil de ler, e fica muito pior a medida que voc for usando. Seria muito mais fcil de ler se voc identasse as linhas para os blocos internos. Para fazer isso, voc vai precisar saber quo profundamente aninhado voc est toda vez que for escrever algo no log. Para fazer isso, use uma varivel global, uma varivel que voc possa ver de qualquer lugar de seu cdigo. Para instnciar uma varivel global, voc deve preced-la com um $, assim: $global, $nestingDepth, e $bigTopPeeWee. Enfim, seu logger deve ter uma sada parecida com essa:
Comeando "bloco externo"... Comeando "um pequeno bloco"... Comeando "pequenino bloco"... ..."pequenino bloco" terminou retornando: muito amor ..."um pequeno bloco" terminou retornando: 42 Comeando "um outro bloco"... ..."um outro bloco" terminou retornando: Eu adoro comida indiana! ..."bloco externo" terminou retornando: true

Bem, isso tudo que voc aprendeu com esse tutorial. Parabns! Voc aprendeu muito. Talvez voc sinta como se no lembrasse de nada, ou talvez voc tenha pulado algumas partes... Relaxe. Programao no o que voc sabe, e sim o que voc faz. medida que voc for aprendendo onde procurar as coisas que voc esquecer, voc estar indo bem. Eu espero que voc no ache que eu escrevi tudo isso sem ficar conferindo a cada minuto! Porque eu fiz isso. Eu tambm tive muita ajuda com os cdigos que rodam em todos os exemplos desse tutorial. Mas onde eu estava pesquisando tudo e a quem eu estava pedindo ajuda? Deixe-me conhec-lo...

2003-2011 Chris Pine

11. A LM

D ES TE

T U TOR I A L

Ento, onde que podemos ir agora? Se voc tiver uma pergunta, para quem pode perguntar? E se voc quer que seu programa abra uma pgina da Web, envie um e-mail, ou redimensione uma foto digital? Pois bem, h muitos, muitos lugares onde encontrar ajuda para Ruby. Infelizmente, essa resposta no tem muita utilidade, no ? :-) Para mim, realmente existem apenas trs lugares onde procuro para ajuda para o Ruby. Se for uma pequena questo e eu acho que posso experimentar sozinho para encontrar a resposta, uso irb. Se for uma questo maior, procuro no meu Pickaxe. E se simplesmente no consigo dar conta do recado, ento peo ajuda na lista ruby-talk.

IRB: R U BY

INT E RA T IV O

Se voc instalou Ruby, ento voc instalou irb. Para us-lo, basta ir ao seu prompt de comando e digitar irb . Quando voc estiver em irb, voc pode digitar qualquer expresso ruby que voc queira, e ele devolver o valor da mesma. Digite 1 + 2 , e devolver 3 . (Note que voc no precisa usar puts). como uma espcie de calculadora Ruby gigante. Quando tiver concludo, digite simplesmente exit . H muito mais do que isso a respeito do irb, mas voc pode aprender tudo sobre ele no Pickaxe.

O P IC K A XE : "P RO G RA MMING R U BY "


O livro sobre Ruby que voc no pode perder de jeito nenhum "Programming Ruby, The Pragmatic Programmer's Guide", de Andrew Hunt e David Thomas (os Programadores Pragmticos). Embora eu recomende fortemente a 2 edio deste livro excelente, com a cobertura de todas as ltimas novidades do Ruby, voc tambm pode obter uma verso on-line grtis de pouco mais antiga (mas ainda relevante). (Na verdade, se voc instalou a verso do Ruby para Windows, voc j tem ela). Voc pode encontrar praticamente tudo sobre Ruby, do bsico ao avanado, neste livro. fcil de ler; abrangente; quase perfeito. Eu gostaria que todas as linguagens (de programao) tivessem um livro desse nvel. Na parte final do livro, voc encontrar uma enorme seo detalhando cada mtodo de cada classe, explicando-o e dando exemplos. Eu simplesmente amo este livro! H um sem nmero de lugares onde voc pode obt-lo (incluindo o prprio site do Pragmatic Programmers), mas o meu lugar favorito no ruby-doc.org. Esta verso tem um bom ndice , bem como um ndice remessivo (no ruby-doc.org tem muitas outras timas documentaes, tais como a API Central (Core API) e a Biblioteca Padro (Standard Library)... Basicamente, isso documenta tudo que vem com o Ruby. Verifique.). E por que chamado de "o Pickaxe" (picareta)? Pois bem, h uma imagem de uma picareta na capa do livro. um nome bobo, eu acho, mas pegou.

R U BY -T A L K :

U MA L IS T A DE DIS C U S S O S O BRE

R U BY

Mesmo com o irb e o Pickaxe, s vezes voc ainda pode no dar conta sozinho. Ou talvez voc queira saber se algum j fez o que voc est fazendo, para ver se voc pode utiliz-lo. Nestes casos, o melhor lugar ruby-talk, a lista de discusso do Ruby. cheia de gente amigvel, inteligente, colaborativa. Para

saber mais sobre ela, ou para se inscrever, procure aqui. ATENO: Existe um grande nmero de e-mails na lista todos os dias. Eu criei uma regra no meu cliente de e-mail para que no fique tudo na mesma pasta. Mas se voc no quiser ter que fazer isso, voc no precisa! A lista de discusso ruby-talk tem um espelho no grupo de notcias comp.lang.ruby, assim, voc pode ver as mensagens por l. Em suma, voc ver as mesmas mensagens, mas de uma maneira um pouco diferente.

T IM T O A DY
Tenho tentado proteger voc de algo com o que vai esbarrar em breve, o conceito de TMTOWTDI (pronunciado como "Tim Toady"): There's More Than One Way To Do It (H Mais De Uma Maneira Para Fazer Isso). Agora alguns vo lhe dizer que TMTOWTDI uma coisa maravilhosa, enquanto outros se sentem bastante diferente. Eu realmente no tenho fortes sentimentos sobre o assunto em geral, mas eu acho que uma pssima maneira de ensinar para algum como programar. (Como se aprender uma maneira de fazer alguma coisa no fosse suficientemente desafiante e confuso!). No entanto, agora que voc est indo alm deste tutorial, voc ver muito cdigo diversificado. Por exemplo, posso pensar em pelo menos cinco outras maneiras de criar uma string (alm de circundar algum texto com aspas simples), e cada um deles funciona de maneira um pouco diferente. Eu s lhe mostrei o mais simples dos seis. E quando conversamos sobre ramificaes, mostrei para voc if, mas no lhe mostrei unless. Eu vou deix-lo entender isso no irb. Outro agradvel atalho que voc pode usar com if, unless, while, a elegante verso de uma linha:
# Estas palavras so de um programa que escrevi para gerar # baboseiras em ingls. Bacana, no? puts 'grobably combergearl kitatently thememberate' if 5 == 2**2 + 1**1 puts 'enlestrationshifter supposine follutify blace' unless 'Chris'.length == 5

grobably combergearl kitatently thememberate

E, finalmente, h uma outra forma de escrever mtodos que recebem blocos (no procs). Vimos isso onde recebemos o bloco e o transformamos em uma proc usando o truque do &block na lista de parmetros quando se define a funo. Depois, para chamar o bloco, voc usa block.call. Pois bem, h um caminho mais curto (embora pessoalmente eu o julgue mais confuso). Em vez disto:
def facaDuasVezes(&bloco) bloco.call bloco.call end facaDuasVezes do puts 'murditivent flavitemphan siresent litics' end

murditivent flavitemphan siresent litics murditivent flavitemphan siresent litics

...voc faz isso:


def facaDuasVezes yield yield end

facaDuasVezes do puts 'buritiate mustripe lablic acticise' end

buritiate mustripe lablic acticise buritiate mustripe lablic acticise

No sei ... O que voc acha? Talvez seja eu, mas... yield?! Se fosse algo como chame_o_bloco_escondido (call_the_hidden_block) ou algo assim, faria muito mais sentido para mim. Muitas pessoas dizem que yield faz sentido para elas. Mas acho que esse o propsito de TMTOWTDI: elas fazem do jeito delas, e eu vou fazer minha maneira.

O F IM
Use-o para o bem e no para o mal. :-) E se voc achou este tutorial til (ou confuso, ou se voc encontrou um erro), me faa saber!

2003-2011 Chris Pine

Você também pode gostar