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