From a.r.ferreira em gmail.com Sat Aug 1 14:41:31 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sat, 1 Aug 2009 18:41:31 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_B=E1sico=5D_=234_Subrot?= =?iso-8859-1?q?inas_-_Parte_I?= Message-ID: <73ddeb6c0908011441u2da99bbci2ebbdce7ea16d055@mail.gmail.com> [Perl 5 - Básico] #4 Subrotinas - Parte I Para a reutilização de código, a primeira facilidade provida por Perl 5 são as subrotinas. Subrotinas são usadas como funções (para retornar um valor), rotinas (para executar uma sequência de passos), e como métodos (em programação com objetos). # twice($n) calcula 2*$n (duas vezes $n) sub twice { $_[0]*2 } Como em funções C, subrotinas Perl podem ou não retornar valores, e o código que as chama pode ou não usar destes retornos. Assim: $m = twice(2); vai atribuir 4 à variável escalar $m. Enquanto: sub print_array { local $" = ', '; print "(@_)\n" } print_array(1,2,3,4); vai apresentar a saída: (1, 2, 3, 4) Sim, se você é iniciante, deve estar pensando: $_[0]?! $"?! @_?! Cruz credo! O que é isso? Xingação? Não, é Perl. Perl é cheio de variáveis mágicas, com as quais você vai se familiarizar aos poucos e vai aprender a apreciar quando for mais fluente na linguagem. Mas não fui muito justo nos exemplos acima. Pois então vamos recomeçar. Toda subrotina em Perl passa os seus parâmetros através de uma variável *array* @_. As formas mais legíveis para tratar os argumentos é lhes dar nomes logo nas primeiras linhas de código das subrotinas. Há duas formas básicas de fazer isto: com "shift": sub twice { my $n = shift; return $n*2; } Por agora, basta saber que "shift" retorna o primeiro argumento em @_, ao mesmo tempo que o remove da lista de argumentos. Assim, para uma subrotina com dois argumentos: sub tuple { my $a = shift; my $b = shift; return [$a, $b]; } Ao invocar "tuple(8,10)", $a vai tomar o valor 8 e $b receberá 10 e o retorno será o "*array*" "[8,10]". A segunda forma é fazendo uma atribuição de @_ a uma lista de variáveis: sub tuple { my ($a, $b) = @_; return [$a, $b]; } é equivalente ao código anterior (com a diferença de que @_ permanece intacto, enquanto na versão com "shift", @_ é modificado). Há muito o que falar sobre subrotinas. E é por isso que esta é só a Parte I desta estória. Triangulo-pm, 2009-08-01 14:00 -------------- next part -------------- An HTML attachment was scrubbed... URL: From a.r.ferreira em gmail.com Sun Aug 2 08:42:49 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sun, 2 Aug 2009 12:42:49 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_B=E1sico=5D_=235_Hashes?= Message-ID: <73ddeb6c0908020842o3abec29fi101f82d471d17212@mail.gmail.com> [Perl 5 - Básico] #5 Hashes Perl 5 *hashes* são estruturas de dados que indexam valores através de chaves *strings*. %days = ( Sunday => 1, Monday => 2, Tuesday => 3, Wednesday => 4, Thursday => 5, Friday => 6, Saturday => 7, ); *Hashes* são *arrays* associativos, conhecidos por diferentes nomes em diferentes linguagens de programação: por exemplo, dicionários em Python e Smalltalk, mapas em Java. Saber utilizar bem dos *hashes* em seu código simplifica uma variedade de problemas, alguns dos quais se tornam extremamente triviais com o uso destas estruturas. Por exemplo, dado um *array* de *strings*, remova todos os valores repetidos, produzindo um novo *array*: @array = qw(one two one three four four five five five); my %seen; # hash de strings já vistos my @uniq; # o novo array que conterá os elementos sem duplicatas for my $s (@array) { next if $seen{$s}; # ignore se já visto push @uniq, $s; # inclua no hash, pois é $s é uma novidade $seen{$s}++; # atualize o hash } print "uniq: ", join(',', @uniq), "\n"; O código acima vai produzir a saída: uniq: one,two,three,four,five Variáveis *hash* são identificadas pelo *sigil* "%" (o *sigil* é o primeiro caracter no nome da variável). my %seen; cria uma variável léxica %seen que é um *hash*. Um elemento do *hash* tem uma sintaxe diferente: $seen{$k} Perceba que o *sigil* mudou, de "%" para "$", porque o elemento do *hash* é uma variável escalar. Nesta expressão, o que nos permite identificar que uma variável *hash* está sendo acessada é simultaneamente o *sigil* "$" seguido do índice ente chaves: "{$k}". Outro exemplo do possível uso de *hashes* é uma solução para um problema do tipo: dada uma lista de avaliações de um produto qualquer de 1 a 5 estrelas, calcule quantas vezes o produto recebeu 1 estrela, 2 estrelas e assim por diante. Calcule também a média de estrelas atribuída ao produto: @ratings = (1,2,3,4,3,4,2,1,5,5,5,5,1,2,2); my %stars; my $sum; $stars{$_}++, $sum+=$_ for @ratings; my $average = $sum/(scalar @ratings); Executado este código, o *hash* %stars vai conter: ( 1 => 3, 2 => 4, 3 => 2, 4 => 2, 5 => 4, ) onde "1 => 3" significa 3 avaliações de uma estrela, "2 => 4" são 4 avaliações de duas estrelas, e assim por diante. A variável $average vai terminar com 3, que é o número médio de estrelas calculado a partir destas notas: (1+2+3+4+3+4+2+1+5+5+5+5+1+2+2)/15 Triangulo-pm, 2009-08-02 11:00 -------------- next part -------------- An HTML attachment was scrubbed... URL: From a.r.ferreira em gmail.com Sun Aug 2 09:09:37 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sun, 2 Aug 2009 13:09:37 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_B=E1sico=5D_=231_Hello_?= =?iso-8859-1?q?World?= Message-ID: <73ddeb6c0908020909o4c9607e6r291c26228eddf3b5@mail.gmail.com> [Perl 5 - Básico] #1 Hello World Perl é uma linguagem concisa (até demais em certos casos). Mas o mais importante disso é que permite expressar em poucos comandos ou expressões certas tarefas que exigem muito mais codificação em outras linguagens. O exemplo clássico é o programa "Hello, World". Em Perl, ele é simplesmente #!/usr/bin/perl print "Hello, World!\n"; que não tem nada das baboseiras de um "Hello, World" em C (ou Java) com include's (import's), declarações de main(), etc. A filosofia é assim: "Hello, World!" é um programa cujo comportamento é estupidamente simples (e inútil - mas isto não vem o caso, ele é um clássico). Se assim é assim tão simples, o código deve ser simples. Portanto um único comando. Para dizer a verdade, ele é tão simples que não merece nem a edição de um arquivo para colocar um *shebang line* (aquela linha que começa com #!) e o "print". Você pode fazer direto do interpretador de comandos: $ perl -e 'print "Hello, World!\n" ' ou (para aqueles em Windows) > perl -e " print qq{Hello, World!\n} " Triangulo-pm, 2008-05-17 17:00 -------------- next part -------------- An HTML attachment was scrubbed... URL: From a.r.ferreira em gmail.com Sun Aug 2 09:10:12 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sun, 2 Aug 2009 13:10:12 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_B=E1sico=5D_=232_Vari?= =?iso-8859-1?q?=E1veis?= Message-ID: <73ddeb6c0908020910x63e85258i812c85512581dba5@mail.gmail.com> [Perl 5 - Básico] #2 Variáveis Perl é conhecido pelo uso (ou abuso) de caracteres não alfanuméricos no código fonte dos programas. Neste ponto, a linguagem vai muito além dos tradicionais operadores "+", "*", "=", "!" que tudo mundo conhece de linguagens como C ou Java. A introdução destes caracteres estranhos já começa pelas variáveis. Variáveis em Perl são claramente marcadas por um símbolo estranho no começo: $contador @servidores %nome_de *GLOB &my_sub Os três primeiros exemplos são fundamentais e aparecem o tempo todo em programação Perl. $contador é uma variável escalar. @servidores é um *array*. %nome_de é um *hash*. Sobre os outros, podemos falar mais tarde: *GLOB tem a ver com a tabela de símbolos de um programa Perl e &my_sub é uma forma exótica de referenciar uma subrotina (que tem os seus usos e suas surpresas). Estes caracteres '$', '@', '%', '*', '&' são chamados de *sigils* e marcam claramente as variáveis no programa fonte. use LWP::Simple qw( get ); my $uri = 'http://search.cpan.org/src/GAAS/libwww-perl-5.812/README '; # download 'README' da distribuição libwww-perl-5.812 my $content = get($uri); Neste pedaço de código acima, as variáveis são $uri e $content. "LWP::Simple" é o nome de um módulo e "get" uma subrotina vinda deste módulo. Não há confusão entre variáveis e módulos/subrotinas. Esta distinção pode parecer redundante, mas tem seus benefícios. Ela estabelece *namespaces* (espaços de nomes) diferentes para variáveis escalares, *arrays*, *hashes* e subrotinas/módulos. E um bônus: interpolação em strings sem complicações: my $name = 'Fulano'; my %bag = { laranja => 2, pera => 3 }; print "$name tem $bag{laranja} laranjas e $bag{pera} peras\n"; # saída: Fulano tem 2 laranjas e 3 peras Triangulo-pm, 2008-06-11 09:40 -------------- next part -------------- An HTML attachment was scrubbed... URL: From a.r.ferreira em gmail.com Sun Aug 2 09:10:54 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sun, 2 Aug 2009 13:10:54 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_B=E1sico=5D_=233_Estrit?= =?iso-8859-1?q?o_e_Cuidadoso?= Message-ID: <73ddeb6c0908020910y7af31735rda4f5748716f7137@mail.gmail.com> [Perl 5 - Básico] #3 Estrito e Cuidadoso A linguagem Perl foi propositalmente projetada para servir tanto a programadores experientes quanto a iniciantes. Esta flexibilidade veio ao longo de anos de desenvolvimento. As práticas da linguagem mudaram junto com a mudança de hábitos de seus programadores. Uma destas práticas para se ter em mente logo ao iniciar o aprendizado de Perl é: sempre coloque no início de seus programas os comandos: use strict; use warnings; Por quê? Porque em seu modo *default*, Perl é extremamente complacente e compatível com a programação de anos atrás. Estes comandos ativam uma série de checagens que ajudam iniciantes e quaisquer outros tipos de programadores a seguir confiantes escrevendo programas Perl de qualquer tamanho. Sem "strict", muitas coisas surpreendentes podem acontecer: variáveis ganham vida automaticamente (quer você queira ou não) $count++; vai automaticamente trazer a variável $count à vida e o incremento vai passar o seu valor inicial de "undef" (que é 0 do ponto de vista numérico) para 1. O grande problema com esta capacidade é que estas variáveis surgidas do nada podem ter o mesmo nome que outras que ocorrem em outros pontos do programa. O pior é que elas serão as mesmas porque vão compartilhar o mesmo espaço. Outro problema comum são erros de digitação, que podem demorar para ser percebidos e levar a *bugs* difíceis de encontrar. Por exemplo, se em um pedaço razoavelmente longo de código, você se refere a $cont quando queria dizer $count e o Perl fica quieto (porque você deve saber o que está fazendo). Com "use strict", as coisas são diferentes: $count++ leva ao erro Global symbol "$count" requires explicit package name [Símbolo global "$count" requer nome de pacote explícito] O uso correto é tornar a variável local ao escopo onde ela precisa existir com uma declaração "my": my $count; ... $count++; Sem "warnings", algumas situações suspeitas passam sem chamar atenção. Por exemplo, my $count = 'a'; $count += 1; converte o string 'a' silenciosamente para 0 e incrementa o valor da variável $count para 1. Provavelmente, não é esta a intenção do programador. Com "use warnings", a seguinte mensagem vai para "STDERR": Argument "a" isn't numeric in addition (+) [O argumento "a" não é numérico na adição (+)] Note que *warnings* não interrompem o programa, como os erros de verdade gerados por "strict". A mensagem é enviada para o "arquivo" de erros, gerando ruído inesperado na saída do programa. O programador, que deve estar sempre atento a estas mensagens porque indicam erros em potencial, deve encontrar a sua fonte e tratar de entender e provavelmente consertar a sua causa. Há muito mais em "use strict" e "use warnings". Mas a recomendação básica é use sempre. Hoje apenas código muito exótico do núcleo do interpretador Perl ousa omitir estas diretivas. (E mesmo em alguns destes casos, eles foram testados com estas diretivas ligadas e então desativadas para evitar problemas de compatibilidade com programas antigos e questões de desempenho.) Programar em Perl sem "strict" e "warnings" é como andar na corda bamba sem corda de segurança. É possível mas exige concentração contínua e os efeitos de um engano podem ser inconvenientes no mínimo. Triangulo-pm, 2008-06-12 10:00 -------------- next part -------------- An HTML attachment was scrubbed... URL: From a.r.ferreira em gmail.com Sun Aug 2 09:11:29 2009 From: a.r.ferreira em gmail.com (Adriano Ferreira) Date: Sun, 2 Aug 2009 13:11:29 -0300 Subject: [Triangulo-pm] =?iso-8859-1?q?=5BPerl_5_-_Intermedi=E1rio=5D_=231?= =?iso-8859-1?q?_Acessores?= Message-ID: <73ddeb6c0908020911q4a07328ey95e37a8437778607@mail.gmail.com> [Perl 5 - Intermediário] #1 Acessores Programação Orientada a Objeto em Perl é algo poderoso, embora cheio de idiossincracias (como "objetos são referências abençoadas"). A forma como classes são criadas (com "packages") e métodos são escritos (com "subs") tem uma série de vantagens e desvantagens. Uma das coisas mais comuns é criar *setters* e *getters* para os atributos de um objeto, como uma representação de "CD" que deve ter atributos como "id", "title", "artist". Para criar estes métodos, a forma tradicional é decidir pela representação de um objeto como um *hash ref* e escrever: # CD.pm package CD; sub new { my $proto = shift; my $class = ref $proto || $proto; my $obj = bless {@_}, $class; return $obj; } sub id { my $self = shift; if (@_) { $self->{id} = shift; } $self->{id}; } sub title { my $self = shift; if (@_) { $self->{title} = shift; } $self->{title}; } sub artist { my $self = shift; if (@_) { $self->{artist} = shift; } $self->{artist}; } "the truth at the end of the package"; onde os acessores funcionam simultaneamente como "setters" e "getters" (o que é comum em muita programação Perl) e se usa desta forma: use CD; my $cd1 = CD->new(); $cd1->id(1); $cd1->title('Born Again'); $cd1->artist('Black Sabbath'); # perceba que esta apenas é uma ilustração # didática e ingênua: # o objeto pode ser criado # e as variáveis automaticamente # preenchidas simultaneamente # por um comando como: # # $cd1 = CD->new( id => 1, title => 'Born Again', artist => 'Black Sabath' ); print "title: ", $cd1->title, "\n"; # imprime "title: Black Sabbath\n" Obviamente que o código acima é claramente redundante e chato. Se Perl é deste jeito, talvez programar em Java tenha mais *sex appeal*. Pelo menos lá, eu nem tenho de ficar referenciando o objeto sobre o qual o método foi invocado (o *$self*). package namespace.too.long.for.seemingly.respectful.java.code.CD; private int id; private String title; private String artist; # getters int get_id() { return id; } int get_title() { return title; } int get_artist() { return artist; } # setters void set_id( int id ) { this.id = id; } void set_title( String title ) { this.title = title; } void set_artist( String artist ) { this.artist = artist; } Pensando bem, Java é uma meleca com estas declarações todas, e tipos, etc. (A frase "é uma meleca" não foi muito técnica e talvez deva ser substituída por algo como "é tão prolixo quanto". Mas no fim, é uma embolação que "meleca" até define bem.) Mas não precisa ser assim. (Estou falando do código Perl. Para o Java, você pode usar o Eclipse para fazer o serviço sujo e repetir todo este código para você.) Usar "Class::Accessor" é uma alternativa (entre tantas outras) e o nosso código anterior se reduz a: # CD.pm package CD; use base qw( Class::Accessor ); BEGIN { __PACKAGE__->mk_accessors(qw( id title artist )); } 42; # the truth at the end of the package O mesmo código ilustrado antes para ser usado para construir instâncias de "CD" continua válido. Nenhuma repetição desnecessária e os acessores são automaticamente criados para você (inclusive poupando-o de inconvenientes com erros de nomes de variáveis e tal). Triangulo-pm, 2008-05-17 19:50 -------------- next part -------------- An HTML attachment was scrubbed... URL: