2016-04-01 17 views
3

すべての引数をとり、入力されたとおりに文字列として出力できる関数を作成しようとしています。次の関数の使用例についてはサブルーチンに渡されるすべての引数をPerlの文字列として取得する

:私はしたい

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

を:

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

私は機能の内部に次の文字列を取得したいと思いをEXACTLYの下に見られるようにを書式設定これを行うと、デバッグ/テストの目的で入力されたのと同じ方法ですべての引数を出力できます。

+0

もう一つの例:あなたは 'test(time)'をしたいと言っています。単純に '@ _ 'を表示すると、現在の時刻のエポック値と、現在の時刻を実際にテストしている(一見すると)非常に不明確な値が出力されます。 – 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)、['データ:: 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を提供し、コンパイルされたソースファイルの生の行を表示できます。サブルーチンが呼び出されるたびに元の行を出力するカスタムデバッガを書くことができます。

次に、一致させる1つ以上のサブルーチンを指定します。一致するサブルーチンが呼び出されるたびに、対応する行が印刷されます。

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-> close(); $ foo-> close(); 'を使うと、おそらく最初の' close'が接続を閉じたいと思っていますが、2回目の '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); 

あなたが出力としてこれを取得します

試験(時間);

関連する問題