Arquivo do Autor

Depuração de scripts Perl

janeiro 26, 2009

Sabe-se que em Perl os warnings nem sempre são esclarecedores. Ao contrário, o que era fácil, fica críptico.

Pegando leve, vamos ver um exemplo:

use strict;
use warnings;
my %hash = {
  cachorro => 'mamífero',
  golfinho => 'mamífero',
  tartaruga => 'réptil',
  galinha => 'galináceo'
}

E é claro que isso vai dar um erro grotesco:

Reference found where even-sized list expected at hasht.pl line 5.  (WTF!??)

Pra resolver a questão de vez, adicione o pacote diagnostics, ficando assim:

use warnings;
use strict;
use diagnostics;
my %hash = {
  cachorro => 'mamífero',
  golfinho => 'mamífero',
  tartaruga => 'réptil',
  galinha => 'galináceo'
}

Magicamente, o Perl praticamente nos dá uma aula junto com o erro:

Reference found where even-sized list expected at hasht.pl line 5 (#1)
(W misc) You gave a single reference where Perl was expecting a list
with an even number of elements (for assignment to a hash). This
usually means that you used the anon hash constructor when you meant
to use parens. In any case, a hash requires key/value pairs.

%hash = { one => 1, two => 2, };        # WRONG
%hash = [ qw/ an anon array / ];        # WRONG
%hash = ( one => 1, two => 2, );        # right
%hash = qw( one 1 two 2 );              # also fine

Ou seja, era só trocar as chaves por parênteses. Agora ficou mole, ou pelo menos bem mais fácil de entender as mensagens esquisitas dessa linguagem fabulosa!

Array, Hash, Referência de Array, Referência de Hash

janeiro 21, 2009

Serei breve. Resumão de como e quando acessar array, hash, referência de array e referência de hash.

pai_mei
(more…)

Calendários do Advento Natalino

dezembro 4, 2008

Replico aqui um post interessante do Breno na lista de Perl do Rio de Janeiro sobre recomendações de módulos de no mês de dezembro.

Acompanhem!
http://perladvent.pm.org/2008/

———- Forwarded message ———-
From: breno
Date: 2008/12/4
Subject: [Rio-pm] Calendários do Advento Natalino!
To: Perl Mongers Rio de Janeiro

O calendário Perl do advento natalino é uma tradição na comunidade desde o ano 2000. A idéia é apresentar um módulo bacana (para qualquer definição de “bacana”) do CPAN em cada dia de dezembro que antecede o Natal.

O desse ano já está no ar!

http://perladvent.pm.org/2008/

O dia 1 fala do ToolSet, um módulo que agrega todos os seus módulos mais usados em um único import, evitando assim o “ctrl-c/ctrl-v”.

Dia 2 fala de um módulo que eu particularmente acho o maior barato, o Math::Prime::TiedArray, que cria um array virtual com todos os números primos.Todos?! Todos. Afinal, é um array virtual, ele computa o número primo que ocupa a posição desejada conforme a demanda 😉

Fiquem atentos ao site oficial do calendário! Quem tiver curiosidade é só olhar o histórico para os outros anos, e se vc acha que seu [insira módulo xodó aqui] está sendo injustiçado por não ter sido apresentado
até hoje, escreva para eles! O pessoal do calendário está sempre atrás de idéias (e escritores!!!!!)

Finalmente, mas não menos importante, já saiu também o calendário Catalyst do advento natalino, que desde 2005 complementa o calendário do Perl com dicas e módulos específicos para o Catalyst!

http://www.catalystframework.org/calendar/2008/

O dia 1 apresenta as estatísticas da pesquisa de Catalyst (que circulou inclusive pela lista, infelizmente apenas 2 brasileiros responderam).

Dia 2 mostra as diferentes formas de se implantar o Catalyst em servidores Web (servidor built-in, mod_perl, fastcgi, etc)

O dia 3 apresenta um módulo bonitão que já mencionei por aqui, o Chart::Clicker, e como usá-lo junto com o Catalyst para exibir páginas com gráficos informativos.

Como sempre, é possível ver calendários de anos anteriores, e eles também adoram voluntários!

[]s, e boas festas 😉

-b
_______________________________________________
Rio-pm mailing list
Rio-pm@pm.org
http://mail.pm.org/mailman/listinfo/rio-pm

Template Toolkit no Perl

dezembro 3, 2008

Acho que uma das poucas coisas que gosto no Perl é o módulo Template Toolkit. Como a documentação é boa, vou só dar uma olhada superficial.

Comecemos pela instalação:

# aptitude install libtemplate-perl

O uso é semelhante a qualquer biblioteca de templates, como o Smarty no PHP. Preparamos as variáveis que serão disponibilizadas e em seguida processamos determinado arquivo.

O script fica assim:

use strict;
use warnings;
 
use Template;
use File::Basename;
 
my $r = shift;
$r->content_type("text/html");
 
my $directory = (fileparse $r->filename)[1];
 
my $template = Template->new({
    INCLUDE_PATH => "$directory/templates",
});
 
my $vars = {
    artista => 'Pink Floyd',
    album   => 'Pulse',
    musicas => [
        { numero => 12, titulo => 'Comfortably Numb' },
        { numero => 11, titulo => 'Wish You Were Here' },
        { numero => 3,  titulo => 'Time' },
    ],
};
 
$template->process('musica.tt2', $vars)
    || die $template->error();

E o template:

<html>
<body>
    <h1>[% artista %]</h1>
    <h2>[% album %]</h2>
    [% IF musicas %]
        <ul>
        [% FOREACH musica IN musicas %]
            <li>[% musica.numero %] – [% musica.titulo %]</li>
        [% END %]
        </ul>
    [% ELSE %]
        <p>Nenhuma música.</p>
    [% END %]
</body>
</html>

Quem já está acostumado a utilizar templates vai precisar apenas se adaptar à sintaxe do Template Toolkit.

Em relação ao script, o trecho my $directory = (fileparse $r->filename)[1]; é uma peculiaridade do mod_perl. O diretório atual do processo não é o diretório do script, aqui ficou como sendo a raiz do sistema. Então se tentássemos carregar o template templates/musica.tt2 ele não encontraria o arquivo.

A função fileparse do módulo File::Basename retorna uma lista com o nome do arquivo, diretório e sufixo, respectivamente. Da forma como foi utilizada, o diretório do arquivo que está sendo processado é atribuído à variável $directory. Essa variável então é utilizada como base para o caminho absoluto do diretório dos templates que é passado como configuração para o Template Toolkit.

Também é importante verificar se o template foi processado corretamente. Se não houvesse a linha || die $template->error(); e o processamento do template desse erro, a função process apenas retornaria 0, sem mostrar nada na tela. Utilizando o die como demonstrado, qualquer problema vai mostrar Internal Server Error no browser e detalhes do erro no error.log do Apache.

Recomendo a leitura

Conectando no banco com DBI

dezembro 1, 2008

A interface com banco de dados no Perl é centralizada no módulo DBI. Para este módulo, existem os drivers para cada banco de dados, como DBD::mysql, DBD::pgsql, etc.

No Debian, o Mysql já instala o driver de conexão do Perl automaticamente, mas se não estivesse instalado, para pegar os pacotes da distribuição seria:

# aptitude install libdbi-perl libdbd-mysql-perl

A interface para utilização é bem simples:

#!/usr/bin/perl
 
use strict;
use warnings;
 
use DBI;
 
my $dbh = DBI->connect('dbi:mysql:wordpress', 'nobody', 'nobody');
 
my $sth = $dbh->prepare('SELECT * FROM wp_posts');
$sth->execute();
 
while ( my $row = $sth->fetchrow_hashref ) {
    print $row->{post_title}, "\n";
}

A diferença pra quem está vindo do PHP é que primeiro preparamos a query com o método prepare no objeto da conexão. O método retorna um objeto DBI::st que representa o statement, e então executamos a query com execute.

O legal na verdade é quando utilizamos parâmetros. Preparamos a query com placeholders e passamos os parâmetros pro execute.

Além de evitar preocupação com escapar os dados, queries que serão executadas mais de uma vez com parâmetros diferentes são preparadas uma única vez, com ganhos de performance consideráveis em alguns SGBDs.

$sth = $dbh->prepare('
    SELECT * FROM wp_posts
    WHERE post_author = ?
      AND post_title = ?
');
 
$sth->execute(1, 'Hello world!');
printf "Total de hello world: %d\n", $sth->rows;
 
$sth->execute(1, 'Teste');
printf "Total de teste: %d\n", $sth->rows;

E é isso. Post rápido só pra dar base pra alguma aplicação que a gente queira testar mais pra frente.

Veja a documentação da API pra detalhes interessantes:
http://search.cpan.org/~timb/DBI-1.607/DBI.pm

Obs: Sabe-se que, pelo menos até a versão 5.0, o query cache não funciona no MySQL se utilizado com prepared statements. Já o Oracle consegue guardar o plano de execução, evitando ter que determinar a melhor estragégia de busca a cada query. Com prepared statements o plano de execução fica em cache indepentente dos parâmetros, conseguindo um ganho significativo de performance.

Variáveis do GET e POST no Perl

novembro 18, 2008

Dando continuidade à tentativa de fazer algo web com Perl, acho que o próximo passo pode ser receber parâmetros vindos de um formulário ou url.

O primeiro script de teste ficou assim:

use strict;
use warnings;
 
my $r = shift;
 
$r->content_type('text/html');
 
print '<h1>Funcionou!</h1>';

O script é executado pelo modperl como se fosse uma função e recebe como parâmetro um objeto do tipo Apache2::RequestRec. Quando fazemos o shift, este parâmetro passa para a variável local $r.

Para ter acesso aos dados submetidos por GET ou POST de forma legível, precisamos instanciar um objeto Apache2::Request, que recebe no construtor o RequestRec da requisição atual:

use strict;
use warnings;
 
use Apache2::Request;
 
my $r = shift;
my $req = Apache2::Request->new($r);
 
$r->content_type('text/html');
 
print '<h1>Funcionou!</h1>';

Os parâmetros passados, tanto por GET quanto por POST, estão disponíveis pelo accessor param:

use strict;
use warnings;
 
use Apache2::Request;
 
my $r = shift;
my $req = Apache2::Request->new($r);
 
$r->content_type('text/html');
 
print '<h1>Funcionou!</h1>';
 
print $req->param('variavel_por_get');
print $req->param('variavel_por_post');

Caso o nome da variável não seja passado para o accessor, ele retorna um array que pode ser iterado, como neste caso:

use strict;
use warnings;
 
use Apache2::Request;
 
my $r = shift;
my $req = Apache2::Request->new($r);
 
$r->content_type('text/html');
 
foreach my $param ( $req->param ) {
    print "$param: ", $req->param($param), "<br />";
}

Além do accessor param, os dados do POST também estão no accessor body. Para acessar uma variável exclusivamente submetida por POST fica assim:

use strict;
use warnings;
 
use Apache2::Request;
 
my $r = shift;
my $req = Apache2::Request->new($r);
 
$r->content_type('text/html');
 
print '<h1>Funcionou!</h1>';
 
print $req->body('somente_variavel_por_post');

Assim como no param, também é possível ter um array com o nome dos parâmetros passados por POST ao acessar o body sem nenhum argumento.

E é isso.

Referências:

Parâmetros de funções em Perl

novembro 14, 2008

Uma coisa que ainda me irrita um pouco é a falta de assinatura de funções em Perl. Quando eu já estava me acostumando com parâmetros tipados e começava a desejar type hint para retorno de métodos, no Perl parece que não temos nada disso.

Os argumentos de funções chegam no array @_. Dentro da função você precisa pegar os argumentos dessa lista e fazer as validações necessárias.

Exemplo:
sub escrever_dados {
    my ($nome, $cidade) = @_;
    print "Nome: $nome, cidade: $cidade\n";
}
 
escrever_dados('Mary', 'Rio de Janeiro');

A função nesse caso recebe uma lista e os seus elementos são passados para as variáveis locais.

O que mais me incomoda é que parâmetros a mais ou a menos na chamada à função não resultam em erro algum. O que pode ser feito é validar dentro da função a quantidade e tipo dos parâmetros, mas torna o código extremamente repetitivo e mais sujeito a erros.
sub escrever_dados {
    if (scalar @_ != 2) {
        print "Função espera 2 argumentos\n";
        return 0;
    }
    my ($nome, $cidade) = @_;
    print "Nome: $nome, cidade: $cidade\n";
}
 
escrever_dados('Mary', 'Rio de Janeiro', 'Vai dar erro');
escrever_dados('Também vai dar erro');
escrever_dados(); # Lista vazia (scalar 0) também dá erro

A não ser que alguém conheça uma forma melhor. Alguém? Alguém?

Como o @_ é uma lista normal, qualquer forma de acesso é válida:
sub saudacao {
    my $nome = shift;
    print "Oi, $nome!\n";
}
 
saudacao('Mundo');

sub erro {
    die "Erro inesperado $_[0]\n";
}
 
erro('Valor inválido!');

Mas ainda acho que associar as variáveis na forma my ($nome, $cidade) = @_; fica mais claro. Exceto quando estamos trabalhando com objetos, aí acho mais claro fazer my $self = shift; antes. Mas aí já é outra história.

Divirta-se.

var_dump em Perl

novembro 12, 2008

Nos primeiros dias de Perl eu já precisei de algo parecido com var_dump do PHP, até pela falta de um debug mais adequado.

No Perl o módulo correspondente é o Data::Dumper:
use Data::Dumper;
 
my $scalar = 'Teste';
print Dumper($scalar);
 
my %hash = ( nome => 'Jane' );
print Dumper(\%hash);
 
my @array = ( 'Jane', 'Doe' );
print Dumper(\@array);
 
my $hashref = { idade => 27 };
print Dumper($hashref);
 
my $arrayref = [ 'um', 'dois', 3 ];
print Dumper($arrayref);
 

Um detalhe importante é que a função Dumper retorna a estrutura como string, então para ver os dados é preciso dar print.

Observe ainda que as variáveis @array e %hash foram passadas por referência, com uma barra invertida antes do nome.

Se não fosse feita a referência, o conteúdo de cada uma seria expandido. Ao invés de uma lista com os nomes Jane e Doe, o Dumper exibiria as strings separadamente, como se ele tivesse sido chamado como Dumper('Jane', 'Joe'). A mesma coisa para o hash; sem a referência seria como Dumper('nome', 'Jane').

Esse assunto de referenciar e de-referenciar vale a pena deixar para um post futuro.

Teste aí e veja no que dá 😉

Monges do Perl

novembro 11, 2008

Perl Monks é uma comunidade que visa a interatividade e compartilhamento de conhecimento entre programadores Perl, iniciantes e avançados. É uma achado, e já me cadastrei.

Junte-se ao monastério e siga a trilha que nos levará em direção à iluminação junto com os maiores monges da programação!

www.perlmonks.org

Writing serious Perl

novembro 10, 2008

Esse tutorial é fundamental. É um dos mais cotados no del.icio.us. Já imprimi e estou testando as dicas.
Explica a melhor maneira de trabalhar com Packages e orientação a objetos. Conhecimento básico em Perl é necessário para um entendimento total.

http://www.netalive.org/tinkering/serious-perl/