1.002000 release
[p5sagit/Eval-WithLexicals.git] / lib / Eval / WithLexicals / WithHintPersistence.pm
1 package Eval::WithLexicals::WithHintPersistence;
2 use Moo::Role;
3 use Sub::Quote;
4
5 our $VERSION = '1.002000'; # 1.2.0
6 $VERSION = eval $VERSION;
7
8 # Used localised
9 our($hints, %hints);
10
11 has hints => (
12   is => 'rw',
13   default => quote_sub q{ {} },
14 );
15
16 has _first_eval => (
17   is => 'rw',
18   default => quote_sub q{ 1 },
19 );
20
21 around eval => sub {
22   my $orig = shift;
23   my($self) = @_;
24
25   local *Eval::WithLexicals::Cage::capture_hints;
26   local $Eval::WithLexicals::Cage::hints = { %{$self->hints} };
27
28   my @ret = $orig->(@_);
29
30   $self->hints({ Eval::WithLexicals::Cage::capture_hints() });
31
32   @ret;
33 };
34
35 # XXX: Sub::Quote::capture_unroll without 'my'
36 use B();
37 sub _capture_unroll_global {
38   my ($from, $captures, $indent) = @_;
39   join(
40     '',
41     map {
42       /^([\@\%\$])/
43         or die "capture key should start with \@, \% or \$: $_";
44       (' ' x $indent).qq{${_} = ${1}{${from}->{${\B::perlstring $_}}};\n};
45     } keys %$captures
46   );
47 }
48
49 sub setup_code {
50   my($self) = @_;
51   # Only run the prelude on the first eval, hints will be set after
52   # that.
53   if($self->_first_eval) {
54     $self->_first_eval(0);
55     return $self->prelude;
56   } else {
57     # Seems we can't use the technique of passing via @_ for code in a BEGIN
58     # block
59     return q[ BEGIN { ],
60       _capture_unroll_global('$Eval::WithLexicals::Cage::hints', $self->hints, 2),
61       q[ } ],
62   }
63 };
64
65 around capture_code => sub {
66   my $orig = shift;
67   my($self) = @_;
68
69   ( q{ sub Eval::WithLexicals::Cage::capture_hints {
70           no warnings 'closure';
71           my($hints, %hints);
72           BEGIN { $hints = $^H; %hints = %^H; }
73           return q{$^H} => \$hints, q{%^H} => \%hints;
74         } },
75     $orig->(@_) )
76 };
77
78 =head1 NAME
79
80 Eval::WithLexicals::WithHintPersistence - Persist compile hints between evals
81
82 =head1 SYNOPSIS
83
84  use Eval::WithLexicals;
85
86  my $eval = Eval::WithLexicals->with_plugins("HintPersistence")->new;
87
88 =head1 DESCRIPTION
89
90 Persist pragams and other compile hints between evals (for example the
91 L<strict> and L<warnings> flags in effect).
92
93 Saves and restores the C<$^H> and C<%^H> variables.
94
95 =head1 METHODS
96
97 =head2 hints
98
99  $eval->hints('$^H')
100
101 Returns the internal hints hash, keys are C<$^H> and C<%^H> for the hint bits
102 and hint hash respectively.
103
104 =cut
105
106 1;