naoyaの日記 RSSフィード

 | 

2006-05-04

naoya2006-05-04

Trac 05:18

ぼちぼち自宅の環境Subversion にしようと重い腰を上げて作業。というか cvs 使ってたけどまともにバージョン管理してるとは言えない状態だったので、ここらでちゃんとやってみることにする。ということでレポジトリ作ってディレクトリ切って、DAV で公開できるようにして、ようやく Trac が動いた。

Trac はお古の自宅サーバーに入れたんだけど、もうディストリビューションが古すぎるもんで一から入れていったらかなりめんどくさかった。

まだ tracd で動いただけなので、明日は Apache で動かせるように設定とかしないとな。

Perl学習コスト 00:01

自分も Perl学習コストが高いと思う派。いや、1990年代頃の CGI = Perl な風味なのでよかったら学習コストは低いっていうかすぐわかるPerl読めば OK 的な感じなんだけども、いまやそういう人は PHP ですね。

Perl のみでいこうとするとオブジェクト指向がまず分かんない。理解不能。Perl の OO のシンタックスがきもいとかじゃなくって、Perl OO で OO を丁寧に解説した本とか情報がほとんどない。宮川さんのメルマガは分かりやすけど、あれも OO 全くわかりませんって人向けではないもんなあ。

ということで、ある程度まで行ったらやっぱ Java とか Ruby とかやるのがいいんじゃないかなと思うけども、ちょっと前までは Ruby やって OO 楽しいーと言うところまで行ってもウェブアプリのまともな環境ないからなーとか言ってでも Java はアレだしスクリプト言語で OO で実行環境も充実、といえば Perl なわけでしたが、いまなら Rails があるという罠があって結局 Perl の OO を学ぶ前に Rubyist になって二度と帰ってこなかったりとか! オゥッ。

自分の体験から行くと、Java をやる前までは OO とかサパーリわからんでした。そんなわけで OO の学習には Java はとてもいい気がする。言語仕様も小さいし、テキスト豊富だし。

Class::Pluggable#2 19:41

ちょっと趣を変えたもの。SYNOPSYS から。

## MyApp2
package MyApp2;
use strict;
use warnings;
use Class::Pluggable2 plugin_method => 'function';

sub new {
    bless {}, shift;
}

1;

## MyApp2/Plugin/Hello.pm
package MyApp2::Plugin::Hello;
use strict;
use warnings;
use base qw 'MyApp2::Plugin';

sub function {
    my ($self, $app) = @_;
    sprintf "Hello, World! %s", $self->config->{foo};
}

1;

## MyApp2/Plugin/Bye.pm
package MyApp2::Plugin::Hello;
use strict;
use warnings;
use base qw 'MyApp2::Plugin';

sub function {
    my ($self, $app) = @_;
    sprintf "Hello, World! %s", $self->config->{foo};
}

1;

## main.pl
use MyApp2;

MyApp2->plugin_config({
    Hello => {
        foo => 'bar',
    }
});
MyApp2->install_plugin(
    hello => 'Hello',
    bye   => 'Bye',
);

my $app = MyApp2->new;
print $app->hello, "\n";
print $app->bye, "\n";

結果。

[naoya@hydralisk pluggable]$ perl test2.pl
Hello, World! bar
Good Bye!!!

欠点としては、各プラグインごとにメソッドを一個しか拡張できない。プラグイン一個で複数のメソッドを、拡張される側に追加することはできない。そういう場合は、内部でその辺のメソッドを全部もったインスタンスを作ってそれを返すようにするとかそんな感じか。

あと、この実装はあくまで拡張される側にメソッドを追加するためだけの実装で、Catalyst みたいに既存のクラスの動作をカスタマイズするためのものではないので、一個前のとはちょっと趣が異なる。

実装はこんな感じ。クロージャまくりでエラくきもい。

package Class::Pluggable2;
use strict;
use warnings;
use Carp;
use UNIVERSAL::require;
use base qw 'Class::Data::Inheritable';
use Class::Pluggable2::Plugin;

sub import {
    my $class = shift;
    my %args = @_;
    my $callpkg = caller;
    $class->mk_classdata(plugin_method => $args{plugin_method} || 'do_task');
    $class->mk_classdata(namespace     => $args{namespace} || join('::', $callpkg, 'Plugin'));
    $class->mk_classdata('plugin_config');
    {
        no strict 'refs';
        push @{$class->namespace . "::ISA"}, join('::',$class, 'Plugin');
        *{"$callpkg\::plugin_config"} = sub {
            my $self = shift;
            $class->plugin_config(@_);
        };
        *{"$callpkg\::install_plugin"} = sub  {
            my $callpkg = shift;
            my %args = @_;
            for my $name (keys %args) {
                my $plugin_name = $args{$name};
                my $plugin_class = $class->namespace . "::$plugin_name";
                $plugin_class->require;
                croak qq/Could not load plugn "$plugin_class", "$@"/ if $@;
                my $plugin = $plugin_class->new({
                    config => $class->plugin_config->{$plugin_name},
                });
                $plugin->initialize if $plugin->can('initialize');
                {
                    no strict 'refs';
                    my $plugin_method = $class->plugin_method;
                    *{"$callpkg\::$name"} = sub { $plugin->$plugin_method(shift) };
                }
            }
        };
    }
}

1;

プラグインの親クラス。いまのところコンストラクタと config のアクセサを持ってるだけ。

package Class::Pluggable2::Plugin;
use strict;
use warnings;
use base qw(Class::Accessor::Fast);

__PACKAGE__->mk_accessors(qw(config));

1;

Class::Pluggable 16:39

アプリケーションのコアになるオブジェクト、まあ言うなればずばり Catalyst のコンテキストオブジェクトなんだけど、ああいう感じで全体で使い回されるオブジェクトというのが時々必要になる。特にフレームワークでそういうオブジェクトが良く登場する。

そのオブジェクトはいろいろ機能を持ってるんだけど、フレームワークのコアであったりするが故に、後からいろいろメソッドを追加したいとか、特定のドメインに特化したこういう機能が欲しいとか、そういうことがよく起こる。という要求に応えられるように、コアオブジェクトプラグイン方式で拡張できると都合が良い。

などなど。

ということで Catalyst の仕組みみたいなのをクラスにしたもの、というか結果的に Catalyst からその部分を持ってきたものみたいなのになっちゃったけど、そういうのを作ってみている。似たようなものが他に CPAN にありそうで車輪の再発明かもしれないけど。(ちなみに Module::Pluggable はちょっと用途が違う)

SYNOPSYS は

# MyApp.pm
package MyApp;
use strict;
use warnings;
use base qw(Class::Pluggable);

sub new { bless {}, shift }

1;

# MyApp/Plugin/Hello.pm
package MyApp::Plugin::Hello;
use strict;
use warnings;

sub hello {
    return sprintf "%s 'Hello, World!'\n", ref $self;
}

1;

# MyApp/Plugin/Bye.pm
package MyApp::Plugin::Bye;
use strict;
use warnings;

sub bye {
    return "Good Bye\n";
}

1;

# main.pl
use MyApp plugins => ['Hello'];

MyApp->install_plugins('Bye');
MyApp->plugin(prototype => 'HTML::Prototype');

my $app = MyApp->new;
print $app->hello;
print $app->bye;
print $app->prototype->define_javascript_functions;

とこんな感じで。

的なもの。あと、Catalyst のコードを見てて

MyApp->plugin(prototype => 'HTML::Protytpe');

とすると HTML::Prototypeインスタンス化してそのインスタンス$c->prototype で取得できるみたいなメソッドがあったので、その機能も追加してみてる。

package Class::Pluggable;
use strict;
use warnings;
use Carp;
use UNIVERSAL::require;
use base qw 'Class::Data::Inheritable';

__PACKAGE__->mk_classdata(registered_plugins => []);

sub import {
    my $class = shift;
    my %args = @_;
    $class->_setup_plugins(@{$args{plugins}}) if $args{plugins};
}

sub install_plugins {
    my $class = shift;
    $class->_setup_plugins(@_);
}

sub plugin {
    my ($class, $name, $plugin, @args) = @_;
    $class->_register_plugin($plugin);
    eval { $plugin->import };
    $class->mk_classdata($name);
    my $obj;
    eval { $obj = $plugin->new(@args) };
    croak qq/Could not instantiate instant plugin "$plugin", "$@"/ if $@;
    $class->$name($obj);
}

sub _register_plugin {
    my ($class, $plugin) = @_;
    $plugin->require;
    croak qq/Could not load plugin "$plugin", "$@"/ if $@;
    push @{$class->registered_plugins}, $plugin;
}

sub _setup_plugins {
    my $class = shift;
    my @plugins = ref $_[0] eq 'ARRAY' ? @{$_[0]} : @_;
    for my $plugin (@plugins) {
        $plugin = "$class\::Plugin::$plugin";
        $class->_register_plugin($plugin);
        {
            no strict 'refs';
            push @{"$class\::ISA"}, $plugin;
        }
    }
}

1;

いろいろ考えなきゃいけないことはあり、

  • プラグインを初期化する方法が用意されてない
    • Template メソッド式にしてやってみる?
  • プラグインアプリケーションの設定ファイルを渡したいけど
    • これはプラグイン側で $self が取れるし MyApp 側に実装してそれを使ってねという感じかなあ
  • Class::Pluggable を継承する方法だと Class::Data::Inheritable を、MyApp も継承しちゃう
    • import 式に変える?
  • Catalyst はコアが持ってるメソッドも拡張できたりするのがいいんだよ、という話
    • それは自分で NEXT とか Class::Trigger とか使ってなんとでもできるのでなんとかしる、とか?
  • MyApp に plugins とか install_plugin とかメソッドが追加されちゃって嫌?
    • まあこれはしょうがないかな
  • プラグインがいっぱいになってくると同じ名前のメソッドでバッティングする罠
  • プラグイン名前空間が MyApp::Plugin 固定なのが使いづらい

などなど。もうちょっと試しながら作り込んでみよう。

Plagger病 15:43

[naoya@hydralisk naoya]$ perldoc Module::Plaggable
No documentation found for "Module::Plaggable".
[naoya@hydralisk naoya]$ sudo cpan Module::Plaggable
CPAN: Storable loaded ok
Going to read /Users/naoya/.cpan/Metadata
  Database was generated on Thu, 04 May 2006 05:01:59 GMT
Warning: Cannot install Module::Plaggable, don't know what it is.
Try the command

    i /Module::Plaggable/

to find objects with matching identifiers.

小一時間悩んだりする病気のこと。

キーワード化しておく。→ Plagger病

PowerBookメモリ 12:58

メモリでも増設しようかなと。今 512 x 2 = 1GB。で、

Apple仕様書見ると PC2-4200 DDR2 なのに 333MHz と書いてあるんだけど、これって 533MHz の間違いかな? DDR 333 は PC2700 なはず。 (http://www.adtec.co.jp/glossary/memory/index.html にも書いてる)

ということでこれかな。

CPAN 10:43

YAPCコマンドラインから CPANアップロードするスクリプトがあるとか聞いた気がするんだけど、何だったっけ...

typestertypester2006/05/04 13:42http://search.cpan.org/dist/cpan-upload/
僕はこれつかってます。なんかほかにもあったきがするんですけども。

naoyanaoya2006/05/04 13:51おお、どもども。これだこれだ。

DorablueDorablue2006/05/05 07:14オブジェクト指向のお勉強なら、まずかる〜くSmalltalkやってみるのがいいと思いますよっ!なーんて。

BaysideBayside2006/05/08 03:59C++ や Java とくらべて Perl の学習コストが高いかといわれれば、そうでもないと思います。ただ Perl の OO の文法はキモイですね。Perl6 の OO は Ruby 並みか Ruby 以上に綺麗になってくれることを期待しています。自分も OO は Java からやるのがシンプルでよいと思います。

ya_kenya_ken2006/06/30 21:06初めまして(でも無いのですが…)、実はちょっと相談したい事があります。本当に気づかなかったのですが、最近たまたまClass::PluggableというモジュールをCPANに登録してしまったんです。やろうとしている意図は近いと思うのですが、なにしろnaoyaさんの方が先に作ってますし、より洗練されているように見えるし…。「盗んだ」と言われてもしょうがない状況なので、もしnaoyaさんがClass::PluggableをCPANに登録する意思があるのであれば、私は退こうかな、と考えています。もちろん、私も自分で作ったものですので、より良くしていきたい気持ちはあるのですが、後ろめたい気持ちがあっては何も出来ませんし…。
突然すいませんが、なにかご意見いただければと思います。

naoyanaoya2006/06/30 21:20ああ、いいですよー。僕のはなんか途中で放り投げてて up するつもりないですし。あと up するとしたら名前返ればいいだけなんで。
CPAN Author オメ。

ya_kenya_ken2006/06/30 22:55ありがとうございます。お言葉に甘えて、このままにさせていただきます。
一応、up前に同名のものが無いか探したつもりでしたが、探したりませんでした。これからはもう少し良く探すようにします。

 | 
この日記のはてなブックマーク数