Perl - Data::Dumper の冗長さを調整する
Use Data::Dump filters for nicer pretty-printing | The Effective Perler
を読んで、有益だと思ったのでそれをここにも書いておく。
次の Perl のコード
use DateTime; use List::Util qw(shuffle); use Data::Dumper; my $data = { today => DateTime->now, array => [shuffle(1 .. 30)], }; print Dumper $data;
を実行すると
$VAR1 = { 'array' => [ 1, 7, 19, 23, 24, 29, 9, 3, 18, 2, 12, 27, 6, 4, 16, 15, 22, 25, 13, 28, 5, 17, 20, 30, 8, 10, 26, 11, 21, 14 ], 'today' => bless( { 'local_rd_secs' => 16240, 'local_rd_days' => 734540, 'rd_nanosecs' => 0, 'locale' => bless( { 'default_time_format_length' => 'medium', 'native_territory' => 'United States', 'native_language' => 'English', 'native_complete_name' => 'English United States', 'en_language' => 'English', 'id' => 'en_US', 'default_date_format_length' => 'medium', 'en_complete_name' => 'English United States', 'en_territory' => 'United States' }, 'DateTime::Locale::en_US' ), 'local_c' => { 'hour' => 4, 'second' => 40, 'month' => 2, 'quarter' => 1, 'day_of_year' => 38, 'day_of_quarter' => 38, 'minute' => 30, 'day' => 7, 'day_of_week' => 2, 'year' => 2012 }, 'utc_rd_secs' => 16240, 'formatter' => undef, 'tz' => bless( { 'name' => 'UTC' }, 'DateTime::TimeZone::UTC' ), 'utc_year' => 2013, 'utc_rd_days' => 734540, 'offset_modifier' => 0 }, 'DateTime' ) };
と見るのも放棄したくなる結果が得られる。 Dumper は構造を知りたいがためにやってるのに、これじゃ構造がよく分からない。
そこで
- DateTime オブジェクトは 2012/02/07 12:30:00 +0900 のように表示すれば十分
- 配列の要素数が多いときは、そのうちいくつかを表示すれば十分
を実現させる。
どうやるかというと、 Data::Dumper じゃなくて Data::Dump モジュールの dumpf 関数を使う。この関数は第一変数に dump したい変数をとり、そして第二変数に表示のカスタマイズ方法を定義したサブルーチンのリファレンスを指定する。
詳しくは始めに挙げたサイトと
を参照してもらうこととして、上記2条件を満たすコードを書くと
#!/usr/bin/env perl use strict; use warnings; use Data::Dump qw(dumpf); use DateTime; use List::Util qw(shuffle); my $data = { today => DateTime->now, array => [shuffle(1 .. 30)], }; print dumpf($data, \&get_filter); BEGIN { my %filters = ( DateTime => sub { require Storable; my $date = Storable::dclone(shift); $date->set_time_zone('local'); $date->strftime('%Y/%m/%d %H:%M:%S %z'); }, ARRAY => sub { my @array = @{shift()}; [@array[0, 1], "...", $array[-1]]; }, ); sub get_filter { my ($ctx, $object_ref) = @_; if ($ctx->is_blessed and exists $filters{$ctx->class}) { my $string = $filters{$ctx->class}->($object_ref); return { dump => $string }; } elsif ($ctx->is_array && @{$object_ref} > 4) { my $number_of_items = scalar @{$object_ref}; my $object = $filters{$ctx->reftype}->($object_ref); return { object => $object, comment => "some items hidden: " ."actual number of items=$number_of_items", }; } return undef; } }
となる。これを実行すると
{ array => # some items hidden: actual number of items=30 [4, 9, "...", 7], today => 2012/02/07 13:41:35 +0900, }
となる。素晴らしい!
ということで、複雑な構造をもつ変数を dump しても冗長過ぎて意味が理解しにくいときや、dump 方法を独自に決めたいときは、 Data::Dump モジュールの dumpf を使うといいと分かった。
今日の疑問
- なんで BEGIN で括らないといけないのかはおいおい理解する。