preserving call context
[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
de19f115 11our $VERSION = '0.02';
12
13# introspection
2eb717d5 14
727919c5 15sub meta {
16 require Class::MOP::Class;
aa448b16 17 Class::MOP::Class->initialize(blessed($_[0]) || $_[0]);
727919c5 18}
2eb717d5 19
de19f115 20# construction
21
22sub new {
2eb717d5 23 my $class = shift;
24 my $code = shift;
2eb717d5 25 (reftype($code) && reftype($code) eq 'CODE')
de19f115 26 || confess "You must supply a CODE reference to bless";
27 bless $code => blessed($class) || $class;
28}
29
30{
31 my %MODIFIERS;
32
33 sub wrap {
34 my $code = shift;
35 (blessed($code))
36 || confess "Can only ask the package name of a blessed CODE";
855d2774 37 my $modifier_table = {
38 orig => $code,
39 before => [],
40 after => [],
41 around => {
42 cache => $code,
43 methods => [],
44 },
45 };
de19f115 46 my $method = $code->new(sub {
47 $_->(@_) for @{$modifier_table->{before}};
8768d570 48 my (@rlist, $rval);
49 if (defined wantarray) {
50 if (wantarray) {
51 @rlist = $modifier_table->{around}->{cache}->(@_);
52 }
53 else {
54 $rval = $modifier_table->{around}->{cache}->(@_);
55 }
56 }
57 else {
58 $modifier_table->{around}->{cache}->(@_);
59 }
de19f115 60 $_->(@_) for @{$modifier_table->{after}};
8768d570 61 return unless defined wantarray;
62 return wantarray ? @rlist : $rval;
de19f115 63 });
64 $MODIFIERS{$method} = $modifier_table;
65 $method;
66 }
67
68 sub add_before_modifier {
69 my $code = shift;
70 my $modifier = shift;
71 (exists $MODIFIERS{$code})
72 || confess "You must first wrap your method before adding a modifier";
73 (blessed($code))
74 || confess "Can only ask the package name of a blessed CODE";
75 (reftype($modifier) && reftype($modifier) eq 'CODE')
76 || confess "You must supply a CODE reference for a modifier";
77 unshift @{$MODIFIERS{$code}->{before}} => $modifier;
78 }
79
80 sub add_after_modifier {
81 my $code = shift;
82 my $modifier = shift;
83 (exists $MODIFIERS{$code})
84 || confess "You must first wrap your method before adding a modifier";
85 (blessed($code))
86 || confess "Can only ask the package name of a blessed CODE";
87 (reftype($modifier) && reftype($modifier) eq 'CODE')
88 || confess "You must supply a CODE reference for a modifier";
89 push @{$MODIFIERS{$code}->{after}} => $modifier;
855d2774 90 }
91
92 {
93 my $compile_around_method = sub {{
94 my $f1 = pop;
95 return $f1 unless @_;
96 my $f2 = pop;
97 push @_, sub { $f2->( $f1, @_ ) };
98 redo;
99 }};
100
101 sub add_around_modifier {
102 my $code = shift;
103 my $modifier = shift;
104 (exists $MODIFIERS{$code})
105 || confess "You must first wrap your method before adding a modifier";
106 (blessed($code))
107 || confess "Can only ask the package name of a blessed CODE";
108 (reftype($modifier) && reftype($modifier) eq 'CODE')
109 || confess "You must supply a CODE reference for a modifier";
110 unshift @{$MODIFIERS{$code}->{around}->{methods}} => $modifier;
111 $MODIFIERS{$code}->{around}->{cache} = $compile_around_method->(
112 @{$MODIFIERS{$code}->{around}->{methods}},
113 $MODIFIERS{$code}->{orig}
114 );
115 }
116 }
de19f115 117}
118
119# informational
120
121sub package_name {
122 my $code = shift;
123 (blessed($code))
124 || confess "Can only ask the package name of a blessed CODE";
125 svref_2object($code)->GV->STASH->NAME;
126}
127
128sub name {
129 my $code = shift;
130 (blessed($code))
131 || confess "Can only ask the package name of a blessed CODE";
132 svref_2object($code)->GV->NAME;
2eb717d5 133}
de19f115 134
8b978dd5 1351;
136
137__END__
138
139=pod
140
141=head1 NAME
142
143Class::MOP::Method - Method Meta Object
144
145=head1 SYNOPSIS
146
fe122940 147 # ... more to come later maybe
148
8b978dd5 149=head1 DESCRIPTION
150
552e3d24 151The Method Protocol is very small, since methods in Perl 5 are just
152subroutines within the particular package. Basically all we do is to
fe122940 153bless the subroutine.
154
155Currently this package is largely unused. Future plans are to provide
156some very simple introspection methods for the methods themselves.
157Suggestions for this are welcome.
552e3d24 158
2eb717d5 159=head1 METHODS
160
de19f115 161=head2 Introspection
2eb717d5 162
de19f115 163=over 4
fe122940 164
2eb717d5 165=item B<meta>
166
fe122940 167This will return a B<Class::MOP::Class> instance which is related
168to this class.
169
2eb717d5 170=back
171
de19f115 172=head2 Construction
173
174=over 4
175
176=item B<new (&code)>
177
178This simply blesses the C<&code> reference passed to it.
179
180=back
181
182=head2 Informational
183
184=over 4
185
186=item B<name>
187
188=item B<package_name>
189
190=back
191
192=head1 SEE ALSO
193
194http://dirtsimple.org/2005/01/clos-style-method-combination-for.html
195
196http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html
197
8b978dd5 198=head1 AUTHOR
199
a2e85e6c 200Stevan Little E<lt>stevan@iinteractive.comE<gt>
8b978dd5 201
202=head1 COPYRIGHT AND LICENSE
203
204Copyright 2006 by Infinity Interactive, Inc.
205
206L<http://www.iinteractive.com>
207
208This library is free software; you can redistribute it and/or modify
209it under the same terms as Perl itself.
210
211=cut