get_linestr works, callback code works, set_linestr compiles but not tested
[p5sagit/Devel-Declare.git] / lib / Devel / Declare.pm
CommitLineData
94caac6e 1package Devel::Declare;
2
3use strict;
4use warnings;
5use 5.008001;
6
bedac9ff 7our $VERSION = '0.001011';
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
569ac469 199sub linestr_callback_const {
200 warn "Linestr_callback_const: @_\n";
201 my $l = get_linestr();
202 warn "linestr: ${l}\n";
203 warn "w/offset: ".substr($l, $_[1])."\n";
204}
205
206sub linestr_callback {
207 my $type = shift;
208 my $meth = "linestr_callback_${type}";
209 __PACKAGE__->can($meth)->(@_);
210 return 'foo';
211}
212
94caac6e 213=head1 NAME
214
215Devel::Declare -
216
217=head1 SYNOPSIS
218
f5f9f113 219Look at the tests. This module is currently on CPAN to ease smoke testing
220and allow early adopters who've been involved in the design to experiment
221with it.
222
94caac6e 223=head1 DESCRIPTION
224
225=head2 import
226
227 use Devel::Declare qw(list of subs);
228
229Calls Devel::Declare->setup_for(__PACKAGE__ => \@list_of_subs);
230
231=head2 unimport
232
233 no Devel::Declare;
234
235Calls Devel::Declare->teardown_for(__PACKAGE__);
236
237=head2 setup_for
238
239 Devel::Declare->setup_for($package => \@subnames);
240
241Installs declarator magic (unless already installed) and registers
242"${package}::$name" for each member of @subnames
243
244=head2 teardown_for
245
246 Devel::Declare->teardown_for($package);
247
248Deregisters all subs currently registered for $package and uninstalls
249declarator magic if number of teardown_for calls matches number of setup_for
250calls.
251
252=head1 AUTHOR
253
02f5a508 254Matt S Trout - <mst@shadowcat.co.uk>
94caac6e 255
02f5a508 256Company: http://www.shadowcat.co.uk/
94caac6e 257Blog: http://chainsawblues.vox.com/
258
259=head1 LICENSE
260
261This library is free software under the same terms as perl itself
262
263=cut
264
2651;