Beginning of dzilization
[gitmo/Moose.git] / lib / Moose / Meta / Role / Composite.pm
CommitLineData
fb1e11d5 1package Moose::Meta::Role::Composite;
2
3use strict;
4use warnings;
5use metaclass;
6
21f1e231 7use Scalar::Util 'blessed';
fb1e11d5 8
fb1e11d5 9our $AUTHORITY = 'cpan:STEVAN';
10
11use base 'Moose::Meta::Role';
12
13# NOTE:
d03bd989 14# we need to override the ->name
fb1e11d5 15# method from Class::MOP::Package
d03bd989 16# since we don't have an actual
fb1e11d5 17# package for this.
18# - SL
19__PACKAGE__->meta->add_attribute('name' => (reader => 'name'));
20
21# NOTE:
d03bd989 22# Again, since we don't have a real
23# package to store our methods in,
24# we use a HASH ref instead.
fb1e11d5 25# - SL
0385d05e 26__PACKAGE__->meta->add_attribute('_methods' => (
27 reader => '_method_map',
fb1e11d5 28 default => sub { {} }
29));
30
7071e2cb 31__PACKAGE__->meta->add_attribute(
32 'application_role_summation_class',
33 reader => 'application_role_summation_class',
34 default => 'Moose::Meta::Role::Application::RoleSummation',
35);
36
fb1e11d5 37sub new {
38 my ($class, %params) = @_;
12d8c847 39
fb1e11d5 40 # the roles param is required ...
70ea9161 41 foreach ( @{$params{roles}} ) {
42 unless ( $_->isa('Moose::Meta::Role') ) {
43 require Moose;
44 Moose->throw_error("The list of roles must be instances of Moose::Meta::Role, not $_");
45 }
46 }
12d8c847 47
48 my @composition_roles = map {
4701ceff 49 $_->composition_class_roles
12d8c847 50 } @{ $params{roles} };
51
52 if (@composition_roles) {
53 my $meta = Moose::Meta::Class->create_anon_class(
54 superclasses => [ $class ],
55 roles => [ @composition_roles ],
56 cache => 1,
57 );
12d8c847 58 $class = $meta->name;
59 }
60
fb1e11d5 61 # and the name is created from the
62 # roles if one has not been provided
63 $params{name} ||= (join "|" => map { $_->name } @{$params{roles}});
e606ae5f 64 $class->_new(\%params);
fb1e11d5 65}
66
87e63626 67# This is largely a cope of what's in Moose::Meta::Role (itself
68# largely a copy of Class::MOP::Class). However, we can't actually
69# call add_package_symbol, because there's no package to which which
70# add the symbol.
71sub add_method {
fb1e11d5 72 my ($self, $method_name, $method) = @_;
70ea9161 73
74 unless ( defined $method_name && $method_name ) {
75 Moose->throw_error("You must define a method name");
76 }
87e63626 77
78 my $body;
79 if (blessed($method)) {
80 $body = $method->body;
81 if ($method->package_name ne $self->name) {
82 $method = $method->clone(
83 package_name => $self->name,
d03bd989 84 name => $method_name
87e63626 85 ) if $method->can('clone');
86 }
87 }
88 else {
89 $body = $method;
90 $method = $self->wrap_method_body( body => $body, name => $method_name );
91 }
fb1e11d5 92
0385d05e 93 $self->_method_map->{$method_name} = $method;
94}
95
96sub get_method_list {
97 my $self = shift;
98 return keys %{ $self->_method_map };
99}
100
723576c6 101sub _get_local_methods {
102 my $self = shift;
103 return values %{ $self->_method_map };
104}
105
0385d05e 106sub has_method {
107 my ($self, $method_name) = @_;
108
109 return exists $self->_method_map->{$method_name};
110}
111
112sub get_method {
113 my ($self, $method_name) = @_;
114
115 return $self->_method_map->{$method_name};
fb1e11d5 116}
117
7071e2cb 118sub apply_params {
119 my ($self, $role_params) = @_;
120 Class::MOP::load_class($self->application_role_summation_class);
121
122 $self->application_role_summation_class->new(
123 role_params => $role_params,
124 )->apply($self);
125
126 return $self;
127}
128
6e04cb0e 129sub reinitialize {
f785aad8 130 my ( $class, $old_meta, @args ) = @_;
131
132 Moose->throw_error(
133 'Moose::Meta::Role::Composite instances can only be reinitialized from an existing metaclass instance'
134 )
135 if !blessed $old_meta
136 || !$old_meta->isa('Moose::Meta::Role::Composite');
137
138 my %existing_classes = map { $_ => $old_meta->$_() } qw(
139 application_role_summation_class
140 );
141
142 return $old_meta->meta->clone_object( $old_meta, %existing_classes, @args );
6e04cb0e 143}
144
fb1e11d5 1451;
146
ad46f524 147# ABSTRACT: An object to represent the set of roles
148
fb1e11d5 149__END__
150
151=pod
152
fb1e11d5 153=head1 DESCRIPTION
154
da5cc486 155A composite is a role that consists of a set of two or more roles.
156
157The API of a composite role is almost identical to that of a regular
158role.
159
160=head1 INHERITANCE
161
162C<Moose::Meta::Role::Composite> is a subclass of L<Moose::Meta::Role>.
163
fb1e11d5 164=head2 METHODS
165
166=over 4
167
da5cc486 168=item B<< Moose::Meta::Role::Composite->new(%options) >>
fb1e11d5 169
da5cc486 170This returns a new composite role object. It accepts the same
171options as its parent class, with a few changes:
fb1e11d5 172
da5cc486 173=over 8
fb1e11d5 174
da5cc486 175=item * roles
fb1e11d5 176
da5cc486 177This option is an array reference containing a list of
178L<Moose::Meta::Role> object. This is a required option.
179
180=item * name
181
182If a name is not given, one is generated from the roles provided.
183
7071e2cb 184=item * apply_params(\%role_params)
185
186Creates a new RoleSummation role application with C<%role_params> and applies
187the composite role to it. The RoleSummation role application class used is
188determined by the composite role's C<application_role_summation_class>
189attribute.
190
6e04cb0e 191=item * reinitialize($metaclass)
192
193Like C<< Class::MOP::Package->reinitialize >>, but doesn't allow passing a
194string with the package name, as there is no real package for composite roles.
195
da5cc486 196=back
fb1e11d5 197
198=back
199
200=head1 BUGS
201
d4048ef3 202See L<Moose/BUGS> for details on reporting bugs.
fb1e11d5 203
e606ae5f 204=cut