Subject: | [PATCH] Fix caller() emulation |
Contextual::Return's emulation of caller() is slightly wrong in two ways.
1) It does not declare a prototype for its caller, which should be (;$),
so that passing it a list causes a different behavior. It uses the
first argument rather than the scalar value of the list.
2) If you do not pass it an argument it still returns 10 values, it
should only return 3.
The attached patch fixes this.
Subject: | caller_with_args.patch |
=== MANIFEST
==================================================================
--- MANIFEST (revision 27911)
+++ MANIFEST (local)
@@ -29,4 +29,5 @@
t/RECOVER_exception_RESULT.t
t/args_RESULT.t
t/caller.t
+t/check_caller.t
t/simple_RESULT.t
=== lib/Contextual/Return.pm
==================================================================
--- lib/Contextual/Return.pm (revision 27911)
+++ lib/Contextual/Return.pm (local)
@@ -4,11 +4,18 @@
BEGIN {
no warnings 'redefine';
- *CORE::GLOBAL::caller = sub {
- my ($uplevels) = shift || 0;
- return CORE::caller($uplevels + 2 + $Contextual::Return::uplevel)
- if $Contextual::Return::uplevel;
- return CORE::caller($uplevels + 1);
+ *CORE::GLOBAL::caller = sub (;$) {
+ my ($uplevels) = $_[0] || 0;
+ $uplevels += $Contextual::Return::uplevel
+ ? 2 + $Contextual::Return::uplevel
+ : 1;
+
+ if( wantarray and !@_ ) {
+ return (CORE::caller($uplevels))[0..2];
+ }
+ else {
+ return CORE::caller($uplevels);
+ }
};
use Carp;
=== t/check_caller.t
==================================================================
--- t/check_caller.t (revision 27911)
+++ t/check_caller.t (local)
@@ -0,0 +1,42 @@
+#!/usr/bin/perl -w
+
+use Test::More 'no_plan';
+
+use Contextual::Return;
+
+sub caller_no_args {
+ caller;
+}
+
+sub core_caller_no_args {
+ CORE::caller;
+}
+
+sub caller_with_args {
+ caller(0);
+}
+
+sub core_caller_with_args {
+ CORE::caller(0);
+}
+
+sub caller_with_list {
+ my @args = (0);
+ caller @args;
+}
+
+sub core_caller_with_list {
+ my @args = (0);
+ CORE::caller(@args);
+}
+
+# Keep the calls on the same line so caller() comes out the same.
+is_deeply [caller_no_args], [core_caller_no_args],
+ "caller with no args returns right values";
+
+# Skip over the "subroutine" argument since it will be different
+is_deeply [ (caller_with_args)[0..2,4..9] ], [ (core_caller_with_args)[0..2,4..9] ],
+ "caller with args returns right values";
+
+is_deeply [caller_with_list], [core_caller_with_list],
+ "caller with a list returns right values";