- A Continuação da História do Instrutor de Órgão da Minha Filha: >
Eu sei que você pode estar surpreso em saber que eu tenho uma filha. Você pensa que meu estilo
de escrever indica uma mente imatura ou infantil. Bem, por favor relaxe. Eu não tenho uma filha.
Mas isso não me impede de pensar no treinamento musical dela.
Enquanto essas histórias do planeta Endertromb eram relatadas a mim, eu me vi vagando
por corredores, passando as pontas dos meus dedos por sofás fortemente abotoados
e me envolvendo nos gritos saturados dos tubos, enquanto o instrutor de órgão da minha filha
tocava. Suas notas ressoavam tão ocas e profundas nas paredes de sua mansão
que eu comecei a confundí-las com um silêncio nefasto, e achava ainda mais fácil
me recolher ao espaço infinito dos meus pensamentos. Para pensar no planeta ancestral
e suas filosofias obscuras: seus templos carnais, corados com os resíduos dérmicos
dos seus mártires; seus cartéis de baleias, engolindo seus inimigos e prendendo-os por
décadas, arrastando-os para cima e para baixo em suas escadarias de costelas; suas brumas venenosas e
seus portais dolorosos; e, as cruéis dinastias
dos Originais, a espécie que clama paternidade de toda vida inteligente no universo.
Mas, eventualmente, eu ouvia aqueles tubos de oitavas mais altas cantar e acabava voltando
para a mesma tarde jovial de onde havia saído.
É interessante como até a brisa do nosso planeta é uma coisa um tanto estranha para
forasteiros. Ele também me contou sobre viajantes de Rath-d, que se aventuraram na Terra
cinco séculos atrás, mas se dissiparam rapidamente nas nossas correntes de ar já que eles, seus equipamentos e
sua armadura eram todos feitos de carvão.
Eu tinha me sentado ao órgão, ouvindo as histórias sobre sua colônia, enquanto ele acentuava suas
sinfonias e as histórias desapareciam por um tempo, até que a melodia terminasse.
Ele falava sobre ele e seus irmãos sendo abraçados pela cauda de sua mãe e arrancando
o tecido macio da parede interna. Um sabão suculento, esponjoso e melado que limpou
suas bocas e esôfagos enquanto descia. Eles mastigaram fortemente aquilo e espuma se formava.
Depois de comer, eles sopraram bolhas uns sobre os outros, cada bolha cheia de uma espuma densa,
sobre a qual eles dormiram. E de manhã bem cedo, quando a mãe os soltava do abraço, ela observava
serenamente enquanto seus bebês dormiam em um ensopado de bolas de carne escuras e um molho doce e grudento.
Ele soletrou todos os gostos de Endertromb. Dos seus órgãos cor de salmão engomados, que se tornavam
uma pasta quando cozidos, e seus olhos que derretiam e viravam um rico creme. Das suas manteigocias com tentáculos.
E ele estava apenas começando a apreciar essas delícias, ainda criança, para ser elevado de um
jardim de infância por um par de elefantes pigmeus que desçeram um enorme guindaste dos céus, e o ergueram
pela gola.
Eles o transplantaram para a Terra, o guiaram em seu ofício, tompeteando suas trombas alto para a cidade de
Grand Rapids ouvir, então se foram, chorando e abraçando uns aos outros.
"Mas, estranhamente (em-pithy-dah), Eu aprendi, toquei (pon-shoo) nos órgãos no meu planeta
(oth-rea) natal," ele disse.
O instrutor de órgão da minha filha fala essas palavras extras que você vê em parênteses. Quem é
que sabe se é sua língua nativa ou seu soluço sonoro. Ele mantém outro
traço de Endertromb: ele tem doze nomes.
"Não, (wen-is-wen)," ele disse. "Eu tenho um nome (im-apalla) que é dito (iff)
de muitas-muitas maneiras difentes."
Eu o chamo de Paij-ree nas manhãs e Paij-plo de tarde.
Já que estou escrevendo de dia, o chamarei de Paij-ree aqui.
h3. Protetores de Ouvido Múrmurio-Free
!>i/my.daughters.organ-1.gif(Alien at the keys.)!
Então eu disse a Paij-ree, "Paij-ree, eu estou escrevendo um livro. Para ensinar ao mundo Ruby."
"Oh, (pill-nog-pill-yacht) bacana," ele disse. Ele conhece Ruby há mais tempo que eu, mas mesmo assim:
_Eu_ serei o instrutor de Ruby da minha filha.
E eu disse, "Paij-ree, você está no livro. E as estórias do seu planeta." Eu falo com ele como
se ele fosse o E.T. Eu não sei porquê. Como o que eu disse em seguida: "E daí talvez algum dia
você possa ir pra casa pro seu pai e pra sua mãe!"
Ele replicou, "(pon-shoo) (pon-shoo) (em-pithy-dah)." Que é o jeito dele de expressar em voz alta
seu silêncio e receio.
Ele queria ver o que eu havia escrito, então eu mostrei a ele este pequeno método que escrevi pra você.
<pre>
def limpar_murmurios_de( frase )
while frase.include? '('
abre = frase.index( '(' )
fecha = frase.index( ')', abre )
frase[abre..fecha] = '' if fecha
end
end
</pre>
"Viu o que isto faz, Paij-ree? Qualquer Smotchkkiss velho pode usar este método
pra remover toda essa poluição incoerente das suas falas," eu disse.
E eu alimentei o método com algo que ele havia dito mais cedo.
<pre>
o_que_ele_disse = "Mas, estranhamente (em-pithy-dah),
Eu aprendi, toquei (pon-shoo) em órgãos no meu planeta
(oth-rea) natal."
limpar_murmurios_de( o_que_ele_disse )
print o_que_ele_disse
</pre>
E saiu de certa forma uma frase mais clara.
<pre>
Mas, estranhamente ,
Eu aprendi, toquei em órgãos no meu planeta
natal.
</pre>
"Você não deveria usar este (wary-to) loop while," ele disse. "Existem jeitos mais amáveis, (thopt-er),
e gentis."
No método @limpar_murmurios_de@, estou basicamente procurando por abre parênteses. Quando eu
encontro um, eu procuro um fecha parênteses na sequência. Uma vez que tenha encontrado ambos, eu troco
eles e seu conteúdo por uma string vazia. O loop @while@ continua até que todos os parênteses se acabem.
Os murmúrios são removidos e o método termina.
"Agora olhando este método," eu disse. "Eu vejo que há alguns aspectos confusos
e outras coisas que eu poderia ter feito melhor." Por favor não me olhe estranho por seu professor
ter escrito este código. Eu acho certo lhe mostrar algumas técnicas desleixadas
pra te ajudar a trabalha-las comigo. Vamos lá.
Okay, *Aspecto confuso No. 1*: Este método limpa uma string. Mas e se nós acidentalmente
dermos a ele um @File@? Ou um número? O que acontece? E se rodarmos @limpar_murmurios_de( 1 )@?
Se nós dermos ao @limpar_murmurios_de@ o número 1, o Ruby irá imprimir o seguinte e depois sair.
<pre>
NoMethodError: undefined method `include?' for 1:Fixnum
from (irb):2:in `limpar_murmurios_de'
from (irb):8
</pre>
O que você vê aqui ere is a rather twisted and verbose (mas noutras vezes muito útil) amiguinho
chamado de o *depurador*. He's a wound-up policeman who, ao menor sinal de problema,
imediatamente apreende todo e qualquer suspeito, os põe contra a parede e lê os direitos deles
tão rapidamente que ninguém consegue ouvir tudo. Mas está claro que há um problema.
E, é claro, tudo não passou de um mal entendido, certo?
Quando o Ruby ler pra você esses direitos de Miranda, preste atenção no começo. A primeira linha
é quase sempre tudo que você precisa. Nessa primeira linha está contido a mensagem essencial. E ali
em cima, a primeira linha está nos dizendo que não há método @include?@ para o número 1.
Lembra, quando estávamos conversando sobre o método @reverse@ no capítulo anterior? Naquela hora, eu disse,
"*vários métodos só estão disponíveis com certos tipos de valores*." Ambos @reverse@ e
@include?@ são métodos que funcionam com strings mas são sem sentido e indisponíveis para números.
Pra deixar claro: o método tenta usar o número. O método vai iniciar com @frase@ valendo 1.
Então, ele chega na segunda linha: @while frase.include? '('@. Números não têm método @include?@.
Maravilha, o depurador nos mostrou onde o problema está. Eu não esperava que alguém fosse passar
um número, então estou usando métodos que não funcionam com números.
*Viu, é só isso.* Nosso método é seu próprio bolso de ferramentas, certo? Ele age como seu próprio
widget independente de todo o resto. Pra todos por aí usando o método @limpar_murmurios_de@,
se eles passarem um número, será atirado pra eles esta mensagem de pânico que não faz
sentido pra eles. Eles serão convidados a bisbilhotar o método, o que realmente não é
trabalho deles. Eles não sabem como se virar lá dentro.
Felizmente, nós podemos inserir nossos próprios erros, nossas próprias *exceções*, o que pode fazer mais
sentido a algum desavisado que dê um objeto errado pra ser limpo.
<pre>
def limpar_murmurios_de( frase )
unless frase.respond_to? :include?
raise ArgumentError,
"não posso limpar os múrmurios de um(a) #{ frase.class }"
end
while frase.include? '('
abre = frase.index( '(' )
fecha = frase.index( ')', abre )
frase[abre..fecha] = '' if fecha
end
end
</pre>
Desta vez, se passarmos um número (de novo, o número 1), teremos algo mais sensato.
<pre>
ArgumentError: não posso limpar os múrmurios de um(a) Fixnum
from (irb):3:in `limpar_murmurios_de'
from (irb):12
</pre>
O método @respond_to?@ é realmente bacana e eu imploro que você nunca se esqueça dele.
O @respond_to?@ checa qualquer objeto para garantir que nele contém um determinado método. Ele então retorna
com @true@ o @false@. No caso acima, é checado se o objeto @frase@ recebido contém algum método
@include?@. Se nenhum método @include?@ for encontrado, então causamos o erro.
Você deve estar pensando por que eu usei um símbolo com o @respond_to?@. Eu usei um símbolo @:include?@
invés da string @'include?'@. Na verdade, ambos funcionarão com o @respond_to?@.
Geralmente símbolos são usados quando você está passando o nome de um método ou qualquer outro construtor.
É mais eficiente, chama mais atenção. O @respond_to?@ pergunta ao Ruby to look inside itself
and see if a method is available. Estamos conversando com o Ruby, então o símbolo helps denote that.
Não é grande coisa, Ruby só reconhece símbolos mais rapidamente que strings.
Agora, *Aspecto Confuso No. 2*: Você notou como nosso método modifica a frase?
<pre>
algo_dito = "Uma (gith) espaçonave."
limpar_murmurios_de( algo_dito )
print algo_dito
</pre>
Você notou isso? Na primeira linha do código acima, a variável @algo_dito@
contém a string @"Uma espaçonave (gith)."@. Mas, depois de invocar o método, na terceira
linha, nós imprimimos a variável @algo_dito@ e nesse momemento ela contém a string limpa
string @"Uma espaçonave."@.
Como isso funciona? Como o método modifica a string? Ele não deveria fazer uma cópia
da string antes de modificá-la?
Sim, absolutamente, ele deveria! *É falta de educação modificar strings daquele jeito.*
Nós usamos @gsub@ e @gsub!@ no capítulo passado. Você se lembra qual destes dois métodos
é um *método destrutivo*, que modifica strings diretamente?
Ou nós chamamos este método de @limpar_murmurios_de!@ (cortesia a todos os colegas bacanas
por aí que podem vir a usar este método) ou modificar o método para trabalhar em uma cópia
da string invés da coisa real. O que é uma modificação muito fácil! Nós só precisamos dar
um @dup@ na string.
<pre>
def limpar_murmurios_de( frase )
unless frase.respond_to? :include?
raise ArgumentError,
"não posso limpar os múrmurios de um(a) #{ frase.class }"
end
frase = frase.dup
while frase.include? '('
abre = frase.index( '(' )
fecha = frase.index( ')', abre )
frase[abre..fecha] = '' if fecha
end
frase
end
</pre>
O método @dup@ faz uma cópia de qualquer objeto. Veja a linha que adicionamos separada:
<pre>
frase = frase.dup
</pre>
Que linha de código peculiar. Como que @frase@ vira uma cópia de @frase@?
Ela se apaga? O que acontece com a @frase@ original? Ela desaparece?
Lembre que variáveis são como apelidos. Quando você vê @frase = "Uma (gith) espaçonave."@,
você o Ruby criando uma string e então dando um apelido a essa string.
Do mesmo modo, quando você vê @frase = frase.dup@, você ve o Ruby criando uma nova string e então
dando um apelido a essa string. Iso é útil dentro do seu método porque agora @frase@ é
um pelido para uma nova cópia da string que você pode usar seguramente *sem modificar a string
que foi passada pro método*.
Você vai ver muitos exemplos de nomes de variáveis seudo reusados.
<pre>
x = 5
x = x + 1
# x agora é igual a 6
y = "Endertromb"
y = y.length
# y agora é igual a 10
z = :include?
z = "a string".respond_to? z
# z agora é igual a true
</pre>
E, sim, algumas vezes objetos desaparecem. *Se você não consege pegar um objeto por uma váriavel, então
o Ruby vai entender que você já terminou com ele e vai se livrar dele.* Periodicamente, o Ruby envia seu
*garbage collector (coletor de lixo)* pra libertar estes objetos. Todo objeto é mantido na memória do
seu computador até que o coletor de lixo se livre dele.