reallocate PL_linestr to 8192 chars min in a source filter to avoid need to realloc...
[p5sagit/Devel-Declare.git] / lib / Devel / Declare.pm
CommitLineData
94caac6e 1package Devel::Declare;
2
3use strict;
4use warnings;
5use 5.008001;
6
498cc8bc 7our $VERSION = '0.001006';
94caac6e 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}
67
94caac6e 68my $temp_name;
0ba8c7aa 69my $temp_save;
94caac6e 70
71sub init_declare {
0f070758 72 my ($usepack, $use, $inpack, $name, $proto, $traits) = @_;
53e3ab32 73 my ($name_h, $XX_h, $extra_code)
9026391e 74 = $declarator_handlers{$usepack}{$use}->(
0f070758 75 $usepack, $use, $inpack, $name, $proto, defined(wantarray), $traits
53e3ab32 76 );
15d0d014 77 ($temp_name, $temp_save) = ([], []);
0ba8c7aa 78 if ($name) {
9026391e 79 $name = "${inpack}::${name}" unless $name =~ /::/;
0ba8c7aa 80 push(@$temp_name, $name);
81 no strict 'refs';
15d0d014 82 push(@$temp_save, \&{$name});
0ba8c7aa 83 no warnings 'redefine';
84 no warnings 'prototype';
15d0d014 85 *{$name} = $name_h;
0ba8c7aa 86 }
87 if ($XX_h) {
9026391e 88 push(@$temp_name, "${inpack}::X");
0ba8c7aa 89 no strict 'refs';
9026391e 90 push(@$temp_save, \&{"${inpack}::X"});
0ba8c7aa 91 no warnings 'redefine';
92 no warnings 'prototype';
9026391e 93 *{"${inpack}::X"} = $XX_h;
0ba8c7aa 94 }
53e3ab32 95 if (defined wantarray) {
96 return $extra_code || '0;';
97 } else {
98 return;
99 }
94caac6e 100}
101
102sub done_declare {
103 no strict 'refs';
86c3de80 104 my $name = shift(@{$temp_name||[]});
0ba8c7aa 105 die "done_declare called with no temp_name stack" unless defined($name);
86c3de80 106 my $saved = shift(@$temp_save);
15d0d014 107 $name =~ s/(.*):://;
108 my $temp_pack = $1;
0ba8c7aa 109 delete ${"${temp_pack}::"}{$name};
110 if ($saved) {
111 no warnings 'prototype';
112 *{"${temp_pack}::${name}"} = $saved;
113 }
94caac6e 114}
115
323ae557 116sub build_sub_installer {
117 my ($class, $pack, $name, $proto) = @_;
118 return eval "
119 package ${pack};
120 my \$body;
121 sub ${name} (${proto}) :lvalue {\n"
003ac394 122 .' if (wantarray) {
c5912dc7 123 goto &$body;
003ac394 124 }
125 my $ret = $body->(@_);
86c3de80 126 return $ret;
323ae557 127 };
128 sub { ($body) = @_; };';
129}
130
131sub setup_declarators {
132 my ($class, $pack, $to_setup) = @_;
86c3de80 133 die "${class}->setup_declarators(\$pack, \\\%to_setup)"
134 unless defined($pack) && ref($to_setup) eq 'HASH';
135 my %setup_for_args;
323ae557 136 foreach my $name (keys %$to_setup) {
137 my $info = $to_setup->{$name};
138 my $flags = $info->{flags} || DECLARE_NAME;
139 my $run = $info->{run};
140 my $compile = $info->{compile};
141 my $proto = $info->{proto} || '&';
142 my $sub_proto = $proto;
143 # make all args optional to enable lvalue for DECLARE_NONE
144 $sub_proto =~ s/;//; $sub_proto = ';'.$sub_proto;
86c3de80 145 #my $installer = $class->build_sub_installer($pack, $name, $proto);
146 my $installer = $class->build_sub_installer($pack, $name, '@');
86c3de80 147 $installer->(sub :lvalue {
003ac394 148#{ no warnings 'uninitialized'; warn 'INST: '.join(', ', @_)."\n"; }
c5534496 149 if (@_) {
150 if (ref $_[0] eq 'HASH') {
151 shift;
003ac394 152 if (wantarray) {
153 my @ret = $run->(undef, undef, @_);
154 return @ret;
155 }
c5534496 156 my $r = $run->(undef, undef, @_);
157 return $r;
158 } else {
003ac394 159 return @_[1..$#_];
c5534496 160 }
86c3de80 161 }
162 return my $sv;
163 });
164 $setup_for_args{$name} = [
165 $flags,
166 sub {
0f070758 167 my ($usepack, $use, $inpack, $name, $proto, $shift_hashref, $traits) = @_;
168 my $extra_code = $compile->($name, $proto, $traits);
003ac394 169 my $main_handler = sub { shift if $shift_hashref;
c5534496 170 ("DONE", $run->($name, $proto, @_));
003ac394 171 };
86c3de80 172 my ($name_h, $XX);
173 if (defined $proto) {
174 $name_h = sub :lvalue { return my $sv; };
175 $XX = $main_handler;
c5534496 176 } elsif (defined $name && length $name) {
86c3de80 177 $name_h = $main_handler;
178 }
003ac394 179 $extra_code ||= '';
180 $extra_code = '}, sub {'.$extra_code;
86c3de80 181 return ($name_h, $XX, $extra_code);
182 }
183 ];
323ae557 184 }
86c3de80 185 $class->setup_for($pack, \%setup_for_args);
186}
187
188sub install_declarator {
189 my ($class, $target_pack, $target_name, $flags, $filter, $handler) = @_;
190 $class->setup_declarators($target_pack, {
191 $target_name => {
192 flags => $flags,
193 compile => $filter,
194 run => $handler,
195 }
196 });
323ae557 197}
198
94caac6e 199=head1 NAME
200
201Devel::Declare -
202
203=head1 SYNOPSIS
204
f5f9f113 205Look at the tests. This module is currently on CPAN to ease smoke testing
206and allow early adopters who've been involved in the design to experiment
207with it.
208
94caac6e 209=head1 DESCRIPTION
210
211=head2 import
212
213 use Devel::Declare qw(list of subs);
214
215Calls Devel::Declare->setup_for(__PACKAGE__ => \@list_of_subs);
216
217=head2 unimport
218
219 no Devel::Declare;
220
221Calls Devel::Declare->teardown_for(__PACKAGE__);
222
223=head2 setup_for
224
225 Devel::Declare->setup_for($package => \@subnames);
226
227Installs declarator magic (unless already installed) and registers
228"${package}::$name" for each member of @subnames
229
230=head2 teardown_for
231
232 Devel::Declare->teardown_for($package);
233
234Deregisters all subs currently registered for $package and uninstalls
235declarator magic if number of teardown_for calls matches number of setup_for
236calls.
237
238=head1 AUTHOR
239
02f5a508 240Matt S Trout - <mst@shadowcat.co.uk>
94caac6e 241
02f5a508 242Company: http://www.shadowcat.co.uk/
94caac6e 243Blog: http://chainsawblues.vox.com/
244
245=head1 LICENSE
246
247This library is free software under the same terms as perl itself
248
249=cut
250
2511;