Lazy initialization of coercions
[gitmo/Mouse.git] / lib / Mouse / Role.pm
CommitLineData
f9e68395 1package Mouse::Role;
8bdd9cfc 2use Mouse::Exporter; # enables strict and warnings
f3bb863f 3
420d69e8 4our $VERSION = '0.86';
8bdd9cfc 5
6use Carp qw(confess);
43523060 7use Scalar::Util qw(blessed);
f9e68395 8
6d28c5cf 9use Mouse ();
fea36fd2 10
11Mouse::Exporter->setup_import_methods(
12 as_is => [qw(
13 extends with
14 has
15 before after around
16 override super
17 augment inner
18
19 requires excludes
20 ),
21 \&Scalar::Util::blessed,
22 \&Carp::confess,
23 ],
2cb8b713 24);
25
43523060 26
9ee0e57c 27sub extends {
28 Carp::croak "Roles do not support 'extends'";
29}
43523060 30
4cc4f8ed 31sub with {
32 Mouse::Util::apply_all_roles(scalar(caller), @_);
9ee0e57c 33 return;
34}
35
36sub has {
37 my $meta = Mouse::Meta::Role->initialize(scalar caller);
38 my $name = shift;
39
40 $meta->throw_error(q{Usage: has 'name' => ( key => value, ... )})
41 if @_ % 2; # odd number of arguments
42
13f78bbc 43 for my $n(ref($name) ? @{$name} : $name){
44 $meta->add_attribute($n => @_);
9ee0e57c 45 }
46 return;
47}
b32e8fb9 48
49sub before {
8bc2760b 50 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 51 my $code = pop;
013ee5f0 52 for my $name($meta->_collect_methods(@_)) {
53 $meta->add_before_method_modifier($name => $code);
b32e8fb9 54 }
9ee0e57c 55 return;
b32e8fb9 56}
57
58sub after {
8bc2760b 59 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 60 my $code = pop;
013ee5f0 61 for my $name($meta->_collect_methods(@_)) {
62 $meta->add_after_method_modifier($name => $code);
f9e68395 63 }
9ee0e57c 64 return;
b32e8fb9 65}
66
67sub around {
8bc2760b 68 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 69 my $code = pop;
013ee5f0 70 for my $name($meta->_collect_methods(@_)) {
71 $meta->add_around_method_modifier($name => $code);
b32e8fb9 72 }
9ee0e57c 73 return;
b32e8fb9 74}
75
67199842 76
77sub super {
85bd3f44 78 return if !defined $Mouse::SUPER_BODY;
67199842 79 $Mouse::SUPER_BODY->(@Mouse::SUPER_ARGS);
80}
81
82sub override {
85bd3f44 83 # my($name, $code) = @_;
84 Mouse::Meta::Role->initialize(scalar caller)->add_override_method_modifier(@_);
9ee0e57c 85 return;
67199842 86}
87
88# We keep the same errors messages as Moose::Role emits, here.
89sub inner {
6d28c5cf 90 Carp::croak "Roles cannot support 'inner'";
67199842 91}
92
93sub augment {
6d28c5cf 94 Carp::croak "Roles cannot support 'augment'";
67199842 95}
96
59089ec3 97sub requires {
8bc2760b 98 my $meta = Mouse::Meta::Role->initialize(scalar caller);
6d28c5cf 99 $meta->throw_error("Must specify at least one method") unless @_;
59089ec3 100 $meta->add_required_methods(@_);
9ee0e57c 101 return;
59089ec3 102}
b32e8fb9 103
6d28c5cf 104sub excludes {
1d76ae62 105 Mouse::Util::not_supported();
6d28c5cf 106}
b32e8fb9 107
fea36fd2 108sub init_meta{
9704fe9d 109 shift;
110 my %args = @_;
7daedfff 111
9704fe9d 112 my $class = $args{for_class}
fea36fd2 113 or Carp::confess("Cannot call init_meta without specifying a for_class");
b32e8fb9 114
fea36fd2 115 my $metaclass = $args{metaclass} || 'Mouse::Meta::Role';
7daedfff 116
9704fe9d 117 my $meta = $metaclass->initialize($class);
7daedfff 118
fea36fd2 119 $meta->add_method(meta => sub{
120 $metaclass->initialize(ref($_[0]) || $_[0]);
3a63a2e7 121 });
b32e8fb9 122
9704fe9d 123 # make a role type for each Mouse role
124 Mouse::Util::TypeConstraints::role_type($class)
125 unless Mouse::Util::TypeConstraints::find_type_constraint($class);
126
fea36fd2 127 return $meta;
b32e8fb9 128}
f9e68395 129
1301;
131
cadd5b5e 132__END__
133
134=head1 NAME
135
1820fffe 136Mouse::Role - The Mouse Role
137
a25ca8d6 138=head1 VERSION
139
420d69e8 140This document describes Mouse version 0.86
a25ca8d6 141
1820fffe 142=head1 SYNOPSIS
143
f5366662 144 package Comparable;
145 use Mouse::Role; # the package is now a Mouse role
146
147 # Declare methods that are required by this role
148 requires qw(compare);
149
150 # Define methods this role provides
151 sub equals {
152 my($self, $other) = @_;
153 return $self->compare($other) == 0;
154 }
155
156 # and later
157 package MyObject;
158 use Mouse;
159 with qw(Comparable); # Now MyObject can equals()
160
161 sub compare {
162 # ...
163 }
164
165 my $foo = MyObject->new();
166 my $bar = MyObject->new();
167 $obj->equals($bar); # yes, it is comparable
cadd5b5e 168
0f913746 169=head1 DESCRIPTION
cadd5b5e 170
0f913746 171This module declares the caller class to be a Mouse role.
cadd5b5e 172
0f913746 173The concept of roles is documented in L<Moose::Manual::Roles>.
174This document serves as API documentation.
cadd5b5e 175
0f913746 176=head1 EXPORTED FUNCTIONS
cadd5b5e 177
0f913746 178Mouse::Role supports all of the functions that Mouse exports, but
179differs slightly in how some items are handled (see L</CAVEATS> below
180for details).
cadd5b5e 181
0f913746 182Mouse::Role also offers two role-specific keywords:
cadd5b5e 183
0f913746 184=head2 C<< requires(@method_names) >>
cadd5b5e 185
0f913746 186Roles can require that certain methods are implemented by any class which
187C<does> the role.
cadd5b5e 188
0f913746 189Note that attribute accessors also count as methods for the purposes of
190satisfying the requirements of a role.
cadd5b5e 191
0f913746 192=head2 C<< excludes(@role_names) >>
67199842 193
0f913746 194This is exported but not implemented in Mouse.
67199842 195
0f913746 196=head1 IMPORT AND UNIMPORT
67199842 197
0f913746 198=head2 import
67199842 199
0f913746 200Importing Mouse::Role will give you sugar. C<-traits> are also supported.
67199842 201
0f913746 202=head2 unimport
cadd5b5e 203
0f913746 204Please unimport (C<< no Mouse::Role >>) so that if someone calls one of the
205keywords (such as L</has>) it will break loudly instead breaking subtly.
cadd5b5e 206
0f913746 207=head1 CAVEATS
cadd5b5e 208
0f913746 209Role support has only a few caveats:
cadd5b5e 210
0f913746 211=over
cadd5b5e 212
0f913746 213=item *
cadd5b5e 214
0f913746 215Roles cannot use the C<extends> keyword; it will throw an exception for now.
216The same is true of the C<augment> and C<inner> keywords (not sure those
217really make sense for roles). All other Mouse keywords will be I<deferred>
218so that they can be applied to the consuming class.
cadd5b5e 219
0f913746 220=item *
cadd5b5e 221
0f913746 222Role composition does its best to B<not> be order-sensitive when it comes to
223conflict resolution and requirements detection. However, it is order-sensitive
224when it comes to method modifiers. All before/around/after modifiers are
225included whenever a role is composed into a class, and then applied in the order
226in which the roles are used. This also means that there is no conflict for
227before/around/after modifiers.
cadd5b5e 228
0f913746 229In most cases, this will be a non-issue; however, it is something to keep in
230mind when using method modifiers in a role. You should never assume any
231ordering.
cadd5b5e 232
0f913746 233=back
cadd5b5e 234
1820fffe 235=head1 SEE ALSO
236
0f913746 237L<Mouse>
238
1820fffe 239L<Moose::Role>
240
cadd5b5e 241=cut
242