水曜日, 12月 13, 2006

[Perl]useなしでどこでもDump(@INCにオブジェクトを格納するパターン)

PERL HACKSを読んでいたら@INCにはhookが仕込めるということが書いてありました。

■[Perl]use無しでどこでも変数をダンプするpackage P;p

でも言及されているとおりかねてからuseがめんどうだと思っていたのですが、これを使えばうまくいくんじゃないか?ということでやってみました。

@INCの仕組み

http://perldoc.perl.org/functions/require.html


によると@INCにはCODEやオブジェクトを格納することができます。
これを利用するとモジュールロード前にhookを仕込むことができます。

There are three forms of hooks: subroutine references,
array references and blessed objects.


とあります。subroutine referencesが簡単ですがどーせならblessed objectsの方がということでこちらでやってみます。
オブジェクトの場合はINCというメソッドを定義するとモジュールをロードするたびにそのメソッドを呼び出してくれます。ただmainパッケージになってしまう(ここがよくわらかなかった)らしいのでパッケージ名をフル指定しないといけないようです。

package P;
use strict;
use YAML;

sub new {
  my $class = shift;
  return bless { modules => [ @_ ] }, $class;
}

sub import {
  my $class = shift;
  my (@modules) = @_;
  push @modules, split /[,\s]+/msx, $ENV{P} || q{};

  unshift @INC, P->new(@modules)
     unless (grep {ref $_ eq __PACKAGE__ } @INC);
  
}

sub p {
  my ($package, $file, $line) = caller();

  warn "[$file at line $line] " . YAML::Dump(@_);
}

sub P::INC {
  my ($self, $module) = @_;
  if (my @modules = @{$self->{modules}}) {
   return unless ( grep { $module =~ m|^$_| } @modules);
  }

  (my $mod_name = $module) =~ s|/|::|g;
  $mod_name =~ s|\.pm$||;

  no strict 'refs';
  *{"$mod_name\::p"} = \&p;
  return;
}

1;

こんな感じで実装してみました。

pを使う方

package PUser;
use strict;
use base 'Class::Accessor';

sub hoge {
  p "Hello Debug P";
  p { hoge => 'foo' }, "bar bar";
  warn "hoge called";
}

1;


起動ファイル(run_p.pl)
use strict;
use PUser;
PUser->hoge();



これで

perl -MP run_p.pl
とやると全てのパッケージでp関数が利用できます。

0 件のコメント: