Vamos começar com este código feio.
sub grow {
my ($self) = @_;
my $moustache = $self->app->moustaches->create({});
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $moustache->id );
}
sub show {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$self->stash( moustache => $moustache );
}
sub trim {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
my $moustache = $self->app->moustaches->find( $self->param('id') );
if (!$moustache) {
$self->render_not_found;
}
$moustache->delete;
$self->res->code(204);
}
A primeira refatoração agradável que podemos fazer aqui é definir um atributo com um retorno de chamada do construtor lento.
has 'moustache' => sub {
my ($self) = @_;
return $self->app->moustaches->find( $self->param('id') );
};
sub grow {
my ($self) = @_;
$self->moustache( $self->app->moustaches->create({}) );
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $self->moustache->id );
}
sub show {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->stash( moustache => $self->moustache );
}
sub trim {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
if ( !$self->moustache ) {
$self->render_not_found;
}
$self->moustache->delete;
$self->res->code(204);
}
O próximo candidato óbvio para refatoração é a verificação de existência, mas não há nenhum análogo de Rails before_filter
no Mojolious. Felizmente, há um bom módulo Class::Method::Modifiers
, que é usado Moo
, aliás.
use Class::Method::Modifiers;
has 'moustache' => sub {
my ($self) = @_;
return $self->app->moustaches->find( $self->param('id') );
};
around [ qw{ show trim shave } ] => &_assert_moustache;
sub grow {
my ($self) = @_;
$self->moustache( $self->app->moustaches->create({}) );
$self->res->code(303);
$self->redirect_to( 'show_moustache', id => $self->moustache->id );
}
sub show {
my ($self) = @_;
$self->stash( moustache => $self->moustache );
}
sub trim {
my ($self) = @_;
$self->moustache->trim;
$self->res->code(204);
}
sub shave {
my ($self) = @_;
$self->moustache->delete;
$self->res->code(204);
}
sub _assert_moustache {
my $orig = shift;
my $self = shift;
if ( !$self->moustache ) {
$self->render_not_found;
}
return $orig->($self);
}
Note que para poder impedir a execução do método, ao qual aplicamos um filtro, precisamos de usar around
, porque before
não o permite.