method modifier with regexp is done now
[gitmo/Moose.git] / lib / Moose / Role.pm
CommitLineData
e185c027 1
2package Moose::Role;
3
4use strict;
5use warnings;
6
e65dccbc 7use Scalar::Util 'blessed';
e185c027 8use Carp 'confess';
e185c027 9
c4538447 10use Data::OptList;
2d562421 11use Sub::Exporter;
12
1b2aea39 13our $VERSION = '0.09';
d44714be 14our $AUTHORITY = 'cpan:STEVAN';
e185c027 15
d7d8a8c7 16use Moose ();
17use Moose::Util ();
e65dccbc 18
e185c027 19use Moose::Meta::Role;
7eaef7ad 20use Moose::Util::TypeConstraints;
e185c027 21
2d562421 22{
23 my ( $CALLER, %METAS );
24
25 sub _find_meta {
7eaef7ad 26 my $role = $CALLER;
2d562421 27
7eaef7ad 28 return $METAS{$role} if exists $METAS{$role};
fb1e11d5 29
7eaef7ad 30 # make a subtype for each Moose class
e324865b 31 role_type $role unless find_type_constraint($role);
2d562421 32
fb1e11d5 33 my $meta;
34 if ($role->can('meta')) {
35 $meta = $role->meta();
36 (blessed($meta) && $meta->isa('Moose::Meta::Role'))
68efb014 37 || confess "You already have a &meta function, but it does not return a Moose::Meta::Role";
fb1e11d5 38 }
39 else {
40 $meta = Moose::Meta::Role->initialize($role);
41 $meta->alias_method('meta' => sub { $meta });
42 }
2d562421 43
7eaef7ad 44 return $METAS{$role} = $meta;
2d562421 45 }
fb1e11d5 46
47
48 my %exports = (
2d562421 49 extends => sub {
50 my $meta = _find_meta();
1b2aea39 51 return Class::MOP::subname('Moose::Role::extends' => sub {
2d562421 52 confess "Moose::Role does not currently support 'extends'"
1b2aea39 53 });
fb1e11d5 54 },
55 with => sub {
56 my $meta = _find_meta();
1b2aea39 57 return Class::MOP::subname('Moose::Role::with' => sub (@) {
d7d8a8c7 58 Moose::Util::apply_all_roles($meta, @_)
1b2aea39 59 });
fb1e11d5 60 },
2d562421 61 requires => sub {
62 my $meta = _find_meta();
1b2aea39 63 return Class::MOP::subname('Moose::Role::requires' => sub (@) {
68117c45 64 confess "Must specify at least one method" unless @_;
2d562421 65 $meta->add_required_methods(@_);
1b2aea39 66 });
fb1e11d5 67 },
d79e62fd 68 excludes => sub {
69 my $meta = _find_meta();
1b2aea39 70 return Class::MOP::subname('Moose::Role::excludes' => sub (@) {
68117c45 71 confess "Must specify at least one role" unless @_;
d79e62fd 72 $meta->add_excluded_roles(@_);
1b2aea39 73 });
fb1e11d5 74 },
2d562421 75 has => sub {
76 my $meta = _find_meta();
1b2aea39 77 return Class::MOP::subname('Moose::Role::has' => sub ($;%) {
fb1e11d5 78 my ($name, %options) = @_;
79 $meta->add_attribute($name, %options)
1b2aea39 80 });
fb1e11d5 81 },
2d562421 82 before => sub {
83 my $meta = _find_meta();
1b2aea39 84 return Class::MOP::subname('Moose::Role::before' => sub (@&) {
0558683c 85 my $code = pop @_;
401cb5a6 86 do {
87 confess "Moose::Role do not currently support "
88 . ref($_)
89 . " references for before method modifiers"
90 if ref $_;
91 $meta->add_before_method_modifier($_, $code)
92 } for @_;
1b2aea39 93 });
fb1e11d5 94 },
2d562421 95 after => sub {
96 my $meta = _find_meta();
1b2aea39 97 return Class::MOP::subname('Moose::Role::after' => sub (@&) {
fb1e11d5 98 my $code = pop @_;
401cb5a6 99 do {
100 confess "Moose::Role do not currently support "
101 . ref($_)
102 . " references for after method modifiers"
103 if ref $_;
104 $meta->add_after_method_modifier($_, $code)
105 } for @_;
1b2aea39 106 });
fb1e11d5 107 },
2d562421 108 around => sub {
109 my $meta = _find_meta();
1b2aea39 110 return Class::MOP::subname('Moose::Role::around' => sub (@&) {
fb1e11d5 111 my $code = pop @_;
401cb5a6 112 do {
113 confess "Moose::Role do not currently support "
114 . ref($_)
115 . " references for around method modifiers"
116 if ref $_;
117 $meta->add_around_method_modifier($_, $code)
118 } for @_;
1b2aea39 119 });
fb1e11d5 120 },
3f9e4b0a 121 # see Moose.pm for discussion
fb1e11d5 122 super => sub {
401cb5a6 123 return Class::MOP::subname('Moose::Role::super' => sub {
124 return unless $Moose::SUPER_BODY; $Moose::SUPER_BODY->(@Moose::SUPER_ARGS)
125 });
2d562421 126 },
127 override => sub {
128 my $meta = _find_meta();
1b2aea39 129 return Class::MOP::subname('Moose::Role::override' => sub ($&) {
0558683c 130 my ($name, $code) = @_;
131 $meta->add_override_method_modifier($name, $code);
1b2aea39 132 });
fb1e11d5 133 },
2d562421 134 inner => sub {
135 my $meta = _find_meta();
1b2aea39 136 return Class::MOP::subname('Moose::Role::inner' => sub {
0558683c 137 confess "Moose::Role cannot support 'inner'";
1b2aea39 138 });
fb1e11d5 139 },
2d562421 140 augment => sub {
141 my $meta = _find_meta();
1b2aea39 142 return Class::MOP::subname('Moose::Role::augment' => sub {
06b30515 143 confess "Moose::Role cannot support 'augment'";
1b2aea39 144 });
fb1e11d5 145 },
2d562421 146 confess => sub {
147 return \&Carp::confess;
148 },
149 blessed => sub {
150 return \&Scalar::Util::blessed;
fb1e11d5 151 }
152 );
2d562421 153
fb1e11d5 154 my $exporter = Sub::Exporter::build_exporter({
2d562421 155 exports => \%exports,
156 groups => {
157 default => [':all']
158 }
159 });
fb1e11d5 160
2d562421 161 sub import {
fc9a40d7 162 $CALLER =
163 ref $_[1] && defined $_[1]->{into} ? $_[1]->{into}
164 : ref $_[1]
165 && defined $_[1]->{into_level} ? caller( $_[1]->{into_level} )
166 : caller();
167
86dd5d11 168 # this works because both pragmas set $^H (see perldoc perlvar)
169 # which affects the current compilation - i.e. the file who use'd
170 # us - which is why we don't need to do anything special to make
171 # it affect that file rather than this one (which is already compiled)
fb1e11d5 172
c235cd98 173 strict->import;
fb1e11d5 174 warnings->import;
2d562421 175
176 # we should never export to main
177 return if $CALLER eq 'main';
178
179 goto $exporter;
180 };
181
e185c027 182}
183
1841;
185
186__END__
187
188=pod
189
190=head1 NAME
191
192Moose::Role - The Moose Role
193
76d37e5a 194=head1 SYNOPSIS
195
196 package Eq;
85424612 197 use Moose::Role; # automatically turns on strict and warnings
fb1e11d5 198
e46edf94 199 requires 'equal';
fb1e11d5 200
201 sub no_equal {
76d37e5a 202 my ($self, $other) = @_;
203 !$self->equal($other);
204 }
fb1e11d5 205
76d37e5a 206 # ... then in your classes
fb1e11d5 207
76d37e5a 208 package Currency;
85424612 209 use Moose; # automatically turns on strict and warnings
fb1e11d5 210
76d37e5a 211 with 'Eq';
fb1e11d5 212
76d37e5a 213 sub equal {
214 my ($self, $other) = @_;
bdabd620 215 $self->as_float == $other->as_float;
76d37e5a 216 }
217
e185c027 218=head1 DESCRIPTION
219
85424612 220Role support in Moose is pretty solid at this point. However, the best
221documentation is still the the test suite. It is fairly safe to assume Perl 6
222style behavior and then either refer to the test suite, or ask questions on
223#moose if something doesn't quite do what you expect.
d44714be 224
85424612 225We are planning writing some more documentation in the near future, but nothing
226is ready yet, sorry.
76d37e5a 227
2c0cbef7 228=head1 EXPORTED FUNCTIONS
229
85424612 230Moose::Role currently supports all of the functions that L<Moose> exports, but
231differs slightly in how some items are handled (see L<CAVEATS> below for
232details).
76d37e5a 233
85424612 234Moose::Role also offers two role-specific keyword exports:
e185c027 235
236=over 4
237
2c0cbef7 238=item B<requires (@method_names)>
76d37e5a 239
fb1e11d5 240Roles can require that certain methods are implemented by any class which
85424612 241C<does> the role.
9e93dd19 242
2c0cbef7 243=item B<excludes (@role_names)>
244
9e93dd19 245Roles can C<exclude> other roles, in effect saying "I can never be combined
fb1e11d5 246with these C<@role_names>". This is a feature which should not be used
85424612 247lightly.
9e93dd19 248
2c0cbef7 249=back
250
251=head1 CAVEATS
252
85424612 253Role support has only a few caveats:
2c0cbef7 254
255=over 4
76d37e5a 256
76d37e5a 257=item *
258
fb1e11d5 259Roles cannot use the C<extends> keyword; it will throw an exception for now.
260The same is true of the C<augment> and C<inner> keywords (not sure those
261really make sense for roles). All other Moose keywords will be I<deferred>
85424612 262so that they can be applied to the consuming class.
76d37e5a 263
fb1e11d5 264=item *
2c0cbef7 265
85424612 266Role composition does its best to B<not> be order-sensitive when it comes to
267conflict resolution and requirements detection. However, it is order-sensitive
268when it comes to method modifiers. All before/around/after modifiers are
269included whenever a role is composed into a class, and then applied in the order
270in which the roles are used. This also means that there is no conflict for
271before/around/after modifiers.
2c0cbef7 272
85424612 273In most cases, this will be a non-issue; however, it is something to keep in
274mind when using method modifiers in a role. You should never assume any
2c0cbef7 275ordering.
276
277=item *
278
fb1e11d5 279The C<requires> keyword currently only works with actual methods. A method
280modifier (before/around/after and override) will not count as a fufillment
2c0cbef7 281of the requirement, and neither will an autogenerated accessor for an attribute.
282
85424612 283It is likely that attribute accessors will eventually be allowed to fufill those
284requirements, or we will introduce a C<requires_attr> keyword of some kind
285instead. This decision has not yet been finalized.
2c0cbef7 286
e185c027 287=back
288
289=head1 BUGS
290
fb1e11d5 291All complex software has bugs lurking in it, and this module is no
e185c027 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
db1ab48d 299Christian Hansen E<lt>chansen@cpan.orgE<gt>
98aae381 300
e185c027 301=head1 COPYRIGHT AND LICENSE
302
778db3ac 303Copyright 2006-2008 by Infinity Interactive, Inc.
e185c027 304
305L<http://www.iinteractive.com>
306
307This library is free software; you can redistribute it and/or modify
fb1e11d5 308it under the same terms as Perl itself.
e185c027 309
68117c45 310=cut