Home > C::M::App Archive

[ 1  2 >> ]

C::M::App Archive

CGI フレームワークブーム

すべてに共通していえることは

  • コンセプトがはっきりしている
  • コード短い

一方オレオレフレームワークである C::M::App は、わりきりが足らず、肥大化している (現在約 700 行) orz

1 年以上使ってきて、自分にとって実用的な部分、足りていない部分、使わない部分が見えてきたので、ばっさりシンプル化することにした

  • db 関連部分は別途書くことがほとんどなので、ばっさり削る
  • request の dispatch 部分もいつも同じことしかしないので、なんでもやろうとせず、ルール化してばっさり削る
  • 現状公開していないことだし、互換性は考えない。名前変える

この 3 つをやるだけで、多少シンプルになるはずなので、今の仕事が一段落したら Perl 脳に戻してとっととやる

C::M::App のテストケースを書き始める

つうか、整理する

ぜんぜん Minimal でなくなったので、テストケースも肥大化
 ↓
途中で面倒になってテケトウなテスト
 ↓
こりゃ配布できんわ <= 今ここ

というわけで、書き始めたわけでも整理し始めたわけでもなくて、整理しようと決心しただけ

実装予定メモ

  • Cookie 食べたりするのに手で書くのが面倒になったので、CGI::Cookie ぽい何か 07/01 完了
  • ついでに Session 管理っぽいこともできると楽しいかな
  • db 関連は C::M::A::DBI として実装したので、C::M::App からはバッサリ消す
  • ところどころにある日本語コメントをなんとかする
  • C::M::A::Util の整理

使うものじゃなくて作るもの

via New Generation Chronicle:開拓者から改革者へ ネタで未来を切り開く男 大沢和宏 (2/6) - ITmedia エンタープライズ

 メリットは、自分で作ってるので手足のように使える、Catalystとかの嫌な部分が体感できた。そんな感じです。やっぱりフレームワークは使うものじゃなくて作るものだと思うので、そろそろSoozyの次の別のフレームワークを作ろうとしています。

非常に納得。手前味噌ながら、一年以上日記では触れていないCGI::Minimal::App、自分で作ったものだけに、日常使いに最適! 自分で作ってるから、自分が好きなように直し放題! 公開していないので本当にいじり放題! そして、公開前に飽きてきた!

つっても次のフレームワークを作るかというとそこまでの気持ちはなくて「如何に日常書くコード量を減らしてギター弾く考えることに時間を使うか」ということをやるためには、まだまだ C::M::App には進化してもらわなければならない

フレームワーク (12) - 悩み中

メール送信関連の実装、と言うのは簡単だが、まじめに作るとそれだけでフレームワークになってしまうので、どの程度で妥協するのか悩み中

  • メール本文はテンプレートファイルで。テンプレートファイル名を指定しない場合のルールを決める
  • From, To, Subject は設定ファイルに書くなりどっかから持ってくるなり、なんなりするが、テンプレートエンジンは通す
  • 7bit ISO-2022-JP 決め打ちにしよかとも思ったが、イマドキの MUA なら 8bit UTF-8 で大丈夫かな? 携帯電話はまずそげ。まぁ、無難に 7bit JIS にしとくか
  • 添付ファイルや HTML メールは、いらね

などと考えて「普通のメールを無難に送るだけのメソッドをおまけ的に実装」することにした

メールの実装終わったら、次は validation を考えることにした。ものすごく楽したくて、ものすごく手を抜けない部分なので、じっくり考えよう

フレームワーク (11) - config 関連実装完了

明日以降の実装のためのメモ

YAML ファイルの runmode 名と同じ項からいろいろ取得、というところまで仕様にするとやりすぎかなとも思ったので、prerun モードで実行するから不要なら上書きしてね、というスタンスにした

あと、実行可能な runmode を指定するホワイトリスト形式は安全でいいんだが、ちょっと作ってみるって時に面倒なので、ブラックリスト形式にした

  • 予約語=C::M::App のメソッドの場合は実行しない
  • アンダースコアで始まるメソッドは実行しない
  • それ以外のメソッドは全部実行する

という感じで

存在しない runmode を指定した場合は 404 ページを表示したいので、not_found というオーバーライド可能なメソッドを追加した

次は、メール送信とログ出力の予定

mod_perl とか fcgi はかなり後回し。ログイン画面を簡単に作る工夫とかもあると嬉しい。。。かな?

フレームワーク (10) - 現状整理

少し間があいてしまったが、やっていないわけではなくて、Template-Toolkit 関連部分の実装を終えたので、現在試用しながら実装変更中

使っててわかったのが、

  • config 関連の実装が必要
    • YAML 形式のファイル読み込みにする予定
  • Mail 送信関連の実装が必要
    • トレンドは Email::* っぽいので、Email::SimpleEmail::Send あたりを使ってみようかと思っている。でも、Email::* はお互い依存してそげなんで、後で考える。愛用してきた MIME::Lite でもいいんだが

。。。とか思ってたら、MIME::Lite も久しぶりにアップデートされてるじゃん!

First release from Perl Email Project. Updated packaging.

らしい。RJBS すげえ!

フレームワーク (9) - DBIx::Simple::DeadObject

今日は DBIx::Simple 周り
DB 関連のエラー拾うために、よく

$dbh->select(...) or die $dbh->error;

とかするが、わざとエラーにしてみるために

$dbh->disconnect;
$dbh->select(...) or die $dbh->error;

してみたら、

Database object no longer usable (because of ...)

と返ってきたので、さらに実験

use DBIx::Simple;
use Data::Dumper;

my $dbh = DBIx::Simple->connect('dbi:SQLite:dbname=dum.db');
print Dumper $dbh;

$dbh->disconnect;
print Dumper $dbh;

実行結果

$VAR1 = bless( {
                 'lc_columns' => 1,
                 'dbh' => bless( {}, 'DBI::db' ),
                 'dbd' => 'SQLite'
               }, 'DBIx::Simple' );
$VAR1 = bless( {
                 'what' => 'Database object',
                 'cause' => 'DBIx::Simple=HASH(0x812c15c)->disconnect at db.pl line 7'
               }, 'DBIx::Simple::DeadObject' );

おー、なるほど

if ( ref $dbh eq 'DBIx::Simple::DeadObject' ) {
  print 'DB object has been already a-born.';
  undef $dbh;
}

とかできるのね。使うことがあるかどうかはわからないけど

フレームワーク (8) - サブクラスでのメソッドのオーバーライドを禁止する

C::M::App は、CGI::Application と同様、自分のクラスから継承されることを想定している

package MyClass;
use basee 'CGI::Minimal::App';

1;

んだが、一部メソッドは子クラスでのオーバーライド前提だし、一部メソッドはオーバーライドされたくないし、ということで、思案。他の言語みたいに attribute :final とか用意されてると

sub cannot_override :final {
}

とかするだけだし、そういうことを行うモジュール Attribute::Final もあるんだが、外部モジュール使うほどでもないし、attribute で実装しなくてもよかろう

# 子クラスの時だけ実行
unless ( ref $self eq __PACKAGE__ ) {
  for my $method (@all_methods) {
    next if .... ; # 親クラスのメソッドだったら何もしない

    die 'You can NOT OVERRIDE method'
      if ( grep {$_ eq $method} @not_override_methods );
  }
}

まずは基本ということで、Class::Inspector 使ってみる

# Check methods that cannot override in Sub-Class
unless ( ref $self eq __PACKAGE__ ) {
  my @not_override_methods = qw(
                                new run
                                _tt_obj _setup_http_headers _lvalue_method
                               );
  for my $method ( @{Class::Inspector->methods(ref $self, 'expanded') || [[]]} ) {
    next if $method->[1] eq __PACKAGE__;
    die 'You can NOT OVERRIDE method ',__PACKAGE__,'::',$method->[2],' in ',$method->[1]
      if ( grep {$_ eq $method->[2]} @not_override_methods );
  }
}

続いて、Class::Inspector はコアモジュールではないので、使わない版

# Check methods that cannot override in Sub-Class
unless ( ref $self eq __PACKAGE__ ) {
  my @not_override_methods = qw(
                                new run
                                _tt_obj _setup_http_headers _lvalue_method
                               );
  {
     no strict 'refs';
     for my $method ( keys %{ref($self).'::'} ) {
       next unless defined &{ref($self).'::'.$method};
       die 'You can NOT OVERRIDE method ',__PACKAGE__,'::',$method,' in ',ref($self)
         if ( grep {$_ eq $method} @not_override_methods );
     }
  }
}

タイムリーなことに、「どう書く?org」で「メソッド名一覧の表示」がお題になっているので、良さげな回答がでてきたらマネさせてもらおう

で、この実装だとコンストラクタ生成後にチェックするので、use した時点でチェクする方法考えた方がいいのかなぁ、とちょっと思った。new のしょっぱなにやっとけば同じかな

フレームワーク (7) - lvalue で validation もしたい - その2 -

もっとスマートな実装方法はないものか

って、絶対あるはず。Class::Accessor::Lvalue とかあるんじゃね? と思ったら、やっぱりあった。速度比較とかしているこんなサイトも見つけた

楽々アクセサ生成だけならどれでもできそうだが、今回の要件を満たすかどうかはわからないので、後日勉強するということで。つうか、lvalue やめればシンプルになりますな

[ 1  2 >> ]

Home > C::M::App Archive

Feeds

Return to page top