Fix RT #49902
[gitmo/Mouse.git] / lib / Mouse / Role.pm
CommitLineData
f9e68395 1package Mouse::Role;
2use strict;
3use warnings;
b32e8fb9 4use base 'Exporter';
f9e68395 5
67199842 6use Carp 'confess', 'croak';
6c169c50 7use Scalar::Util 'blessed';
f9e68395 8
a2227e71 9use Mouse::Meta::Role;
ff687069 10use Mouse::Util qw(load_class);
a2227e71 11
67199842 12our @EXPORT = qw(before after around super override inner augment has extends with requires excludes confess blessed);
3a63a2e7 13our %is_removable = map{ $_ => undef } @EXPORT;
14delete $is_removable{confess};
15delete $is_removable{blessed};
b32e8fb9 16
17sub before {
8bc2760b 18 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 19
20 my $code = pop;
21 for (@_) {
22 $meta->add_before_method_modifier($_ => $code);
23 }
24}
25
26sub after {
8bc2760b 27 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 28
29 my $code = pop;
30 for (@_) {
31 $meta->add_after_method_modifier($_ => $code);
f9e68395 32 }
b32e8fb9 33}
34
35sub around {
8bc2760b 36 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 37
38 my $code = pop;
39 for (@_) {
40 $meta->add_around_method_modifier($_ => $code);
41 }
42}
43
67199842 44
45sub super {
46 return unless $Mouse::SUPER_BODY;
47 $Mouse::SUPER_BODY->(@Mouse::SUPER_ARGS);
48}
49
50sub override {
51 my $classname = caller;
52 my $meta = Mouse::Meta::Role->initialize($classname);
53
54 my $name = shift;
55 my $code = shift;
56 my $fullname = "${classname}::${name}";
57
58 defined &$fullname
59 && confess "Cannot add an override of method '$fullname' " .
60 "because there is a local version of '$fullname'";
61
62 $meta->add_override_method_modifier($name => sub {
63 local $Mouse::SUPER_PACKAGE = shift;
64 local $Mouse::SUPER_BODY = shift;
65 local @Mouse::SUPER_ARGS = @_;
66
67 $code->(@_);
68 });
69}
70
71# We keep the same errors messages as Moose::Role emits, here.
72sub inner {
73 croak "Moose::Role cannot support 'inner'";
74}
75
76sub augment {
77 croak "Moose::Role cannot support 'augment'";
78}
79
b32e8fb9 80sub has {
8bc2760b 81 my $meta = Mouse::Meta::Role->initialize(scalar caller);
b32e8fb9 82
83 my $name = shift;
84 my %opts = @_;
85
86 $meta->add_attribute($name => \%opts);
87}
88
ff687069 89sub extends { confess "Roles do not support 'extends'" }
b32e8fb9 90
b1b81553 91sub with {
8bc2760b 92 my $meta = Mouse::Meta::Role->initialize(scalar caller);
ff687069 93 Mouse::Util::apply_all_roles($meta->name, @_);
b1b81553 94}
b32e8fb9 95
59089ec3 96sub requires {
8bc2760b 97 my $meta = Mouse::Meta::Role->initialize(scalar caller);
59089ec3 98 Carp::croak "Must specify at least one method" unless @_;
99 $meta->add_required_methods(@_);
100}
b32e8fb9 101
2badb84a 102sub excludes { confess "Mouse::Role does not currently support 'excludes'" }
b32e8fb9 103
104sub import {
7daedfff 105 my $class = shift;
106
b32e8fb9 107 strict->import;
108 warnings->import;
109
110 my $caller = caller;
7daedfff 111
112 # we should never export to main
113 if ($caller eq 'main') {
114 warn qq{$class does not export its sugar to the 'main' package.\n};
115 return;
116 }
117
3a63a2e7 118 Mouse::Meta::Role->initialize($caller)->add_method(meta => sub {
119 return Mouse::Meta::Role->initialize(ref($_[0]) || $_[0]);
120 });
b32e8fb9 121
122 Mouse::Role->export_to_level(1, @_);
123}
f9e68395 124
b32e8fb9 125sub unimport {
126 my $caller = caller;
e71d8033 127
3a63a2e7 128 my $stash = do{
129 no strict 'refs';
130 \%{$caller . '::'}
131 };
132
b32e8fb9 133 for my $keyword (@EXPORT) {
3a63a2e7 134 my $code;
135 if(exists $is_removable{$keyword}
136 && ($code = $caller->can($keyword))
137 && (Mouse::Util::get_code_info($code))[0] eq __PACKAGE__){
138
139 delete $stash->{$keyword};
140 }
f9e68395 141 }
3a63a2e7 142 return;
b32e8fb9 143}
f9e68395 144
1451;
146
cadd5b5e 147__END__
148
149=head1 NAME
150
137498b8 151Mouse::Role - define a role in Mouse
cadd5b5e 152
153=head1 KEYWORDS
154
155=head2 meta -> Mouse::Meta::Role
156
157Returns this role's metaclass instance.
158
159=head2 before (method|methods) => Code
160
161Sets up a "before" method modifier. See L<Moose/before> or
162L<Class::Method::Modifiers/before>.
163
164=head2 after (method|methods) => Code
165
166Sets up an "after" method modifier. See L<Moose/after> or
167L<Class::Method::Modifiers/after>.
168
169=head2 around (method|methods) => Code
170
171Sets up an "around" method modifier. See L<Moose/around> or
172L<Class::Method::Modifiers/around>.
173
4e8817b8 174=over 4
175
67199842 176=item B<super>
177
178Sets up the "super" keyword. See L<Moose/super>.
179
180=item B<override ($name, &sub)>
181
182Sets up an "override" method modifier. See L<Moose/Role/override>.
183
184=item B<inner>
185
186This is not supported and emits an error. See L<Moose/Role>.
187
188=item B<augment ($name, &sub)>
189
190This is not supported and emits an error. See L<Moose/Role>.
191
4e8817b8 192=back
193
cadd5b5e 194=head2 has (name|names) => parameters
195
196Sets up an attribute (or if passed an arrayref of names, multiple attributes) to
197this role. See L<Mouse/has>.
198
199=head2 confess error -> BOOM
200
201L<Carp/confess> for your convenience.
202
203=head2 blessed value -> ClassName | undef
204
205L<Scalar::Util/blessed> for your convenience.
206
207=head1 MISC
208
209=head2 import
210
211Importing Mouse::Role will give you sugar.
212
213=head2 unimport
214
215Please unimport Mouse (C<no Mouse::Role>) so that if someone calls one of the
216keywords (such as L</has>) it will break loudly instead breaking subtly.
217
218=cut
219