--- /dev/null
+package Catalyst::Controller::ActionRole;
+BEGIN {
+ $Catalyst::Controller::ActionRole::VERSION = '0.14';
+}
+# ABSTRACT: Apply roles to action instances
+
+use Moose;
+use Class::MOP;
+use Catalyst::Utils;
+use Moose::Meta::Class;
+use String::RewritePrefix;
+use MooseX::Types::Moose qw/ArrayRef Str RoleName/;
+use List::Util qw(first);
+
+use namespace::clean -except => 'meta';
+
+extends 'Catalyst::Controller';
+
+
+__PACKAGE__->mk_classdata(qw/_action_role_prefix/);
+__PACKAGE__->_action_role_prefix([ 'Catalyst::ActionRole::' ]);
+
+
+has _action_role_args => (
+ traits => [qw(Array)],
+ isa => ArrayRef[Str],
+ init_arg => 'action_roles',
+ default => sub { [] },
+ handles => {
+ _action_role_args => 'elements',
+ },
+);
+
+has _action_roles => (
+ traits => [qw(Array)],
+ isa => ArrayRef[RoleName],
+ init_arg => undef,
+ lazy_build => 1,
+ handles => {
+ _action_roles => 'elements',
+ },
+);
+
+sub _build__action_roles {
+ my $self = shift;
+ my @roles = $self->_expand_role_shortname($self->_action_role_args);
+ Class::MOP::load_class($_) for @roles;
+ return \@roles;
+}
+
+sub BUILD {
+ my $self = shift;
+ # force this to run at object creation time
+ $self->_action_roles;
+}
+
+sub create_action {
+ my ($self, %args) = @_;
+
+ my $class = exists $args{attributes}->{ActionClass}
+ ? $args{attributes}->{ActionClass}->[0]
+ : $self->_action_class;
+
+ Class::MOP::load_class($class);
+
+ my @roles = ($self->_action_roles, @{ $args{attributes}->{Does} || [] });
+ if (@roles) {
+ Class::MOP::load_class($_) for @roles;
+ my $meta = Moose::Meta::Class->initialize($class)->create_anon_class(
+ superclasses => [$class],
+ roles => \@roles,
+ cache => 1,
+ );
+ $meta->add_method(meta => sub { $meta });
+ $class = $meta->name;
+ }
+
+ return $class->new(\%args);
+}
+
+sub _expand_role_shortname {
+ my ($self, @shortnames) = @_;
+ my $app = $self->_application;
+
+ my $prefix = $self->can('_action_role_prefix') ? $self->_action_role_prefix : ['Catalyst::ActionRole::'];
+ my @prefixes = (qq{${app}::ActionRole::}, @$prefix);
+
+ return String::RewritePrefix->rewrite(
+ { '' => sub {
+ my $loaded = Class::MOP::load_first_existing_class(
+ map { "$_$_[0]" } @prefixes
+ );
+ return first { $loaded =~ /^$_/ }
+ sort { length $b <=> length $a } @prefixes;
+ },
+ '~' => $prefixes[0],
+ '+' => '' },
+ @shortnames,
+ );
+}
+
+sub _parse_Does_attr {
+ my ($self, $app, $name, $value) = @_;
+ return Does => $self->_expand_role_shortname($value);
+}
+
+
+1;
+
+__END__
+=pod
+
+=head1 NAME
+
+Catalyst::Controller::ActionRole - Apply roles to action instances
+
+=head1 VERSION
+
+version 0.14
+
+=head1 SYNOPSIS
+
+ package MyApp::Controller::Foo;
+
+ use parent qw/Catalyst::Controller::ActionRole/;
+
+ sub bar : Local Does('Moo') { ... }
+
+=head1 DESCRIPTION
+
+This module allows to apply roles to the C<Catalyst::Action>s for different
+controller methods.
+
+For that a C<Does> attribute is provided. That attribute takes an argument,
+that determines the role, which is going to be applied. If that argument is
+prefixed with C<+>, it is assumed to be the full name of the role. If it's
+prefixed with C<~>, the name of your application followed by
+C<::ActionRole::> is prepended. If it isn't prefixed with C<+> or C<~>,
+the role name will be searched for in C<@INC> according to the rules for
+L<role prefix searching|/ROLE PREFIX SEARCHING>.
+
+Additionally it's possible to to apply roles to B<all> actions of a controller
+without specifying the C<Does> keyword in every action definition:
+
+ package MyApp::Controller::Bar
+
+ use parent qw/Catalyst::Controller::ActionRole/;
+
+ __PACKAGE__->config(
+ action_roles => ['Foo', '~Bar'],
+ );
+
+ # has Catalyst::ActionRole::Foo and MyApp::ActionRole::Bar applied
+ # if MyApp::ActionRole::Foo exists and is loadable, it will take
+ # precedence over Catalyst::ActionRole::Foo
+ sub moo : Local { ... }
+
+=head1 ATTRIBUTES
+
+=head2 _action_role_prefix
+
+This class attribute stores an array reference of role prefixes to search for
+role names in if they aren't prefixed with C<+> or C<~>. It defaults to
+C<[ 'Catalyst::ActionRole::' ]>. See L</role prefix searching>.
+
+=head2 _action_roles
+
+This attribute stores an array reference of role names that will be applied to
+every action of this controller. It can be set by passing a C<action_roles>
+argument to the constructor. The same expansions as for C<Does> will be
+performed.
+
+=head1 ROLE PREFIX SEARCHING
+
+Roles specified with no prefix are looked up under a set of role prefixes. The
+first prefix is always C<MyApp::ActionRole::> (with C<MyApp> replaced as
+appropriate for your application); the following prefixes are taken from the
+C<_action_role_prefix> attribute.
+
+=for Pod::Coverage BUILD
+
+=head1 AUTHORS
+
+ Florian Ragwitz <rafl@debian.org>
+ Hans Dieter Pearcey <hdp@weftsoar.net>
+
+=head1 COPYRIGHT AND LICENSE
+
+This software is copyright (c) 2010 by Florian Ragwitz.
+
+This is free software; you can redistribute it and/or modify it under
+the same terms as the Perl 5 programming language system itself.
+
+=cut
+