]> git.vpit.fr Git - perl/modules/Scope-Upper.git/blobdiff - README
This is 0.17
[perl/modules/Scope-Upper.git] / README
diff --git a/README b/README
index b917cb2595fdcd281dc408a24ab91126dca47853..faa4a768d5ef3ba30225e7fd74f0e87f3531abe1 100644 (file)
--- a/README
+++ b/README
@@ -2,14 +2,14 @@ NAME
     Scope::Upper - Act on upper scopes.
 
 VERSION
-    Version 0.14
+    Version 0.17
 
 SYNOPSIS
     "reap", "localize", "localize_elem", "localize_delete" and "WORDS" :
 
         package Scope;
 
-        use Scope::Upper qw/reap localize localize_elem localize_delete :words/;
+        use Scope::Upper qw<reap localize localize_elem localize_delete :words>;
 
         sub new {
          my ($class, $name) = @_;
@@ -72,7 +72,7 @@ SYNOPSIS
 
         package Try;
 
-        use Scope::Upper qw/unwind want_at :words/;
+        use Scope::Upper qw<unwind want_at :words>;
 
         sub try (&) {
          my @result = shift->();
@@ -84,16 +84,35 @@ SYNOPSIS
 
         sub zap {
          try {
-          my @things = qw/a b c/;
+          my @things = qw<a b c>;
           return @things; # returns to try() and then outside zap()
           # not reached
          };
          # not reached
         }
 
-        my @stuff = zap(); # @stuff contains qw/a b c/
+        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:
@@ -105,7 +124,10 @@ DESCRIPTION
         "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 setting of an upper subroutine stack
+        frame with "uplevel".
 
 FUNCTIONS
     In all those functions, $context refers to the target scope.
@@ -234,6 +256,75 @@ FUNCTIONS
 
     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); # $count 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 can only 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 the Perl keyword "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.
@@ -316,27 +407,30 @@ WORDS
         # $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 cannot 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'.
@@ -378,6 +472,21 @@ CAVEATS
     may help to use a perl higher than 5.8.9 or 5.10.0, as they contain some
     context-related fixes.
 
+    Calling "goto" to replace an "uplevel"'d code frame does not work when a
+    custom runloop is used or when debugging flags are set with "perl -D".
+    In those two cases, "uplevel" will look for a "goto &sub" statement in
+    its callback and, if there is one, throw an exception before executing
+    the code.
+
+    Moreover, in order to handle "goto" statements properly, "uplevel"
+    currently has to suffer a run-time overhead proportional to the size of
+    the the callback in every case (with a small ratio), and proportional to
+    the size of all the code executed as the result of the "uplevel" call
+    (including subroutine calls inside the callback) when a "goto" statement
+    is found in the "uplevel" callback. Despite this shortcoming, this XS
+    version of "uplevel" should still run way faster than the pure-Perl
+    version from Sub::Uplevel.
+
 DEPENDENCIES
     XSLoader (standard since perl 5.006).
 
@@ -386,6 +495,8 @@ SEE ALSO
 
     Alias, Hook::Scope, Scope::Guard, Guard.
 
+    Sub::Uplevel.
+
     Continuation::Escape is a thin wrapper around Scope::Upper that gives
     you a continuation passing style interface to "unwind". It's easier to
     use, but it requires you to have control over the scope where you want