!!!技術的雑談-PPIを使ってみる !!環境 *OS:CentOS3.5 *perl:5.8.0(OS Installそのまま) !!PPIとは Perlを構文解析し、Perl Scriptの中から参照・操作できるようにするための物です。 構文解析されたPerl ScriptはPDOM(Perl Document Object Model)というObject形式になっているようです。 !!PPIのInstall 今回使用したCentOS3.5のperlにはPPI packageが入っていませんでした。 CPANを使えば簡単にInstallできるのかもしれませんが、今回はネットに繋がっていないサーバだったので手動でInstallしました。 !CPANよりPPI-1.199_02.tar.gzを入手 http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/PPI-1.199_02.tar.gz !PPIの展開とInstall tarで展開し、作成されたPPI-1.199ディレクトリにcdして、 $ perl Makefile.PL でMakefileの作成を行ないますが、その際に Checking if your kit is complete... Looks good Warning: prerequisite Clone 0.22 not found. Warning: prerequisite Digest::MD5 2.27 not found. We have 2.20. Warning: prerequisite File::Spec 0.84 not found. We have 0.83. Warning: prerequisite IO::String 1.07 not found. Warning: prerequisite List::MoreUtils 0.13 not found. Warning: prerequisite List::Util 1.18 not found. We have 1.09. Warning: prerequisite Params::Util 0.10 not found. Warning: prerequisite Storable 2.14 not found. We have 2.06. Warning: prerequisite Task::Weaken 0 not found. Warning: prerequisite Test::ClassAPI 1.03 not found. Warning: prerequisite Test::Object 0.07 not found. Writing Makefile for PPI と、出るので、必要なモジュールを別途入手しました。 どのModuleも基本的には「展開」「cd」「perl Makefile.PL」「make」「make test」「make install(root権限で)」でInstallされます。 (どうも.pmではなくNative binaryを含むModuleがあるようです。) !Clone 0.22 http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/R/RD/RDF/Clone-0.22.tar.gz !Digest::MD5 http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/G/GA/GAAS/Digest-1.15.tar.gz http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/G/GA/GAAS/Digest-MD5-2.36.tar.gz 但し、Digest::base 1.00が必要とのWarnningが出る。 Warning: prerequisite Digest::base 1.00 not found. なので、Digest::baseを先にInstallする。 !File::Spec これはPathTool 3.24に入っている。 http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/K/KW/KWILLIAMS/PathTools-3.24.tar.gz !IO::String http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/G/GA/GAAS/IO-String-1.08.tar.gz !List::MoreUtils http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/V/VP/VPARSEVAL/List-MoreUtils-0.21.tar.gz !Params::Util http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/G/GB/GBARR/Scalar-List-Utils-1.19.tar.gz http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Params-Util-0.23.tar.gz 但し、Params::Utilのperl Makefile.PL時にScalar::Utilが必要といわれるので先にInstallする。 Warning: prerequisite Scalar::Util 1.14 not found. We have 1.09. !Storable   http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AM/AMS/Storable-2.15.tar.gz !Task::Weaken http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/M/MS/MSCHWERN/ExtUtils-MakeMaker-6.32.tar.gz (http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/Y/YV/YVES/ExtUtils-Install-1.41.tar.gz) (http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/R/RK/RKOBES/ExtUtils-Command-1.13.tar.gz) http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Task-Weaken-0.99.tar.gz 但し、Task::Weakenのmake installの時に原因不明のエラーが出る。 これはExtUtils::MakeMakerのVersionが古いことにより発生しているっぽい。 今回はExtUtils::Install→ExtUtils::Command→ExtUtils::MakeMakerの順でアップデートしたが、ExtUtils::MakeMakerを入れるまでTask::Weakenのエラーメッセージに変化がなかったのでExtUtils::MakeMakerだけでも良いかもしれない。 もしExtUtils::MakeMakerをアップデートする前にTask::Weakenのperl Makefile.PLを行なった場合は、一度make cleanしてperl Makefile.PLから再度やり直す必要があるらしい。 !Test::ClassAPI http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Config-Tiny-2.10.tar.gz http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Class-Inspector-1.16.tar.gz   http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Test-ClassAPI-1.04.tar.gz これも依存性の関係で上記の順番でInstallしないとperl Makefile.PLでWarnningが出る。 !Test::Object http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/M/MS/MSCHWERN/Test-Simple-0.70.tar.gz http://ftp.yz.yamagata-u.ac.jp/pub/lang/cpan/authors/id/A/AD/ADAMK/Test-Object-0.07.tar.gz これも依存性の関係で上記の順番でInstallしないとperl Makefile.PLでWarnningが出る。 このほかにも、使っているperlのバージョン、OSのディストリビューションなどによって必要だったり更新したりするパッケージが変わるかもしれない。 また、PPI自体がまだVersion 1.0未満なので頻繁に更新されるっぽい。 !!PPIを試す   下記のようなテストプログラムを作ってみる。 #!/usr/bin/perl use strict; # a comment. use Dumpvalue; package ABC; $ABC::value1 = 100; @ABC::array1 = ('A', 'B', 'C'); %ABC::hash1 = ( 'X' => '1', 'Y' => '2', 'Z' => '3' ); print "*** start ***\n\n"; print "\$ABC::value1 = $ABC::value1 \n"; foreach my $i (@ABC::array1) { print "\$ABC::array1[$i] = $ABC::array1[$i] \n"; } foreach my $i (sort keys(%ABC::hash1)) { print "\$ABC::hash1{'$i'} = $ABC::hash1{$i} \n"; } my $ret = function1($ABC::value1); print "\$ret = $ret\n"; exit 0; sub function1 { my $val = shift; print "Hello $val !!!! \n"; } 0; これをtest1.plとして保存しておく。 ちなみに実行すると以下のような結果が表示される。 *** start *** $ABC::value1 = 100 $ABC::array1[A] = A $ABC::array1[B] = A $ABC::array1[C] = A $ABC::hash1{'X'} = 1 $ABC::hash1{'Y'} = 2 $ABC::hash1{'Z'} = 3 Hello 100 !!!! $ret = 1 さらに、以下のScriptを入力する。 こちらはtest2.plとして保存する。 #!/usr/bin/perl use strict; use PPI; use PPI::Dumper; my $document = PPI::Document->new($ARGV[0]); my $dumper = PPI::Dumper->new($document); $dumper->print; exit(0); これらができたところで、 $ perl test2.pl test1.pl として実行すると、下記のようにtest1.plのPerl scriptが構文解析され、Object化されていることがわかる。 PPI::Document PPI::Token::Comment '#!/usr/bin/perl\n' PPI::Token::Whitespace '\n' PPI::Statement::Include PPI::Token::Word 'use' PPI::Token::Whitespace ' ' PPI::Token::Word 'strict' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Token::Comment '# a comment.\n' PPI::Token::Whitespace '\n' PPI::Statement::Include PPI::Token::Word 'use' PPI::Token::Whitespace ' ' PPI::Token::Word 'Dumpvalue' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Package PPI::Token::Word 'package' PPI::Token::Whitespace ' ' PPI::Token::Word 'ABC' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Symbol '$ABC::value1' PPI::Token::Whitespace ' ' PPI::Token::Operator '=' PPI::Token::Whitespace ' ' PPI::Token::Number '100' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Symbol '@ABC::array1' PPI::Token::Whitespace ' ' PPI::Token::Operator '=' PPI::Token::Whitespace ' ' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Quote::Single ''A'' PPI::Token::Operator ',' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''B'' PPI::Token::Operator ',' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''C'' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Symbol '%ABC::hash1' PPI::Token::Whitespace ' ' PPI::Token::Operator '=' PPI::Token::Whitespace ' ' PPI::Structure::List ( ... ) PPI::Token::Whitespace ' ' PPI::Statement::Expression PPI::Token::Quote::Single ''X'' PPI::Token::Whitespace ' ' PPI::Token::Operator '=>' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''1'' PPI::Token::Operator ',' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''Y'' PPI::Token::Whitespace ' ' PPI::Token::Operator '=>' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''2'' PPI::Token::Operator ',' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''Z'' PPI::Token::Whitespace ' ' PPI::Token::Operator '=>' PPI::Token::Whitespace ' ' PPI::Token::Quote::Single ''3'' PPI::Token::Whitespace ' ' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"*** start ***\n\n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"\$ABC::value1 = $ABC::value1 \n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Statement::Compound PPI::Token::Word 'foreach' PPI::Token::Whitespace ' ' PPI::Token::Word 'my' PPI::Token::Whitespace ' ' PPI::Token::Symbol '$i' PPI::Token::Whitespace ' ' PPI::Structure::ForLoop ( ... ) PPI::Statement PPI::Token::Symbol '@ABC::array1' PPI::Token::Whitespace ' ' PPI::Structure::Block { ... } PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\t' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"\$ABC::array1[$i] = $ABC::array1[$i] \n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Compound PPI::Token::Word 'foreach' PPI::Token::Whitespace ' ' PPI::Token::Word 'my' PPI::Token::Whitespace ' ' PPI::Token::Symbol '$i' PPI::Token::Whitespace ' ' PPI::Structure::ForLoop ( ... ) PPI::Statement PPI::Token::Word 'sort' PPI::Token::Whitespace ' ' PPI::Token::Word 'keys' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Symbol '%ABC::hash1' PPI::Token::Whitespace ' ' PPI::Structure::Block { ... } PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\t' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"\$ABC::hash1{'$i'} = $ABC::hash1{$i} \n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Variable PPI::Token::Word 'my' PPI::Token::Whitespace ' ' PPI::Token::Symbol '$ret' PPI::Token::Whitespace ' ' PPI::Token::Operator '=' PPI::Token::Whitespace ' ' PPI::Token::Word 'function1' PPI::Structure::List ( ... ) PPI::Statement::Expression PPI::Token::Symbol '$ABC::value1' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"\$ret = $ret\n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Word 'exit' PPI::Token::Whitespace ' ' PPI::Token::Number '0' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement::Sub PPI::Token::Word 'sub' PPI::Token::Whitespace ' ' PPI::Token::Word 'function1' PPI::Token::Whitespace '\n' PPI::Structure::Block { ... } PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\t' PPI::Statement::Variable PPI::Token::Word 'my' PPI::Token::Whitespace ' ' PPI::Token::Symbol '$val' PPI::Token::Whitespace ' ' PPI::Token::Operator '=' PPI::Token::Whitespace ' ' PPI::Token::Word 'shift' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\t' PPI::Statement PPI::Token::Word 'print' PPI::Token::Whitespace ' ' PPI::Token::Quote::Double '"Hello $val !!!! \n"' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' PPI::Statement PPI::Token::Number '0' PPI::Token::Structure ';' PPI::Token::Whitespace '\n' PPI::Token::Whitespace '\n' !!PPI::Documentの使い方 ''これから書きます'' !!PPI::Nodesの使い方 ''これから書きます'' !!何ができるのか? ''これから書きます'' perldocによると、 *ソースコードからDocumentを起こすツール *コードチェッカー(ロジックチェック) *バグ検出ツール などに使えるっぽいです。 !!参照 *CAPNのPPIのページ http://search.cpan.org/~adamk/PPI-1.199_02/lib/PPI.pm PPI::Document、PPI::Node、PPI::Elementなどへのリンクもあります。 !!履歴 2007/03/20 -- 初版(書きかけ) [[技術的雑談]]へ戻る !!突っ込み {{comment}} [[技術的雑談]]へ戻る {{trackback}} [[技術的雑談]]へ戻る