1 package Scope::Context;
11 use Scope::Upper 0.18 ();
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 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 corresponding to the topic L<Scope::Context> object.
142 Read-only accessor to the L<Scope::Upper> UID of the topic L<Scope::Context> object.
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 topic context is still valid (that is, it designates a scope that is higher than the topic context in the call stack).
178 sub is_valid { Scope::Upper::validate_uid($_[0]->uid) }
180 =head2 C<assert_valid>
184 Throws an exception if the topic context 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 corresponding to the topic L<Scope::Context> object.
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 topic context.
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 for 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) = @_;
239 if (Scalar::Util::blessed($self)) {
242 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
245 $frames = 1 unless defined $frames;
247 my $cxt = $self->cxt;
248 $cxt = Scope::Upper::UP($cxt) for 1 .. $frames;
255 my $sub_cxt = $cxt->sub;
256 my $sub_cxt = $cxt->sub($frames);
257 my $sub_cxt = Scope::Context->sub;
259 Returns a new L<Scope::Context> object pointing to the C<$frames>-th subroutine scope above the topic context.
261 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.
263 If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclosing the topic context.
272 my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub(1)
273 # $sub points to the context for the outer() sub.
279 my ($self, $frames) = @_;
281 if (Scalar::Util::blessed($self)) {
284 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
287 $frames = 0 unless defined $frames;
289 my $cxt = Scope::Upper::SUB($self->cxt);
290 $cxt = Scope::Upper::SUB(Scope::Upper::UP($cxt)) for 1 .. $frames;
297 my $eval_cxt = $cxt->eval;
298 my $eval_cxt = $cxt->eval($frames);
299 my $eval_cxt = Scope::Context->eval;
301 Returns a new L<Scope::Context> object pointing to the C<$frames>-th C<eval> scope above the topic context.
303 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.
305 If omitted, C<$frames> defaults to C<0>, which results in the closest eval enclosing the topic context.
309 my $eval = Scope::Context->new->eval; # = Scope::Context->eval
310 # $eval points to the eval context.
317 my ($self, $frames) = @_;
319 if (Scalar::Util::blessed($self)) {
322 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
325 $frames = 0 unless defined $frames;
327 my $cxt = Scope::Upper::EVAL($self->cxt);
328 $cxt = Scope::Upper::EVAL(Scope::Upper::UP($cxt)) for 1 .. $frames;
337 Execute C<$code> when the topic context ends.
339 See L<Scope::Upper/reap> for details.
344 my ($self, $code) = @_;
348 &Scope::Upper::reap($code, $self->cxt);
353 $cxt->localize($what, $value);
355 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.
357 See L<Scope::Upper/localize> for details.
362 my ($self, $what, $value) = @_;
366 Scope::Upper::localize($what, $value, $self->cxt);
369 =head2 C<localize_elem>
371 $cxt->localize_elem($what, $key, $value);
373 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.
375 See L<Scope::Upper/localize_elem> for details.
380 my ($self, $what, $key, $value) = @_;
384 Scope::Upper::localize_elem($what, $key, $value, $self->cxt);
387 =head2 C<localize_delete>
389 $cxt->localize_delete($what, $key);
391 Delete the element C<$key> from the variable C<$what> when the control flow returns to the scope pointed by the topic context.
393 See L<Scope::Upper/localize_delete> for details.
397 sub localize_delete {
398 my ($self, $what, $key) = @_;
402 Scope::Upper::localize_delete($what, $key, $self->cxt);
407 $cxt->unwind(@values);
409 Immediately returns the scalars listed in C<@values> from the closest subroutine enclosing the topic context.
411 See L<Scope::Upper/unwind> for details.
420 Scope::Upper::unwind(@_ => $self->cxt);
425 my @ret = $cxt->uplevel($code, @args);
427 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>.
429 See L<Scope::Upper/uplevel> for details.
439 &Scope::Upper::uplevel($code => @_ => $self->cxt);
444 L<Carp> (core module since perl 5), L<Scalar::Util> (since 5.7.3).
446 L<Scope::Upper> 0.18.
452 L<Continuation::Escape>.
456 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
458 You can contact me by mail or on C<irc.perl.org> (vincent).
462 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>.
463 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
467 You can find documentation for this module with the perldoc command.
469 perldoc Scope::Context
471 =head1 COPYRIGHT & LICENSE
473 Copyright 2011 Vincent Pit, all rights reserved.
475 This program is free software; you can redistribute it and/or modify it
476 under the same terms as Perl itself.
480 1; # End of Scope::Context