Commit | Line | Data |
8b978dd5 |
1 | |
2 | package Class::MOP::Method; |
3 | |
4 | use strict; |
5 | use warnings; |
6 | |
2eb717d5 |
7 | use Carp 'confess'; |
aa448b16 |
8 | use Scalar::Util 'reftype', 'blessed'; |
de19f115 |
9 | use B 'svref_2object'; |
2eb717d5 |
10 | |
de19f115 |
11 | our $VERSION = '0.02'; |
12 | |
13 | # introspection |
2eb717d5 |
14 | |
727919c5 |
15 | sub meta { |
16 | require Class::MOP::Class; |
aa448b16 |
17 | Class::MOP::Class->initialize(blessed($_[0]) || $_[0]); |
727919c5 |
18 | } |
2eb717d5 |
19 | |
de19f115 |
20 | # construction |
21 | |
22 | sub 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 | |
121 | sub 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 | |
128 | sub 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 |
135 | 1; |
136 | |
137 | __END__ |
138 | |
139 | =pod |
140 | |
141 | =head1 NAME |
142 | |
143 | Class::MOP::Method - Method Meta Object |
144 | |
145 | =head1 SYNOPSIS |
146 | |
fe122940 |
147 | # ... more to come later maybe |
148 | |
8b978dd5 |
149 | =head1 DESCRIPTION |
150 | |
552e3d24 |
151 | The Method Protocol is very small, since methods in Perl 5 are just |
152 | subroutines within the particular package. Basically all we do is to |
fe122940 |
153 | bless the subroutine. |
154 | |
155 | Currently this package is largely unused. Future plans are to provide |
156 | some very simple introspection methods for the methods themselves. |
157 | Suggestions 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 |
167 | This will return a B<Class::MOP::Class> instance which is related |
168 | to this class. |
169 | |
2eb717d5 |
170 | =back |
171 | |
de19f115 |
172 | =head2 Construction |
173 | |
174 | =over 4 |
175 | |
176 | =item B<new (&code)> |
177 | |
178 | This 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 | |
194 | http://dirtsimple.org/2005/01/clos-style-method-combination-for.html |
195 | |
196 | http://www.gigamonkeys.com/book/object-reorientation-generic-functions.html |
197 | |
8b978dd5 |
198 | =head1 AUTHOR |
199 | |
a2e85e6c |
200 | Stevan Little E<lt>stevan@iinteractive.comE<gt> |
8b978dd5 |
201 | |
202 | =head1 COPYRIGHT AND LICENSE |
203 | |
204 | Copyright 2006 by Infinity Interactive, Inc. |
205 | |
206 | L<http://www.iinteractive.com> |
207 | |
208 | This library is free software; you can redistribute it and/or modify |
209 | it under the same terms as Perl itself. |
210 | |
211 | =cut |