1 package Scope::Context;
11 use Scope::Upper 0.21 ();
15 Scope::Context - Object-oriented interface for inspecting or acting upon upper scope frames.
23 our $VERSION = '0.01';
32 # Create Scope::Context objects for different upper frames.
33 my ($block, $sub, $eval, $loop);
35 $block = Scope::Context->new;
36 $sub = $block->sub; # = $block->up
37 $eval = $block->eval; # = $block->up(2)
38 $loop = $eval->up; # = $block->up(3)
42 # This will throw an exception, since $block has expired.
43 $block->localize('$x' => 1);
46 # This prints "hello" when the eval block above ends.
47 $eval->reap(sub { print "hello\n" });
49 # Ignore $SIG{__DIE__} just for the loop body.
50 $loop->localize_delete('%SIG', '__DIE__');
52 # Execute the callback as if it ran in place of the sub.
53 my @values = $sub->uplevel(sub {
57 # Immediately return (1, 2, 3) from the sub, bypassing the eval.
58 $sub->unwind(@values, 3);
66 # unwind() returns here. "hello\n" was printed, and now
67 # $SIG{__DIE__} is undefined.
72 This class provides an object-oriented interface to L<Scope::Upper>'s functionalities.
73 A L<Scope::Context> object represents a currently active dynamic scope (or context), and encapsulates the corresponding L<Scope::Upper>-compatible context identifier.
74 All of L<Scope::Upper>'s functions are then made available as methods.
75 This gives you a prettier and safer interface when you are not reaching for extreme performance, but rest assured that the overhead of this module is minimal anyway.
77 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.
82 $cxt = Scope::Context->new;
84 $cxt->reap(sub { print "hello\n });
86 will croak when L</reap> is called.
92 my $cxt = Scope::Context->new;
93 my $cxt = Scope::Context->new($scope_upper_cxt);
95 Creates a new immutable L<Scope::Context> object from the L<Scope::Upper>-comptabile context identifier C<$context>.
96 If omitted, C<$context> defaults to the current context.
101 my ($self, $cxt) = @_;
103 my $class = Scalar::Util::blessed($self);
104 unless (defined $class) {
105 $class = defined $self ? $self : __PACKAGE__;
108 $cxt = Scope::Upper::UP() unless defined $cxt;
112 uid => Scope::Upper::uid($cxt),
118 A synonym for L</new>.
134 my $scope_upper_cxt = $cxt->cxt;
136 Read-only accessor to the L<Scope::Upper> context identifier associated with the invocant.
142 Read-only accessor to the L<Scope::Upper> unique identifier representing the L<Scope::Upper> context associated with the invocant.
148 eval "sub $_ { \$_[0]->{$_} }; 1" or die $@ for qw<cxt uid>;
153 This class also overloads the C<==> operator, which will return true if and only if its two operands are L<Scope::Context> objects that have the same UID.
159 my ($left, $right) = @_;
161 unless (Scalar::Util::blessed($right) and $right->isa(__PACKAGE__)) {
162 $left->_croak('Cannot compare a Scope::Context object with something else');
165 $left->uid eq $right->uid;
172 my $is_valid = $cxt->is_valid;
174 Returns true if and only if the invocant is still valid (that is, it designates a scope that is higher on the call stack than the current scope).
178 sub is_valid { Scope::Upper::validate_uid($_[0]->uid) }
180 =head2 C<assert_valid>
184 Throws an exception if the invocant has expired and is no longer valid.
185 Returns true otherwise.
192 $self->_croak('Context has expired') unless $self->is_valid;
199 my $want = $cxt->want;
201 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 pointed by the invocant.
210 Scope::Upper::want_at($self->cxt);
215 my $up_cxt = $cxt->up;
216 my $up_cxt = $cxt->up($frames);
217 my $up_cxt = Scope::Context->up;
219 Returns a new L<Scope::Context> object pointing to the C<$frames>-th upper scope above the scope pointed by the invocant.
221 This method can also be invoked as a class method, in which case it is equivalent to calling L</up> on a L<Scope::Context> object representing the current context.
223 If omitted, C<$frames> defaults to C<1>.
228 my $up = Scope::Context->new->up(2); # = Scope::Context->up(2)
229 # $up points two contextes above this one, which is the sub.
237 my ($self, $frames) = @_;
240 if (Scalar::Util::blessed($self)) {
244 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
247 $frames = 1 unless defined $frames;
249 $cxt = Scope::Upper::UP($cxt) for 1 .. $frames;
256 my $sub_cxt = $cxt->sub;
257 my $sub_cxt = $cxt->sub($frames);
258 my $sub_cxt = Scope::Context->sub;
260 Returns a new L<Scope::Context> object pointing to the C<$frames>-th subroutine scope above the scope pointed by the invocant.
262 This method can also be invoked as a class method, in which case it is equivalent to calling L</sub> on a L<Scope::Context> object for the current context.
264 If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclosing the scope pointed by the invocant.
273 my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub(1)
274 # $sub points to the context for the outer() sub.
280 my ($self, $frames) = @_;
283 if (Scalar::Util::blessed($self)) {
287 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
290 $frames = 0 unless defined $frames;
292 $cxt = Scope::Upper::SUB($cxt);
293 $cxt = Scope::Upper::SUB(Scope::Upper::UP($cxt)) for 1 .. $frames;
300 my $eval_cxt = $cxt->eval;
301 my $eval_cxt = $cxt->eval($frames);
302 my $eval_cxt = Scope::Context->eval;
304 Returns a new L<Scope::Context> object pointing to the C<$frames>-th C<eval> scope above the scope pointed by the invocant.
306 This method can also be invoked as a class method, in which case it is equivalent to calling L</eval> on a L<Scope::Context> object for the current context.
308 If omitted, C<$frames> defaults to C<0>, which results in the closest eval enclosing the scope pointed by the invocant.
312 my $eval = Scope::Context->new->eval; # = Scope::Context->eval
313 # $eval points to the eval context.
320 my ($self, $frames) = @_;
323 if (Scalar::Util::blessed($self)) {
327 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
330 $frames = 0 unless defined $frames;
332 $cxt = Scope::Upper::EVAL($cxt);
333 $cxt = Scope::Upper::EVAL(Scope::Upper::UP($cxt)) for 1 .. $frames;
342 Execute C<$code> when the scope pointed by the invocant ends.
344 See L<Scope::Upper/reap> for details.
349 my ($self, $code) = @_;
353 &Scope::Upper::reap($code, $self->cxt);
358 $cxt->localize($what, $value);
360 Localize the variable described by C<$what> to the value C<$value> when the control flow returns to the scope pointed by the invocant.
362 See L<Scope::Upper/localize> for details.
367 my ($self, $what, $value) = @_;
371 Scope::Upper::localize($what, $value, $self->cxt);
374 =head2 C<localize_elem>
376 $cxt->localize_elem($what, $key, $value);
378 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 invocant.
380 See L<Scope::Upper/localize_elem> for details.
385 my ($self, $what, $key, $value) = @_;
389 Scope::Upper::localize_elem($what, $key, $value, $self->cxt);
392 =head2 C<localize_delete>
394 $cxt->localize_delete($what, $key);
396 Delete the element C<$key> from the variable C<$what> when the control flow returns to the scope pointed by the invocant.
398 See L<Scope::Upper/localize_delete> for details.
402 sub localize_delete {
403 my ($self, $what, $key) = @_;
407 Scope::Upper::localize_delete($what, $key, $self->cxt);
412 $cxt->unwind(@values);
414 Immediately returns the scalars listed in C<@values> from the closest subroutine enclosing the scope pointed by the invocant.
416 See L<Scope::Upper/unwind> for details.
425 Scope::Upper::unwind(@_ => $self->cxt);
430 $cxt->yield(@values);
432 Immediately returns the scalars listed in C<@values> from the scope pointed by the invocant, whatever it may be (except a substitution eval context).
434 See L<Scope::Upper/yield> for details.
443 Scope::Upper::yield(@_ => $self->cxt);
448 my @ret = $cxt->uplevel($code, @args);
450 Executes the code reference C<$code> with arguments C<@args> in the same setting as the closest subroutine enclosing the scope pointed by the invocant, then returns to the current scope the values returned by C<$code>.
452 See L<Scope::Upper/uplevel> for details.
462 &Scope::Upper::uplevel($code => @_ => $self->cxt);
467 L<Carp> (core module since perl 5), L<Scalar::Util> (since 5.7.3).
469 L<Scope::Upper> 0.21.
475 L<Continuation::Escape>.
479 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
481 You can contact me by mail or on C<irc.perl.org> (vincent).
485 Please report any bugs or feature requests to C<bug-scope-context at rt.cpan.org>, or through the web interface at L<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Scope-Context>.
486 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
490 You can find documentation for this module with the perldoc command.
492 perldoc Scope::Context
494 =head1 COPYRIGHT & LICENSE
496 Copyright 2011,2012,2013 Vincent Pit, all rights reserved.
498 This program is free software; you can redistribute it and/or modify it
499 under the same terms as Perl itself.
503 1; # End of Scope::Context