« 2005年07月 | メイン | 2005年09月 »

2005年08月31日

PATH_INFOで検索クエリー + CGI::AppのAUTOLOAD

CGI::ApplicationのAUTOLOAD機能をつかった実験。
PATH_INFOで検索ワードを送ってみる。つまり、

http://example.com/app.cgi/検索ワード

な感じで検索をする。実際のページは以下。

http://nomadscafe.jp/test/cgiappautoload/app.cgi/

formのonsubmitに

this.action= this.elements['word'].value;

をいれてSubmitする。

わざわざこんなことをした訳は、CGI::ApplicationのAUTOLOAD機能を試すため。
CGI::AppのAUTOLOAD機能は、

sub setup{
	my $self = shift;
	$self->run_modes(
		'__start_index'=>'do_index',
		'AUTOLOAD'=>'do_search'
	);
}

と言う風になっていたときに、run_modeが__start_index以外のときはAUTOLOADに設定されたdo_searchがリクエストされたrun_modeを引数に実行されるのです。

	$self->do_search($run_mode)

と。PerlのAUTOLOADと同じようなもの。
今回mode_paramを

	$self->mode_param(
		path_info=>1
	);

とPATH_INFOの1つ目の値=検索ワードとしているので、イメージ的には

	$self->$検索ワード

実際は

	$self->do_search($検索ワード)

な訳です。

これで何がしたいかというと、会員のmypage機能なんかを

index.cgi/User-ID

とかで実現できたらちょっとモテ系じゃないかと。でも実際のパターンとしては、

index.cgi/User-ID/run_mode

な形だとおもうので、CGI::Application::Dispatchの方をごにょごにょしてみる必要がありそうだな。

素直にmod_rewrite使うというのもありますが、、、。

2005年08月28日

Template-ToolkitはPure Perlでも動く

高速化のためにXSを使用していたり、普通にインストールする依存モジュールが多いためインストールが大変なイメージがあるTemplate-Toolkitは実はPure Perlでも動く。
単純な使い方をするだけなら、アーカイブをDLしてきて、展開、Template-Toolkit-2.14以下の

lib/Template.pm
lib/Templateディレクトリ

これを適当なパスにコピー。
Perlスクリプトで

#!/usr/bin/perl
use strict;
use lib "Template.pmを置いたディレクトリ";
use Template;

で使える。単純な使い方をする場合には依存モジュールはなかったりします。
READMEの

    Text::Autoformat 1.03+
    DBI 1.14+ (and relevant DBD drivers)
    GD 1.32+
    GD::Text 0.80+
    GD::Graph 1.33+
    GD::Graph3d 0.55+
    Pod::POM 0.1+
    XML::Parser 2.23+
    XML::DOM 1.27+ (in libxml-enno)
    XML::RSS 0.9+ 
    XML::XPath 1.00+

これは、あくまでoptional。標準添付のPluginで使用しているモジュールでそのモジュールを使わない限り必要はありません。

Template-ToolkitのXSはソースみると、Template:: Stash::XSだけです。
XSを使うかどうかは、Template/Config.pmの頭にある、「$STASH = 'Template::Stash';」で設定されています。インストール時のMakefile.PLをで書き換える処理を行っているようです。デフォルトはXSではないPure Perlバージョンなのでそのまま使えます。

Fedora Core、Redhatの場合は、dagのrpmを使うこともできます。
http://dag.wieers.com/packages/perl-Template-Toolkit/
http://dag.wieers.com/packages/perl-AppConfig/
こちらはAppConfig依存です。ダウンロードしてrpm -Uvh で入れるだけ。

これでかなりTemplate-Toolkitを使う障壁が低くなるハズ。

「よつばと!」4巻

よつばと! 4 (4)
よつばと! 4 (4)
posted with amazlet at 05.08.28
あずま きよひこ
メディアワークス (2005/08/27)
売り上げランキング: 2


出ました。買いました。

2005年08月26日

Class::DBI関連モジュール

いま作っているWebアプリで、Class:DBIをはじめてきちんと使った。
いろいろとPluginを使ったのでメモ。

ベースクラスには、

package Object;
use strict;
use base qw(Class::DBI::mysql);
use Class::DBI::AbstractSearch;
use Class::DBI::Plugin::NoCache;
use Class::DBI::Plugin::AbstractCount;
use Class::DBI::Plugin::RetrieveAll;
use Class::DBI::Plugin::Iterator qw(prefetch=>10);
use Class::DBI::Pager; 

__PACKAGE__->nocache(1);
__PACKAGE__->connection(...);

こんな感じでプラグインの読み込みがたくさん。精神的によくない数です

1つ1つメモです。

Class::DBI::mysql

MySQL用で、テーブルのセットアップを簡単にしてくれるもの。

package Object;
use base qw(Class::DBI::mysql);
__PACKAGE__->set_up_table("table名");

これだけでOKになる。tableやcolumnsの設定がいらない。

Class::DBI::AbstractSearch

SQL::Abstractを利用した検索をするsearch_whereを追加してくれるプラグイン

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::AbstractSearch;
__PACKAGE__->set_up_table("table");

package main;
my @ret = Object-> search_where({
	id=>?@list,
	name=>{'like'=>'a%'}
})

とすることで、

select * from table where ((id=? or id=? or ..) and name like ?)

などのクエリーが発行される。set_sqlを書くのが面倒なときに。

Class::DBI::Plugin::NoCache

CPANにはあがってないモジュールです。CPANにあがりましたClass-DBI-0.96の自動キャッシュの問題を解決してくれるもの。_initで

$Class::DBI::Weaken_Is_Available=0;

をしています。

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::Plugin::NoCache;
__PACKAGE__->nocache(1);

としておくとグー。


Class::DBI::Plugin::AbstractCount

Class::DBI::AbstractSearchと同じくSQL::Abstractを利用したcountをするメソッドを追加。

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::Plugin::AbstractCount;
__PACKAGE__->set_up_table("table");

package main;
my $count = Object->count_search_where({
	name=>{'like'=>'a%'}
});

aから始まる人の数が得られます。

Class::DBI::Plugin::RetrieveAll

retrieve_allにsortをくっつける、retrieve_all_sorted_byメソッドを追加するんだけど、それよりretrieve_all時のsortのデフォルト設定ができるretrieve_all_sort_fieldが便利

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::Plugin::AbstractCount;
__PACKAGE__->set_up_table("table");
__PACKAGE__->retrieve_all_sort_field('birthday desc');

package main;
my $count = Object->retrieve_all()

常に誕生日順でソートされたイテレータが返ります。というか最初からretrieve_all({order_by=>"birthday"})をサポートしてほしいところ

Class::DBI::Plugin::IteratorClass::DBI::Pager

Class::DBI::Pagerはページングを行うプラグイン

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::Pager;
__PACKAGE__->set_up_table("table");

package main;
my $pager = Object->pager(20,1);#(1ページの個数,ページ)
my @page1 = $pager-> retrieve_all

ページングが簡単に行えます。
ただこのPagerを使った場合でもretrieve_all時には、全てのデータを取得してしまってます。
そこで、Class::DBI::Plugin::Iteratorの登場

package Object;
use base qw(Class::DBI::mysql);
use Class::DBI::Plugin::Iterator qw(prefetch=>10);
use Class::DBI::Pager;
__PACKAGE__->set_up_table("table");

とすることで、pagerやnext時に適当なlimit offsetをSQLにいれて実行してくれます。
たくさんのデータがある場合には速度向上が見込めそうです。

ここまで書いてきたけど、Class::DBI::Sweetなるものがあって、上の機能がけっこう実現されてそうな勢いです。

2005年08月23日

CGI::Applicationでpost_dispatch

CGI::Applicationで、Sledgeでいうところのpost_dispatch_hogehogeが欲しいなと思ってCGI::ApplicationのPluginのCGI::Application::Plugin::Dispatchをこしらえた。post_dispatch_hogehogeだけではなく、run_modesを設定しなくても、dispatch_hogehogeを書いていくだけで済みます。
↓のような感じです。

package TestApp::PluginDispatch;

use strict;
use base qw(CGI::Application);
use CGI::Application::Plugin::Dispatch;#プラグイン読み込み

sub setup{
	my $self = shift;
	$self->mode_param(path_info=>1);	
	$self->start_mode('index');
}
sub dispatch_index{
	my $self=shift;
}
sub dispatch_search{
	my $self=shift;
	#post_dispatch_searchを下で定義しているのでGETの時のみ
}
sub post_dispatch_search{
	my $self=shift;
	#RUNモードがsearchでPOSTメソッドの時実行
}

run_modesを設定しなくて良いのですこし楽。post_dispatchを呼び出さないのであればどこかに、

$self->post_dispatch(0);

としておく。プラグインの構造としては、init時にcallbackで、run_modesにAUTOLOADを追加してます。

$self->run_modes(
	'AUTOLOAD'=>'dispatch'
);

CGI::Appは該当するrunモードがなく、AUTOLOADが設定されている場合、AUTOLOADで指定されたメソッドを呼び出します。ここではdispatchメソッドになります。dispatch内では必要あれば「post_dispatch_hoge」、もしくは「dispatch_hoge」を実行します

前回のHTML::Template::Plugin::Dotのサンプルをちょっといじって実装
検索がpostメソッドになっただけです。getで直接アクセスすると検索が行われません。

ソースはこちら

2005年08月17日

HTML::Template::Plugin::Dotを使ってみた

HTML::TemplateにTTのようなdotでメソッドを呼び出す機能を持たせるHTML::Template::Plugin::Dotを使ってみた。0.06でloop内の動作もよくなってきた感じがするので試してみることにした。

UnixUserの伊藤直也さんの連載の「作って学ぶ、いまどきのWebサービス」を参考に、OpenSearchを利用したアプリケーションを作ってみることにする。
コマンドライン版をまず制作。

my $engine = WWW::OpenSearch->new($osxml);
my $feed = $engine->search($word);
my $tmpl=HTML::Template::Pluggable->new(
	scalarref=>?$template,
	die_on_bad_params=>0,
	loop_context_vars=>1,
	case_sensitive=>1
);
$tmpl->param('result',$feed);

テンプレートは、

<ul>
<!-- TMPL_LOOP NAME=result.items:item -->
<li><!-- TMPL_VAR NAME=item.title ESCAPE=HTML --></li>
<!-- /TMPL_LOOP -->
</ul>

こんな感じ。case_sensitiveをOnにしておくのが吉です。大文字小文字が混じったメッソドを呼び出すには必要です。
ただしこのサンプル。HTML::Templateにpatchを当てないとうまく動かない。LOOPは動くけど中身が入らない。これはHTML::Templateがsubクラスを作りにくい構造になっているためです。しかし、本当にpatchを当てるのは少々面倒なので、HTML::Templateの_parseメソッド650行をコピペして、Perlスクリプト中に埋め込みます。んで上述のpatchを参考に

         = HTML::Template->_new_from_loop(

のあたりを書き換えます。下のようになります。

sub HTML::Template::_parse{
  my $self = shift;
  my $options = $self->{options};
〜〜中略〜〜
	# does _parse() - sub-templates get their parse_stack and
	# param_map fed to them already filled in.
	my $pkg = ref $self; 
	$loop->[HTML::Template::LOOP::TEMPLATE_HASH]{$starts_at}             
           = $pkg->_new_from_loop(
					   parse_stack => $parse_stack,
〜〜中略〜〜
# get rid of filters - they cause runtime errors if Storable tries
  # to store them.  This can happen under global_vars.
  delete $options->{filter};
}

これで動かすことができました。スクリプトはこちらに置きました。

次に、Web版。前述のUnixUserの記事と同じようにCGI::Applicationを使ってみました。。HTML::Template::Plugin::Dotを利用するためのCGI::ApplicationのプラグインCGI::Application::Plugin::HTPluginDotを書いて、HTML::Template::_parseはその中に埋め込んだ。

デモはこちら。

ページがそんなにないのでdispatchを利用しなかったのと、ページ移動のFOREACH部分は実装していません。この部分は別方法を考えるしかないなぁ。
ソースはこちら

ちょっと使えそうな気がした。

2005年08月14日

ユーザからアイディアを大っぴらに聞くなんてことはできない

どうやらはてなアイディアができてからこっち、こことかここを読むとはてなの開発者とはてなユーザとのずれがでてきてしまっているような最近だ。はてなアイディアができたときに「すげぇことするなぁ」と思ってちょっと懸念していたことが表に出てきた感じか。

ハピタンとかぱどタウンでは、機能の追加の希望についてのアンケートは、すくなても自分が賛同してやったことはない。ユーザではなくこちら側の人間にそういうアンケートを望む声はあるが、開発の責任、アイディアを提供してくださる方への責任を考えると、軽い気持ちで、「聞いたらいいんじゃない?」という形でユーザに対することはできない。

ユーザにとって、アイディアを伝えるというのは、自分の脳みそや考えたことを提供する場で、その提供した分の見返りとして望むのは、第一にアイディアが実現されることではないでしょうか。開発者にできることはそのアイディアを実現させるために最大限努力をすること。
それができない、する勇気がない限りはユーザからアイディアなんてきけないよと、アイディアを出すことの大変さを開発の面から知っている人間としては思うのです。

はてなも近藤さんのCNETブログを読んでいるとアイディアに対して非常にセンシティブですからはてなアイディアをこれからどうしていくのか興味のあるところです。

スターウォーズ観てきた

ようやくスターウォーズ観てきた。
ジョージ・ルーカスはやはり映画の監督をやるのをやめた方が良いんじゃないかと思う。プロデューサとして監督を呼んできた方が最終的にいいものができるのでは。映画に詰め込み過ぎなんだよな。ストーリーが長いのも言いたいこと、見せたいことがたくさんあるのはわかるけど。それをばっさりと切る勇気も編集に責任をもつ監督として必要なことだな。とは言いつつなかなかのものです、やはり。損はないです。大規模な映画ですこしディスカウント効いて1600円ってところかな。
ところで、二条のBiViで観てきたんだけど、DLPでした。DOLBYのロゴ(サウンドデモ?)がめちゃくちゃきれいだった。DLPは2度目で前回は「千と千尋」だったりします。今回本編の方はそれほどDLPだと思うことがなかったんだけど、「千と千尋」の時は映画もよかったけど、ずっとDLP万歳状態だったのを思い出した。アニメーションの方がDLPとの相性がいいなぁ。イノセンスをあれで観たかった。

2005年08月13日

ギヤのワイヤーが裂けた

KRPから帰ってくるとき、自転車で転けたときにギヤのワイヤーが裂けた。
SN310063.JPG
修理にいかなくちゃ。。

2005年08月12日

連休前の21時過ぎに仕事を出しますか?

連休前の21時過ぎに仕事を出しますか?
しかも具体的なやるべき内容のリストがわからんし、やるべきリストをくれと言うのに精一杯でいつまでか聞くの忘れたし。。連休にやれってことか?
紙でだせ紙をだせ紙が必要、判子印鑑ハンコ、運用運用・・なんていうくせに仕事を頼むのが口頭。何言っているかわからん。議論は紙で連絡は口頭でってか。
ふざけんな。

2005年08月09日

巨人次期監督に星野仙一浮上

Yahoo!ニュース経由

原辰徳前監督の復帰が最有力とはいえ、親会社内には、根本的な再建を求め、カリスマ性のある阪神・星野仙一シニアディレクターを新監督に推す意見が消えない。水面下で交渉を続けているというのだ。


この間、家で奥さん相手にこんな話をしていたなと。原辰徳には是非拒否してもらって、巨人の根本的な再建≒日本球界のことを考えて、星野さんって手もあるんじゃないかなぁ。

2005年08月08日

911に選挙

今年の911は日曜日ってことか。
Yahoo!ニュースの『首相「郵政民営化解散」と強調=与野党、命名さまざま

これに対し、反対派議員らの間では「自爆テロ解散」との声がもっぱら。

↑これを言った人は現在の世界情勢から照らし合わせても非常識じゃないかな。まして選挙は911。

googleの検索結果にonmousedownでajax

googleの検索結果にonmousedownに入っているのだが、これが個人的に問題。
Safariだけみたいだが、アンカーを別ウィンドウにドラッグして開くことができない。マウスを押す(クリックではない)だけでページが開いてしまう。

検索結果部分の

<a href="http://dev.mysql.com/doc/mysql/ja/Using_mysqlcheck.html" onmousedown="return asq(event,this,'res','1','')">


asq functionは

function asq(event,el,ct,cd,sg){
  if(window.XMLHttpRequest){
    if(el.handledFirstTime){
      el.handledFirstTime=false;
      window.location=el.href;
      return false;
    }
    el.handledFirstTime=true;
    var x=new XMLHttpRequest();
    x.open("GET","/url?sa=T&ct="+escape(ct)+"&cd="+escape(cd)+"&url="+escape(el.href).replace(/?+/g,"%2B")+"&ei=b_T2QpuxNJmasgH57biMDg"+sg,true);
    var m=event.altKey||event.metaKey;
    if(m){
      x.onreadystatechange=function(){
        if(x.readyState==4){
          clearTimeout(timeoutid);
          el.dispatchEvent(event);
        }
      };
      var timeoutid=setTimeout(function(){
        x.abort();
        el.dispatchEvent(event);
      },1000);
    }
    x.send(null);
    return m;
  }
  return true;
}

クリックしたURLをajaxでgoogleに送っているのね。

なんか微妙。

2005年08月05日

箱一杯の壊れたHDD

SN310054.JPG
事務所を一部片付けしてて集まった壊れた(壊れていると思われる)HDD達。
HDDは消耗品だと再認識

2005年08月04日

CGI.pmのheaderでsend_cgi_headerをさせない

CGI.pmのheaderをHTTP headerを作るためだけに使いたいというときに、普通のCGIなら良いのですが、Apache::Registoryなどmod_perlで動かしていると、

my $str = $q->header(-charset=>'EUC-JP');

とした瞬間にApacheにsend_cgi_header(send_http_header)が送られてしまって具合よろしくありません。

my $str = $q->header(-charset=>'EUC-JP');
$strになにか処理。
print $str;

というのはうまく動かない。実際のところ$strは空です。CGI.pmのheaderメソッドは便利なので、これをもう少し汎用的に使いたいのでこれを修正したいと。CGI.pmのその分のコードをみると、

    my $header = join($CRLF,@header)."${CRLF}${CRLF}";
    if ($MOD_PERL and not $nph) {
        $self->r->send_cgi_header($header);
        return '';
    }
    return $header;

となっているので、$MOD_PERLの値をlocalで変更すればOKかなと思ってCGI.pmを継承してheader_as_stringメソッドを追加するモジュールをつくってみた。簡単なのでソース貼付け

package CGI::HeaderAsString;

use strict;
use CGI;
use Exporter;
use base qw(CGI);
use vars qw($VERSION);
$VERSION='0.01';

sub import{
	if(grep { /:(?:standard|cgi)/ } @_){
		my $header_as_string_sub= caller(0) . '::header_as_string';
		my $redirect_as_string_sub= caller(0) . '::redirect_as_string';
		{
			no strict 'refs';
			*{$header_as_string_sub}   = \&header_as_string;
			*{$redirect_as_string_sub}   = \&redirect_as_string;
		}
	}
	goto &CGI::import;
}

sub header_as_string {
	my($self,@p) = CGI::self_or_default(@_);
	local $CGI::HEADERS_ONCE=0;
	local $CGI::MOD_PERL=0;
	return $self->header(@p);
}

sub redirect_as_string{
	my($self,@p) = CGI::self_or_default(@_);
	local $CGI::HEADERS_ONCE=0;
	local $CGI::MOD_PERL=0;
	return $self->redirect(@p);
}


1;

2005年08月03日

複雑なスタイルシート+全角記号の連続でIEがつぶれかける

ぱどタウンのHTMLタグであった話。

<table>
<tr>
<td><font style="ふくざつなスタイルシート">同じ全角記号を連続してたくさん</font></td>
</tr>
</table>


といったHTMLタグでIEの描画が非常に重たくなって固まったような状態になる。待っていれば必ずでてくる。全角記号が続くと改行処理が正しく行われないIEの禁則処理のバグとそれにともなう描画の計算の負荷なんだろうと思う。

とりあえず、全角記号が続いたら適当に改行を入れてしまうところで対策。

$text =~ s/((!|?|#|$|¥|%|&|@|.|,|:|;|(|)|[|]|{|}|/|\|_| ̄|||^|`|+|<|=|>|*){40})/$1?n/g;


ブラクラそのもの。

2005年08月02日

ついにMacにも右クリック。

ApplelからMighty Mouseというマウスがでるそうです。
mighty.jpg
ついにMacにも右クリック&スクロール。ついでにマルチボタン。
とりあえず、許可が下りたので注文するかと思ったけど、Apple Storeにまだないみたい(23時17分

今現在は、このマウスを使用中。

コードレス オプティカルマウス MX-700
ロジクール (2002/11/15)
売り上げランキング: 1,907


ドライバーはオフィシャルのものではなくて、USB Overdriveを使っている。実はOS9のときから利用してました。
マウスはパソコンでもっとも使うインターフェイスなので、いつも慎重に選んでます

買いました(8時44分

PHPをどうとらえているか

使える言語は Perl と言うと何故にバカにされるのか?」に関連して、

「( ´_ゝ`)フーン Java じゃないんだぁ」

これはまぁ、Javaが必要なところもあるんだろうから良いとして、もうひとつPerlと比較としてPHPがあげられます。新規案件でも「PHPで」ということがそれなりにある。PHPも最近はYahoo!やcybozuなどで使われていて、大きなプロジェクトの事例が増えています。mod_php版であれば、CGI(≠Perl)より動作が速いでしょうし導入もしやすい。HTML埋め込みでだれでも使えそうな感じもする。

ただ、自分にはPHPがしっくりきません。2度ぐらい挑戦したけど今も全てPerlです。
理由としては「慣れ」なんだろうけど気になっていることをあげると、
PHPのHTML埋め込みと言う形が、Perl-CGIの中にHTMLを埋め込むところからHTML::Templateへ移行した後では馴染めない(最近ではSmartyというテンプレートエンジンがある)。
Perlの顔しているのにC/C++/Java的な関数名の付け方になっていて戸惑う。
ライブラリが充実しているのはいいことなんだけど、柔軟性がなさそう。

柔軟性については、

$subject="タイトル";
$body   ="本文";
mb_send_mail("hoge@example.com",$subject,$body);

と書いてしまうのは楽だけど。Perlでモジュール使って、

use MIME::Lite;
my $mime = MIME::Lite->new(
	To=>'hoge@example.com',
	From=>'anonymouse@example.com',
	Data=>'mime::lite smtp test.....',
	Encoding=>'7bit',
);
$mime->send('smtp','localhost');

としておく方が細かいカスタマイズに対応できる。PerlというよりCPANのおかげなのだが。
TMTOWTDI(There's More Than One Way To Do It)のスローガンと膨大なCPANライブラリで車輪の再発明を防ぐことができることがやはりPerlの良いところだと思う。AmazonもPerlでできていることだし、「PHPで」と言うお客さんにはPerlの利点とAmazonで使われている事例等を説明してなるべくPerlでやっていければ、作るのも早いと思われ。

ぱどタウンもPerlでできています。コミュニティ部分はmod_perlで、2〜3日で作る物を含め周辺で動くものは普通のCGIで構築。Apache::Registryで動かしているだけなので、同じようにCGIを書いていけるのも良いところ。先月のアクセスは2億件台。相変わらずシステム担当二人でやっております。

2005年08月01日

i855GMEm-LFS(533)検証中

データセンターの電源が足りなくなりつつあるので、Pentium Mのサーバの導入を検討中。
i855GMEm-LFS(533)を通販で購入して、検証しているのですが、再起動ができない問題が発生。
Linuxのリブートや、BIOSで設定を保存後、帰ってこない。
似た状態の方が、こちらこちらに。初期不良で交換かしら。
上のURLも半年以上前の話なのに。もひとつ問題が、キーボードレスの起動ができないこと。KVMの検討もしておく必要があるかな。

Pentium Mの性能については、Plathomeのページが参考になりそう。
カーネルコンパイル時の例で、

Pen4 1259.1秒/166.4W
PenM 1309.6秒/84W

ほぼ同じ能力で消費電力半減。
リースの切れたサーバからこっちへの置き換えをやっていくのが良さそうかな。

Redhat7.3の場合はネットワークを認識しません。MarvelのNICのドライバはここ。install.shで簡単にインストールできますし、カスタムカーネルの場合のPatchも作ることができたり結構良くできています。CentOS 4.1の場合は最初から認識してました。