=head1 VERSION
-Version 0.06
+Version 0.09
=cut
our $VERSION;
BEGIN {
- $VERSION = '0.06';
+ $VERSION = '0.09';
}
=head1 SYNOPSIS
sub zap {
try {
return @things; # returns to try() and then outside zap()
+ # not reached
}
+ # not reached
}
my @what = zap(); # @what contains @things
=head1 DESCRIPTION
-This module lets you defer actions that will take place when the control flow returns into an upper scope.
-Currently, you can hook an upper scope end, or localize variables, array/hash values or deletions of elements in higher contexts.
-You can also return to an upper level and know which context was in use then.
+This module lets you defer actions I<at run-time> that will take place when the control flow returns into an upper scope.
+Currently, you can:
+
+=over 4
+
+=item *
+
+hook an upper scope end with L</reap> ;
+
+=item *
+
+localize variables, array/hash values or deletions of elements in higher contexts with respectively L</localize>, L</localize_elem> and L</localize_delete> ;
+
+=item *
+
+return values immediately to an upper level with L</unwind>, and know which context was in use then with L</want_at>.
+
+=back
=head1 FUNCTIONS
In all those functions, C<$context> refers to the target scope.
-You have to use one or a combination of L</WORDS> to build the C<$context> to pass to these functions.
+You have to use one or a combination of L</WORDS> to build the C<$context> passed to these functions.
This is needed in order to ensure that the module still works when your program is ran in the debugger.
-Don't try to use a raw value or things will get messy.
-
-The only thing you can assume is that it is an I<absolute> indicator of the frame.
-This means that you can safely store it at some point and use it when needed, and it will still denote the original scope.
+The only thing you can assume is that it is an I<absolute> indicator of the frame, which means that you can safely store it at some point and use it when needed, and it will still denote the original scope.
=cut
=head2 C<reap $callback, $context>
-Add a destructor that calls C<$callback> when the upper scope represented by C<$context> ends.
+Add a destructor that calls C<$callback> (in void context) when the upper scope represented by C<$context> ends.
=head2 C<localize $what, $value, $context>
my $num = sub {
my @a = ('a' .. 'z');
unwind @a => HERE;
+ # not reached
}->();
will set C<$num> to C<'z'>.
my $num = sub {
my @a = ('a' .. 'z');
unwind +(want_at(HERE) ? @a : scalar @a) => HERE;
+ # not reached
}->();
-will righteously set C<$num> to C<26>.
+will rightfully set C<$num> to C<26>.
+
+=head1 CONSTANTS
+
+=head2 C<SU_THREADSAFE>
+
+True iff the module could have been built when thread-safety features.
=head1 WORDS
=head3 C<SUB $from>
The context of the closest subroutine above C<$from>.
+Note that C<$from> is returned if it is already a subroutine context ; hence C<SUB SUB == SUB>.
=head3 C<EVAL $from>
The context of the closest eval above C<$from>.
+Note that C<$from> is returned if it is already an eval context ; hence C<EVAL EVAL == EVAL>.
=head2 Getting a context from a level
The context of the C<$level>-th upper subroutine/eval/format.
It kind of corresponds to the context represented by C<caller $level>, but while e.g. C<caller 0> refers to the caller context, C<CALLER 0> will refer to the top scope in the current context.
+=head2 Examples
+
+Where L</reap> fires depending on the C<$cxt> :
+
+ sub {
+ eval {
+ sub {
+ {
+ reap \&cleanup => $cxt;
+ ...
+ } # $cxt = SCOPE(0), or HERE
+ ...
+ }->(); # $cxt = SCOPE(1), or UP, or SUB, or CALLER, or CALLER(0)
+ ...
+ }; # $cxt = SCOPE(2), or UP UP, or UP SUB, or EVAL, or CALLER(1)
+ ...
+ }->(); # $cxt = SCOPE(3), or SUB UP SUB, or SUB EVAL, or CALLER(2)
+ ...
+
+Where L</localize>, L</localize_elem> and L</localize_delete> act depending on the C<$cxt> :
+
+ sub {
+ eval {
+ sub {
+ {
+ localize '$x' => 1 => $cxt;
+ # $cxt = SCOPE(0), or HERE
+ ...
+ }
+ # $cxt = SCOPE(1), or UP, or SUB, or CALLER, or CALLER(0)
+ ...
+ }->();
+ # $cxt = SCOPE(2), or UP UP, or UP SUB, or EVAL, or CALLER(1)
+ ...
+ };
+ # $cxt = SCOPE(3), or SUB UP SUB, or SUB EVAL, or CALLER(2)
+ ...
+ }->();
+ # $cxt = SCOPE(4), UP SUB UP SUB, or UP SUB EVAL, or UP CALLER(2), or TOP
+ ...
+
+Where L</unwind> and L</want_at> point to depending on the C<$cxt>:
+
+ sub {
+ eval {
+ sub {
+ {
+ unwind @things => $cxt;
+ ...
+ }
+ ...
+ }->(); # $cxt = SCOPE(0 .. 1), or HERE, or UP, or SUB, or CALLER(0)
+ ...
+ }; # $cxt = SCOPE(2), or UP UP, or UP SUB, or EVAL, or CALLER(1)
+ ...
+ }->(); # $cxt = SCOPE(3), or SUB UP SUB, or SUB EVAL, or CALLER(2)
+ ...
+
=head1 EXPORT
The functions L</reap>, L</localize>, L</localize_elem>, L</localize_delete>, L</unwind> and L</want_at> are only exported on request, either individually or by the tags C<':funcs'> and C<':all'>.
+The constant L</SU_THREADSAFE> is also only exported on request, individually or by the tags C<':consts'> and C<':all'>.
+
Same goes for the words L</TOP>, L</HERE>, L</UP>, L</SUB>, L</EVAL>, L</SCOPE> and L</CALLER> that are only exported on request, individually or by the tags C<':words'> and C<':all'>.
=cut
our @EXPORT = ();
our %EXPORT_TAGS = (
- funcs => [ qw/reap localize localize_elem localize_delete unwind want_at/ ],
- words => [ qw/TOP HERE UP SUB EVAL SCOPE CALLER/ ],
+ funcs => [ qw/reap localize localize_elem localize_delete unwind want_at/ ],
+ words => [ qw/TOP HERE UP SUB EVAL SCOPE CALLER/ ],
+ consts => [ qw/SU_THREADSAFE/ ],
);
our @EXPORT_OK = map { @$_ } values %EXPORT_TAGS;
$EXPORT_TAGS{'all'} = [ @EXPORT_OK ];
The first case is "solved" by moving the C<local> before the C<reap>, and the second by using L</localize> instead of L</reap>.
-L</reap>, L</localize> and L</localize_elem> effects can't cross C<BEGIN> blocks, hence calling those functions in C<import> is deemed to be useless.
+The effects of L</reap>, L</localize> and L</localize_elem> can't cross C<BEGIN> blocks, hence calling those functions in C<import> is deemed to be useless.
This is an hopeless case because C<BEGIN> blocks are executed once while localizing constructs should do their job at each run.
+However, it's possible to hook the end of the current scope compilation with L<B::Hooks::EndOfScope>.
Some rare oddities may still happen when running inside the debugger.
-It may help to use a perl higher than 5.8.9 or 5.10.0, as they contain some context fixes.
+It may help to use a perl higher than 5.8.9 or 5.10.0, as they contain some context-related fixes.
=head1 DEPENDENCIES
L<Alias>, L<Hook::Scope>, L<Scope::Guard>, L<Guard>.
+L<Continuation::Escape> is a thin wrapper around L<Scope::Upper> that gives you a continuation passing style interface to L</unwind>.
+It's easier to use, but it requires you to have control over the scope where you want to return.
+
=head1 AUTHOR
Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
=head1 COPYRIGHT & LICENSE
-Copyright 2008-2009 Vincent Pit, all rights reserved.
+Copyright 2008,2009,2010 Vincent Pit, all rights reserved.
This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.