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 wrap>;
17 with - Lexically call methods with a default object.
25 our $VERSION = '0.02';
29 This module was an early experiment which turned out to be completely unpractical.
30 Therefore its use is officially B<deprecated>.
31 Please don't use it, and don't hesitate to contact me if you want to reuse the namespace.
37 sub new { my $class = shift; bless { id = > shift }, $class }
39 sub hlagh { my $self = shift; print "Deuce::hlagh $self->{id}\n" }
44 sub hlagh { print "Pants::hlagh\n" }
48 my $deuce = new Deuce 1;
54 hlagh; # Deuce::hlagh 1
55 Pants::hlagh; # Pants::hlagh
58 use with \Deuce->new(2);
59 hlagh; # Deuce::hlagh 2
62 hlagh; # Deuce::hlagh 1
72 This pragma lets you define a default object against with methods will be called in the current scope when possible.
73 It is enabled by the C<use with \$obj> idiom (note that you must pass a reference to the object).
74 If you C<use with> several times in the current scope, the default object will be the last specified one.
79 my $CUT = qr/\n=cut.*$EOP/;
81 ^=(?:head[1-4]|item) .*? $CUT
84 | ^=begin \s* (\S+) .*? \n=end \s* \1 .*? $EOP
85 | ^__(DATA|END)__\r?\n.*
89 { 'with::COMMENT' => qr/(?<![\$\@%])#.*/ },
90 { 'with::PODDATA' => $pod_or_DATA },
91 { 'with::QUOTELIKE' => sub {
92 extract_quotelike $_[0], qr/(?=(?:['"]|\bq.|<<\w+))/
94 { 'with::VARIABLE' => sub {
95 extract_variable $_[0], qr/(?=\\?[\$\@\%\&\*])/
97 { 'with::HASHKEY' => qr/\w+\s*=>/ },
98 { 'with::QUALIFIED' => qr/\w+(?:::\w+)+(?:::)?/ },
99 { 'with::SUB' => qr/sub\s+\w+(?:::\w+)*/ },
100 { 'with::FILEHANDLE' => qr/<[\$\*]?[^\W>]*>/ },
101 { 'with::USE' => qr/(?:use|no)\s+\S+/ },
105 $skip{$_} = 1 for qw<my our local sub do eval goto return
106 if else elsif unless given when or and
107 while until for foreach next redo last continue
108 eq ne lt gt le ge cmp
109 map grep system exec sort print say
111 STDIN STDOUT STDERR>;
113 my @core = qw<abs accept alarm atan2 bind binmode bless caller chdir chmod
114 chomp chop chown chr chroot close closedir connect cos crypt
115 dbmclose dbmopen defined delete die do dump each endgrent
116 endhostent endnetent endprotoent endpwent endservent eof eval
117 exec exists exit exp fcntl fileno flock fork format formline
118 getc getgrent getgrgid getgrnam gethostbyaddr gethostbyname
119 gethostent getlogin getnetbyaddr getnetbyname getnetent
120 getpeername getpgrp getppid getpriority getprotobyname
121 getprotobynumber getprotoent getpwent getpwnam getpwuid
122 getservbyname getservbyport getservent getsockname getsockopt
123 glob gmtime goto grep hex index int ioctl join keys kill last lc
124 lcfirst length link listen local localtime lock log lstat map
125 mkdir msgctl msgget msgrcv msgsnd my next no oct open opendir
126 ord our pack package pipe pop pos print printf prototype push
127 quotemeta rand read readdir readline readlink recv redo ref
128 rename require reset return reverse rewinddir rindex rmdir
129 scalar seek seekdir select semctl semget semop send setgrent
130 sethostent setnetent setpgrp setpriority setprotoent setpwent
131 setservent setsockopt shift shmctl shmget shmread shmwrite
132 shutdown sin sleep socket socketpair sort splice split sprintf
133 sqrt srand stat study sub substr symlink syscall sysopen sysread
134 sysseek system syswrite tell telldir tie tied time times
135 truncate uc ucfirst umask undef unlink unpack unshift untie use
136 utime values vec wait waitpid wantarray warn write>;
139 $core{$_} = prototype "CORE::$_" for @core;
143 $core{'defined'} = '_';
144 $core{'undef'} = ';\[$@%&*]';
150 my $name = @_ > 1 ? join '::', @_
152 return *{$name}{CODE};
156 my ($name, $par) = @_;
157 return '' unless $name;
158 my $wrap = 'with::core::' . $name;
159 if (not code $wrap) {
160 my $proto = $core{$name};
161 my $func = wrap { 'CORE::' . $name => $proto }, compile => 1;
162 my $code = set_prototype sub {
163 my ($caller, $H) = (caller 0)[0, 10];
164 my $id = ($H || {})->{with};
167 if ($id and $obj = $hints{$id}) {
168 if (my $meth = $$obj->can($name)) {
169 @_ = flatten $proto, @_ if defined $proto;
174 # Try function call in caller namescape.
175 my $qname = $caller . '::' . $name;
177 @_ = flatten $proto, @_ if defined $proto;
180 # Try core function call.
181 my @ret = eval { $func->(@_) };
183 # Produce a correct error in regard of the caller.
185 $msg =~ s/(called)\s+at.*/$1/s;
188 return wantarray ? @ret : $ret[0];
195 return $wrap . ' ' . $par;
199 my ($name, $par, $proto) = @_;
200 return '' unless $name;
201 return "with::defer $par'$name'," unless defined $proto;
202 my $wrap = 'with::sub::' . $name;
203 if (not code $wrap) {
204 my $code = set_prototype sub {
205 my ($caller, $H) = (caller 0)[0, 10];
206 my $id = ($H || {})->{with};
209 if ($id and $obj = $hints{$id}) {
210 if (my $meth = $$obj->can($name)) {
211 @_ = flatten $proto, @_;
216 # Try function call in caller namescape.
217 my $qname = $caller . '::' . $name;
218 goto &$qname if code $qname;
219 # This call won't succeed, but it'll throw an exception we should propagate.
220 eval { no strict 'refs'; $qname->(@_) };
222 # Produce a correct 'Undefined subroutine' error in regard of the caller.
224 $msg =~ s/(called)\s+at.*/$1/s;
227 croak "$qname didn't exist and yet the call succeeded\n";
234 return $wrap . ' '. $par;
239 my ($caller, $H) = (caller 0)[0, 10];
240 my $id = ($H || {})->{with};
243 if ($id and $obj = $hints{$id}) {
244 if (my $meth = $$obj->can($name)) {
249 # Try function call in caller namescape.
250 $name = $caller . '::' . $name;
251 goto &$name if code $name;
252 # This call won't succeed, but it'll throw an exception we should propagate.
253 eval { no strict 'refs'; $name->(@_) };
255 # Produce a correct 'Undefined subroutine' error in regard of the caller.
257 $msg =~ s/(called)\s+at.*/$1/s;
260 croak "$name didn't exist and yet the call succeeded\n";
264 return unless defined $_[1] and ref $_[1];
265 my $caller = (caller 0)[0];
266 my $id = refaddr $_[1];
267 $hints{$^H{with} = $id} = $_[1];
269 my ($status, $lastline);
270 my ($data, $count) = ('', 0);
271 while ($status = filter_read) {
272 return $status if $status < 0;
273 return $status unless defined $^H{with} && $^H{with} == $id;
274 if (/^__(?:DATA)__\r?$/ || /\b(?:use|no)\s+with\b/) {
282 return $count if not $count;
285 for (extract_multiple($data, $extractor)) {
286 if (ref) { push @components, $_; $instr = 0 }
287 elsif ($instr) { $components[-1] .= $_ }
288 else { push @components, $_; $instr = 1 }
292 map { (ref) ? $; . pack('N', $i++) . $; : $_ }
294 @components = grep ref, @components;
296 \b &? ([^\W\d]\w+) \s* (?!=>) (\(?)
299 : exists $core{$1} ? corewrap $1, $2
300 : subwrap $1, $2, prototype($caller.'::'.$1)
302 s/\Q$;\E(\C{4})\Q$;\E/${$components[unpack('N',$1)]}/g;
303 $_ .= $lastline if defined $lastline;
313 =head1 HOW DOES IT WORK
315 The main problem to address is that lexical scoping and source modification can only occur at compile time, while object creation and method resolution happen at run-time.
317 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>.
318 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.
319 When the replaced function has a prototype or is part of the core, the call is deferred to a corresponding wrapper generated in the C<with> namespace.
320 Some keywords that couldn't possibly be replaced are also completely skipped.
321 C<no with> undefines the hint and deletes the source filter, stopping any subsequent modification in the current scope.
323 When the script is executed, deferred calls first fetch the default object back from the address stored into the hint.
324 If the object C<< ->can >> the original function name, a method call is issued.
325 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.
326 If that fails too, the core function with the same name is recalled if possible, or an "Undefined subroutine" error is thrown.
328 =head1 IGNORED KEYWORDS
330 A call will never be dispatched to a method whose name is one of :
332 my our local sub do eval goto return
333 if else elsif unless given when or and
334 while until for foreach next redo last continue
335 eq ne lt gt le ge cmp
336 map grep system exec sort print say
342 No function or constant is exported by this pragma.
347 Almost surely non thread-safe.
348 Contains source filters, hence brittle.
349 Messes with the dreadful prototypes.
353 Don't put anything on the same line of C<use with \$obj> or C<no with>.
355 When there's a function in the caller namespace that has a core function name, and when no method with the same name is present, the ambiguity is resolved in favor of the caller namespace.
356 That's different from the usual perl semantics where C<sub push; push @a, 1> gets resolved to CORE::push.
358 If a method has the same name as a prototyped function in the caller namespace, and if a called is deferred to the method, it will have its arguments passed by value.
364 L<Carp> (core module since perl 5).
366 L<Filter::Util::Call>, L<Scalar::Util> and L<Text::Balanced> (core since 5.7.3).
368 L<Sub::Prototype::Util> 0.08.
372 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
374 You can contact me by mail or on C<irc.perl.org> (vincent).
378 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>.
379 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
383 You can find documentation for this module with the perldoc command.
387 =head1 ACKNOWLEDGEMENTS
389 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.
391 =head1 COPYRIGHT & LICENSE
393 Copyright 2008 Vincent Pit, all rights reserved.
395 This program is free software; you can redistribute it and/or modify it
396 under the same terms as Perl itself.