Minilla で Perl モジュールをつくる


[Minilla](https://metacpan.org/release/Minilla) で Perl モジュールを開発するための環境構築から、実際にモジュールを作ってテストするまでをやってみました。

## ライブラリをインストールする場所

以後、環境構築で必要になる実行プログラムやライブラリをインストールするディレクトリが `$PERL5_LOCAL_LIB_HOME` で参照できるものとします。今回は、`$HOME/Developer/Library/Perl` としました。

    PERL5_LOCAL_LIB_HOME=$HOME/Developer/Library/Perl

また、実行プログラムをインストールする `$PERL5_LOCAL_LIB_HOME/bin` を `$PATH` に追加しておきます。

    export PATH="PERL5_LOCAL_LIB_HOME/bin:$PATH"

## cpanm のインストール

[CPAN](https://www.google.co.jp/search?client=safari&rls=en&q=CPAN&ie=UTF-8&oe=UTF-8&gfe_rd=ctrl&ei=qaEvU6NihZPxB9SBgZgI&gws_rd=cr) で公開されているライブラリのインストールには、コマンドラインツールの [cpanm](http://search.cpan.org/~miyagawa/App-cpanminus/) を使うのが便利です。cpanm 自体は、いくつかの方法でインストールできます（それぞれの手順については[公式のドキュメント](http://search.cpan.org/~miyagawa/App-cpanminus-1.7001/lib/App/cpanminus.pm#INSTALLATION)を参照）。

1. OS のパッケージ管理ツール (apt-get など)
2. 最新の cpanm をダウンロード、実行して cpanm をインストール
3. スタンドアローンなプログラムをダウンロード

たとえば、3 の方法だと:

```bash
% mkdir -p $PERL5_LOCAL_LIB_HOME/bin; cd $PERL5_LOCAL_LIB_HOME/bin
% curl -LO http://xrl.us/cpanm
% chmod u+x cpanm
```

だけで、`cpanm` コマンドラインツールを利用できるようになります。

## local::lib

Minilla に関連するライブラリが `$PERL5_LOCAL_LIB_HOME` にインストールされるように、[local::lib](http://search.cpan.org/dist/local-lib/lib/local/lib.pm) をセットアップしておきましょう。

```Bash
% cpanm --local-lib $PERL5_LOCAL_LIB_HOME local::lib
```

local::lib を use して perl を実行することで、適切な環境変数が出力されることを確認します。

```Bash
% perl -I$PERL5_LOCAL_LIB_HOME/lib/perl5 -Mlocal::lib=$PERL5_LOCAL_LIB_HOME
PATH="$HOME/Developer/Library/Perl/bin${PATH+:}$PATH"; export PATH;
PERL5LIB="$HOME/Developer/Library/Perl/lib/perl5${PERL5LIB+:}$PERL5LIB"; export PERL5LIB;
...
```

`.bashrc` などに追記して、シェルの起動時に環境変数が設定されるようにします。

```Bash
[ $SHLVL -eq 1 ] && eval "$(perl -I$PERL5_LOCAL_LIB_HOME/lib/perl5 -Mlocal::lib=$PERL5_LOCAL_LIB_HOME)"
```

## Minilla のインストール

Minilla のインストールも、cpanm を実行するだけです（依存しているライブラリが多く、それなりに時間がかかります）。

```Bash
% cpanm Minilla
--> Working on Minilla
...
Successfully installed Minilla-v0.12.0
37 distributions installed
```

試しに動かしてみます。

```Bash
% minil -v
Minilla: v0.12.0
```

あとは、このへんを読みながら実際に開発を進めていきます。

* [Minilla::Tutorial - Tutorial document for Minilla - metacpan.org](https://metacpan.org/pod/distribution/Minilla/lib/Minilla/Tutorial.pod)
* [Minilla を用いた Perl モジュールの作り方 - blog.64p.org](http://blog.64p.org/entry/2013/05/14/080423)

## プロジェクトの雛形をつくる

`minil` コマンドでプロジェクトの雛形を作成します。

今回は、Rails の [ActiveSupport::Inflector](http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html) っぽいモジュールを開発しようと思うので、名前は String-Inflector にしました。

```Bash
% minil new String-Inflector
Writing lib/String/Inflector.pm
Writing Changes
Writing t/00_compile.t
Writing .travis.yml
Writing .gitignore
Writing LICENSE
Writing cpanfile
Initializing git String::Inflector
[String-Inflector] $ git init
Initialized empty Git repository in $HOME/Developer/Workspace/String-Inflector/.git/
Detecting project name from directory name.
Retrieving meta data from lib/String/Inflector.pm.
Name: String::Inflector
Abstract: It's new $module
Version: 0.01
fatal: bad default revision 'HEAD'
[String-Inflector] $ git add .
Finished to create String::Inflector
```

途中で `fatal: bad default revision 'HEAD'` という git のエラーが出ていますが、これは、コミットがないときに出る `git log` のエラーです。プロジェクトを作ったばかりでコミットがないのは当然なので特に問題ありません ([Minilla/Issues/49](https://github.com/tokuhirom/Minilla/issues/49))

どんなファイルが作成されているかを確認しましょう。

```Bash
% cd String-Inflector
% tree
.
├── Build.PL
├── Changes
├── LICENSE
├── META.json
├── README.md
├── cpanfile
├── lib
│   └── String
│       └── Inflector.pm
├── minil.toml
└── t
    └── 00_compile.t

3 directories, 9 files
```

この時点で `git init` と `git add` が済んでいるので、commit もしておきます。

```Bash
% git commit -m 'initial import'
```

## 依存するモジュールの追加

`minil new` した時点で cpanfile というファイルが作成されていますが、このファイルにはプロジェクトが依存するモジュールを記述します。

```perl
requires 'perl', '5.008001';

on 'test' => sub {
    requires 'Test::More', '0.98';
};
```

cpanfile の詳しい書き方は [POD](http://search.cpan.org/~miyagawa/Module-CPANfile-1.0002/lib/cpanfile.pod) を参照してください。また、バージョン指定の書式については [CPAN::Meta::Spec の POD](http://search.cpan.org/~dagolden/CPAN-Meta-2.140640/lib/CPAN/Meta/Spec.pm#Version_Formats) が詳しいです。

cpanfile で記述した依存モジュールは、`cpanm` コマンドで

```bash
cpanm --installdeps .
```

または、[Carton](http://search.cpan.org/dist/Carton) を使って、

```bash
carton install
```

でインストールできます。`carton` を使うと、依存モジュールがプロジェクトのディレクトリ以下にインストールされるので、管理が楽になります（Carton も `cpanm Carton` 一発でインストールできます）。

## デフォルトからの変更

### Perl バージョンの変更

デフォルトだと Perl 5.8.5 以上に対応するモジュールとしてビルドされます。変更したい場合は lib/String/Inflector.pm の `use VERSION` を変更します。

今回は自分の Mac にインストールされていた Perl 5.12 以降を対象にしました。

```perl
package String::Inflector;
use 5.012;
```

また、cpanfile にも Perl のバージョン指定があるので、こちらも変更します。

```perl
requires 'perl', '5.012';
```

### ライセンスの変更

デフォルトだと [Perl ライセンス](http://dev.perl.org/licenses/)になっています。こちらの変更もファイルは同じ lib/String/Inflector.pm ですが、POD の LICENSE セクションを変更します。

今回は、個人的な好みで [MIT ライセンス](http://opensource.org/licenses/MIT)を選択しました。

```perl
=head1 LICENSE

MIT License
```

ただし、Perl ライセンス以外を選択した場合、あとで `Build.PL` を生成するときに「[Software::License](http://search.cpan.org/dist/Software-License) が必要！」と怒られるので、`cpanfile` に追加しておきます。

```perl
on 'develop' => sub {
    requires 'Software::License'
};
```

## 開発

あとは開発するだけです。モジュールに新規コードとテストを追加し、Carton を使用している場合は `carton exec` でテストを実行します。

```
% carton exec -- prove -Ilib -r t
```

問題なければ `git add` して `minil test` すると、実際にビルドしてテストを実行してくれます。

## まだ分からないこと

* Carton を使って開発していても、`minil test` した時点で依存モジュールが `$PERL5_LOCAL_LIB_HOME` にインストールされてしまう
    * Minilla を cpanfile の develop フェーズに記述して、`minil` の実行も `carton exec` するようにした方がいいかも？（試してない）
* CPAN にリリースやったことありません