Scope::Upper - Act on upper scopes.
VERSION
- Version 0.15
+ Version 0.16
SYNOPSIS
"reap", "localize", "localize_elem", "localize_delete" and "WORDS" :
my @stuff = zap(); # @stuff contains qw<a b c>
my $stuff = zap(); # $stuff contains 3
+ "uplevel" :
+
+ package Uplevel;
+
+ use Scope::Upper qw<uplevel CALLER>;
+
+ sub target {
+ faker(@_);
+ }
+
+ sub faker {
+ uplevel {
+ my $sub = (caller 0)[3];
+ print "$_[0] from $sub()";
+ } @_ => CALLER(1);
+ }
+
+ target('hello'); # "hello from Uplevel::target()"
+
DESCRIPTION
This module lets you defer actions *at run-time* that will take place
when the control flow returns into an upper scope. Currently, you can:
"localize_delete" ;
* return values immediately to an upper level with "unwind", and know
- which context was in use then with "want_at".
+ which context was in use then with "want_at" ;
+
+ * execute a subroutine in the context of an upper subroutine stack
+ frame with "uplevel".
FUNCTIONS
In all those functions, $context refers to the target scope.
will rightfully set $num to 26.
+ "uplevel $code, @args, $context"
+ Executes the code reference $code with arguments @args as if it were
+ located at the subroutine stack frame pointed by $context, effectively
+ fooling "caller" and "die" into believing that the call actually
+ happened higher in the stack. The code is executed in the context of the
+ "uplevel" call, and what it returns is returned as-is by "uplevel".
+
+ sub target {
+ faker(@_);
+ }
+
+ sub faker {
+ uplevel {
+ map { 1 / $_ } @_;
+ } @_ => CALLER(1);
+ }
+
+ my @inverses = target(1, 2, 4); # @inverses contains (0, 0.5, 0.25)
+ my $count = target(1, 2, 4); # $target is 3
+
+ Sub::Uplevel also implements a pure-Perl version of "uplevel". Both are
+ identical, with the following caveats :
+
+ * The Sub::Uplevel implementation of "uplevel" may execute a code
+ reference in the context of any upper stack frame. The Scope::Upper
+ version only allows to uplevel to a subroutine stack frame, and will
+ croak if you try to target an "eval" or a format.
+
+ * Exceptions thrown from the code called by this version of "uplevel"
+ will not be caught by "eval" blocks between the target frame and the
+ uplevel call, while they will for Sub::Uplevel's version. This means
+ that :
+
+ eval {
+ sub {
+ local $@;
+ eval {
+ sub {
+ uplevel { die 'wut' } CALLER(2); # for Scope::Upper
+ # uplevel(3, sub { die 'wut' }) # for Sub::Uplevel
+ }->();
+ };
+ print "inner block: $@";
+ $@ and exit;
+ }->();
+ };
+ print "outer block: $@";
+
+ will print "inner block: wut..." with Sub::Uplevel and "outer block:
+ wut..." with Scope::Upper.
+
+ * Sub::Uplevel globally overrides "CORE::GLOBAL::caller", while
+ Scope::Upper does not.
+
+ A simple wrapper lets you mimic the interface of "uplevel" in
+ Sub::Uplevel :
+
+ use Scope::Upper;
+
+ sub uplevel {
+ my $frame = shift;
+ my $code = shift;
+ my $cxt = Scope::Upper::CALLER($frame);
+ &Scope::Upper::uplevel($code => @_ => $cxt);
+ }
+
+ Albeit the three exceptions listed above, it passes all the tests of
+ Sub::Uplevel.
+
CONSTANTS
"SU_THREADSAFE"
True iff the module could have been built when thread-safety features.
# $cxt = SCOPE(4), UP SUB UP SUB, or UP SUB EVAL, or UP CALLER(2), or TOP
...
- Where "unwind" and "want_at" point to depending on the $cxt:
+ Where "unwind", "want_at" and "uplevel" point to depending on the $cxt:
sub {
eval {
sub {
{
- unwind @things => $cxt;
+ unwind @things => $cxt; # or uplevel { ... } $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(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)
...
+ # (*) Note that uplevel() will croak if you pass that scope frame,
+ # because it can't target eval scopes.
+
EXPORT
The functions "reap", "localize", "localize_elem", "localize_delete",
- "unwind" and "want_at" are only exported on request, either individually
- or by the tags ':funcs' and ':all'.
+ "unwind", "want_at" and "uplevel" are only exported on request, either
+ individually or by the tags ':funcs' and ':all'.
The constant "SU_THREADSAFE" is also only exported on request,
individually or by the tags ':consts' and ':all'.
Scope::Escape.
+ Sub::Uplevel provides a pure-Perl implementation of "uplevel".
+
AUTHOR
Vincent Pit, "<perl at profvince.com>", <http://www.profvince.com>.