From fe890fb97648df1253becf110e4e4dfa3c2c8015 Mon Sep 17 00:00:00 2001 From: Jesse Luehrs Date: Wed, 10 Nov 2010 05:13:27 -0600 Subject: use Devel::Hints where possible this will avoid breaking memoization when generating coderefs with descriptions, and should be more robust and useful --- dist.ini | 1 + lib/Eval/Closure.pm | 18 ++++++++++++--- t/03-description.t | 2 +- t/05-memoize.t | 27 ++++++++++++++++++---- t/11-line-differences.t | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 9 deletions(-) create mode 100644 t/11-line-differences.t diff --git a/dist.ini b/dist.ini index 75234df..620f458 100644 --- a/dist.ini +++ b/dist.ini @@ -7,6 +7,7 @@ copyright_holder = Jesse Luehrs dist = Eval-Closure [Prereqs] +Devel::Hints = 0.22 Scalar::Util = 0 Sub::Exporter = 0 Try::Tiny = 0 diff --git a/lib/Eval/Closure.pm b/lib/Eval/Closure.pm index b03df5b..ee93a7a 100644 --- a/lib/Eval/Closure.pm +++ b/lib/Eval/Closure.pm @@ -8,11 +8,14 @@ use Sub::Exporter -setup => { # ABSTRACT: safely and cleanly create closures via string eval use Carp; +use Devel::Hints qw(cop_file cop_line); use overload (); use Memoize; use Scalar::Util qw(reftype); use Try::Tiny; +use constant USE_DEVEL_HINTS => ($] >= 5.010); + =head1 SYNOPSIS use Eval::Closure; @@ -93,14 +96,23 @@ sub eval_closure { $args{source} = _canonicalize_source($args{source}); _validate_env($args{environment} ||= {}); - $args{source} = _line_directive($args{description}) . $args{source} - if defined $args{description}; + if (!USE_DEVEL_HINTS) { + $args{source} = _line_directive($args{description}) . $args{source} + if defined $args{description}; + } my ($code, $e) = _clean_eval_closure(@args{qw(source environment)}); croak("Failed to compile source: $e\n\nsource:\n$args{source}") unless $code; + if (USE_DEVEL_HINTS) { + if (defined $args{description}) { + cop_file($code, $args{description}); + cop_line($code, 1); + } + } + return $code; } @@ -147,7 +159,7 @@ sub _validate_env { sub _line_directive { my ($description) = @_; - return qq{#line 1 "$description"\n}; + return qq{#line 0 "$description"\n}; } sub _clean_eval_closure { diff --git a/t/03-description.t b/t/03-description.t index 97f8372..c9e8b21 100644 --- a/t/03-description.t +++ b/t/03-description.t @@ -32,7 +32,7 @@ SOURCE like( exception { $code->() }, - qr/^foo at accessor foo \(defined at Class\.pm line 282\) line 2\n/, + qr/^foo at accessor foo \(defined at Class\.pm line 282\) line 1\n/, "description is set" ); } diff --git a/t/05-memoize.t b/t/05-memoize.t index 02fd11f..e4b582b 100644 --- a/t/05-memoize.t +++ b/t/05-memoize.t @@ -8,7 +8,12 @@ use Test::Requires 'Test::Output'; use Eval::Closure; { - my $source = 'BEGIN { warn "foo\n" } sub { $foo * 2 }'; + my $source = <<'SOURCE'; + sub { + $foo * 2; + }; + BEGIN { warn "foo\n" } +SOURCE my $code; my $bar = 15; @@ -38,7 +43,12 @@ use Eval::Closure; } { - my $source = 'BEGIN { warn "bar\n" } sub { $bar * 2 }'; + my $source = <<'SOURCE'; + sub { + $bar * 2; + }; + BEGIN { warn "bar\n" } +SOURCE my $code; my $foo = 60; @@ -56,7 +66,8 @@ use Eval::Closure; my $code2; my $baz = 23; - { local $TODO = "description breaks memoization"; + { local $TODO = $] < 5.010 ? "description breaks memoization on 5.8" + : undef; stderr_is { $code2 = eval_closure( source => $source, @@ -72,7 +83,12 @@ use Eval::Closure; } { - my $source = 'BEGIN { warn "baz\n" } sub { Carp::confess "baz" }'; + my $source = <<'SOURCE'; + sub { + Carp::confess "baz"; + }; + BEGIN { warn "baz\n" } +SOURCE my $code; stderr_is { @@ -86,7 +102,8 @@ use Eval::Closure; "got the right description"); my $code2; - { local $TODO = "description breaks memoization"; + { local $TODO = $] < 5.010 ? "description breaks memoization on 5.8" + : undef; stderr_is { $code2 = eval_closure( source => $source, diff --git a/t/11-line-differences.t b/t/11-line-differences.t new file mode 100644 index 0000000..4dd3625 --- /dev/null +++ b/t/11-line-differences.t @@ -0,0 +1,61 @@ +#!/usr/bin/env perl +use strict; +use warnings; +use Test::More; +use Test::Requires 'Test::Output'; + +use Eval::Closure; + +{ + my $code = eval_closure( + source => 'sub { warn "foo" }', + description => 'bar', + ); + { local $TODO = $] < 5.010 ? "line numbers from #line are slightly different" : undef; + stderr_is { $code->() } "foo at bar line 1.\n", "got the right line"; + } +} + +{ + my $code = eval_closure( + source => <<'SOURCE', + sub { + + warn "foo"; + + } +SOURCE + description => 'bar', + ); + { local $TODO = $] < 5.010 ? "line numbers from #line are slightly different" : undef; + stderr_is { $code->() } "foo at bar line 1.\n", "got the right line"; + } +} + +{ + my $code = eval_closure( + source => <<'SOURCE', + + sub { + warn "foo"; + } +SOURCE + description => 'bar', + ); + { local $TODO = $] < 5.010 ? "line numbers from #line are slightly different" : undef; + stderr_is { $code->() } "foo at bar line 1.\n", "got the right line"; + } +} + +{ + my $code = eval_closure( + source => '$sub', + environment => { '$sub' => \sub { warn "foo" } }, + description => 'bar', + ); + { local $TODO = $] < 5.010 ? "#line can't adjust line numbers inside non-evaled subs" : undef; + stderr_is { $code->() } "foo at bar line 1.\n", "got the right line"; + } +} + +done_testing; -- cgit v1.2.3-54-g00ecf