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