use Sub::Defer;
use B 'perlstring';
+use Scalar::Util qw(weaken);
use base qw(Exporter);
our @EXPORT = qw(quote_sub unquote_sub quoted_from_sub);
our %QUOTED;
+our %WEAK_REFS;
+
sub capture_unroll {
my ($from, $captures, $indent) = @_;
join(
$ENV{SUB_QUOTE_DEBUG} && warn $assembled_code;
}
$assembled_code .= "\n1;";
- unless (_clean_eval $assembled_code, \@assembled_captures) {
- die "Eval went very, very wrong:\n\n${debug_code}\n\n$@";
+ {
+ local $@;
+ unless (_clean_eval $assembled_code, \@assembled_captures) {
+ die "Eval went very, very wrong:\n\n${debug_code}\n\n$@";
+ }
}
$ENV{SUB_QUOTE_DEBUG} && warn $debug_code;
%QUOTE_OUTSTANDING = ();
$QUOTE_OUTSTANDING{$outstanding} = $QUOTED{$outstanding} = [
$name, $code, $captures
];
+ weaken($WEAK_REFS{$outstanding} = $deferred);
return $deferred;
}
sub quoted_from_sub {
my ($sub) = @_;
- $QUOTED{$sub||''};
+ $WEAK_REFS{$sub||''} and $QUOTED{$sub||''};
}
sub unquote_sub {
1;
-=pod
+=head1 NAME
+
+Sub::Quote - efficient generation of subroutines via string eval
=head1 SYNOPSIS
quote_sub 'Silly::doggy', q{ print "woof" };
- my $sound; $$sound = 0;
+ my $sound = 0;
quote_sub 'Silly::dagron',
- q{ print ++$$sound % 2 ? 'burninate' : 'roar' },
+ q{ print ++$sound % 2 ? 'burninate' : 'roar' },
{ '$sound' => \$sound };
And elsewhere:
=head2 quote_sub
- my $coderef = quote_sub 'Foo:bar', q{ print $x++ . "\n" }, { '$x' => \0 };
+ my $coderef = quote_sub 'Foo::bar', q{ print $x++ . "\n" }, { '$x' => \0 };
Arguments: ?$name, $code, ?\%captures, ?\%options
=item * no_install
B<Boolean>. Set this option to not install the generated coderef into the
-passed subroutine.
+passed subroutine name on undefer.
=back
=head2 unquote_sub
- my $coderef = unquote_sub 'Foo::bar';
+ my $coderef = unquote_sub $sub;
-Forcibly replace subroutine with actual code. Note that as many subs are
-unquoted at a time for performance reasons. This means that if you have a
-syntax error in one of your quoted subs you may find out when some other sub
-is unquoted.
+Forcibly replace subroutine with actual code. Note that for performance
+reasons all quoted subs declared so far will be globally unquoted/parsed in
+a single eval. This means that if you have a syntax error in one of your
+quoted subs you may find out when some other sub is unquoted.
+
+If $sub is not a quoted sub, this is a no-op.
=head2 quoted_from_sub
- my $coderef = quoted_from_sub 'Foo::bar';
+ my $data = quoted_from_sub $sub;
+
+ my ($name, $code, $captures, $compiled_sub) = @$data;
+
+Returns original arguments to quote_sub, plus the compiled version if this
+sub has already been unquoted.
-Returns quoted coderef based on subroutine name.
+Note that $sub can be either the original quoted version or the compiled
+version for convenience.
=head2 inlinify