=encoding utf-8

=heed1 注意

この記事は書きかけです。

=head1 1. Simoとは

SimoはPerlのオブジェクト指向を簡単にするモジュールです。

主な特徴として

=over 4

=item 1. アクセッサを簡潔に記述することができる。

=item 2. コンストラクタ new が準備されている。

=item 3. 各フィールドに対して、デフォルト値の設定、値の制約などが可能。

=item 4. エラーをオブジェクトとして投げるので、詳細なエラー処理が可能。

=back

ということが挙げられます。

Simoを使えば、クラスの作成するときの面倒な作業から解放されます。

もしL<Mouse>やL<Mouse>などのオブジェクト指向を簡単にするためのモジュールを知っているのなら
Simoはこれらのモジュールをもっと簡潔にしたものだと考えてください。

Simoはオブジェクト指向のための直感的で簡潔なインターフェイスを提供します。

=cut

=head1 2. Simoのインストール

Simoをインストールするには

    cpan Simo

とします。

Windows環境でインストールしたい場合は、先に nmake をインストールしておく必要があります。
「windows nmake」という語句で検索するとインストール方法がすぐに見つかると思います。

=cut

=head1 3. Simo関連モジュールのインストール

Simoに関連するモジュールがいくつかあります。
これらのモジュールはオブジェクト指向を簡潔にすることを手助けしてくれます。

=over 4

=item 1. Simo::Wrapper - オブジェクトの操作を便利にします。

=item 2. Simo::Error - エラーオブジェクトを生成します。

=item 3. Simo::Util - オブジェクトの操作を便利にします。

=item 4. Simo::Constrain - フィールドに設定される値を制約します。

=back

Simoのみのインストールでもクラスの作成は行うことができますが、
これらのモジュールも一緒にインストールしておくとさらに便利です。

これらのモジュールを一度にインストールするには

    cpan Bundle::Simo

とします。

=cut

=head1 2. アクセッサの記述

Simoを使えば、アクセッサを簡潔に記述することができます。
以下の例は、title,author,priceという3つのフィールドを持つBookクラスの定義です。

    package Book;
    use Simo;
    
    sub title{ ac }
    sub author{ ac }
    sub price{ ac }

アクセッサを定義するには ac 関数を呼ぶだけです。
またコンストラクタ new は自動的に準備されます。

=cut

=head1 3. オブジェクトの作成

作成したクラスは,普通のクラスと同じように使用することができます。
以下は、オブジェクトを作成する例です。

    use Book;
    
    my $book = Book->new( title => 'Goog new', author => 'Kimoto', price => 2000 );

コンストラクタ new が準備されているので呼び出すことができます。
new には、ハッシュかハッシュのリファレンスを渡すことができます。

以下はハッシュのリファレンスを渡す例です。

    my $book = Book->new( { title => 'Goog new', author => 'Kimoto', price => 2000 } );

=cut

=head1 4. フィールドのデフォルト値 default

フィールドのデフォルト値の設定は以下のように行います。

    package Book;
    use Simo;
    
    sub title{ ac default => 'Good news' }
    sub author{ ac default => [ 'Kimoto', 'Kishimoto' ] }
    sub price{ ac default => { low => 1500, normal => 2000 } }

フィールドに値が設定されていないときにアクセッサを呼び出すと default で指定された値が使用されます。

取得される値は、defaultで指定された値のB<コピー>です。
デフォルト値がリファレンスなどの「数値や文字列」以外のものであった場合は、L<Storable>のclone関数によって値がコピーされます。
これは、大きなデータであった場合はオーバーヘッドになりえます。

デフォルト値がリファレンスやオブジェクトであった場合は、
default ではなくて後で解説する auto_build を使用することも考慮に入れてください。

=cut

=head1 5. フィールドの構築 auto_build

ときに、他のフィールドの値に基づいて、フィールドを構築したい場合があります。
たとえば、フィールドに設定されたホスト名からNet::FTPオブジェクトを構築したい場合などです。

このような場合は、auto_build を使用すると便利です。
auto_build オプションを指定すると、アクセッサが呼ばれたときに
ビルダーメソッドを自動的に呼び出してくれます。

    package YourApp;
    use Simo;
    use Net::FTP;
    
    sub host{ default => 'some.host.name' }
    
    sub net_ftp{ ac auto_build => 1 }

    sub build_net_ftp{
        my $self = shift;
        $self->net_ftp( Net::FTP->new( $self->host ) );
    }

ビルダーメソッドは、build_net_ftp のように

    build_アクセッサ名

にする必要があります。

2回目移行のフィールドへのアクセスは、ビルダーメソッドによって設定された値が使用されます。

=cut

=head1 6. フィールドの制約 constrain

フィールドに制約を持たせたい場合があります。
数値だけを受け入れたかったり、特定のクラスのオブジェクトだけを受け入れたかったりする場合です。

このような場合は、constrain を使用します。
constarin には、好きな制約関数を渡すこともできますが、
通常は、L<Simo::Constrain> に制約のための関数が用意されているのでそれを使います。

    package Book;
    use Simo;
    use Simo::Constrain qw( is_str is_int isa );
    
    sub title{ ac constrain => \&is_str }
    
    sub author{ ac constrain => sub{ isa 'Person' } }
    
    sub price{ ac constrain => \&is_int }

titleに設定できるの文字列だけ、authorに設定できるのはPersonクラスのオブジェクトだけ、
priceに設定できるのは整数値だけといったように、フィールドに設定できる値が制約できます。

もし制約に違反すれば、例外が発生しプログラムは終了します。
以下のようなメッセージが表示されます。

    Book::price must be integer.( this value is bad ) at b.pl line 6

=cut

=head1 7. 制約違反にに対する例外処理

Simoはフィールドに制約違反が起こったときに例外を投げます。
この例外は単なる文字列ではなくて、L<Simo::Error>オブジェクトです。

このオブジェクトは、制約違反を起こしたフィールド名、設定された値などの情報を持っています。

このオブジェクトの情報を見たいときは、L<Simo::Util> の err 関数を使用します。

以下の例では、priceに整数以外を渡したので例外が発生します。
この例外をevalでキャッチした後、err 関数で内容を取得することができます。

    use Book;
    use Simo::Util qw( err );
    
    my $book = eval{ Book->new( price => 'string', title => 'Good news' ) };
    
    if( my $err = err ){
        my $type = $err->type;  # 例外の種類
        my $msg = $err->msg;    # 例外メッセージ
        my $pos = $err->pos;    # 例外が起こった場所
        my $pkg = $err->pkg;    # 例外が起こったパッケージ名
        my $attr = $err->attr   # 例外を起こしたフィールド名
        my $val = $err->val;    # 例外の原因になった値
        
        if( $attr eq 'price' ){
            # やりたいエラー処理を行う。
        }
        else( $attr eq 'title' ){
            # ...
        }
        else{
            # ...
        }
    }

どのフィールド名で制約違反が起こって、それがどのような値なのかを取得できるため
詳細なエラー処理を行うことができます。

エラーオブジェクトについては L<Simo::Error> も参照してください。

=cut