File Coverage

blib/lib/Scope/Context.pm
Criterion Covered Total %
statement 144 159 90.5
branch 33 46 71.7
condition 4 5 80.0
subroutine 36 39 92.3
pod 27 27 100.0
total 244 276 88.4


line stmt bran cond sub pod time code
1             package Scope::Context;
2              
3 8     8   162656 use 5.006;
  8         38  
  8         338  
4              
5 8     8   49 use strict;
  8         18  
  8         328  
6 8     8   53 use warnings;
  8         20  
  8         254  
7              
8 8     8   45 use Carp ();
  8         17  
  8         211  
9 8     8   45 use Scalar::Util ();
  8         15  
  8         192  
10              
11 8     8   8218 use Scope::Upper 0.21 ();
  8         10567  
  8         1251  
12              
13             =head1 NAME
14              
15             Scope::Context - Object-oriented interface for inspecting or acting upon upper scope frames.
16              
17             =head1 VERSION
18              
19             Version 0.02
20              
21             =cut
22              
23             our $VERSION = '0.02';
24              
25             =head1 SYNOPSIS
26              
27             use Scope::Context;
28              
29             for (1 .. 5) {
30             sub {
31             eval {
32             # Create Scope::Context objects for different upper frames.
33             my ($block, $sub, $eval, $loop);
34             {
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)
39             }
40              
41             eval {
42             # This will throw an exception, since $block has expired.
43             $block->localize('$x' => 1);
44             };
45              
46             # This prints "hello" when the eval block above ends.
47             $eval->reap(sub { print "hello\n" });
48              
49             # Ignore $SIG{__DIE__} just for the loop body.
50             $loop->localize_delete('%SIG', '__DIE__');
51              
52             # Execute the callback as if it ran in place of the sub.
53             my @values = $sub->uplevel(sub {
54             return @_, 2;
55             }, 1);
56              
57             # Immediately return (1, 2, 3) from the sub, bypassing the eval.
58             $sub->unwind(@values, 3);
59              
60             # Not reached.
61             }
62              
63             # Not reached.
64             }->();
65              
66             # unwind() returns here. "hello\n" was printed, and now
67             # $SIG{__DIE__} is undefined.
68             }
69              
70             =head1 DESCRIPTION
71              
72             This class provides an object-oriented interface to L's functionalities.
73             A L object represents a currently active dynamic scope (or context), and encapsulates the corresponding L-compatible context identifier.
74             All of L'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.
76              
77             The L methods actually do more than their subroutine counterparts from L : 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.
78             This means that :
79              
80             my $cxt;
81             {
82             $cxt = Scope::Context->new;
83             }
84             $cxt->reap(sub { print "hello\n });
85              
86             will croak when L is called.
87              
88             =head1 METHODS
89              
90             =head2 C
91              
92             my $cxt = Scope::Context->new;
93             my $cxt = Scope::Context->new($scope_upper_cxt);
94              
95             Creates a new immutable L object from the L-comptabile context identifier C<$context>.
96             If omitted, C<$context> defaults to the current context.
97              
98             =cut
99              
100             sub new {
101 48     48 1 11074 my ($self, $cxt) = @_;
102              
103 48         115 my $class = Scalar::Util::blessed($self);
104 48 100       137 unless (defined $class) {
105 39 100       101 $class = defined $self ? $self : __PACKAGE__;
106             }
107              
108 48 100       191 $cxt = Scope::Upper::UP() unless defined $cxt;
109              
110 48         640 bless {
111             cxt => $cxt,
112             uid => Scope::Upper::uid($cxt),
113             }, $class;
114             }
115              
116             =head2 C
117              
118             A synonym for L.
119              
120             =cut
121              
122             BEGIN {
123 8     8   742 *here = \&new;
124             }
125              
126             sub _croak {
127 12     12   15 shift;
128 12         60 require Carp;
129 12         1401 Carp::croak(@_);
130             }
131              
132             =head2 C
133              
134             my $scope_upper_cxt = $cxt->cxt;
135              
136             Read-only accessor to the L context identifier associated with the invocant.
137              
138             =head2 C
139              
140             my $uid = $cxt->uid;
141              
142             Read-only accessor to the L unique identifier representing the L context associated with the invocant.
143              
144             =cut
145              
146             BEGIN {
147 8     8   20 local $@;
148 8   50 38 1 6827 eval "sub $_ { \$_[0]->{$_} }; 1" or die $@ for qw;
  38     47 1 819  
  47         496  
149             }
150              
151             =pod
152              
153             This class also overloads the C<==> operator, which will return true if and only if its two operands are L objects that have the same UID.
154              
155             =cut
156              
157             use overload (
158             '==' => sub {
159 3     3   675 my ($left, $right) = @_;
160              
161 3 100 100     35 unless (Scalar::Util::blessed($right) and $right->isa(__PACKAGE__)) {
162 2         9 $left->_croak('Cannot compare a Scope::Context object with something else');
163             }
164              
165 1         24 $left->uid eq $right->uid;
166             },
167 8         88 fallback => 1,
168 8     8   12012 );
  8         8050  
169              
170             =head2 C
171              
172             my $is_valid = $cxt->is_valid;
173              
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).
175              
176             =cut
177              
178 45     45 1 1844 sub is_valid { Scope::Upper::validate_uid($_[0]->uid) }
179              
180             =head2 C
181              
182             $cxt->assert_valid;
183              
184             Throws an exception if the invocant has expired and is no longer valid.
185             Returns true otherwise.
186              
187             =cut
188              
189             sub assert_valid {
190 41     41 1 59 my $self = shift;
191              
192 41 100       101 $self->_croak('Context has expired') unless $self->is_valid;
193              
194 31         424 1;
195             }
196              
197             =head2 C
198              
199             $cxt->package;
200              
201             Returns the namespace in use when the scope denoted by the invocant begins.
202              
203             =head2 C
204              
205             $cxt->file;
206              
207             Returns the name of the file where the scope denoted by the invocant belongs to.
208              
209             =head2 C
210              
211             $cxt->line;
212              
213             Returns the line number where the scope denoted by the invocant begins.
214              
215             =head2 C
216              
217             $cxt->sub_name;
218              
219             Returns the name of the subroutine called for this context, or C if this is not a subroutine context.
220              
221             =head2 C
222              
223             $cxt->sub_has_args;
224              
225             Returns a boolean indicating whether a new instance of C<@_> was set up for this context, or C if this is not a subroutine context.
226              
227             =head2 C
228              
229             $cxt->gimme;
230              
231             Returns the context (in the sense of L) in which the scope denoted by the invocant is executed.
232              
233             =head2 C
234              
235             $cxt->eval_text;
236              
237             Returns the contents of the string being compiled for this context, or C if this is not an eval context.
238              
239             =head2 C
240              
241             $cxt->is_require;
242              
243             Returns a boolean indicating whether this eval context was created by C, or C if this is not an eval context.
244              
245             =head2 C
246              
247             $cxt->hints_bits;
248              
249             Returns the value of the lexical hints bit mask (available as C<$^H> at compile time) in use when the scope denoted by the invocant begins.
250              
251             =head2 C
252              
253             $cxt->warnings_bits;
254              
255             Returns the bit string representing the warnings (available as C<${^WARNING_BITS}> at compile time) in use when the scope denoted by the invocant begins.
256              
257             =head2 C
258              
259             $cxt->hints_hash;
260              
261             Returns a reference to the lexical hints hash (available as C<%^H> at compile time) in use when the scope denoted by the invocant begins.
262             This method is available only on perl 5.10 and greater.
263              
264             =cut
265              
266             BEGIN {
267 8     8   2384 my %infos = (
268             package => 0,
269             file => 1,
270             line => 2,
271             sub_name => 3,
272             sub_has_args => 4,
273             gimme => 5,
274             eval_text => 6,
275             is_require => 7,
276             hints_bits => 8,
277             warnings_bits => 9,
278             (hints_hash => 10) x ("$]" >= 5.010),
279             );
280              
281 8         150 for my $name (sort { $infos{$a} <=> $infos{$b} } keys %infos) {
  221         314  
282 88         151 my $idx = $infos{$name};
283 88         141 local $@;
284 88 100   2 1 13329 eval <<" TEMPLATE";
  2 50   1 1 34  
  2 50   3 1 7  
  2 0   0 1 4  
  2 0   0 1 34  
  2 50   1 1 36  
  1 50   1 1 10  
  1 50   1 1 4  
  1 50   1 1 4  
  1 100   2 1 5  
  1 0   0 1 6  
  3         7  
  3         10  
  3         7  
  3         97  
  3         20  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
  1         3  
  1         4  
  1         2  
  1         5  
  1         12  
  1         3  
  1         8  
  1         2  
  1         21  
  1         6  
  1         50  
  1         6  
  1         4  
  1         36  
  1         11  
  1         3  
  1         4  
  1         3  
  1         5  
  1         8  
  2         36  
  2         8  
  2         5  
  2         37  
  2         37  
  0         0  
  0         0  
  0         0  
  0         0  
  0         0  
285             sub $name {
286             my \$self = shift;
287              
288             \$self->assert_valid;
289              
290             my \$info = \$self->{info};
291             \$info = \$self->{info} = [ Scope::Upper::context_info(\$self->cxt) ]
292             unless \$info;
293              
294             return \$info->[$idx];
295             }
296             TEMPLATE
297 88 50       6531 die $@ if $@;
298             }
299             }
300              
301             =head2 C
302              
303             my $want = $cxt->want;
304              
305             Returns the Perl context (in the sense of C : C for void context, C<''> for scalar context, and true for list context) in which is executed the scope pointed by the invocant.
306              
307             =cut
308              
309             sub want {
310 3     3 1 4 my $self = shift;
311              
312 3         8 $self->assert_valid;
313              
314 3         67 Scope::Upper::want_at($self->cxt);
315             }
316              
317             =head2 C
318              
319             my $up_cxt = $cxt->up;
320             my $up_cxt = $cxt->up($frames);
321             my $up_cxt = Scope::Context->up;
322              
323             Returns a new L object pointing to the C<$frames>-th upper scope above the scope pointed by the invocant.
324              
325             This method can also be invoked as a class method, in which case it is equivalent to calling L on a L object representing the current context.
326              
327             If omitted, C<$frames> defaults to C<1>.
328              
329             sub {
330             {
331             {
332             my $up = Scope::Context->new->up(2); # = Scope::Context->up(2)
333             # $up points two contextes above this one, which is the sub.
334             }
335             }
336             }
337              
338             =cut
339              
340             sub up {
341 13     13 1 5831 my ($self, $frames) = @_;
342              
343 13         16 my $cxt;
344 13 100       52 if (Scalar::Util::blessed($self)) {
345 6         16 $self->assert_valid;
346 5         117 $cxt = $self->cxt;
347             } else {
348 7         35 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
349             }
350              
351 12 100       40 $frames = 1 unless defined $frames;
352              
353 12         66 $cxt = Scope::Upper::UP($cxt) for 1 .. $frames;
354              
355 12         39 $self->new($cxt);
356             }
357              
358             =head2 C
359              
360             my $sub_cxt = $cxt->sub;
361             my $sub_cxt = $cxt->sub($frames);
362             my $sub_cxt = Scope::Context->sub;
363              
364             Returns a new L object pointing to the C<$frames>-th subroutine scope above the scope pointed by the invocant.
365              
366             This method can also be invoked as a class method, in which case it is equivalent to calling L on a L object for the current context.
367              
368             If omitted, C<$frames> defaults to C<0>, which results in the closest sub enclosing the scope pointed by the invocant.
369              
370             outer();
371              
372             sub outer {
373             inner();
374             }
375              
376             sub inner {
377             my $sub = Scope::Context->new->sub(1); # = Scope::Context->sub(1)
378             # $sub points to the context for the outer() sub.
379             }
380              
381             =cut
382              
383             sub sub {
384 7     7 1 4267 my ($self, $frames) = @_;
385              
386 7         10 my $cxt;
387 7 100       40 if (Scalar::Util::blessed($self)) {
388 3         11 $self->assert_valid;
389 2         47 $cxt = $self->cxt;
390             } else {
391 4         17 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
392             }
393              
394 6 100       16 $frames = 0 unless defined $frames;
395              
396 6         14 $cxt = Scope::Upper::SUB($cxt);
397 6         28 $cxt = Scope::Upper::SUB(Scope::Upper::UP($cxt)) for 1 .. $frames;
398              
399 6         18 $self->new($cxt);
400             }
401              
402             =head2 C
403              
404             my $eval_cxt = $cxt->eval;
405             my $eval_cxt = $cxt->eval($frames);
406             my $eval_cxt = Scope::Context->eval;
407              
408             Returns a new L object pointing to the C<$frames>-th C scope above the scope pointed by the invocant.
409              
410             This method can also be invoked as a class method, in which case it is equivalent to calling L on a L object for the current context.
411              
412             If omitted, C<$frames> defaults to C<0>, which results in the closest eval enclosing the scope pointed by the invocant.
413              
414             eval {
415             sub {
416             my $eval = Scope::Context->new->eval; # = Scope::Context->eval
417             # $eval points to the eval context.
418             }->()
419             }
420              
421             =cut
422              
423             sub eval {
424 5     5 1 1130 my ($self, $frames) = @_;
425              
426 5         8 my $cxt;
427 5 100       17 if (Scalar::Util::blessed($self)) {
428 3         8 $self->assert_valid;
429 2         49 $cxt = $self->cxt;
430             } else {
431 2         5 $cxt = Scope::Upper::UP(Scope::Upper::SUB());
432             }
433              
434 4 100       11 $frames = 0 unless defined $frames;
435              
436 4         9 $cxt = Scope::Upper::EVAL($cxt);
437 4         12 $cxt = Scope::Upper::EVAL(Scope::Upper::UP($cxt)) for 1 .. $frames;
438              
439 4         9 $self->new($cxt);
440             }
441              
442             =head2 C
443              
444             $cxt->reap($code);
445              
446             Execute C<$code> when the scope pointed by the invocant ends.
447              
448             See L for details.
449              
450             =cut
451              
452             sub reap {
453 2     2 1 578 my ($self, $code) = @_;
454              
455 2         8 $self->assert_valid;
456              
457 1         30 &Scope::Upper::reap($code, $self->cxt);
458             }
459              
460             =head2 C
461              
462             $cxt->localize($what, $value);
463              
464             Localize the variable described by C<$what> to the value C<$value> when the control flow returns to the scope pointed by the invocant.
465              
466             See L for details.
467              
468             =cut
469              
470             sub localize {
471 2     2 1 683 my ($self, $what, $value) = @_;
472              
473 2         26 $self->assert_valid;
474              
475 1         30 Scope::Upper::localize($what, $value, $self->cxt);
476             }
477              
478             =head2 C
479              
480             $cxt->localize_elem($what, $key, $value);
481              
482             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.
483              
484             See L for details.
485              
486             =cut
487              
488             sub localize_elem {
489 2     2 1 541 my ($self, $what, $key, $value) = @_;
490              
491 2         8 $self->assert_valid;
492              
493 1         33 Scope::Upper::localize_elem($what, $key, $value, $self->cxt);
494             }
495              
496             =head2 C
497              
498             $cxt->localize_delete($what, $key);
499              
500             Delete the element C<$key> from the variable C<$what> when the control flow returns to the scope pointed by the invocant.
501              
502             See L for details.
503              
504             =cut
505              
506             sub localize_delete {
507 2     2 1 619 my ($self, $what, $key) = @_;
508              
509 2         8 $self->assert_valid;
510              
511 1         33 Scope::Upper::localize_delete($what, $key, $self->cxt);
512             }
513              
514             =head2 C
515              
516             $cxt->unwind(@values);
517              
518             Immediately returns the scalars listed in C<@values> from the closest subroutine enclosing the scope pointed by the invocant.
519              
520             See L for details.
521              
522             =cut
523              
524             sub unwind {
525 2     2 1 650 my $self = shift;
526              
527 2         5 $self->assert_valid;
528              
529 1         28 Scope::Upper::unwind(@_ => $self->cxt);
530             }
531              
532             =head2 C
533              
534             $cxt->yield(@values);
535              
536             Immediately returns the scalars listed in C<@values> from the scope pointed by the invocant, whatever it may be (except a substitution eval context).
537              
538             See L for details.
539              
540             =cut
541              
542             sub yield {
543 2     2 1 568 my $self = shift;
544              
545 2         6 $self->assert_valid;
546              
547 1         29 Scope::Upper::yield(@_ => $self->cxt);
548             }
549              
550             =head2 C
551              
552             my @ret = $cxt->uplevel($code, @args);
553              
554             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>.
555              
556             See L for details.
557              
558             =cut
559              
560             sub uplevel {
561 2     2 1 672 my $self = shift;
562 2         3 my $code = shift;
563              
564 2         7 $self->assert_valid;
565              
566 1         30 &Scope::Upper::uplevel($code => @_ => $self->cxt);
567             }
568              
569             =head1 DEPENDENCIES
570              
571             L (core module since perl 5), L (since 5.7.3).
572              
573             L 0.21.
574              
575             =head1 SEE ALSO
576              
577             L.
578              
579             L.
580              
581             =head1 AUTHOR
582              
583             Vincent Pit, C<< >>, L.
584              
585             You can contact me by mail or on C (vincent).
586              
587             =head1 BUGS
588              
589             Please report any bugs or feature requests to C, or through the web interface at L.
590             I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
591              
592             =head1 SUPPORT
593              
594             You can find documentation for this module with the perldoc command.
595              
596             perldoc Scope::Context
597              
598             =head1 COPYRIGHT & LICENSE
599              
600             Copyright 2011,2012,2013 Vincent Pit, all rights reserved.
601              
602             This program is free software; you can redistribute it and/or modify it
603             under the same terms as Perl itself.
604              
605             =cut
606              
607             1; # End of Scope::Context