fixed the test for method modifiers
[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 @_;
86 $meta->add_before_method_modifier($_, $code) for @_;
1b2aea39 87 });
fb1e11d5 88 },
2d562421 89 after => sub {
90 my $meta = _find_meta();
1b2aea39 91 return Class::MOP::subname('Moose::Role::after' => sub (@&) {
fb1e11d5 92 my $code = pop @_;
93 $meta->add_after_method_modifier($_, $code) for @_;
1b2aea39 94 });
fb1e11d5 95 },
2d562421 96 around => sub {
97 my $meta = _find_meta();
1b2aea39 98 return Class::MOP::subname('Moose::Role::around' => sub (@&) {
fb1e11d5 99 my $code = pop @_;
100 $meta->add_around_method_modifier($_, $code) for @_;
1b2aea39 101 });
fb1e11d5 102 },
3f9e4b0a 103 # see Moose.pm for discussion
fb1e11d5 104 super => sub {
1b2aea39 105 return Class::MOP::subname('Moose::Role::super' => sub { return unless $Moose::SUPER_BODY; $Moose::SUPER_BODY->(@Moose::SUPER_ARGS) })
2d562421 106 },
3f9e4b0a 107 #next => sub {
108 # return subname 'Moose::Role::next' => sub { @_ = @Moose::SUPER_ARGS; goto \&next::method };
109 #},
2d562421 110 override => sub {
111 my $meta = _find_meta();
1b2aea39 112 return Class::MOP::subname('Moose::Role::override' => sub ($&) {
0558683c 113 my ($name, $code) = @_;
114 $meta->add_override_method_modifier($name, $code);
1b2aea39 115 });
fb1e11d5 116 },
2d562421 117 inner => sub {
118 my $meta = _find_meta();
1b2aea39 119 return Class::MOP::subname('Moose::Role::inner' => sub {
0558683c 120 confess "Moose::Role cannot support 'inner'";
1b2aea39 121 });
fb1e11d5 122 },
2d562421 123 augment => sub {
124 my $meta = _find_meta();
1b2aea39 125 return Class::MOP::subname('Moose::Role::augment' => sub {
06b30515 126 confess "Moose::Role cannot support 'augment'";
1b2aea39 127 });
fb1e11d5 128 },
2d562421 129 confess => sub {
130 return \&Carp::confess;
131 },
132 blessed => sub {
133 return \&Scalar::Util::blessed;
fb1e11d5 134 }
135 );
2d562421 136
fb1e11d5 137 my $exporter = Sub::Exporter::build_exporter({
2d562421 138 exports => \%exports,
139 groups => {
140 default => [':all']
141 }
142 });
fb1e11d5 143
2d562421 144 sub import {
fc9a40d7 145 $CALLER =
146 ref $_[1] && defined $_[1]->{into} ? $_[1]->{into}
147 : ref $_[1]
148 && defined $_[1]->{into_level} ? caller( $_[1]->{into_level} )
149 : caller();
150
86dd5d11 151 # this works because both pragmas set $^H (see perldoc perlvar)
152 # which affects the current compilation - i.e. the file who use'd
153 # us - which is why we don't need to do anything special to make
154 # it affect that file rather than this one (which is already compiled)
fb1e11d5 155
c235cd98 156 strict->import;
fb1e11d5 157 warnings->import;
2d562421 158
159 # we should never export to main
160 return if $CALLER eq 'main';
161
162 goto $exporter;
163 };
164
e185c027 165}
166
1671;
168
169__END__
170
171=pod
172
173=head1 NAME
174
175Moose::Role - The Moose Role
176
76d37e5a 177=head1 SYNOPSIS
178
179 package Eq;
85424612 180 use Moose::Role; # automatically turns on strict and warnings
fb1e11d5 181
e46edf94 182 requires 'equal';
fb1e11d5 183
184 sub no_equal {
76d37e5a 185 my ($self, $other) = @_;
186 !$self->equal($other);
187 }
fb1e11d5 188
76d37e5a 189 # ... then in your classes
fb1e11d5 190
76d37e5a 191 package Currency;
85424612 192 use Moose; # automatically turns on strict and warnings
fb1e11d5 193
76d37e5a 194 with 'Eq';
fb1e11d5 195
76d37e5a 196 sub equal {
197 my ($self, $other) = @_;
bdabd620 198 $self->as_float == $other->as_float;
76d37e5a 199 }
200
e185c027 201=head1 DESCRIPTION
202
85424612 203Role support in Moose is pretty solid at this point. However, the best
204documentation is still the the test suite. It is fairly safe to assume Perl 6
205style behavior and then either refer to the test suite, or ask questions on
206#moose if something doesn't quite do what you expect.
d44714be 207
85424612 208We are planning writing some more documentation in the near future, but nothing
209is ready yet, sorry.
76d37e5a 210
2c0cbef7 211=head1 EXPORTED FUNCTIONS
212
85424612 213Moose::Role currently supports all of the functions that L<Moose> exports, but
214differs slightly in how some items are handled (see L<CAVEATS> below for
215details).
76d37e5a 216
85424612 217Moose::Role also offers two role-specific keyword exports:
e185c027 218
219=over 4
220
2c0cbef7 221=item B<requires (@method_names)>
76d37e5a 222
fb1e11d5 223Roles can require that certain methods are implemented by any class which
85424612 224C<does> the role.
9e93dd19 225
2c0cbef7 226=item B<excludes (@role_names)>
227
9e93dd19 228Roles can C<exclude> other roles, in effect saying "I can never be combined
fb1e11d5 229with these C<@role_names>". This is a feature which should not be used
85424612 230lightly.
9e93dd19 231
2c0cbef7 232=back
233
234=head1 CAVEATS
235
85424612 236Role support has only a few caveats:
2c0cbef7 237
238=over 4
76d37e5a 239
76d37e5a 240=item *
241
fb1e11d5 242Roles cannot use the C<extends> keyword; it will throw an exception for now.
243The same is true of the C<augment> and C<inner> keywords (not sure those
244really make sense for roles). All other Moose keywords will be I<deferred>
85424612 245so that they can be applied to the consuming class.
76d37e5a 246
fb1e11d5 247=item *
2c0cbef7 248
85424612 249Role composition does its best to B<not> be order-sensitive when it comes to
250conflict resolution and requirements detection. However, it is order-sensitive
251when it comes to method modifiers. All before/around/after modifiers are
252included whenever a role is composed into a class, and then applied in the order
253in which the roles are used. This also means that there is no conflict for
254before/around/after modifiers.
2c0cbef7 255
85424612 256In most cases, this will be a non-issue; however, it is something to keep in
257mind when using method modifiers in a role. You should never assume any
2c0cbef7 258ordering.
259
260=item *
261
fb1e11d5 262The C<requires> keyword currently only works with actual methods. A method
263modifier (before/around/after and override) will not count as a fufillment
2c0cbef7 264of the requirement, and neither will an autogenerated accessor for an attribute.
265
85424612 266It is likely that attribute accessors will eventually be allowed to fufill those
267requirements, or we will introduce a C<requires_attr> keyword of some kind
268instead. This decision has not yet been finalized.
2c0cbef7 269
e185c027 270=back
271
272=head1 BUGS
273
fb1e11d5 274All complex software has bugs lurking in it, and this module is no
e185c027 275exception. If you find a bug please either email me, or add the bug
276to cpan-RT.
277
278=head1 AUTHOR
279
280Stevan Little E<lt>stevan@iinteractive.comE<gt>
281
db1ab48d 282Christian Hansen E<lt>chansen@cpan.orgE<gt>
98aae381 283
e185c027 284=head1 COPYRIGHT AND LICENSE
285
778db3ac 286Copyright 2006-2008 by Infinity Interactive, Inc.
e185c027 287
288L<http://www.iinteractive.com>
289
290This library is free software; you can redistribute it and/or modify
fb1e11d5 291it under the same terms as Perl itself.
e185c027 292
68117c45 293=cut