Perl の Cpanm と Minilla を使ってみる
この記事に関連するお話です。
Perl でのパッケージ作成をしてみます。デフォルトでの支援はないので、cpanm と minilla をインストールして、ライブラリはローカルにインストールするように環境変数を設定しました。
雛形の作成
Ruby の gem にあたる cpanm が必要らしいので、次のコマンドを入力してインストール。
curl -L https://cpanmin.us | perl - App::cpanminus
でも何かエラーが出ているような?それとも ~/bin
の中で curl -LOk http://xrl.us/cpanm
を実行する方法のほうが良いのかな?
! ! Can't write to /Library/Perl/5.18 and /usr/local/bin: Installing modules to /Users/home/perl5 ! To turn off this warning, you have to do one of the following: ! - run me as a root or with --sudo option (to install to /Library/Perl/5.18 and /usr/local/bin) ! - Configure local::lib in your existing shell to set PERL_MM_OPT etc. ! - Install local::lib by running the following commands ! ! cpanm --local-lib=~/perl5 local::lib && eval $(perl -I ~/perl5/lib/perl5/ -Mlocal::lib) ! --> Working on App::cpanminus Fetching http://www.cpan.org/authors/id/M/MI/MIYAGAWA/App-cpanminus-1.7044.tar.gz ... OK Configuring App-cpanminus-1.7044 ... OK Building and testing App-cpanminus-1.7044 ... OK Successfully installed App-cpanminus-1.7044 1 distribution installed
ホームディレクトリに perl5 というディレクトリが作成されていました。~/perl5/bin/cpanm を実行すれば良さそう。
プロジェクトの雛形を作成するには Minilla が必要らしいです。~/perl5/bin/cpanm Minnila
でインストール。関連するライブラリが多くてかなり時間がかかる。一度目はエラーになってしまったけれど、--force
を付けて再実行するとインストールできました。ネット回線の速度が遅いからかな?
~/perl5/bin/minil new Mto
としてもエラーになってしまう。次のようにして環境変数を設定しておかなければいけなかったのでした。.bashrc
にでも書いておこうっと。
export PERL_CPANM_OPT='--local-lib=~/perl5' export PATH=$HOME/perl5/bin:$PATH; export PERL5LIB=$HOME/perl5/lib/perl5:$PERL5LIB;
これでモジュールプロジェクトの雛形ができました。
> minil new Mto Writing lib/Mto.pm Writing Changes Writing t/00_compile.t Writing .travis.yml Writing .gitignore Writing LICENSE Writing cpanfile Initializing git Mto [Mto] $ git init Initialized empty Git repository in /Users/home/Mto/.git/ Retrieving meta data from lib/Mto.pm. Name: Mto Abstract: It's new $module Version: 0.01 [Mto] $ git add . Finished to create Mto
この中で触るのは lib/Mto.pm と t/00_complie.t くらいかな?
プロジェクトの設定
Build.PL や cpanfile があるのだけれど、編集する必要はないみたい。
プロジェクトの実装
lib/Mto.pm に内容をコピペして終了。
テストの記述
以前書いたものの内容をコピペして minil test
してみると、Bareword "Exporter" not allowed while "strict subs" in use at lib/Mto.pm line 9.
というエラーになってしまった。次の行を use strict;
の上に移動すると解決しました。
use Exporter; @ISA = (Exporter); @EXPORT = qw();
どうやら minilla は テンポラリディレクトリを作成し、その中でいろいろするらしい。この過程で、test-jisyo, test-text がそのディレクトリにコピーされないので、ファイルを開けないよと言われてるようです。
git と連携しているようで、トラッキングしていないファイルはコピーされないみたい。git add .
するとコピーされるようになり解決。
テストの内容が厳しくなったようで、Mto.pm
中で my
を付け忘れていた変数の部分でエラーが出てしまった。
read ($a_file, my $text, -s $a_file); my @input = <STDIN>;
関数への引数に配列を渡すときは \@arg
のようにバックスラッシュを入れないといけないそうです。これは、@_
で受けとる時の区切りがわからなくなるためらしい。
内部辞書の作成過程に問題があることがわかりました。正規表現で空行を考慮に入れてなかった……。
unless ($line =~ /^;.*$/) { unless ($line =~ /^;.*$|^$/) {
配列の配列がどうなっているのかがわからない。コンスセルリストのようなものを想像していたのだけれど、Perl では多次元配列というものは存在せず、擬似的に表現しているらしいです。リファレンスという言葉が出てきた。ポインタみたいなやつかな?
sub create_dictionary{ my @dict_arr = (); ... my @pairs = split(/\s* \/\s*/, $line); # ペアの配列にする push @dict_arr, [ @pairs ]; # 配列の配列にする ... return @dict_arr; }
空の配列を ()
で作成し、それに [hoge, fuga] というものを追加していくことで内部辞書を作成していたようです。つまり
@dict_arr = ([hoge, fuga], [foo, bar], [nyan, wan], [piyo, koke])
となっているわけですね。自分で書いているのに覚えてない……。@
を付けた変数名にすれば配列として扱ってくれるものとばかり思っていました。
自分が最初にテストで書いた「期待する配列の結果」は Ruby や Python のように
@valid_arr = [[hoge, fuga], [foo, bar], [nyan, wan], [piyo, koke]]
としていたのだけれど、これは正しくないものらしい。[]
で囲われたものは配列ではなくスカラ値というものらしいので、$
を使って
$valid_arr = [[hoge, fuga], [foo, bar], [nyan, wan], [piyo, koke]]
のように書かなければいけません。でもこれは自分が作成した内部辞書とは異なっているので、is()
で比較することができないのでした。つまり @valid_arr
は、はじめに書いたように、@dict_arr = ([, ], [, ], ...)
という形にしなければならないのです。こうすることで比較が可能になりテストが OK になりました。
テストの実行は minil test
でも perl t/00_comple.t
でも OK になりました。
パッケージの作成
現状ではディレクトリの中で cpanm -i . -l ~/perl5
と実行することにより、~/perl5/lib
以下に Mto.pm がインストールできるようになりました。あとは実行ファイルを bin
にインストールできるようにするだけです。
script 以下に実行ファイルを入れることで ~/perl5/bin
にインストールしてくれるらしいです。これで完了!ちなみに削除する時は cpanm -U Mto -l ~/perl5
とすること。
minil clean
とすることでビルド時に作成されたものを削除してくれます。
GitHub からのインストール
capnm git://github.com/user_name/plmto.git
でインストールできるはずなんだけどな?
正規表現
旧から新への変換のテストを追加したら、エラーが出てしまいました。文字列置換の部分に問題があるのですが、リテラルではなく正規表現で置換しているのが原因らしいです。'(´・_・`)' がグルーピングの意味になってしまうのでした。
my $hoge ="あ!(´・_・`)さんだ"; $hoge =~ s/(´・_・`)/たなこふ/g; print $hoge; => あ!(たなこふ)さんだ
いろいろと調べてみると、C 言語のように substr と index を組み合せてやる方法がありましたが、繰り返しで処理するところで詰まってしまいました。クオートすれば動くのですけれど、内部辞書から繰り返しで持ってくるために使えないのです。
my $hoge ="あ!(´・_・`)さんだ"; $hoge =~ s/\(´・_・`\)/たなこふ/g; print $hoge; => あ!たなこふさんだ
たまたまクオートする方法を発見できましたのでそれを採用しました。下記のようにして挟めばその内側がクオートされるそうです。
$hoge =~ s/\Q(´・_・`)\E/たなこふ/g;`
オフトピだけれども、minil は git でステージングしていないファイルは処理の対象にしないというのを忘れていて、新規に追加したサンプル文章が見つからないというエラーでずいぶんと時間を使ってしまいました。