5 sub _clean_eval { eval $_[0] }
9 use Scalar::Util qw(weaken);
10 use base qw(Exporter);
12 our $VERSION = '1.003001';
13 $VERSION = eval $VERSION;
15 our @EXPORT = qw(quote_sub unquote_sub quoted_from_sub);
22 my ($from, $captures, $indent) = @_;
27 or die "capture key should start with \@, \% or \$: $_";
28 (' ' x $indent).qq{my ${_} = ${1}{${from}->{${\perlstring $_}}};\n};
34 my ($code, $args, $extra, $local) = @_;
35 my $do = 'do { '.($extra||'');
36 if (my ($code_args, $body) = $code =~ / +my \(([^)]+)\) = \@_;(.*)$/s) {
37 if ($code_args eq $args) {
40 $do.'my ('.$code_args.') = ('.$args.'); '.$body.' }';
44 if ($local || $args ne '@_') {
45 $assign = ($local ? 'local ' : '').'@_ = ('.$args.'); ';
47 $do.$assign.$code.' }';
52 # HOLY DWIMMERY, BATMAN!
53 # $name => $code => \%captures => \%options
54 # $name => $code => \%captures
56 # $code => \%captures => \%options
59 (ref($_[-1]) eq 'HASH' and ref($_[-2]) eq 'HASH')
62 my $captures = pop if ref($_[-1]) eq 'HASH';
63 undef($captures) if $captures && !keys %$captures;
67 my $deferred = defer_sub +($options->{no_install} ? undef : $name) => sub {
68 unquote_sub($quoted_info->[4]);
70 $quoted_info = [ $name, $code, $captures, undef, $deferred ];
71 weaken($QUOTED{$deferred} = $quoted_info);
82 unless ($QUOTED{$sub}[3]) {
83 my ($name, $code, $captures) = @{$QUOTED{$sub}};
87 my %captures = $captures ? %$captures : ();
88 $captures{'$_QUOTED'} = \$QUOTED{$sub};
89 $make_sub .= capture_unroll("\$_[1]", \%captures, 2);
93 # disable the 'variable $x will not stay shared' warning since
94 # we're not letting it escape from this scope anyway so there's
95 # nothing trying to share it
96 ? " no warnings 'closure';\n sub ${name} {\n"
97 : " \$_QUOTED->[3] = sub {\n"
100 $make_sub .= " }".($name ? '' : ';')."\n";
102 $make_sub .= " \$_QUOTED->[3] = \\&${name}\n";
104 $make_sub .= "}\n1;\n";
105 $ENV{SUB_QUOTE_DEBUG} && warn $make_sub;
109 local *{$name} if $name;
110 unless (_clean_eval $make_sub, \%captures) {
111 die "Eval went very, very wrong:\n\n${make_sub}\n\n$@";
119 %QUOTED = map { defined $_ ? ($_->[4] => $_) : () } values %QUOTED;
120 weaken($_) for values %QUOTED;
128 Sub::Quote - efficient generation of subroutines via string eval
134 use Sub::Quote qw(quote_sub unquote_sub quoted_from_sub);
136 quote_sub 'Silly::kitty', q{ print "meow" };
138 quote_sub 'Silly::doggy', q{ print "woof" };
142 quote_sub 'Silly::dagron',
143 q{ print ++$sound % 2 ? 'burninate' : 'roar' },
144 { '$sound' => \$sound };
150 Silly->dagron; # burninate
151 Silly->dagron; # roar
152 Silly->dagron; # burninate
156 This package provides performant ways to generate subroutines from strings.
162 my $coderef = quote_sub 'Foo::bar', q{ print $x++ . "\n" }, { '$x' => \0 };
164 Arguments: ?$name, $code, ?\%captures, ?\%options
166 C<$name> is the subroutine where the coderef will be installed.
168 C<$code> is a string that will be turned into code.
170 C<\%captures> is a hashref of variables that will be made available to the
171 code. The keys should be the full name of the variable to be made available,
172 including the sigil. The values should be references to the values. The
173 variables will contain copies of the values. See the L</SYNOPSIS>'s
174 C<Silly::dagron> for an example using captures.
182 B<Boolean>. Set this option to not install the generated coderef into the
183 passed subroutine name on undefer.
189 my $coderef = unquote_sub $sub;
191 Forcibly replace subroutine with actual code.
193 If $sub is not a quoted sub, this is a no-op.
195 =head2 quoted_from_sub
197 my $data = quoted_from_sub $sub;
199 my ($name, $code, $captures, $compiled_sub) = @$data;
201 Returns original arguments to quote_sub, plus the compiled version if this
202 sub has already been unquoted.
204 Note that $sub can be either the original quoted version or the compiled
205 version for convenience.
209 my $prelude = capture_unroll '$captures', {
214 my $inlined_code = inlinify q{
217 print $x + $y . "\n";
218 }, '$x, $y', $prelude;
220 Takes a string of code, a string of arguments, a string of code which acts as a
221 "prelude", and a B<Boolean> representing whether or not to localize the
224 =head2 capture_unroll
226 my $prelude = capture_unroll '$captures', {
231 Arguments: $from, \%captures, $indent
233 Generates a snippet of code which is suitable to be used as a prelude for
234 L</inlinify>. C<$from> is a string will be used as a hashref in the resulting
235 code. The keys of C<%captures> are the names of the variables and the values
236 are ignored. C<$indent> is the number of spaces to indent the result by.
240 Much of this is just string-based code-generation, and as a result, a few caveats
245 Calling C<return> from a quote_sub'ed sub will not likely do what you intend.
246 Instead of returning from the code you defined in C<quote_sub>, it will return
247 from the overall function it is composited into.
251 quote_sub q{ return 1 if $condition; $morecode }
253 It might turn up in the intended context as follows:
259 return 1 if $condition;
266 Which will obviously return from foo, when all you meant to do was return from
267 the code context in quote_sub and proceed with running important code b.
271 Sub::Quote compiles quoted subs in an environment where C<< use strictures >>
272 is in effect. L<strictures> enables L<strict> and FATAL L<warnings>.
274 The following dies I<< Use of uninitialized value in print... >>
277 quote_sub 'Silly::kitty', q{ print undef };
279 If you need to disable parts of strictures, do it within the quoted sub:
281 quote_sub 'Silly::kitty', q{ no warnings; print undef };
285 See L<Moo> for support and contact information.
289 See L<Moo> for authors.
291 =head1 COPYRIGHT AND LICENSE
293 See L<Moo> for the copyright and license.