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.
90 =head2 C<new [ $context ]>
92 Creates a new immutable L<Scope::Context> object from the L<Scope::Upper>-comptabile context C<$context>.
93 If omitted, C<$context> defaults to the current context.
98 my ($self, $cxt) = @_;
100 my $class = Scalar::Util::blessed($self);
101 unless (defined $class) {
102 $class = defined $self ? $self : __PACKAGE__;
105 $cxt = Scope::Upper::UP() unless defined $cxt;
109 uid => Scope::Upper::uid($cxt),
115 A synonym for L</new>.
131 Read-only accessor to the L<Scope::Upper> context corresponding to the topic L<Scope::Context> object.
135 Read-only accessor to the L<Scope::Upper> UID of the topic L<Scope::Context> object.
141 eval "sub $_ { \$_[0]->{$_} }; 1" or die $@ for qw<cxt uid>;
146 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.
152 my ($left, $right) = @_;
154 unless (Scalar::Util::blessed($right) and $right->isa(__PACKAGE__)) {
155 $left->_croak('Cannot compare a Scope::Context object with something else');
158 $left->uid eq $right->uid;
165 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).
169 sub is_valid { Scope::Upper::validate_uid($_[0]->uid) }
171 =head2 C<assert_valid>
173 Throws an exception if the topic context has expired and is no longer valid.
174 Returns true otherwise.
181 $self->_croak('Context has expired') unless $self->is_valid;
188 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.
197 Scope::Upper::want_at($self->cxt);
200 =head2 C<up [ $frames ]>
202 Returns a new L<Scope::Context> object pointing to the C<$frames>-th upper scope above the topic context.
204 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.
206 If omitted, C<$frames> defaults to C<1>.
211 my $up = Scope::Context->new->up(2); # = Scope::Context->up(2)
212 # $up points two contextes above this one, which is the sub.
220 my ($self, $frames) = @_;
222 if (Scalar::Util::blessed($self)) {
225 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
228 $frames = 1 unless defined $frames;
230 my $cxt = $self->cxt;
231 $cxt = Scope::Upper::UP($cxt) for 1 .. $frames;
236 =head2 C<sub [ $frames ]>
238 Returns a new L<Scope::Context> object pointing to the C<$frames>-th subroutine scope above the topic context.
240 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.
242 If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclosing the topic context.
251 my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub(1)
252 # $sub points to the context for the outer() sub.
258 my ($self, $frames) = @_;
260 if (Scalar::Util::blessed($self)) {
263 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
266 $frames = 0 unless defined $frames;
268 my $cxt = Scope::Upper::SUB($self->cxt);
269 $cxt = Scope::Upper::SUB(Scope::Upper::UP($cxt)) for 1 .. $frames;
274 =head2 C<eval [ $frames ]>
276 Returns a new L<Scope::Context> object pointing to the C<$frames>-th C<eval> scope above the topic context.
278 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.
280 If omitted, C<$frames> defaults to C<0>, which results in the closest eval enclosing the topic context.
284 my $eval = Scope::Context->new->eval; # = Scope::Context->eval
285 # $eval points to the eval context.
292 my ($self, $frames) = @_;
294 if (Scalar::Util::blessed($self)) {
297 $self = $self->new(Scope::Upper::UP(Scope::Upper::SUB()));
300 $frames = 0 unless defined $frames;
302 my $cxt = Scope::Upper::EVAL($self->cxt);
303 $cxt = Scope::Upper::EVAL(Scope::Upper::UP($cxt)) for 1 .. $frames;
310 Execute C<$code> when the topic context ends.
312 See L<Scope::Upper/reap> for details.
317 my ($self, $code) = @_;
321 &Scope::Upper::reap($code, $self->cxt);
324 =head2 C<localize $what, $value>
326 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.
328 See L<Scope::Upper/localize> for details.
333 my ($self, $what, $value) = @_;
337 Scope::Upper::localize($what, $value, $self->cxt);
340 =head2 C<localize_elem $what, $key, $value>
342 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.
344 See L<Scope::Upper/localize_elem> for details.
349 my ($self, $what, $key, $value) = @_;
353 Scope::Upper::localize_elem($what, $key, $value, $self->cxt);
356 =head2 C<localize_delete $what, $key>
358 Delete the element C<$key> from the variable C<$what> when the control flow returns to the scope pointed by the topic context.
360 See L<Scope::Upper/localize_delete> for details.
364 sub localize_delete {
365 my ($self, $what, $key) = @_;
369 Scope::Upper::localize_delete($what, $key, $self->cxt);
372 =head2 C<unwind @values>
374 Immediately returns the scalars listed in C<@values> from the closest subroutine enclosing the topic context.
376 See L<Scope::Upper/unwind> for details.
385 Scope::Upper::unwind(@_ => $self->cxt);
388 =head2 C<uplevel $code, @args>
390 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>.
392 See L<Scope::Upper/uplevel> for details.
402 &Scope::Upper::uplevel($code => @_ => $self->cxt);
407 L<Carp> (core module since perl 5), L<Scalar::Util> (since 5.7.3).
409 L<Scope::Upper> 0.18.
415 L<Continuation::Escape>.
419 Vincent Pit, C<< <perl at profvince.com> >>, L<http://www.profvince.com>.
421 You can contact me by mail or on C<irc.perl.org> (vincent).
425 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>.
426 I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
430 You can find documentation for this module with the perldoc command.
432 perldoc Scope::Context
434 =head1 COPYRIGHT & LICENSE
436 Copyright 2011 Vincent Pit, all rights reserved.
438 This program is free software; you can redistribute it and/or modify it
439 under the same terms as Perl itself.
443 1; # End of Scope::Context