Loadable Traits for Catalyst Components
Over the past few months we've developed a loadable traits system for Catalyst components. Components are Models, Views, and Controllers.
Traits are Moose::Roles, that are applied to classes dynamically.
Roles for Controllers, with actual actions, are possible thanks to Tomas Doran's (t0m) and Florian Ragwitz's (rafl) work on MooseX::MethodAttributes.
Loadable traits support is provided by CatalystX::Component::Traits, based on Jonathan Rockway's (jrockway) work on MooseX::Traits.
An Example
Let's make a simple Model and some traits for it, so you can see how you might make use of this feature in your own projects.
package SampleApp::Model::Fortune;
use Moose;
use namespace::autoclean;
extends 'Catalyst::Model';
with 'CatalystX::Component::Traits';
has '+_trait_merge' => (default => 1);
__PACKAGE__->config->{traits} = [ 'OffensiveToo' ];
has fortune_command => (is => 'rw', lazy_build => 1);
has fortune_command_opts => (is => 'rw', lazy_build => 1);
sub get_fortune {
my $self = shift;
my $command =
$self->fortune_command . ' ' . $self->fortune_command_opts;
my $output = qx{$command};
chomp $output;
return $output;
}
sub _build_fortune_command { 'fortune' }
sub _build_fortune_command_opts { '' }
__PACKAGE__->meta->make_immutable;
package SampleApp::TraitFor::Model::Fortune::Russian;
use Moose::Role;
use namespace::autoclean;
has percent_russian => (is => 'rw', default => 100);
around fortune_command_opts => sub {
my ($next, $self) = (shift, shift);
my $dbs =
$self->percent_russian . '% ru'
. ' ' .
(100 - $self->percent_russian) . '% /usr/share/games/fortunes';
return $self->$next(@_) . ' ' . $dbs;
};
package SampleApp::TraitFor::Model::Fortune::Offensive;
use Moose::Role;
use namespace::autoclean;
around fortune_command_opts => sub {
my ($next, $self) = (shift, shift);
return '-o ' . $self->$next(@_);
};
package SampleApp::TraitFor::Model::Fortune::OffensiveToo;
use Moose::Role;
use namespace::autoclean;
around fortune_command_opts => sub {
my ($next, $self) = (shift, shift);
my $opts = $self->$next(@_);
$opts =~ s/-o //; # if Offensive trait is enabled, edit it out
return "-a $opts";
};
1;
Notice we turned on the "TRAIT MERGING" in CatalystX::Component::Traits
feature, and we set a default list of traits to include (OffensiveToo.)
An action to make use of our new Model:
sub index :Path :Args(0) {
my ($self, $c) = @_;
$c->res->content_type('text/plain; charset=utf-8');
$c->res->body($c->model('Fortune')->get_fortune);
}
Now, suppose in production you don't want your customers to see offensive fortunes, and you want 50% of the fortunes to be in Russian.
Just put the following into the .conf:
<Model::Fortune>
traits -OffensiveToo
traits Russian
percent_russian 50
</Model::Fortune>
We turned off the OffensiveToo trait, added the Russian trait and set an
attribute that was defined in a trait directly from the config file.
Hopefully this demonstrates some of the power of using Moose::Roles in your Catalyst applications.
See also the Catalyst::ActionRole:: namespace for other awesome applications
of Moose::Roles.
Components that use Loadable Traits
Catalyst::Model::DBIC::Schema
The model for using DBIx::Class in Catalyst has the following traits available on CPAN:
- Catalyst::TraitFor::Model::DBIC::Schema::Caching
-
For caching the results of queries.
- Catalyst::TraitFor::Model::DBIC::Schema::Replicated
-
For quering replicated MySQL databases.
- Catalyst::TraitFor::Model::DBIC::Schema::QueryLog
-
DBIx::Class::QueryLog support, for analyzing query performance.
CatalystX::SimpleLogin
A reusable login/logout component for Catalyst that is injected through the Plugin list. It has the following traits available on CPAN:
- CatalystX::SimpleLogin::TraitFor::Controller::Login::Logout
-
Adds logout support.
- CatalystX::SimpleLogin::TraitFor::Controller::Login::WithRedirect
-
Combines with Catalyst::ActionRole::NeedsLogin to mark actions as requiring a login and redirecting back to the originally requested page.
- CatalystX::SimpleLogin::TraitFor::Controller::Login::RenderAsTTTemplate
-
Provides a Template template for rendering the login form, for use with Catalyst::View::TT.
AUTHOR
Caelum: Rafael Kitover <rkitover@cpan.org>