]> git.vpit.fr Git - perl/modules/Scope-Upper.git/commitdiff
This is 0.16 v0.16
authorVincent Pit <vince@profvince.com>
Sat, 3 Sep 2011 23:00:26 +0000 (01:00 +0200)
committerVincent Pit <vince@profvince.com>
Sat, 3 Sep 2011 23:00:26 +0000 (01:00 +0200)
Changes
META.json
META.yml
README
lib/Scope/Upper.pm

diff --git a/Changes b/Changes
index 401dc7d4faf937d0aea5ec5b4f34c0187c2df4ac..5fd9db049cb07da22593c02f412b60ae8f071238 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,5 +1,14 @@
 Revision history for Scope-Upper
 
+0.16    2011-09-03 23:00 UTC
+        + Add : uplevel($code, @args, $cxt) executes $code with arguments @args
+                in the upper context pointed by $cxt.
+                This is an XS version of the well-known uplevel() routine from
+                Sub::Uplevel. There are a few differences between both
+                implmentations that are listed in the documentation.
+                The XS version is roughly 10 times faster than the pure-Perl
+                version.
+
 0.15    2011-08-24 14:20 UTC
         + Fix : Localizing subroutines in an higher scope will now correctly
                 update the method cache.
index 2aaa7aa971c127af90aac5b46552c24116b8303c..8c9b3000de2fb521533a6cb91e5e770b1f240ad4 100644 (file)
--- a/META.json
+++ b/META.json
@@ -57,5 +57,5 @@
          "url" : "http://git.profvince.com/?p=perl%2Fmodules%2FScope-Upper.git"
       }
    },
-   "version" : "0.15"
+   "version" : "0.16"
 }
index 55e7233777f84f55640e118bb18fd6e37713e0f4..ee2d6075ddeac7b22c18445516783fe2a4a0046f 100644 (file)
--- a/META.yml
+++ b/META.yml
@@ -32,4 +32,4 @@ resources:
   homepage: http://search.cpan.org/dist/Scope-Upper/
   license: http://dev.perl.org/licenses/
   repository: http://git.profvince.com/?p=perl%2Fmodules%2FScope-Upper.git
-version: 0.15
+version: 0.16
diff --git a/README b/README
index 54b68ffbfde8a517d4c10e1eac61534fcd320d32..3a5d76782328366d48bed86937fcd8cb843cd0d9 100644 (file)
--- a/README
+++ b/README
@@ -2,7 +2,7 @@ NAME
     Scope::Upper - Act on upper scopes.
 
 VERSION
-    Version 0.15
+    Version 0.16
 
 SYNOPSIS
     "reap", "localize", "localize_elem", "localize_delete" and "WORDS" :
@@ -94,6 +94,25 @@ SYNOPSIS
         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 context 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); # $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.
@@ -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 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'.
@@ -393,6 +487,8 @@ SEE ALSO
 
     Scope::Escape.
 
+    Sub::Uplevel provides a pure-Perl implementation of "uplevel".
+
 AUTHOR
     Vincent Pit, "<perl at profvince.com>", <http://www.profvince.com>.
 
index 73961880af228bd3064a65b8ca47025d18031772..34fe41fc26ad6d6c90d4ed6138250c61d0fdd7f8 100644 (file)
@@ -9,13 +9,13 @@ Scope::Upper - Act on upper scopes.
 
 =head1 VERSION
 
-Version 0.15
+Version 0.16
 
 =cut
 
 our $VERSION;
 BEGIN {
- $VERSION = '0.15';
+ $VERSION = '0.16';
 }
 
 =head1 SYNOPSIS