2016-04-01 12 views
3

我正在尝试编写一个函数,该函数可以将所有参数作为字符串输入,并将它们打印为完全一样的字符串。在Perl中将所有传递给子例程的参数作为字符串获取

例如使用以下功能:

test('arg1' => $arg1, 'arg2' => $arg2); 

我想获得格式化EXACTLY功能内的以下字符串所看到如下

"'arg1' => $arg1, 'arg2' => $arg2" 

我想这样做,我可以打印所有参数,就像输入用于调试/测试目的一样。

+0

另一个例子:假设你想做'测试(时间)'。只需打印“@ _”将打印当前时间的纪元值,并且它非常不清楚(乍一看)您正在测试当前时间。 – tjwrona1992

+2

使用[Devel :: Trace](https://metacpan.org/pod/Devel:Trace),或者只是使用普通的调试器并在函数被调用的那一行中断。 – ThisSuitIsBlackNot

+1

参见['Debug :: Show'](https://metacpan.org/pod/Debug::Show),['PadWalker'](https://metacpan.org/pod/PadWalker),['Data :: Dumper :: Names'](https://metacpan.org/pod/Data::Dumper::Names),['Data :: Dumper :: Lazy'](https://metacpan.org/pod/ Data :: Dumper :: Lazy)和['Debug :: ShowStuff :: ShowVar'](https://metacpan.org/pod/Debug::ShowStuff::ShowVar) –

回答

6

Perl提供了特殊的debugging hooks,可让您看到已编译源文件的原始行。您可以编写一个自定义调试器,每次调用子例程时都会打印原始行。

以下内容可让您指定一个或多个要匹配的子例程;每次调用一个匹配的子程序时,都会打印相应的行。

package Devel::ShowCalls; 

our %targets; 

sub import { 
    my $self = shift; 

    for (@_) { 
     # Prepend 'main::' for names without a package specifier 
     $_ = "main::$_" unless /::/; 
     $targets{$_} = 1;   
    } 
} 

package DB; 

sub DB { 
    ($package, $file, $line) = caller; 
} 

sub sub { 
    print ">> $file:$line: ", 
      ${ $main::{"_<$file"} }[$line] if $Devel::ShowCalls::targets{$sub}; 
    &$sub; 
} 

1; 

要跟踪的在下面的程序功能fooBaz::qux调用:

sub foo {} 
sub bar {} 
sub Baz::qux {} 

foo(now => time); 
bar rand; 
Baz::qux(qw/unicorn pony waffles/); 

运行:

$ perl -d:ShowCalls=foo,Baz::qux myscript.pl 
>> myscript.pl:5: foo(now => time); 
>> myscript.pl:7: Baz::qux(qw/unicorn pony waffles/); 

注意,这将只打印的第一行调用,所以它不适用于像

foo(bar, 
    baz); 
+0

唯一的问题是我想用它来编写单元测试脚本。基本上,我希望我的测试都以相关的函数和参数命名,这样我就不需要手动命名每个测试。有没有办法做到这一点,而不是在调试模式下显式运行Perl?或者可能从测试脚本本身调用调试模式? – tjwrona1992

+1

@ tjwrona1992如果你想用相同的输入对同一个函数运行多个测试,那么这种方法就会失败。例如,使用'$ foo-> connect(); $ foo->接近(); $ foo-> close();',你可能希望第一个'close'关闭连接,但你可能想要第二个'close'来警告。不同的行为,但在你的计划中,你将拥有两个完全相同的测试名称。测试名称应该是描述预期行为的人类可读字符串。做任何未来的维护程序员(包括你自己!)的帮助,并写出描述性测试名称。 – ThisSuitIsBlackNot

0

我知道这可能不是最好的解决方案,但它的工作原理:

sub test { 
    my (undef, $file_name, $line_number) = caller; 
    open my $fh, '<', $file_name or die $!; 
    my @lines = <$fh>; 
    close $fh; 

    my $line = $lines[$line_number - 1]; 
    trim($line); 

    print $line."\n"; 
} 

sub trim { 
    return map { $_ =~ s/^\s+|\s+$//g } @_; 
} 

现在,当你运行这个命令:

test(time); 

你会得到这样的输出:

测试(时间);

相关问题