[SP-pm] Subs

Solli Honorio shonorio at gmail.com
Sat Mar 23 05:23:20 PDT 2013


Só reafirmando o que foi escrito pelo pessoal :


Em 22 de março de 2013 20:27, Marcio - Google <marciorp em gmail.com> escreveu:

> Mongers,
>
> Mais algumas dúvidas sobre "boas práticas".
>
> 1. Tenho algumas funções (sub) que são comuns a mais de um aplicativo.
> Qual a forma mais simples, prática e elegante de compartilha-las entre
> vários scripts, sendo que todos ficam no mesmo diretório? Hoje, tenho o
> mesmo código repetido dentro do arquivo de cada script.
>
>
estou assumindo que vc possui um subset de código comum e que será
consumido por diversos scripts diferentes. A melhor maneira de fazer isto,
é através de módulos ! Cria um namespace para você e organize estes códigos
no name espace, mas atenção para o ORGANIZE.

Então criei, por exemplo, o MINHAEMPRESA::Util::DB para os códigos de banco
de dados, por exemplo. Mas faça isto de maneira muito genérica, evitando
coisas muito específicas como por exemplo que o código destes módulos tenha
usuários, senhas e diretórios. Estas coisas específicas devem ser
parametros.

Este módulo pode ser instalado no sistema, ou vc pode colocar ele numa
estrutura de diretório e utlizar o 'lib' para especificar onde o script tem
que procurar o módulo.


Vou dar um exemplo de como um módulo de código comum deve ser genérico.

<code>

package MINHAEMPRESA::Util::DB;

use Moose::Role;
use namespace::clean -except => 'meta';
use DBI;
use DBIx::Connector;

has db_server   => ( is => 'rw', isa => 'Str', default   => 'localhost' );
has db_user     => ( is => 'rw', isa => 'Str' );
has db_password => ( is => 'rw', isa => 'Str' );
has db_database => ( is => 'rw', isa => 'Str' );

has connection => (
    is      => 'ro',
    isa     => 'Any',
    lazy    => 1,
    builder => '_builder_conn'
);

sub _builder_conn {
    my $self = shift;
    my $dsn  = sprintf "DBI:mysql:database=%s; host=%s",
                    $self->db_database,
                    $self->db_server;

    return DBIx::Connector->new(
                $dsn,
                $self->db_user,
                $self->db_password,
                { 'RaiseError' => 1,
                  'mysql_enable_utf8' => 1,
                  'AutoCommit' => 1} );
}

sub do {
    my $self = shift;
    my $sql  = shift;
    my @data = @_;
    my $all  = $self->connection->run( fixup => sub { $_->do( $sql, undef,
@data ) });

    return $all;
}

sub execute {
    my $self = shift;
    my $sql  = shift;
    my @data = @_;
    my $sth  = $self->connection->run( fixup => sub { $_->prepare($sql); }
);
    my $all;

       $sth->execute( @data );

    while ( my $ref = $sth->fetchrow_hashref() ) {
        push @$all, $ref;
    }

    return $all || [];
}

42;




> 2. Tenho algumas funções (sub) que precisam retornar mais de uma
> informação, as vezes até 5. Hoje como não sei fazer isso,
> declaro variáveis no inicio do script e antes de chamar a sub, atribuo
> "undef" para as variáveis. Dentro da sub eu atribuo os valores que preciso
> a elas e depois da sub eu leio essas variáveis. Não me causa problema, só
> acho estranho e pouco elegante. Exemplo de retorno: Se deu erro (1 ou 0),
> Registro que deu erro (numérico), Descrição do Erro (string), Se conseguiu
> cancelar do IPBX (1 ou 0).
>

Existem várias técnicas, a que você está utilizando tem a desvantagem de
utilizar variáveis globais, o que pode ser ok para script (escrevo isto pq
como sysadmin e scripts pequenos utilizo bastante), mas considerando a
primeira pergunta já não fará sentido utilizar variável global para código
reutilizável.

Toda informação para a execução de uma sub tem que estar condida nela,
desta maneira se ela recebe dados externos, tem que receber via parametros
e se tem que retornar dados, também que que ser de maneira apropriada.

Estou considerando a tua pergunta do ponto de vista de retorno de
resultado, e aí podemos fazer de 2 formas :


   1. utilizar o return sempre e somente para retornar o resultado e NUNCA
   erro (no código que eu coloquei acima, só retorno o resultado da interação
   com o banco)
   2. na passagem de parametros, informar uma referência que deverá conter
   o resultado, e o retorno será um valor (código) que indica se ocorreu com
   sucesso a execução;

<code>

sub foo {

  my $param_1 = shift;

  my $param_2 = shift;

  $param_2 = eval { resultado de algum processamento };

  return 501 if $@;

  return 200;

}

my $bar;

if ( foo($alguma_coisa,\$bar) == 200 ) {

   # foi executada com sucesso e por isto estou aqui

   say $bar;

} else {

   # algo não foi bom, então vamos fazer algo diferente

}


<code>

Mas a técnica que eu prefiro é morrer quando ocorre um erro. Se ocorreu um
erro grave, o teu consumidor precisa saber disto imediatamente, e ele é
quem precisa tratar o erro. Então o mesmo código ficaria assim

 sub foo_with_die {

  my $param_1 = shift;

  my $param_2 = shift;

  $param_2 = eval { resultado de algum processamento };

  die { error_code => 500, error_message => $@ } if $@;

  return $param_2;

}

my $bar;

try {
 say foo($alguma_coisa,\$bar) == 200 );

} catch {

   # algo não foi bom, então vamos fazer algo diferente

};


<code>


> 3. Declaro as funções (sub) assim:
> sub NomeDaSub {
>    my ($NomeDoPrimeiroParametro, ..., $NomeDoUltimoParametro)=@_;
> }
>    Está certo? Ou tem uma técnica "mais" correta?
>

O Marcio Ferreira recomendou um excelente link sobre isto, nos avise se
você tiver dificuldade em compreender o conteúdo. E com já escreveu o
Vinceguerra, a gente não gosta muito de Uppercase nas variáveis e funções.


>
>
> Em tempo, não estão faltando artigos no Equinócio?
>

Isto significa que você ainda pode contribuir com algo, mas será preenchido
sim. Só estamos numa fase de garantir o wiskey das crianças também.


>
>
> [...]'s
>
> Marcio
>
> =begin disclaimer
>    Sao Paulo Perl Mongers: http://sao-paulo.pm.org/
>  SaoPaulo-pm mailing list: SaoPaulo-pm em pm.org
>  L<http://mail.pm.org/mailman/listinfo/saopaulo-pm>
> =end disclaimer
>
>


-- 
"o animal satisfeito dorme". - Guimarães Rosa
-------------- Pr?xima Parte ----------
Um anexo em HTML foi limpo...
URL: <http://mail.pm.org/pipermail/saopaulo-pm/attachments/20130323/e6ab518b/attachment-0001.html>


More information about the SaoPaulo-pm mailing list