Add CompositeRole
[gitmo/MooseX-ClassAttribute.git] / lib / MooseX / ClassAttribute / Trait / CompositeRole.pm
1 package MooseX::ClassAttribute::Trait::CompositeRole;
2
3 use strict;
4 use warnings;
5
6 use Moose::Util::MetaRole;
7 use Moose::Util qw(does_role);
8
9 use namespace::autoclean;
10 use Moose::Role;
11 with 'MooseX::ClassAttribute::Trait::Role';
12
13 sub _merge_class_attributes {
14     my $self = shift;
15
16     my @all_attributes;
17     foreach my $role (@{ $self->get_roles }) {
18         if (does_role($role, 'MooseX::ClassAttribute::Trait::Role')) {
19             push @all_attributes,
20                 map { $role->get_class_attribute($_) }
21                 $role->get_class_attribute_list;
22         }
23     }
24
25     my %seen;
26
27     foreach my $attribute (@all_attributes) {
28         my $name = $attribute->name;
29         if (exists $seen{$name}) {
30             next if $seen{$name} == $attribute;
31
32             require Moose;
33             Moose->throw_error( "Role '"
34                     . $self->name()
35                     . "' has encountered a class attribute conflict "
36                     . "during composition. This is fatal error and cannot be disambiguated."
37             );
38         }
39         $seen{$name} = $attribute;
40     }
41     foreach my $attribute (@all_attributes) {
42         $self->add_class_attribute( $attribute->clone() );
43     }
44
45     return keys %seen;
46 }
47
48 around apply_params => sub {
49     my ($orig, $self, @args) = @_;
50
51     my $metarole = Moose::Util::MetaRole::apply_metaroles(
52         for => $self->$orig(@args),
53         role_metaroles => {
54             application_to_class =>
55                 ['MooseX::ClassAttribute::Trait::Application::ToClass'],
56             application_to_role =>
57                 ['MooseX::ClassAttribute::Trait::Application::ToRole'],
58         },
59     );
60     $metarole->_merge_class_attributes;
61     return $metarole;
62 };
63
64 1;
65
66 # ABSTRACT: A trait that supports applying multiple roles at once
67
68 __END__
69
70 =pod
71
72 =head1 DESCRIPTION
73
74 This trait is used to allow the application of multiple roles (one
75 or more of which contain class attributes) to a class or role.
76
77 =head1 BUGS
78
79 See L<MooseX::ClassAttribute> for details.
80
81 =cut