9 use Filter::Util::Call;
10 use Text::Balanced qw/extract_variable extract_quotelike extract_multiple/;
11 use Scalar::Util qw/refaddr set_prototype/;
13 use Sub::Prototype::Util qw/flatten recall wrap/;
17 with - Lexically call methods with a default object.
25 our $VERSION = '0.01';
31 sub new { my $class = shift; bless { id = > shift }, $class }
33 sub hlagh { my $self = shift; print "Deuce::hlagh $self->{id}\n" }
38 sub hlagh { print "Pants::hlagh\n" }
42 my $deuce = new Deuce 1;
48 hlagh; # Deuce::hlagh 1
49 Pants::hlagh; # Pants::hlagh
52 use with \Deuce->new(2);
53 hlagh; # Deuce::hlagh 2
56 hlagh; # Deuce::hlagh 1
66 This pragma lets you define a default object against with methods will be called in the current scope when possible. It is enabled by the C<use with \$obj> idiom (note that you must pass a reference to the object). If you C<use with> several times in the current scope, the default object will be the last specified one.
71 my $CUT = qr/\n=cut.*$EOP/;
73 ^=(?:head[1-4]|item) .*? $CUT
76 | ^=begin \s* (\S+) .*? \n=end \s* \1 .*? $EOP
77 | ^__(DATA|END)__\r?\n.*
81 { 'with::COMMENT' => qr/(?<![\$\@%])#.*/ },
82 { 'with::PODDATA' => $pod_or_DATA },
83 { 'with::QUOTELIKE' => sub {
84 extract_quotelike $_[0], qr/(?=(?:['"]|\bq.|<<\w+))/
86 { 'with::VARIABLE' => sub {
87 extract_variable $_[0], qr/(?=\\?[\$\@\%\&\*])/
89 { 'with::HASHKEY' => qr/\w+\s*=>/ },
90 { 'with::QUALIFIED' => qr/\w+(?:::\w+)+(?:::)?/ },
91 { 'with::SUB' => qr/sub\s+\w+(?:::\w+)*/ },
92 { 'with::FILEHANDLE' => qr/<[\$\*]?[^\W>]*>/ },
93 { 'with::USE' => qr/(?:use|no)\s+\S+/ },
97 $skip{$_} = 1 for qw/my our local sub do eval goto return
98 if else elsif unless given when or and
99 while until for foreach next redo last continue
101 map grep system exec sort print say
103 STDIN STDOUT STDERR/;
105 my @core = qw/abs accept alarm atan2 bind binmode bless caller chdir chmod
106 chop chown chr chroot close closedir connect cos crypt dbmclose
107 defined delete die do dump each endgrent endhostent endnetent
108 endpwent endservent eof eval exec exists exit exp fcntl fileno
109 fork format formline getc getgrent getgrgid getgrnam
110 gethostbyname gethostent getlogin getnetbyaddr getnetbyname
111 getpeername getpgrp getppid getpriority getprotobyname
112 getprotoent getpwent getpwnam getpwuid getservbyname
113 getservent getsockname getsockopt glob gmtime goto grep hex
114 int ioctl join keys kill last lc lcfirst length link listen
115 localtime lock log lstat map mkdir msgctl msgget msgrcv msgsnd
116 next no oct open opendir ord our pack package pipe pop pos print
117 prototype push quotemeta rand read readdir readline readlink
118 redo ref rename require reset return reverse rewinddir rindex
119 scalar seek seekdir select semctl semget semop send setgrent
120 setnetent setpgrp setpriority setprotoent setpwent setservent
121 shift shmctl shmget shmread shmwrite shutdown sin sleep socket
122 sort splice split sprintf sqrt srand stat study sub substr
123 syscall sysopen sysread sysseek system syswrite tell telldir tie
124 time times truncate uc ucfirst umask undef unlink unpack unshift
125 use utime values vec wait waitpid wantarray warn write/;
127 $core{$_} = prototype "CORE::$_" for @core;
131 $core{'defined'} = '_';
132 $core{'undef'} = ';\[$@%&*]';
138 my $name = @_ > 1 ? join '::', @_
140 return *{$name}{CODE};
144 my ($name, $par) = @_;
145 return '' unless $name;
146 my $wrap = 'with::core::' . $name;
147 if (not code $wrap) {
148 my $proto = $core{$name};
149 my $func = wrap { 'CORE::' . $name => $proto }, compile => 1;
150 my $code = set_prototype sub {
151 my ($caller, $H) = (caller 0)[0, 10];
152 my $id = ($H || {})->{with};
155 if ($id and $obj = $hints{$id}) {
156 if (my $meth = $$obj->can($name)) {
157 @_ = flatten $proto, @_ if defined $proto;
162 # Try function call in caller namescape.
163 $name = $caller . '::' . $name;
165 @_ = flatten $proto, @_ if defined $proto;
168 # Try core function call.
169 my @ret = eval { $func->(@_) };
171 # Produce a correct error in regard of the caller.
173 $msg =~ s/(called)\s+at.*/$1/s;
176 return wantarray ? @ret : $ret[0];
183 return $wrap . ' ' . $par;
187 my ($name, $par, $proto) = @_;
188 return '' unless $name;
189 return "with::defer $par'$name'," unless defined $proto;
190 my $wrap = 'with::sub::' . $name;
191 if (not code $wrap) {
192 my $code = set_prototype sub {
193 my ($caller, $H) = (caller 0)[0, 10];
194 my $id = ($H || {})->{with};
197 if ($id and $obj = $hints{$id}) {
198 if (my $meth = $$obj->can($name)) {
199 @_ = flatten $proto, @_;
204 # Try function call in caller namescape.
205 $name = $caller . '::' . $name;
206 goto &$name if code $name;
207 # This call won't succeed, but it'll throw an exception we should propagate.
208 eval { $name->(@_) };
210 # Produce a correct 'Undefined subroutine' error in regard of the caller.
212 $msg =~ s/(called)\s+at.*/$1/s;
215 croak "$name didn't exist and yet the call succeeded\n";
222 return $wrap . ' '. $par;
227 my ($caller, $H) = (caller 0)[0, 10];
228 my $id = ($H || {})->{with};
231 if ($id and $obj = $hints{$id}) {
232 if (my $meth = $$obj->can($name)) {
237 # Try function call in caller namescape.
238 $name = $caller . '::' . $name;
239 goto &$name if code $name;
240 # This call won't succeed, but it'll throw an exception we should propagate.
241 eval { $name->(@_) };
243 # Produce a correct 'Undefined subroutine' error in regard of the caller.
245 $msg =~ s/(called)\s+at.*/$1/s;
248 croak "$name didn't exist and yet the call succeeded\n";
252 return unless defined $_[1] and ref $_[1];
253 my $caller = (caller 0)[0];
254 my $id = refaddr $_[1];
255 $hints{$^H{with} = $id} = $_[1];
257 my ($status, $lastline);
258 my ($data, $count) = ('', 0);
259 while ($status = filter_read) {
260 return $status if $status < 0;
261 return $status unless defined $^H{with} && $^H{with} == $id;
262 if (/^__(?:DATA)__\r?$/ || /\b(?:use|no)\s+with\b/) {
270 return $count if not $count;
273 for (extract_multiple($data, $extractor)) {
274 if (ref) { push @components, $_; $instr = 0 }
275 elsif ($instr) { $components[-1] .= $_ }
276 else { push @components, $_; $instr = 1 }
280 map { (ref) ? $; . pack('N', $i++) . $; : $_ }
282 @components = grep ref, @components;
284 \b &? ([^\W\d]\w+) \s* (?!=>) (\(?)
287 : exists $core{$1} ? corewrap $1, $2
288 : subwrap $1, $2, prototype($caller.'::'.$1)
290 s/\Q$;\E(\C{4})\Q$;\E/${$components[unpack('N',$1)]}/g;
291 $_ .= $lastline if defined $lastline;
301 =head1 HOW DOES IT WORK
303 The main problem to address is that lexical scope and source modifications can only occur at compile time, while object creation and method resolution happen at run-time.
305 The C<use with \$obj> statement stores an address to the variable C<$obj> in the C<with> field of the hints hash C<%^H>. It also starts a source filter that replaces function calls with calls to C<with::defer>, passing the name of the original function as the first argument. When the replaced function is part of Perl core, the call is deferred to a corresponding wrapper generated in the C<with> namespace. Some keywords that couldn't possibly be replaced are also completely skipped. C<no with> undefines the hint and deletes the source filter, stopping any subsequent modification in the current scope.
307 When the script is executed, deferred calls first fetch the default object back from the address stored into the hint. If the object C<< ->can >> the original function name, a method call is issued. If not, the calling namespace is inspected for a subroutine with the proper name, and if it's present the program C<goto>s into it. If that fails too, the core function with the same name is recalled if possible, or an "Undefined subroutine" warning is thrown.
309 =head1 IGNORED KEYWORDS
311 A call will never dispatch to methods whose name is part of :
313 my our local sub do eval goto return
314 if else elsif unless given when or and
315 while until for foreach next redo last continue
317 map grep system exec sort print say
323 No function or constant is exported by this pragma.
327 Most likely slow. Almost surely non thread-safe. Contains source filters, hence brittle. Messes with the dreadful prototypes. Crazy. Will have bugs.
329 Don't put anything on the same line of C<use with \$obj> or C<no with>.
335 L<Carp> (core module since perl 5).
337 L<Filter::Util::Call>, L<Scalar::Util> and L<Text::Balanced> (core since 5.7.3).
339 L<Sub::Prototype::Util> 0.08.
343 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
345 You can contact me by mail or on #perl @ FreeNode (vincent or Prof_Vince).
349 Please report any bugs or feature requests to C<bug-with at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=with>. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
353 You can find documentation for this module with the perldoc command.
357 =head1 ACKNOWLEDGEMENTS
359 A fair part of this module is widely inspired from L<Filter::Simple> (especially C<FILTER_ONLY>), but a complete integration was needed in order to add hints support and more placeholder patterns.
361 =head1 COPYRIGHT & LICENSE
363 Copyright 2008 Vincent Pit, all rights reserved.
365 This program is free software; you can redistribute it and/or modify it
366 under the same terms as Perl itself.