2016-04-01 10 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); 

你會得到這樣的輸出:

測試(時間);

相關問題