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