2 package Class::MOP::Method;
8 use Scalar::Util 'reftype', 'blessed';
11 our $VERSION = '0.03';
12 our $AUTHORITY = 'cpan:STEVAN';
14 use overload '&{}' => sub { $_[0]->{body} },
20 require Class::MOP::Class;
21 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
29 ('CODE' eq (reftype($code) || ''))
30 || confess "You must supply a CODE reference to bless, not (" . ($code || 'undef') . ")";
33 } => blessed($class) || $class;
36 sub body { (shift)->{body} }
41 my $code = shift->{body};
43 # || confess "Can only ask the package name of a blessed CODE";
44 svref_2object($code)->GV->STASH->NAME;
48 my $code = shift->{body};
50 # || confess "Can only ask the package name of a blessed CODE";
51 svref_2object($code)->GV->NAME;
54 sub fully_qualified_name {
57 # || confess "Can only ask the package name of a blessed CODE";
58 $code->package_name . '::' . $code->name;
61 package Class::MOP::Method::Wrapped;
67 use Scalar::Util 'reftype', 'blessed';
68 use Sub::Name 'subname';
70 our $VERSION = '0.01';
72 our @ISA = ('Class::MOP::Method');
75 # this ugly beast is the result of trying
76 # to micro optimize this as much as possible
77 # while not completely loosing maintainability.
78 # At this point it's "fast enough", after all
79 # you can't get something for nothing :)
80 my $_build_wrapped_method = sub {
81 my $modifier_table = shift;
82 my ($before, $after, $around) = (
83 $modifier_table->{before},
84 $modifier_table->{after},
85 $modifier_table->{around},
87 if (@$before && @$after) {
88 $modifier_table->{cache} = sub {
89 $_->(@_) for @{$before};
91 ((defined wantarray) ?
93 (@rval = $around->{cache}->(@_))
95 ($rval[0] = $around->{cache}->(@_)))
97 $around->{cache}->(@_));
98 $_->(@_) for @{$after};
99 return unless defined wantarray;
100 return wantarray ? @rval : $rval[0];
103 elsif (@$before && !@$after) {
104 $modifier_table->{cache} = sub {
105 $_->(@_) for @{$before};
106 return $around->{cache}->(@_);
109 elsif (@$after && !@$before) {
110 $modifier_table->{cache} = sub {
112 ((defined wantarray) ?
114 (@rval = $around->{cache}->(@_))
116 ($rval[0] = $around->{cache}->(@_)))
118 $around->{cache}->(@_));
119 $_->(@_) for @{$after};
120 return unless defined wantarray;
121 return wantarray ? @rval : $rval[0];
125 $modifier_table->{cache} = $around->{cache};
134 (blessed($code) && $code->isa('Class::MOP::Method'))
135 || confess "Can only wrap blessed CODE";
136 my $modifier_table = {
142 cache => $code->body,
146 $_build_wrapped_method->($modifier_table);
147 my $method = $class->SUPER::wrap(sub { $modifier_table->{cache}->(@_) });
148 $MODIFIERS{$method} = $modifier_table;
152 sub get_original_method {
154 $MODIFIERS{$code}->{orig}
155 if exists $MODIFIERS{$code};
158 sub add_before_modifier {
160 my $modifier = shift;
161 (exists $MODIFIERS{$code})
162 || confess "You must first wrap your method before adding a modifier";
164 || confess "Can only ask the package name of a blessed CODE";
165 #('CODE' eq (reftype($code) || ''))
166 # || confess "You must supply a CODE reference for a modifier";
167 unshift @{$MODIFIERS{$code}->{before}} => $modifier;
168 $_build_wrapped_method->($MODIFIERS{$code});
171 sub add_after_modifier {
173 my $modifier = shift;
174 (exists $MODIFIERS{$code})
175 || confess "You must first wrap your method before adding a modifier";
177 || confess "Can only ask the package name of a blessed CODE";
178 #('CODE' eq (reftype($code) || ''))
179 # || confess "You must supply a CODE reference for a modifier";
180 push @{$MODIFIERS{$code}->{after}} => $modifier;
181 $_build_wrapped_method->($MODIFIERS{$code});
186 # this is another possible canidate for
187 # optimization as well. There is an overhead
188 # associated with the currying that, if
189 # eliminated might make around modifiers
191 my $compile_around_method = sub {{
193 return $f1 unless @_;
195 push @_, sub { $f2->( $f1, @_ ) };
199 sub add_around_modifier {
201 my $modifier = shift;
202 (exists $MODIFIERS{$code})
203 || confess "You must first wrap your method before adding a modifier";
205 || confess "Can only ask the package name of a blessed CODE";
206 #('CODE' eq (reftype($code) || ''))
207 # || confess "You must supply a CODE reference for a modifier";
208 unshift @{$MODIFIERS{$code}->{around}->{methods}} => $modifier;
209 $MODIFIERS{$code}->{around}->{cache} = $compile_around_method->(
210 @{$MODIFIERS{$code}->{around}->{methods}},
211 $MODIFIERS{$code}->{orig}
213 $_build_wrapped_method->($MODIFIERS{$code});
225 Class::MOP::Method - Method Meta Object
229 # ... more to come later maybe
233 The Method Protocol is very small, since methods in Perl 5 are just
234 subroutines within the particular package. Basically all we do is to
235 bless the subroutine.
237 Currently this package is largely unused. Future plans are to provide
238 some very simple introspection methods for the methods themselves.
239 Suggestions for this are welcome.
249 This will return a B<Class::MOP::Class> instance which is related
258 =item B<wrap (&code)>
260 This simply blesses the C<&code> reference passed to it.
272 =item B<package_name>
274 =item B<fully_qualified_name>
278 =head1 Class::MOP::Method::Wrapped METHODS
284 =item B<wrap (&code)>
286 This simply blesses the C<&code> reference passed to it.
288 =item B<get_original_method>
296 =item B<add_before_modifier ($code)>
298 =item B<add_after_modifier ($code)>
300 =item B<add_around_modifier ($code)>
306 Stevan Little E<lt>stevan@iinteractive.comE<gt>
308 Yuval Kogman E<lt>nothingmuch@woobling.comE<gt>
310 =head1 COPYRIGHT AND LICENSE
312 Copyright 2006 by Infinity Interactive, Inc.
314 L<http://www.iinteractive.com>
316 This library is free software; you can redistribute it and/or modify
317 it under the same terms as Perl itself.