Aprenda a Programar Em Ruby Por Chris Pine

download Aprenda a Programar Em Ruby Por Chris Pine

of 61

description

http://aprendaaprogramar.rubyonrails.com.br/Aprenda a programar em Ruby

Transcript of Aprenda a Programar Em Ruby Por Chris Pine

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

I NS T A L A O

NO

W INDO W S

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

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

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

I NS T A L A O

P A RA

M A C INT O S H

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

I NS T A L A O

EM

L INU X

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

2003-2011 Chris Pine

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

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

I NT RO DU O

A O PUTS

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

puts simplesmente escreve na tela tudo que vem depois dele.

I NT E IRO

E

FLOAT

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

E aqui esto alguns floats:54.321 0.001 -205.3884 0.0

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

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

Isto o que o programa retorna:3.0 6.0 -3.0 4.5

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

Basicamente a mesma coisa, no ?3 6 -3 4

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

5 -29802

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

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

Eis uma pergunta mais difcil:Se minha idade de 1109 milhes de segundos, qual minha idade em anos?

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

2003-2011 Chris Pine

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

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

Ol, mundo! At logo.

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

A RIT IM T IC A

DA S

S T RING

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

Eu gosto detorta de ma.

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

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

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

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

piscando os olhos dela

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

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

12

VS

'12'

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

24 1212 12 +

12

Que tal isso?puts 2 * puts '2' * puts '2 * 5 5 5'

10 22222 2 * 5

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

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

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

#

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 PineVoc sabia que seu nome possui 22 caracteres, Christopher David Pine?

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

AABBCCDDEE aabbccddee AaBbCcDdEe Aabbccddee a aAbBcCdDeE

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

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

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

Hum... Eu no acho que essa rima assim, mas sou muito preguioso para procurar. (Tambm, eu queria alinhar a parte do .center larguraDaLinha, por isso acrescentei espaos extra antes das strings. Isso s por que acho que fica mais bonito assim. Programadores geralmente tm opinies fortes sobre o que bonito num programa, e eles geralmente discordam sobre o assunto. Quanto mais voc programar, mais vai descobrir seu prprio estilo). Falando em ser preguioso, a preguia nem sempre algo ruim na programao. Por exemplo, viu como eu guardei a largura do poema numa varivel larguraDaLinha? Fiz isso pois se quiser tornar o poema mais largo mais tarde, s precisarei mudar a primeira linha do programa, ao invs de todas as linhas que so centralizadas. Com um poema muito longo, isso poderia me poupar um bom tempo. Esse tipo de preguia na verdade uma virtude na programao. Ento, em relao centralizao... voc deve ter percebido que no est to bonito quanto um processador de texto teria feito. Se voc realmente quer centralizao perfeita (e talvez uma fonte melhor), ento voc deveria apenas usar um processador de texto! Ruby uma ferramenta maravilhosa, mas nenhuma ferramenta a ferramenta certa para qualquer trabalho. Os outros dois mtodos de formatao da string so ljust e rjust, que fazem o texto justificado esquerda e justificado direita. Eles so parecidos com o center, exceto que eliminam os espaos em branco da string do lado direito e esquerdo, respectivamente. Vamos ver os trs em ao:larguraDaLinha = 40 str = '--> text 0 if ((escrevendo == 1) and (falta > 0)) # No podemos escrever "dez e dois", temos que escrever "doze", # ento vamos fazer uma exceo. numExtenso = numExtenso + especiais[falta-1] # O "-1" aqui porque especiais[3] 'catorze', e no 'treze'. # J que cuidamos do dgito das unidades, # no falta mais nada falta = 0 else numExtenso = numExtenso + dezenas[escrevendo-1] # E o "-1" aqui porque dezenas[3] 'quarenta', e no 'trinta'. end if falta > 0 # Como ns no escrevemos "sessentaequatro"... numExtenso = numExtenso + ' e ' end end

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

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

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

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

A L G U MA S C O IS INHA S

P A RA

T E NT A R

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

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

2003-2011 Chris Pine

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

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

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

A

C LASSE

TIME

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

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

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

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

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

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

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

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

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

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

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

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

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

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

cinco cinqenta e oito

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

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

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

5 3

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

V A RI V E IS

DE

I NS T NC IA

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

puts dado.mostrado puts dado.mostrado

6 6 3 3

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

nil

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

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! F i it l l fi t M f i b i d i i D i

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

Ele est cheio Ele no precisa ir ao quintal

def comFome?

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

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

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

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

2003-2011 Chris Pine

10. B LOCOS

E

P R OCS

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

Ol! Ol! Ol!

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

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

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

M T O DO S

QUE

R E C E BE M P RO C S

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

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

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

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

(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