No need for ScalarRef when using Sub::Quote
[gitmo/Role-Tiny.git] / lib / Sub / Quote.pm
index 07a7b11..b5c5cc6 100644 (file)
@@ -6,6 +6,7 @@ sub _clean_eval { eval $_[0] }
 
 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);
@@ -14,6 +15,8 @@ our %QUOTE_OUTSTANDING;
 
 our %QUOTED;
 
+our %WEAK_REFS;
+
 sub capture_unroll {
   my ($from, $captures, $indent) = @_;
   join(
@@ -87,8 +90,11 @@ sub _unquote_all_outstanding {
     $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 = ();
@@ -117,12 +123,13 @@ sub quote_sub {
   $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 {
@@ -133,7 +140,9 @@ sub unquote_sub {
 
 1;
 
-=pod
+=head1 NAME
+
+Sub::Quote - efficient generation of subroutines via string eval
 
 =head1 SYNOPSIS
 
@@ -145,10 +154,10 @@ sub unquote_sub {
 
  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:
@@ -167,7 +176,7 @@ This package provides performant ways to generate subroutines from strings.
 
 =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
 
@@ -185,24 +194,32 @@ code.  See the L</SYNOPSIS>'s C<Silly::dagron> for an example using captures.
 =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