use our own pragma for hints hash test
[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 1;
79 __END__
80
81 =head1 NAME
82
83 Eval::WithLexicals::WithHintPersistence - Persist compile hints between evals
84
85 =head1 SYNOPSIS
86
87  use Eval::WithLexicals;
88
89  my $eval = Eval::WithLexicals->with_plugins("HintPersistence")->new;
90
91 =head1 DESCRIPTION
92
93 Persist pragams and other compile hints between evals (for example the
94 L<strict> and L<warnings> flags in effect).
95
96 Saves and restores the C<$^H> and C<%^H> variables.
97
98 =head1 METHODS
99
100 =head2 hints
101
102  $eval->hints('$^H')
103
104 Returns the internal hints hash, keys are C<$^H> and C<%^H> for the hint bits
105 and hint hash respectively.
106
107 =head1 SUPPORT
108
109 See L<Eval::WithLexicals> for support and contact information.
110
111 =head1 AUTHORS
112
113 See L<Eval::WithLexicals> for authors.
114
115 =head1 COPYRIGHT AND LICENSE
116
117 See L<Eval::WithLexicals> for the copyright and license.
118
119 =cut