made method { ... }; work
[p5sagit/Devel-Declare.git] / lib / Devel / Declare.pm
CommitLineData
94caac6e 1package Devel::Declare;
2
3use strict;
4use warnings;
5use 5.008001;
6
7our $VERSION = 0.001000;
8
0ba8c7aa 9# mirrored in Declare.xs as DD_HANDLE_*
10
11use constant DECLARE_NAME => 1;
12use constant DECLARE_PROTO => 2;
53e3ab32 13use constant DECLARE_NONE => 4;
15d0d014 14use constant DECLARE_PACKAGE => 8+1; # name implicit
0ba8c7aa 15
86c3de80 16use vars qw(%declarators %declarator_handlers @ISA);
94caac6e 17use base qw(DynaLoader);
323ae557 18use Scalar::Util 'set_prototype';
94caac6e 19
20bootstrap Devel::Declare;
21
86c3de80 22@ISA = ();
23
94caac6e 24sub import {
0ba8c7aa 25 my ($class, %args) = @_;
94caac6e 26 my $target = caller;
0ba8c7aa 27 if (@_ == 1) { # "use Devel::Declare;"
28 no strict 'refs';
15d0d014 29 foreach my $name (qw(NAME PROTO NONE PACKAGE)) {
53e3ab32 30 *{"${target}::DECLARE_${name}"} = *{"DECLARE_${name}"};
0ba8c7aa 31 }
32 } else {
33 $class->setup_for($target => \%args);
34 }
94caac6e 35}
36
37sub unimport {
38 my ($class) = @_;
39 my $target = caller;
40 $class->teardown_for($target);
41}
42
43sub setup_for {
44 my ($class, $target, $args) = @_;
45 setup();
0ba8c7aa 46 foreach my $key (keys %$args) {
47 my $info = $args->{$key};
48 my ($flags, $sub);
49 if (ref($info) eq 'ARRAY') {
50 ($flags, $sub) = @$info;
51 } elsif (ref($info) eq 'CODE') {
52 $flags = DECLARE_NAME;
53 $sub = $info;
54 } else {
55 die "Info for sub ${key} must be [ \$flags, \$sub ] or \$sub";
56 }
57 $declarators{$target}{$key} = $flags;
58 $declarator_handlers{$target}{$key} = $sub;
59 }
94caac6e 60}
61
62sub teardown_for {
63 my ($class, $target) = @_;
64 delete $declarators{$target};
0ba8c7aa 65 delete $declarator_handlers{$target};
94caac6e 66 teardown();
67}
68
94caac6e 69my $temp_name;
0ba8c7aa 70my $temp_save;
94caac6e 71
72sub init_declare {
9026391e 73 my ($usepack, $use, $inpack, $name, $proto) = @_;
53e3ab32 74 my ($name_h, $XX_h, $extra_code)
9026391e 75 = $declarator_handlers{$usepack}{$use}->(
76 $usepack, $use, $inpack, $name, $proto, defined(wantarray)
53e3ab32 77 );
15d0d014 78 ($temp_name, $temp_save) = ([], []);
0ba8c7aa 79 if ($name) {
9026391e 80 $name = "${inpack}::${name}" unless $name =~ /::/;
0ba8c7aa 81 push(@$temp_name, $name);
82 no strict 'refs';
15d0d014 83 push(@$temp_save, \&{$name});
0ba8c7aa 84 no warnings 'redefine';
85 no warnings 'prototype';
15d0d014 86 *{$name} = $name_h;
0ba8c7aa 87 }
88 if ($XX_h) {
9026391e 89 push(@$temp_name, "${inpack}::X");
0ba8c7aa 90 no strict 'refs';
9026391e 91 push(@$temp_save, \&{"${inpack}::X"});
0ba8c7aa 92 no warnings 'redefine';
93 no warnings 'prototype';
9026391e 94 *{"${inpack}::X"} = $XX_h;
0ba8c7aa 95 }
53e3ab32 96 if (defined wantarray) {
97 return $extra_code || '0;';
98 } else {
99 return;
100 }
94caac6e 101}
102
103sub done_declare {
104 no strict 'refs';
86c3de80 105 my $name = shift(@{$temp_name||[]});
0ba8c7aa 106 die "done_declare called with no temp_name stack" unless defined($name);
86c3de80 107 my $saved = shift(@$temp_save);
15d0d014 108 $name =~ s/(.*):://;
109 my $temp_pack = $1;
0ba8c7aa 110 delete ${"${temp_pack}::"}{$name};
111 if ($saved) {
112 no warnings 'prototype';
113 *{"${temp_pack}::${name}"} = $saved;
114 }
94caac6e 115}
116
323ae557 117sub build_sub_installer {
118 my ($class, $pack, $name, $proto) = @_;
119 return eval "
120 package ${pack};
121 my \$body;
122 sub ${name} (${proto}) :lvalue {\n"
86c3de80 123 .'my $ret = $body->(@_);
124 return $ret;
323ae557 125 };
126 sub { ($body) = @_; };';
127}
128
129sub setup_declarators {
130 my ($class, $pack, $to_setup) = @_;
86c3de80 131 die "${class}->setup_declarators(\$pack, \\\%to_setup)"
132 unless defined($pack) && ref($to_setup) eq 'HASH';
133 my %setup_for_args;
323ae557 134 foreach my $name (keys %$to_setup) {
135 my $info = $to_setup->{$name};
136 my $flags = $info->{flags} || DECLARE_NAME;
137 my $run = $info->{run};
138 my $compile = $info->{compile};
139 my $proto = $info->{proto} || '&';
140 my $sub_proto = $proto;
141 # make all args optional to enable lvalue for DECLARE_NONE
142 $sub_proto =~ s/;//; $sub_proto = ';'.$sub_proto;
86c3de80 143 #my $installer = $class->build_sub_installer($pack, $name, $proto);
144 my $installer = $class->build_sub_installer($pack, $name, '@');
145 my $proto_maker = eval q!
146 sub {
147 my $body = shift;
148 sub (!.$sub_proto.q!) {
149 $body->(@_);
150 };
151 };
152 !;
153 $installer->(sub :lvalue {
c5534496 154 if (@_) {
155 if (ref $_[0] eq 'HASH') {
156 shift;
157 my $r = $run->(undef, undef, @_);
158 return $r;
159 } else {
160 return $_[1];
161 }
86c3de80 162 }
163 return my $sv;
164 });
165 $setup_for_args{$name} = [
166 $flags,
167 sub {
168 my ($usepack, $use, $inpack, $name, $proto) = @_;
169 my $extra_code = $compile->($name, $proto);
170 my $main_handler = $proto_maker->(sub {
c5534496 171 ("DONE", $run->($name, $proto, @_));
86c3de80 172 });
173 my ($name_h, $XX);
174 if (defined $proto) {
175 $name_h = sub :lvalue { return my $sv; };
176 $XX = $main_handler;
c5534496 177 } elsif (defined $name && length $name) {
86c3de80 178 $name_h = $main_handler;
c5534496 179 } else {
180 $extra_code ||= '';
181 $extra_code = '}, sub {'.$extra_code;
86c3de80 182 }
183 return ($name_h, $XX, $extra_code);
184 }
185 ];
323ae557 186 }
86c3de80 187 $class->setup_for($pack, \%setup_for_args);
188}
189
190sub install_declarator {
191 my ($class, $target_pack, $target_name, $flags, $filter, $handler) = @_;
192 $class->setup_declarators($target_pack, {
193 $target_name => {
194 flags => $flags,
195 compile => $filter,
196 run => $handler,
197 }
198 });
323ae557 199}
200
94caac6e 201=head1 NAME
202
203Devel::Declare -
204
205=head1 SYNOPSIS
206
207=head1 DESCRIPTION
208
209=head2 import
210
211 use Devel::Declare qw(list of subs);
212
213Calls Devel::Declare->setup_for(__PACKAGE__ => \@list_of_subs);
214
215=head2 unimport
216
217 no Devel::Declare;
218
219Calls Devel::Declare->teardown_for(__PACKAGE__);
220
221=head2 setup_for
222
223 Devel::Declare->setup_for($package => \@subnames);
224
225Installs declarator magic (unless already installed) and registers
226"${package}::$name" for each member of @subnames
227
228=head2 teardown_for
229
230 Devel::Declare->teardown_for($package);
231
232Deregisters all subs currently registered for $package and uninstalls
233declarator magic if number of teardown_for calls matches number of setup_for
234calls.
235
236=head1 AUTHOR
237
238Matt S Trout - <mst@shadowcatsystems.co.uk>
239
240Company: http://www.shadowcatsystems.co.uk/
241Blog: http://chainsawblues.vox.com/
242
243=head1 LICENSE
244
245This library is free software under the same terms as perl itself
246
247=cut
248
2491;