2006 年 4 月 20 日 23 時 57 分

モジュールの実装


このアーカイブは同期化されません。 mixi の日記が更新されても、このアーカイブには反映されません。


では、property モジュールに実装を作っていこう。

まずは、use の呼び出しの規約を考える。
プロパティの作成に必要なのは、
名前、setter メソッド, getter メソッドの三つ。
それをハッシュで渡すようにしよう。

use property 'name' => 'salary',
        'get' => \&get_salary,
        'set' => \&set_salary;

========== property.pm ==========

package property;

use v5.6.0;
use strict;
use warnings;

BEGIN {
    our $Version = '0.01';
}

sub import {
    my $package = shift;
    my %param = @_;
    my $target = caller;

    _create_property($target, $param{'name'},
            $param{'get'}, $param{'set'});

}

sub _create_property {
    my ($package, $name, $get, $set) = @_;

    my $propertizer = sub : lvalue {
        my $this = shift;
        tie(my $reflector, __PACKAGE__, $this, $get, $set);
        $reflector;
    };

    _register_code($package, $name, $propertizer);
}

sub _register_code {
    my ($package, $name, $code) = @_;

    my $symbol = "${package}::${name}";
    no strict 'refs';
    *$symbol = $code;
}

sub TIESCALAR {
    my ($package, $object, $get, $set) = @_;
    $package = (ref $package or $package or __PACKAGE__);
    my $this = { 'object' => $object, 'get' => $get, 'set' => $set };
    bless($this, $package);
}

sub FETCH {
    my $this = $_[0];
    $this->{'get'}->($this->{'object'});
}

sub STORE {
    my ($this, $value) = @_;
    $this->{'set'}->($this->{'object'}, $value);
}

1;

========== end of property.pm ==========

import メソッドは、use の時に呼ばれる。
property モジュールは、'name' で示された
プロパティを lvalue メソッドとして追加する。
これにはシンボリックリファレンスを利用するのだ。
これは _register_code ルーチンで行なっている。

登録する lvalue メソッドは sub を使って動的に作成する。
これは _create_property ルーチンで行なっている。

面白いのは、sub の内部から、その外側にあるはずの、
引数として渡されているパラメータを参照してることだ。
このような無名関数をクロージャと呼ぶ。
クロージャはこれらへの参照を保持するので、
_create_property の外に外れても問題なく使える。

クロージャは、lvalue ルーチンであり、
tie されたマジカルなスカラを返却する。

tie の裏にあるオブジェクトは、
独立したパッケージにしても良かったが、
property 自体を利用することにしよう。

TIESCALAR で作成するオブジェクトには、
'get' と 'set' への参照を保持し、
FETCH, STORE のときにそれらを呼び出すのだ。



Copyright (c) 1994-2007 Project Loafer. All rights reserved.