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