[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