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