Você está na página 1de 69

Notas

sobre a traduo em

Portugus brasileiro

Todo comunidade de programao formada pelos amantes de computao, que aprendem linguagens novas no caf
da-manh, mas tambm uma uma grande parcela de pessoas que foram empolgadas por ns mas acabam esbarrando na
barreira inicial do aprendizado. Felizmente autores como Chris Pine resolveram atacar este desafio e o resultado que
temos uma excelente material para programadores iniciantes em Ruby.
Eu, Fabio akita, surgi com esta sugesto em Janeiro de 2008. Fiz o anncio no meu blog e na lista rails-br e foi um
movimento incrvei: dezenas de voluntrios se candidataram a ajudar. Graas a isso a traduo e reviso no durou uma
semana! Fico extremamente satisfeito em ter essa amostra da comunidade se auto-ajudando. Espero ter a oportunidade
de conduzir mais trabalhos desta natureza.
Meus agradecimentos e parabns aos tradutores/revisores: Danilo Sato, Davi Vidal, Reginaldo Russinholi, Oliver
Azevedo Barnes, Vitor Peres, Paulo Fernando Larini, Massimiliano Giroldi, Ricardo Yasuda, Lucas Hngaro,
Anderson Leite. Agradeo tambm a todos que se voluntariaram, mas havia mais colaboradores que captulos para
traduzir e sobrou gente :-) Acho que um bom sinal!
Agradecimentos tambm ao Jlio Santos Monteiro por dar uma "casa" oficial a este trabalho no web site
http://aprendaaprogramar.rubyonrails.com.br.
Esperamos que o resultado deste trabalho seja de grande valia tanto a estudantes quanto a qualquer um que queira
ensinar outros a programar.

um

lugar Para o Futuro Programador comear

Eu acho que tudo isso comeou em 2002. Eu estava pensando em ensinar programao, e como uma grande linguagem
como Ruby seria tima para aprender a como programar. Quer dizer, ns estvamos todos excitados com Ruby pelo seu
poder, elegncia e por ser realmente divertido, mas me pareceu que ele tambm seria um excelente guia para aprender a
programar.
Infelizmente, no havia muita documentao sobre Ruby destinada aos iniciantes naquela poca. Alguns de ns, na
comunidade, estvamos falando sobre como um tutorial "Ruby for the Nuby" era necessrio, e, mais genericamente, um
tutorial ensinando a programar, como um todo. Quanto mais eu pensava nisso, mais eu tinha a dizer (o que me
surpreendeu um pouco). At que algum finalmente disse: "Chris, porque voc no escreve um tutorial ao invs de ficar
falando sobre isso?". Ento eu o fiz.
E isso no foi muito bom. Eu tive todas essas boas idias que eram boas em teoria, mas a real tarefa de fazer um grande
tutorial para no-programadores foi muito mais desafiadora do que eu poderia prever. (Quer dizer, pareciam boas para
mim, mas eu j sabia como programar.)
O que me salvou foi que eu fiz com que fosse fcil para as pessoas falarem comigo, e eu sempre tentei ajudar as
pessoas quando elas empacavam. Quando eu via um monte de gente empacando em uma parte, eu a reescrevia. Isso deu
muito trabalho, mas lentamente foi se tornando melhor e melhor.
Alguns anos depois, isso estava ficando realmente bom. :-) To bom, na verdade, que eu j estava pronto para anunciar
sua finalizao e partir para outra coisa. E justamente nesse instante houve a oportunidade de transformar esse tutorial
em um livro. Uma vez que o bsico j estava pronto, eu achei que no haveria maiores problemas. Eu apenas precisaria

esclarecer umas coisas, adicionar alguns exerccios extras, talvez mais alguns exemplos, um pouquinho mais de
captulos, enviar ele para uns 50 revisores...
Isso me tomou outro ano, mas agora eu acho que est realmente muito bom, grande parte graas s centenas de boas
almas que me ajudaram a escrever este livro.
O que est nesse site o tutorial original, quase inalterado desde 2004. Para o melhor e mais atualizado, voc pode
querer dar uma olhada no livro.

Notas Para ProFessores


H algumas normas de conduta que eu tentei seguir. Eu acho que elas tornam o processo de aprendizado muito mais
suave; ensinar a programar j difcil por si s. Se voc est ensinando ou guiando algum pelas vias hackers, essas
idias podem lhe ajudar tambm.
Primeiramente, eu tentei separar os conceitos o mximo possvel, assim o estudante tem que aprender apenas um
conceito de cada vez. Isso foi difcil no comeo, mas um pouco mais fcil depois que eu peguei a prtica. Algumas
coisas devem ser faladas antes de outras, mas eu fiquei impressionado com quo pouca hierarquia de precedncia
realmente existe. Eventualmente, eu apenas tive que seguir uma ordem, e eu tentei arrumar as coisas de tal maneira que
cada nova seo fosse motivada pela anterior.
Outro princpio que eu tinha em mente era de ensinar apenas uma maneira de fazer alguma coisa. Isso um benefcio
bvio em um tutorial para pessoas que nunca programaram antes. Por um motivo: mais fcil aprender uma maneira de
fazer uma coisa do que duas. Porm o benefcio mais importante que quanto menos coisas voc ensinar a um novo
programador, mais criativo e esperto ele tem que ser na programao. J que muito da programao resoluo de
problemas, torna-se crucial o encorajamento em todos os estgios possveis.
Eu tentei traar um paralelo entre os conceitos de programao com os conceitos que um novo programador j possui;
para apresentar as idias de uma maneira que o entendimento seja intuitivo, ao invs do tutorial despejar apenas
informaes. Programao Orientada a Objetos faz isso, por si s, muito bem. Eu fui capaz de me referir a "objetos" e
diferentes "tipos de objetos" muito rapidamente nesse tutorial, soltando tais informaes nos mais inocentes momentos.
Eu no falei nada do tipo "tudo em Ruby um objeto" ou "nmeros e strings so tipos de objetos", porque essas coisas
no dizem nada para um novo programador. Ao invs disso, eu vou falar sobre strings (e no sobre "objetos do tipo
string"), e algumas vezes eu vou me referir a "objetos", apenas no sentido de "as coisas nesses programas". O fato de
que todas essas coisas em Ruby so objetos fez com que esse tipo de inconsistncia da minha parte funcionasse to
bem.
Sobretudo, eu procurei fugir do jargo desnecessrio da OO, eu procurei ter certeza de que, se eles tm de aprender uma
palavra, que aprendam a certa (Eu no quero que eles tenham de aprender em duplicidade, certo?). Ento, eu chamei
tudo de "strings", e no "texto". Mtodos precisam ser chamados de alguma coisa, ento eu os chamei de mtodos.
A medida que os exerccios foram sendo concebidos, eu achei que estava com bons exerccios, mas voc nunca pode
colocar exerccios demais. Honestamente, eu acho que eu gastei quase metade do meu tempo apenas tentando fazer
exerccios divertidos e interessantes. Exerccios entediantes apenas aniquilam qualquer desejo de programar, enquanto
que o exerccio perfeito cria aquela coceira no programador novo que ele no consegue ficar sem coar. Resumindo,
no gaste muito tempo tentando fazer exerccios bons.

sobre

tutorial origiNal

As pginas do tutorial (esta pgina, inclusive) so geradas por um grande programa em Ruby, claro. :-) Assim, elas
possuem recursos elegantes. Por exemplo, todos os exemplos de cdigo so realmente executados toda vez que voc v
a pgina, e a sada dos mesmos a sada que eles geram. Eu acredito que essa a maneira mais fcil, melhor e,
certamente, a mais legal de ter certeza que todo o cdigo mostrado funciona exatamente como eu digo que funciona.
Voc no precisa se preocupar com a possibilidade de eu ter copiado a sada de um exemplo erroneamente ou
esquecido de testar um cdigo: tudo testado na hora que voc v. Ento, na seo de geradores de nmeros aleatrios,
voc vai ver que os nmeros mudam sempre... lindo. (Eu usei um truque parecido na hora de escrever o livro, mas
bvio que isso muito mais aparente aqui no tutorial.)

sobre

material traduzido

O cdigo original descrito por Chris Pine acima, era uma verso simples e implementada sobre CGI. Em total ritmo de
2008, eu mesmo (Fabio Akita) modifiquei esse cdigo. Sem muitas modificaes sobre o original, transportei o cdigo
para rodar sobre Rails 2.0.2.
Esse cdigo est todo disponvel no GitHub, neste endereo:
https://github.com/jmonteiro/aprendaaprogramar
Por motivos de performance, os cdigos (que localmente so realmente executados em tempo real conforme Chris
explicou) no so executados online, sendo uma cpia esttica. Para ter todos os benefcios do programa em tempo real,
baixe o cdigo para rodar sobre Rails.

agradecimeNtos
Finalizando, eu gostaria de agradecer a todos da lista ruby-talk por suas idis e pelo encorajamento, aos meus
maravilhosos revisores, por sua ajuda em fazer o livro muito melhor do que eu poderia fazer sozinho, especialmente
minha querida esposa, por ser minha principal revisora/testadora/porquinho-da-ndia/musa, ao Matz, por ter criado essa
fabulosa linguagem, e aos Pragmatic Programmers, por me falar sobre a linguageme, claro, por publicar meu livro!
Se voc notar qualquer erro ou falha de digitao, se tiver qualquer comentrio ou sugesto, ou um bom exerccio que
eu possa incluir, por favor me avise (se voc falar ingls) ou, se preferir falar em portugus, avise o Jlio Monteiro.

a verso
melhorada
e s t e n d i d a

0.
1.
2.
3.
4.
5.
6.
7.
8.

Iniciando
Nmeros
Letras
Variveis e Atribuies
Misturando tudo
Mais Sobre Mtodos
Controle de Fluxo
Arrays e Iteradores
Escrevendo seus Prprios
Mtodos
9. Classes
10. Blocos e Procs
11. Alm deste Tutorial
(Verso Original por Chris Pine.)
(Verso Em Portugs
por Jlio Monteiro.)
(Traduo em Japons
por Shin Nishiyama.)
(Traduo em Francs
por Jean Pierre ANGHEL.)
(Traduo em Russo
por Mikhail Shokhirev.)
(Traduo em Dinamarqus
por Gunner Carstens.)
(Traduo em Bsnio

por
Rusmir
Gado.)

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.

Instalao

no

WIndoWs

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.

Instalao

para

MacIntosh

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.

Instalao

eM

lInux

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.

1. N m e r o s
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?

INtroduo

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

INteIro

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!

arItmtIca sImples
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

umas coIsINhas para teNtar


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 1232 milhes de segundos, qual minha idade em anos?

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

2. L e t r 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.

aritimtica

das

string

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 *
10
22222
2 * 5

5
5
5'

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

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

3. V a r i V e i s

atribuies

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!

4. M i s t u r a n d o

tudo

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.

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

uMa outra olhadela

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

os Mtodos

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

uMas Coisinhas Para tentar


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

5. M a i s s o b r e M t o d o s
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.

Mtodos elegantes

da

string

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

UMas Coisinhas Para tentar


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

MateMtiCa avanada
(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.

Mais aritiMtiCa
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 v-los 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

nMeros aleatrios
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))
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.533099438199271
0.692927743758217
0.940976910494312
35
25
43
0
0
0
43268570703742641064840128301077341089498686011220522458380
O homem do tempo disse que existe 42% 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 objeto MATH
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!

6. C o n t r o l e

de

Fluxo

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

Mtodos

de

CoMparao

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 menor-ou-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 compar-las.
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 M i F i C a e s (B r a n C h i n g )
"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 i n g )
Voc vai querer com alguma freqncia que o computador faa a mesma coisa vrias e vrias vezesafinal, 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 pouCo

de

lgiCa

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.

uMas Coisinhas para tentar


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

7. A r r A y s

IterAdores

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 coloc-las 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 Mtodo

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!

MAIs Mtodos

ArrAy

de

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 = []
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

AlguMAs CoIsAs

pArA

tentAr

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.

8. E s c r E v E n d o

sEus

PrPrios Mtodos

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.

puts
puts
puts
puts
puts
puts
puts
puts
puts
puts
puts

'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

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

ParMEtros

dE

Mtodos

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

varivEis Locais
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:0x10a01cec0>>

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.

rEtornando vaLorEs
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?'
mtodo.
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
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

Ns ignoramos o valor de retorno desse

Ns salvamos o retorno desse.

QUESTIONRIO:
Obrigado por...
true

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.

Mais

uM

GrandE ExEMPLo

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

+ 'vinte'
+ 'trinta'
+ 'quarenta'
+ '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. 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!

numExtenso = ''
unidades
dezenas
especiais =

Esta a string que vamos retornar.

= ['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
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...

aLGuMas coisinhas

Para

tEntar

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

9. C l a s s e s
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 Aug 28 11:24:25 -0300 2015

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.

Classe

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

#
#

O instante em que voc carrega esta pgina.


Um minuto depois.

puts tempo
puts tempo2
Fri Aug 28 11:24:25 -0300 2015
Fri Aug 28 11:25:25 -0300 2015

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)
Sat Jan 01 00:00:00 -0200 2000

#
#

Ano 2000.
Ano em que nasci.

Tue Aug 03 10:11:00 -0300 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

algumas Coisinhas Para TenTar


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

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

=
=
=
=
=
=

'vermelho'
'verde'
'azul'
'vermelho'
'verde'
'azul'

colorArray.each do |color|
puts color
end
colorHash.each do |codeType, color|
puts codeType + ': ' + color
end
vermelho
verde
azul
keywords: azul
numbers: verde
strings: vermelho

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.

exPandindo Classes
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.

Criando Classes

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
6
4

(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:

VariVeis

de

insTnCia

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 cham-las 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
puts dado.mostrado
puts dado.mostrado
6
6
4
4

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
4

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

ele est cheio


ele no precisa ir ao quintal

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

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
Norbert nasceu.
Voc alimentou o Norbert.
Voc joga o Norbert no ar.
ele d uma risadinha e queima suas sobrancelhas.
Voc levou o Norbert at o quintal.
Voc colocou o Norbert na cama.
Norbert est roncando e enchendo o quarto de fumaa.
Norbert est roncando e enchendo o quarto de fumaa.
Norbert est roncando e enchendo o quarto de fumaa.

Norbert est acordando.


Voc balana o Norbert gentilmente.
ele comea a cochilar...
...mas acorda quando voc pra.
Voc colocou o Norbert na cama.
ele est acordando!
O estmago do Norbert est roncando...
Voc colocou o Norbert na cama.
ele est acordando!
O estmago do Norbert est roncando...
Voc colocou o Norbert na cama.
ele est acordando!
O estmago do Norbert est roncando...
Norbert faz a dana para ir ao quintal...
Voc colocou o Norbert na cama.
ele est acordando!
Norbert est faminto! em desespero, ele comeu VOC!

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

algumas Coisinhas Para TenTar


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.

10. B l o c o s

Procs

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

Mtodos

que

receBeM Procs

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

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

Mtodos

que

retornaM Procs

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 n d o B l o c o s (e n o P r o c s )

Para

Mtodos

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)


igual.
end
end

# Comutando entre igual para diferente, ou de diferente para

end
['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'
nmero ENORME.
end
sumario 'contando at um milho' do

isso mesmo: o nmero de dgitos nesse

numero = 0
1000000.times do
numero = numero + 1
end
end
7526 dgitos
dobrando 25000 vezes: 0.079249 segundos
contando at um milho: 0.134337 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!

alguMas coisinhas Para tentar


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

11. A l m

deste

tutoriAl

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 B y

interAtivo

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 i c k A x e : "P r o g r A m m i n g r u B y "
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 B y -t A l k :

umA listA de discusso soBre

ruBy

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.

tim toAdy
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!