技術的雑談-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 -- 初版(書きかけ)
技術的雑談へ戻る