Minilla で作ったモジュールにデータフォルダを入れる
全国の銀行・支店コードを取得・表示する ZenginCode というものがあります。
これには!なんと!!Perl 版がないので(しょんぼり)自分で作って使ったりしています。
きっかけは経理業務で必要に迫られ・・・必要に迫られ・・・楽をする必要に迫られ・・・楽がしたい・・・
モジュールの中にデータフォルダを作りたかった
ZenginCode の Ruby 版だと、gem(Perlでいうところのモジュール)の中に全銀コードのデータが格納されており、そのまま利用が可能です。
自分の Perl モジュールは Minilla で作っているのですが、Ruby 版と同じ様にモジュール内にデータファイルを入れる方法がわかりませんでした。
結果、銀行コードの一覧のみを別にダウンロードして、モジュールはそこを参照しにいく、という構成で作りました。
Minillaのモジュールの中にデータフォルダ作れます
が、同じような問題にあたり、そして解決した人がいることを発見!
こちらの方はポケモンGoのデータを用いて、同じようなことをしている・・・!
そして、minilla でモジュール内にデータを置いておく方法についてはしっかり Web+DB での連載でも言及されておりました。あぁ。
ソースコード以外のファイルをモジュールに同梱したい場合があります。たとえば,テンプレートファイルや辞書ファイルなどです。そういったファイルはshareディレクトリに配置します。
その場合,CPANにアップロードしてからも正しく動作させるために,コード内からそれらのファイルに直接アクセスするのではなく,File::Shareなどのモジュールを通してアクセスして開発する必要があります。
さっそくチャレンジ・・・File::Share
ってなに?
File::Shareなどのモジュールを通してアクセスして開発する必要があります。
File::Share
初めて聞きますね。ってことで Google 翻訳片手で見てみます。
・・・ダメだよくわからん。でも大丈夫、Perl の場合は SYNOPSYS が充実してるので、まずはそれをコピって実行。
#!/usr/bin/env perl use strict; use warnings; use File::Share ':all'; my $dir = dist_dir('Foo-Bar'); my $file = dist_file('Foo-Bar', 'file.txt');
で、こんなエラー
Failed to find share dir for dist 'Foo-Bar' at /Users/sironekotoro/.plenv/versions/5.28.1/lib/perl5/site_perl/5.28.1/File/Share.pm line 37. [Finished in 0.2s with exit code 2]
ううん、わからないので Google 翻訳で
File :: Shareはshare、対応するモジュールが開発パスからロードされたことを認識した場合、ローカルディレクトリを探します。
ううーん。
このモジュールの元となった File::ShareDir も見てみたんですがよくわからず・・・で色々試行錯誤した結果です。
File::Share
とは
File::Share
とは汎用的なファイルのパス解決ツールではなく、モジュール作成時に使うもののようです。
標準モジュールではないので、cpanm File::Share
などでインストールが必要です。
まぁ、汎用的なやつなら File::Find とか Path::Tiny とかあるものね。
やってみる
$ minil new Sironekotoro::File
としてモジュールの雛形を作る作ったモジュールのフォルダの中に
share
フォルダを作成するshare
フォルダの中に test.txt を作成する。中には適当に hoge とか書いておくモジュールの中に
test.pl
を作成する。名前の通りテスト用
この時点で Sironekotoro-File
フォルダの中身はこうなってます。
$ tree . ├── Build.PL ├── Changes ├── LICENSE ├── META.json ├── README.md ├── cpanfile ├── lib │ └── Sironekotoro │ └── File.pm ├── minil.toml ├── share │ └── test.txt └── t └── 00_compile.t 4 directories, 10 files
手を入れるのは lib/Sironekotoro/File.pm
と test.pl
です。
まずは lib/Sironekotoro/File.pm
、わかりやすいように warn
を仕掛けておきます。
package Sironekotoro::File; use 5.008001; use strict; use warnings; use File::Share 'dist_dir'; our $VERSION = "0.01"; sub new { my $class = shift; my $self = bless {}, $class; return $self; } sub read { my $self = shift; my $dir = dist_dir('Sironekotoro::File'); warn '$dir: ' . $dir; my $data = "$dir/test.txt"; warn '$data: ' . $data; # ファイルを読み込む処理 my $str; open my $FH , '<', $data; for my $line (<$FH>){ chomp $line; $str .= $line; } close $FH; return $str; } 1;
次にテスト用の test.pl
#!/usr/bin/env perl use strict; use warnings; use lib qw/lib/; use Sironekotoro::File; my $obj = Sironekotoro::File->new(); print "The text of the file's contents\n"; print $obj->read . "\n";
これで $ perl test.pl
とすると、無事、モジュール内のファイルを読んでくれます。
そして、モジュールに仕掛けた warn
の効果でこのような出力になります。
$ perl test.pl The text of the file's contents $dir: /Users/sironekotoro/Dropbox/perl/temp/Sironekotoro-File/share at lib/Sironekotoro/File.pm line 21. $data: /Users/sironekotoro/Dropbox/perl/temp/Sironekotoro-File/share/test.txt at lib/Sironekotoro/File.pm line 25. hoge
これで、モジュールの中の $dir
には、モジュール内の share ディレクトリ までのフルパスが入っていることがわかりました。
同様に $data
にはファイルまでのフルパスです。
なるほど、これであればモジュールからファイルを参照できますね。
Zengin::Perl 鋭意改良・・・します
ということで、やりたかったことを実現する方法を見つけました。
空き時間になんとか良い感じにしていきたいですね。
あと、最近やっと Mouse
の良さ的なものに気づいたので、Mouse
使ったオブジェクト指向にしていきたいなぁ・・・
なお、全銀データをモジュール内に持つ場合、モジュールを定期的にアップデートする必要が出てきますねぇ・・・さてどうするか。考えるの楽しいですね。