Masteries

技術的なことや仕事に関することを書いていきます.

Perlのprintデバッグをシュッと見やすくする 〜Data::Printer編〜

Perl Advent Calendar 2014の7日目の記事です. 宜しくお願いします.

さて, 昨日の記事は@FromAtomさんの「Perlのprintデバッグをシュッと見やすくする」でした.

printデバッグはデバッグの中でも基礎中の基礎, とりあえず詰まったらprintデバッグで試してみる... という方は結構多いのではないでしょうか.
昨日の記事ではData::Dumperを紹介されていましたが, デバッグに役立つダンプ用のモジュールは他にもあります.
今日はその中の1つ, Data::Printerを紹介したいと思います.

Data::Printerのインストール

cpanmコマンドが使えれば簡単です.

$ cpanm Data::Printer

ここがData::Dumperと比べた時のData::Printerの弱点です. つまり「便利だけど, コアモジュールじゃない」という所.
「どんな環境でも使える」という取り回しの良さ(?)は, コアモジュールのData::Dumperが非常に有利です.
というわけで, 時と場合に応じて, DumperとPrinterを使い分けることが大切になってくる訳です.

Data::Dumperの使い方

my $data = {
    abc   => 1,
    def   => 2,
    array => [ 1..3 ],
    hash  => {
        a => 1,
        b => 2,
        c => 3,
    },
    coderef => sub { print "hello!" },
};

このようなデータ構造を, Data::DumperとData::Printerで表示してみます. コードはこんな感じ.

use Data::Dumper;
use DDP;

my $data = {
    abc   => 1,
    def   => 2,
    array => [ 1..3 ],
    hash  => {
        a => 1,
        b => 2,
        c => 3,
    },
    coderef => sub { print "hello!" },
};

print Dumper $data; # Data::Dumperで表示
p $data;            # Data::Printerで表示

DDPというのは, Data::Printerのエイリアスのようなものと思って下さい.
use DDP;とすると, Data::Printerの機能が使えるようになります.
上のコードのように, pという関数が使えるようになるので, これにダンプしたいデータ構造を与えればOKです.

さて, このコードを実行すると, 次のように表示されます.

# Data::Dumperの表示
$VAR1 = {
          'abc' => 1,
          'coderef' => sub { "DUMMY" },
          'hash' => {
                      'b' => 2,
                      'a' => 1,
                      'c' => 3
                    },
          'array' => [
                       1,
                       2,
                       3
                     ],
          'def' => 2
        };
# Data::Printerの表示
\ {
    abc       1,
    array     [
        [0] 1,
        [1] 2,
        [2] 3
    ],
    coderef   sub { ... },
    def       2,
    hash      {
        a   1,
        b   2,
        c   3
    }
}

スクリーンショットを見て頂くと, Data::Printerを使った場合, 出力がカラフルになっているのがわかると思います.

f:id:papix:20141207150138p:plain

Data::Perinterの出力は, Data::Dumperの出力よりもシンプルで見やすいと思っています.

サブルーチンリファレンスの出力

さて, Data::DumperもData::Printerも, $data->{coderef}に格納されているサブルーチンリファレンスが正しく出力されていないことがわかります.

'coderef' => sub { "DUMMY" }, # Data::Dumperの場合
coderef   sub { ... },        # Data::Printerの場合

Data::Printerでは, DDPuseする時に, use DDP { deparse => 1 };のようにuseをすれば, サブルーチンリファレンスの中身(実際のコード)出力してくれるようになります.

use DDP { deparse => 1 };
    
my $data = {
    coderef => sub { print "hello!" },
};
    
p $data;

このコードを実行すると, 次のように出力されます.

\ {
    coderef   sub {
            print 'hello!';
        }
}

日本語のダンプ

use Data::Dumper;
use DDP { deparse => 1 };
    
my $data = {
    en => 'hello!',
    ja => 'こんにちは!',
};
    
print Dumper $data;
p $data;

次は, このように日本語を含んだデータをダンプしてみます.

$VAR1 = {
          'ja' => "\x{3053}\x{3093}\x{306b}\x{3061}\x{306f}!",
          'en' => 'hello!'
        };
\ {
    en   "hello!",
    ja   "こんにちは!"
}

Data::Printerであれば, このようにそのままの日本語で出力してくれます.
ちなみにData::Dumperで日本語文字列を日本語で出力したい場合, @bayashiさんのData::Dumper::AutoEncodeを利用する, などの選択肢が出てくると思います.

Data::Printerを楽に使う

自分の場合, VimのPerl用スニペットファイルに次のような設定を入れています.

snippet dd
    use DDP { deparse => 1 };

snippet dw
    use DDP { deparse => 1 };
    p 

Data::Printerでデバッグしたいと思った時は, このスニペットからData::Printer用のコードを展開して使っています.

まとめ

Data::DumperやData::Printerといったダンプしてくれるモジュールはprintデバッグの友, いざという時に使いこなせるようにしておきたいですね.
ちなみに, 今回紹介したもの以外のPerlのダンパー系モジュールのまとめについては, @hirobanexさんのこちらの記事が参考になります.

さて, 明日のPerl Advent Calendar 2014は... 今のところ担当者不在ですね. 果たして誰が記事を書くのか!? 非常に楽しみです.