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