does
[gitmo/Moose.git] / lib / Moose / Meta / Role.pm
CommitLineData
e185c027 1
2package Moose::Meta::Role;
3
4use strict;
5use warnings;
6use metaclass;
7
8use Carp 'confess';
9
ef333f17 10our $VERSION = '0.02';
e185c027 11
12__PACKAGE__->meta->add_attribute('role_meta' => (
13 reader => 'role_meta'
14));
15
16__PACKAGE__->meta->add_attribute('attribute_map' => (
17 reader => 'get_attribute_map',
18 default => sub { {} }
19));
20
21__PACKAGE__->meta->add_attribute('method_modifier_map' => (
22 reader => 'get_method_modifier_map',
23 default => sub {
24 return {
25 before => {},
26 after => {},
27 around => {},
78cd1d3b 28 override => {}
e185c027 29 };
30 }
31));
32
33sub new {
34 my $class = shift;
35 my %options = @_;
a7d0cd00 36 $options{role_meta} = Class::MOP::Class->initialize(
37 $options{role_name},
38 ':method_metaclass' => 'Moose::Meta::Role::Method'
39 );
e185c027 40 my $self = $class->meta->new_object(%options);
41 return $self;
42}
43
78cd1d3b 44sub apply {
45 my ($self, $other) = @_;
46
47 foreach my $attribute_name ($self->get_attribute_list) {
48 # skip it if it has one already
49 next if $other->has_attribute($attribute_name);
50 # add it, although it could be overriden
51 $other->add_attribute(
52 $attribute_name,
53 %{$self->get_attribute($attribute_name)}
54 );
55 }
56
57 foreach my $method_name ($self->get_method_list) {
58 # skip it if it has one already
59 next if $other->has_method($method_name);
60 # add it, although it could be overriden
a7d0cd00 61 $other->alias_method(
78cd1d3b 62 $method_name,
63 $self->get_method($method_name)
64 );
65 }
66
67 foreach my $method_name ($self->get_method_modifier_list('override')) {
68 # skip it if it has one already
69 next if $other->has_method($method_name);
70 # add it, although it could be overriden
71 $other->add_override_method_modifier(
72 $method_name,
73 $self->get_method_modifier('override' => $method_name),
74 $self->name
75 );
76 }
77
78 foreach my $method_name ($self->get_method_modifier_list('before')) {
79 $other->add_before_method_modifier(
80 $method_name,
81 $self->get_method_modifier('before' => $method_name)
82 );
83 }
84
85 foreach my $method_name ($self->get_method_modifier_list('after')) {
86 $other->add_after_method_modifier(
87 $method_name,
88 $self->get_method_modifier('after' => $method_name)
89 );
90 }
91
92 foreach my $method_name ($self->get_method_modifier_list('around')) {
93 $other->add_around_method_modifier(
94 $method_name,
95 $self->get_method_modifier('around' => $method_name)
96 );
97 }
98
ef333f17 99 ## add the roles and set does()
100
101 $other->add_role($self);
102
103 # NOTE:
104 # this will not replace a locally
105 # defined does() method, those
106 # should work as expected since
107 # they are working off the same
108 # metaclass.
109 # It will override an inherited
110 # does() method though, since
111 # it needs to add this new metaclass
112 # to the mix.
113
114 $other->add_method('does' => sub {
115 my (undef, $role_name) = @_;
116 (defined $role_name)
117 || confess "You much supply a role name to does()";
118 foreach my $class ($other->class_precedence_list) {
119 return 1
120 if $other->initialize($class)->does_role($role_name);
121 }
122 return 0;
123 }) unless $other->has_method('does');
78cd1d3b 124}
125
e185c027 126# NOTE:
127# we delegate to some role_meta methods for convience here
128# the Moose::Meta::Role is meant to be a read-only interface
129# to the underlying role package, if you want to manipulate
130# that, just use ->role_meta
131
132sub name { (shift)->role_meta->name }
133sub version { (shift)->role_meta->version }
134
135sub get_method { (shift)->role_meta->get_method(@_) }
136sub has_method { (shift)->role_meta->has_method(@_) }
137sub get_method_list {
138 my ($self) = @_;
139 # meta is not applicable in this context,
140 # if you want to see it use the ->role_meta
141 grep { !/^meta$/ } $self->role_meta->get_method_list;
142}
143
144# ... however the items in statis (attributes & method modifiers)
145# can be removed and added to through this API
146
147# attributes
148
149sub add_attribute {
150 my ($self, $name, %attr_desc) = @_;
151 $self->get_attribute_map->{$name} = \%attr_desc;
152}
153
154sub has_attribute {
155 my ($self, $name) = @_;
156 exists $self->get_attribute_map->{$name} ? 1 : 0;
157}
158
159sub get_attribute {
160 my ($self, $name) = @_;
161 $self->get_attribute_map->{$name}
162}
163
164sub remove_attribute {
165 my ($self, $name) = @_;
166 delete $self->get_attribute_map->{$name}
167}
168
169sub get_attribute_list {
170 my ($self) = @_;
171 keys %{$self->get_attribute_map};
172}
173
174# method modifiers
175
176sub add_method_modifier {
177 my ($self, $modifier_type, $method_name, $method) = @_;
178 $self->get_method_modifier_map->{$modifier_type}->{$method_name} = $method;
179}
180
181sub has_method_modifier {
182 my ($self, $modifier_type, $method_name) = @_;
183 exists $self->get_method_modifier_map->{$modifier_type}->{$method_name} ? 1 : 0
184}
185
186sub get_method_modifier {
187 my ($self, $modifier_type, $method_name) = @_;
188 $self->get_method_modifier_map->{$modifier_type}->{$method_name};
189}
190
191sub remove_method_modifier {
192 my ($self, $modifier_type, $method_name) = @_;
193 delete $self->get_method_modifier_map->{$modifier_type}->{$method_name};
194}
195
196sub get_method_modifier_list {
197 my ($self, $modifier_type) = @_;
198 keys %{$self->get_method_modifier_map->{$modifier_type}};
199}
200
a7d0cd00 201package Moose::Meta::Role::Method;
202
203use strict;
204use warnings;
205
206our $VERSION = '0.01';
207
208use base 'Class::MOP::Method';
e185c027 209
2101;
211
212__END__
213
214=pod
215
216=head1 NAME
217
218Moose::Meta::Role - The Moose Role metaclass
219
220=head1 DESCRIPTION
221
79592a54 222Moose's Roles are being actively developed, please see L<Moose::Role>
223for more information.
224
e185c027 225=head1 METHODS
226
227=over 4
228
229=item B<meta>
230
231=item B<new>
232
78cd1d3b 233=item B<apply>
234
e185c027 235=back
236
237=over 4
238
239=item B<name>
240
241=item B<version>
242
243=item B<role_meta>
244
245=back
246
247=over 4
248
249=item B<get_method>
250
251=item B<has_method>
252
253=item B<get_method_list>
254
255=back
256
257=over 4
258
259=item B<add_attribute>
260
261=item B<has_attribute>
262
263=item B<get_attribute>
264
265=item B<get_attribute_list>
266
267=item B<get_attribute_map>
268
269=item B<remove_attribute>
270
271=back
272
273=over 4
274
275=item B<add_method_modifier>
276
277=item B<get_method_modifier>
278
279=item B<has_method_modifier>
280
281=item B<get_method_modifier_list>
282
283=item B<get_method_modifier_map>
284
285=item B<remove_method_modifier>
286
287=back
288
289=head1 BUGS
290
291All complex software has bugs lurking in it, and this module is no
292exception. If you find a bug please either email me, or add the bug
293to cpan-RT.
294
295=head1 AUTHOR
296
297Stevan Little E<lt>stevan@iinteractive.comE<gt>
298
299=head1 COPYRIGHT AND LICENSE
300
301Copyright 2006 by Infinity Interactive, Inc.
302
303L<http://www.iinteractive.com>
304
305This library is free software; you can redistribute it and/or modify
306it under the same terms as Perl itself.
307
308=cut