slight speed improvements
[gitmo/Class-MOP.git] / lib / Class / MOP / Method.pm
CommitLineData
8b978dd5 1
2package Class::MOP::Method;
3
4use strict;
5use warnings;
6
2eb717d5 7use Carp 'confess';
aa448b16 8use Scalar::Util 'reftype', 'blessed';
de19f115 9use B 'svref_2object';
2eb717d5 10
f0480c45 11our $VERSION = '0.03';
12our $AUTHORITY = 'cpan:STEVAN';
de19f115 13
7855ddba 14use overload '&{}' => sub { $_[0]->{body} },
15 fallback => 1;
16
de19f115 17# introspection
2eb717d5 18
727919c5 19sub meta {
20 require Class::MOP::Class;
aa448b16 21 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
727919c5 22}
2eb717d5 23
de19f115 24# construction
25
a4258ffd 26sub wrap {
2eb717d5 27 my $class = shift;
28 my $code = shift;
ee5e71d4 29 ('CODE' eq (reftype($code) || ''))
4d47b77f 30 || confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")";
7855ddba 31 bless {
32 body => $code
33 } => blessed($class) || $class;
de19f115 34}
35
7855ddba 36sub body { (shift)->{body} }
37
de19f115 38# informational
39
40sub package_name {
91e0eb4a 41 my $code = (shift)->{body};
de19f115 42 svref_2object($code)->GV->STASH->NAME;
43}
44
45sub name {
91e0eb4a 46 my $code = (shift)->{body};
de19f115 47 svref_2object($code)->GV->NAME;
2eb717d5 48}
de19f115 49
96ceced8 50sub fully_qualified_name {
51 my $code = shift;
96ceced8 52 $code->package_name . '::' . $code->name;
53}
54
ddc8edba 55package Class::MOP::Method::Wrapped;
56
57use strict;
58use warnings;
59
60use Carp 'confess';
61use Scalar::Util 'reftype', 'blessed';
96ceced8 62use Sub::Name 'subname';
ddc8edba 63
64our $VERSION = '0.01';
65
c4970aef 66use base 'Class::MOP::Method';
ddc8edba 67
96ceced8 68# NOTE:
69# this ugly beast is the result of trying
70# to micro optimize this as much as possible
71# while not completely loosing maintainability.
72# At this point it's "fast enough", after all
73# you can't get something for nothing :)
74my $_build_wrapped_method = sub {
75 my $modifier_table = shift;
76 my ($before, $after, $around) = (
77 $modifier_table->{before},
78 $modifier_table->{after},
79 $modifier_table->{around},
80 );
81 if (@$before && @$after) {
82 $modifier_table->{cache} = sub {
83 $_->(@_) for @{$before};
84 my @rval;
85 ((defined wantarray) ?
86 ((wantarray) ?
87 (@rval = $around->{cache}->(@_))
88 :
89 ($rval[0] = $around->{cache}->(@_)))
90 :
91 $around->{cache}->(@_));
92 $_->(@_) for @{$after};
93 return unless defined wantarray;
94 return wantarray ? @rval : $rval[0];
95 }
96 }
97 elsif (@$before && !@$after) {
98 $modifier_table->{cache} = sub {
99 $_->(@_) for @{$before};
100 return $around->{cache}->(@_);
101 }
102 }
103 elsif (@$after && !@$before) {
104 $modifier_table->{cache} = sub {
105 my @rval;
106 ((defined wantarray) ?
107 ((wantarray) ?
108 (@rval = $around->{cache}->(@_))
109 :
110 ($rval[0] = $around->{cache}->(@_)))
111 :
112 $around->{cache}->(@_));
113 $_->(@_) for @{$after};
114 return unless defined wantarray;
115 return wantarray ? @rval : $rval[0];
116 }
117 }
118 else {
119 $modifier_table->{cache} = $around->{cache};
120 }
121};
122
ddc8edba 123sub wrap {
124 my $class = shift;
125 my $code = shift;
126 (blessed($code) && $code->isa('Class::MOP::Method'))
7855ddba 127 || confess "Can only wrap blessed CODE";
ddc8edba 128 my $modifier_table = {
96ceced8 129 cache => undef,
ddc8edba 130 orig => $code,
131 before => [],
132 after => [],
133 around => {
7855ddba 134 cache => $code->body,
96ceced8 135 methods => [],
ddc8edba 136 },
137 };
96ceced8 138 $_build_wrapped_method->($modifier_table);
139 my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) });
c4970aef 140 $method->{modifier_table} = $modifier_table;
ddc8edba 141 $method;
142}
143
195f5bf8 144sub get_original_method {
145 my $code = shift;
c4970aef 146 $code->{modifier_table}->{orig};
195f5bf8 147}
148
ddc8edba 149sub add_before_modifier {
150 my $code = shift;
151 my $modifier = shift;
c4970aef 152 unshift @{$code->{modifier_table}->{before}} => $modifier;
153 $_build_wrapped_method->($code->{modifier_table});
ddc8edba 154}
155
156sub add_after_modifier {
157 my $code = shift;
158 my $modifier = shift;
c4970aef 159 push @{$code->{modifier_table}->{after}} => $modifier;
160 $_build_wrapped_method->($code->{modifier_table});
ddc8edba 161}
162
163{
96ceced8 164 # NOTE:
165 # this is another possible canidate for
166 # optimization as well. There is an overhead
167 # associated with the currying that, if
168 # eliminated might make around modifiers
169 # more manageable.
ddc8edba 170 my $compile_around_method = sub {{
171 my $f1 = pop;
172 return $f1 unless @_;
173 my $f2 = pop;
174 push @_, sub { $f2->( $f1, @_ ) };
175 redo;
176 }};
177
178 sub add_around_modifier {
179 my $code = shift;
180 my $modifier = shift;
c4970aef 181 unshift @{$code->{modifier_table}->{around}->{methods}} => $modifier;
182 $code->{modifier_table}->{around}->{cache} = $compile_around_method->(
183 @{$code->{modifier_table}->{around}->{methods}},
184 $code->{modifier_table}->{orig}->body
ddc8edba 185 );
c4970aef 186 $_build_wrapped_method->($code->{modifier_table});
ddc8edba 187 }
188}
189
8b978dd5 1901;
191
192__END__
193
194=pod
195
196=head1 NAME
197
198Class::MOP::Method - Method Meta Object
199
200=head1 SYNOPSIS
201
fe122940 202 # ... more to come later maybe
203
8b978dd5 204=head1 DESCRIPTION
205
552e3d24 206The Method Protocol is very small, since methods in Perl 5 are just
207subroutines within the particular package. Basically all we do is to
fe122940 208bless the subroutine.
209
210Currently this package is largely unused. Future plans are to provide
211some very simple introspection methods for the methods themselves.
212Suggestions for this are welcome.
552e3d24 213
2eb717d5 214=head1 METHODS
215
de19f115 216=head2 Introspection
2eb717d5 217
de19f115 218=over 4
fe122940 219
2eb717d5 220=item B<meta>
221
fe122940 222This will return a B<Class::MOP::Class> instance which is related
223to this class.
224
2eb717d5 225=back
226
de19f115 227=head2 Construction
228
229=over 4
230
a4258ffd 231=item B<wrap (&code)>
de19f115 232
233This simply blesses the C<&code> reference passed to it.
234
235=back
236
237=head2 Informational
238
239=over 4
240
7855ddba 241=item B<body>
242
de19f115 243=item B<name>
244
245=item B<package_name>
246
96ceced8 247=item B<fully_qualified_name>
248
249=back
250
251=head1 Class::MOP::Method::Wrapped METHODS
252
253=head2 Construction
254
255=over 4
256
257=item B<wrap (&code)>
258
259This simply blesses the C<&code> reference passed to it.
260
195f5bf8 261=item B<get_original_method>
262
de19f115 263=back
264
ee5e71d4 265=head2 Modifiers
266
267=over 4
de19f115 268
ee5e71d4 269=item B<add_before_modifier ($code)>
de19f115 270
ee5e71d4 271=item B<add_after_modifier ($code)>
272
273=item B<add_around_modifier ($code)>
274
275=back
de19f115 276
1a09d9cc 277=head1 AUTHORS
8b978dd5 278
a2e85e6c 279Stevan Little E<lt>stevan@iinteractive.comE<gt>
8b978dd5 280
1a09d9cc 281Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
282
8b978dd5 283=head1 COPYRIGHT AND LICENSE
284
285Copyright 2006 by Infinity Interactive, Inc.
286
287L<http://www.iinteractive.com>
288
289This library is free software; you can redistribute it and/or modify
290it under the same terms as Perl itself.
291
16e960bd 292=cut
293