]> git.vpit.fr Git - perl/modules/Scope-Context.git/blobdiff - lib/Scope/Context.pm
Avoid building a temporary object in up(), sub() and eval()
[perl/modules/Scope-Context.git] / lib / Scope / Context.pm
index 7bf5c8c4e9d01c4c85ae5e44b105fc7a0b84a2ad..9f887b3442975f8097b7513aeaf6b87bbfc01e65 100644 (file)
@@ -29,7 +29,7 @@ our $VERSION = '0.01';
     for (1 .. 5) {
      sub {
       eval {
-       # create Scope::Context objects
+       # Create Scope::Context objects for different upper frames.
        my ($block, $sub, $eval, $loop);
        {
         $block = Scope::Context->new;
@@ -46,7 +46,7 @@ our $VERSION = '0.01';
        # This prints "hello" when the eval block above ends.
        $eval->reap(sub { print "hello\n" });
 
-       # Ignore $SIG{__DIE__} just for the loop.
+       # Ignore $SIG{__DIE__} just for the loop body.
        $loop->localize_delete('%SIG', '__DIE__');
 
        # Execute the callback as if it ran in place of the sub.
@@ -56,8 +56,15 @@ our $VERSION = '0.01';
 
        # Immediately return (1, 2, 3) from the sub, bypassing the eval.
        $sub->unwind(@values, 3);
+
+       # Not reached.
       }
+
+      # Not reached.
      }->();
+
+     # unwind() returns here. "hello\n" was printed, and now
+     # $SIG{__DIE__} is undefined.
     }
 
 =head1 DESCRIPTION
@@ -70,17 +77,20 @@ This gives you a prettier and safer interface when you are not reaching for extr
 The L<Scope::Context> methods actually do more than their subroutine counterparts from L<Scope::Upper> : before each call, the target context will be checked to ensure it is still active (which means that it is still present in the current call stack), and an exception will be thrown if you attempt to act on a context that has already expired.
 This means that :
 
-    my $sc;
+    my $cxt;
     {
-     $sc = Scope::Context->new;
+     $cxt = Scope::Context->new;
     }
-    $sc->reap(sub { print "hello\n });
+    $cxt->reap(sub { print "hello\n });
 
 will croak when L</reap> is called.
 
 =head1 METHODS
 
-=head2 C<new [ $context ]>
+=head2 C<new>
+
+    my $cxt = Scope::Context->new;
+    my $cxt = Scope::Context->new($scope_upper_cxt);
 
 Creates a new immutable L<Scope::Context> object from the L<Scope::Upper>-comptabile context C<$context>.
 If omitted, C<$context> defaults to the current context.
@@ -121,10 +131,14 @@ sub _croak {
 
 =head2 C<cxt>
 
+    my $scope_upper_cxt = $cxt->cxt;
+
 Read-only accessor to the L<Scope::Upper> context corresponding to the topic L<Scope::Context> object.
 
 =head2 C<uid>
 
+    my $uid = $cxt->uid;
+
 Read-only accessor to the L<Scope::Upper> UID of the topic L<Scope::Context> object.
 
 =cut
@@ -155,6 +169,8 @@ use overload (
 
 =head2 C<is_valid>
 
+    my $is_valid = $cxt->is_valid;
+
 Returns true if and only if the topic context is still valid (that is, it designates a scope that is higher than the topic context in the call stack).
 
 =cut
@@ -163,6 +179,8 @@ sub is_valid { Scope::Upper::validate_uid($_[0]->uid) }
 
 =head2 C<assert_valid>
 
+    $cxt->assert_valid;
+
 Throws an exception if the topic context has expired and is no longer valid.
 Returns true otherwise.
 
@@ -178,6 +196,8 @@ sub assert_valid {
 
 =head2 C<want>
 
+    my $want = $cxt->want;
+
 Returns the Perl context (in the sense of C<wantarray> : C<undef> for void context, C<''> for scalar context, and true for list context) in which is executed the scope corresponding to the topic L<Scope::Context> object.
 
 =cut
@@ -190,7 +210,11 @@ sub want {
  Scope::Upper::want_at($self->cxt);
 }
 
-=head2 C<up [ $frames ]>
+=head2 C<up>
+
+    my $up_cxt = $cxt->up;
+    my $up_cxt = $cxt->up($frames);
+    my $up_cxt = Scope::Context->up;
 
 Returns a new L<Scope::Context> object pointing to the C<$frames>-th upper scope above the topic context.
 
@@ -212,21 +236,26 @@ If omitted, C<$frames> defaults to C<1>.
 sub up {
  my ($self, $frames) = @_;
 
+ my $cxt;
  if (Scalar::Util::blessed($self)) {
   $self->assert_valid;
+  $cxt = $self->cxt;
  } else {
-  $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
+  $cxt = Scope::Upper::UP(Scope::Upper::SUB());
  }
 
  $frames = 1 unless defined $frames;
 
- my $cxt = $self->cxt;
  $cxt = Scope::Upper::UP($cxt) for 1 .. $frames;
 
  $self->new($cxt);
 }
 
-=head2 C<sub [ $frames ]>
+=head2 C<sub>
+
+    my $sub_cxt = $cxt->sub;
+    my $sub_cxt = $cxt->sub($frames);
+    my $sub_cxt = Scope::Context->sub;
 
 Returns a new L<Scope::Context> object pointing to the C<$frames>-th subroutine scope above the topic context.
 
@@ -241,7 +270,7 @@ If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclos
     }
 
     sub inner {
-     my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub
+     my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub(1)
      # $sub points to the context for the outer() sub.
     }
 
@@ -250,21 +279,27 @@ If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclos
 sub sub {
  my ($self, $frames) = @_;
 
+ my $cxt;
  if (Scalar::Util::blessed($self)) {
   $self->assert_valid;
+  $cxt = $self->cxt;
  } else {
-  $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
+  $cxt = Scope::Upper::UP(Scope::Upper::SUB());
  }
 
  $frames = 0 unless defined $frames;
 
my $cxt = Scope::Upper::SUB($self->cxt);
$cxt = Scope::Upper::SUB($cxt);
  $cxt = Scope::Upper::SUB(Scope::Upper::UP($cxt)) for 1 .. $frames;
 
  $self->new($cxt);
 }
 
-=head2 C<eval [ $frames ]>
+=head2 C<eval>
+
+    my $eval_cxt = $cxt->eval;
+    my $eval_cxt = $cxt->eval($frames);
+    my $eval_cxt = Scope::Context->eval;
 
 Returns a new L<Scope::Context> object pointing to the C<$frames>-th C<eval> scope above the topic context.
 
@@ -284,21 +319,25 @@ If omitted, C<$frames> defaults to C<0>, which results in the closest eval enclo
 sub eval {
  my ($self, $frames) = @_;
 
+ my $cxt;
  if (Scalar::Util::blessed($self)) {
   $self->assert_valid;
+  $cxt = $self->cxt;
  } else {
-  $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
+  $cxt = Scope::Upper::UP(Scope::Upper::SUB());
  }
 
  $frames = 0 unless defined $frames;
 
my $cxt = Scope::Upper::EVAL($self->cxt);
$cxt = Scope::Upper::EVAL($cxt);
  $cxt = Scope::Upper::EVAL(Scope::Upper::UP($cxt)) for 1 .. $frames;
 
  $self->new($cxt);
 }
 
-=head2 C<reap $code>
+=head2 C<reap>
+
+    $cxt->reap($code);
 
 Execute C<$code> when the topic context ends.
 
@@ -314,7 +353,9 @@ sub reap {
  &Scope::Upper::reap($code, $self->cxt);
 }
 
-=head2 C<localize $what, $value>
+=head2 C<localize>
+
+    $cxt->localize($what, $value);
 
 Localize the variable described by C<$what> to the value C<$value> when the control flow returns to the scope pointed by the topic context.
 
@@ -330,7 +371,9 @@ sub localize {
  Scope::Upper::localize($what, $value, $self->cxt);
 }
 
-=head2 C<localize_elem $what, $key, $value>
+=head2 C<localize_elem>
+
+    $cxt->localize_elem($what, $key, $value);
 
 Localize the element C<$key> of the variable C<$what> to the value C<$value> when the control flow returns to the scope pointed by the topic context.
 
@@ -346,7 +389,9 @@ sub localize_elem {
  Scope::Upper::localize_elem($what, $key, $value, $self->cxt);
 }
 
-=head2 C<localize_delete $what, $key>
+=head2 C<localize_delete>
+
+    $cxt->localize_delete($what, $key);
 
 Delete the element C<$key> from the variable C<$what> when the control flow returns to the scope pointed by the topic context.
 
@@ -362,7 +407,9 @@ sub localize_delete {
  Scope::Upper::localize_delete($what, $key, $self->cxt);
 }
 
-=head2 C<unwind @values>
+=head2 C<unwind>
+
+    $cxt->unwind(@values);
 
 Immediately returns the scalars listed in C<@values> from the closest subroutine enclosing the topic context.
 
@@ -378,7 +425,9 @@ sub unwind {
  Scope::Upper::unwind(@_ => $self->cxt);
 }
 
-=head2 C<uplevel $code, @args>
+=head2 C<uplevel>
+
+    my @ret = $cxt->uplevel($code, @args);
 
 Executes the code reference C<$code> with arguments C<@args> in the same setting as the closest subroutine enclosing the topic context, then returns to the current scope the values returned by C<$code>.