2 nice techniques to refactor Mojolicious controllers
Let's start with this ugly piece of code.
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);
}
The first nice refactoring we can do here is to define an attribute with a lazy builder callback.
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);
}
The next obvious candidate for refactoring is the existence check, but there's no analogue of Rails' before_filter in Mojolious. Fortunately there's a nice module Class::Method::Modifiers, which is used in Moo, by the way.
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, that in order to make it possible to prevent execution of the method, that we apply a filter to, we need to use around, because before doesn't allow it.
Written by Ivan Fomichev
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
 #Perl 
Authors
janosgyerik
25.61K
Jean-Remy Duboc
12.48K
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#