Friday, April 28, 2006

Catalyst newsgroup

ok, 我得说我比较喜欢 newgroup 的形式。很幸运的是,今天看 mailing archive 的时候看到了 news.gmane.org 里有一个转载的 gmane.comp.web.catalyst.general 组。
我平时就用 Thunderbird 来订阅 newsgourp. 一般而言我只订阅两个服务器,一个是 news.gmane.org 另一个是 news.yaako.com
news.gmane.org 里还有 modperl 的组:gmane.comp.apache.mod-perl

喜欢的话我还是推荐试下 newgroup. I love it very much.
Tuesday, April 25, 2006

javascript XML parser

老板要求 Ajax 的 reponse 是 XML, 所以要找一个解析 xml 的 javascript 库。
因为已经用了 JSAN , 所以就在那找了个 XML.ObjTree
我用 XML::Writer 来构造 xml response. 比如说我们的 response 为
<xml><message>OK</message></xml>
然后 javascript 的代码大概为:
function ajax() {
var myAjax = new Ajax.Request( url, {
method: 'get',
parameters: pars,
onSuccess: showResponse,
} );
}
function showResponse(request) {
response = request.responseText;

JSAN.use('XML.ObjTree');
var xotree = new XML.ObjTree();
var tree = xotree.parseXML( response );

$('message').innerHTML = tree.xml.message;
}
这是针对回复只有一个 <message> 的。如果是多个 messages, javascript 的代码可以为:
for (i = 0; i < tree.xml.message.length; i++) {
唯一有点麻烦的是,我们期待回复的是 message array, 但是只有回了一个 message, 那这个 for 会失败,但是有 tree.xml.message 所以在 for 后面得加个
// ugly hack, for only one
if (tree.xml.message) {

Have fun!
Saturday, April 22, 2006

Perl 6 Now

大致上已经读完了 Perl 6 Now
因为以前读过 Perl 6 Synopsis 所以翻阅起来比较轻松,虽然我的英文也不是太好。

诸位如果想读这本书的话,可以上 PerlChinanomas. 只要 nomas 同意我会将这书用快递寄给你。:)
Thursday, April 20, 2006

MySQL SELECT condition

昨天写代码的时候发现 MySQL 的 SELECT 条件多反而比条件少要快很多。
其实我可以用
SELECT * FROM comment WHERE reply_to = ?
来得到我想要的结果。但是我用
SELECT * FROM comment WHERE reply_to = ? AND object_id = ? AND object_type = ?
时,结果是一样的,但是速度从 7-9s 提高到 0.07-0.09, 速度提升了百倍。这东西可能在表的 rows 比较少的时候效果不明显。但在 rows 是 4,530,000 时就有百倍的提升。

又学会一手。
Monday, April 17, 2006

Zorpia team photo and me



右往左数二 is me.

See also: my boss's journal

Catalyst and $c->res->redirect

今天发现关于 $c->res->redirect 的一件事。post 在这 http://lists.rawmode.org/pipermail/catalyst/2006-April/006758.html
sub test : Global {
my ( $self, $c ) = @_;
unless ($c->user_exists) {
$c->res->redirect('/login');
# return 1;
}
$c->res->body($c->user->user_id);
}
注意这里的 $c->res->redirect, 它不是马上一碰到就执行的,而是全部执行完整个 test 子程序才执行的。
也就是说,上面的代码是错误的。当用户没有登陆了,虽然要执行 $c->res->redirect, 但是它还要去执行 $c->res->body($c->user->user_id); 而不是一碰到 redirect 就直接跳转。所以代码会在 $c->res->body($c->user->user_id); 这句出错。因为没登陆时是不能访问 $c->user->user_id 的。把 return 1; 的注释去掉就可以了。

写代码事要注意这件事。:)
Saturday, April 15, 2006

JSAN and Form.Validator

大致上是我第一次用 JSAN. JSAN 的意思是 "CPAN".replace(/CP/, "JS") 它的目标是成为类似 CPAN 一样的 JS 库。 CPAN 是每个 Perl hacker 的骄傲。不过 JSAN 目前的东西不是很多。

我用的是 Form.Validator, 检验 form 输入的东西。不过 JSAN 这个模块的命令似乎在 Win32 下跑不起来。只好一个个去下。
http://www.openjsan.org/doc/c/cw/cwest/JSAN/0.10/
http://www.openjsan.org/doc/b/be/beppu/Form/Validator/0.33/index.html

下回来。目录的结果大致为:
JSAN.js
Form/Validator.js
Form/Validator/*
根据 http://www.openjsan.org/doc/b/be/beppu/Form/Validator/0.33/lib/Form/Validator.html 这里的说法写 HTML 文件。大致为:
<script src='/js/JSAN.js'></script>
<form name="stuff" ...
<script>
JSAN.use('Form.Validator');
JSAN.use('Form.Validator.Report.AlertAll');
fv = new Form.Validator(document.stuff);
fv.reporter('AlertAll'); // show a pop-up with all errors
fv.set('title', 'notBlank', "Title is required.");
fv.set('text', fv.makeValueMin(5), "Text must be 5 or greater.");
</script>

have fun.
Tuesday, April 11, 2006

Ajax.Updater and evalScripts: true

OK, 我昨天说 Catalyst 的 redirect 和 Ajax 的那个不合拍。后来得到那边的提示。用这样的代码解决了。
Controller:
sub vote : Global {
my ( $self, $c ) = @_;

unless ($c->user_exists) {
#$c->res->redirect('/login');
$c->res->body(<<HTML);
<script>
top.location = '/login';
</script>
HTML
return 1;
}
TT files:
var myAjax = new Ajax.Updater('vote_result', url, {method: 'get', parameters: pars, evalScripts: true});


这里多了个 evalScripts: true 这样可以在 div 里运行返回的 javascript.
Yup, It's OK now. 但是我想 prototype.js 应该能自动处理 redirect 这样的 Location header.
Monday, April 10, 2006

work and ask

不工作的时候总是没有问题,可一工作,总是会碰到这样那样的问题。碰到问题解决问题,才算是学会点东西。

写 Catalyst 的时候用 Ajax, 然后某一动作需要先确定用户登陆。但是 Ajax 只是更新某一个 div, 所以在 Controller 里写 $c->res->redirect('/login') unless ($c->user_exists); 是没有用的。redirect 只对整个 page 有效,而对 Ajax 的 div 是没有效果的。
大致的代码如下:
Controller:
sub vote : Global {
my ( $self, $c ) = @_;

$c->res->redirect('/login') unless ($c->user_exists);
and TT files:
var url = '/vote';
var myAjax = new Ajax.Updater('vote_result', url, {method: 'get',
parameters: pars});

<div id='vote_result'></div>
目前没有解决方案。mailling list 的问题在这:http://lists.rawmode.org/pipermail/catalyst/2006-April/thread.html#6563

另两个是 DBIx::Class 的问题。

第一个是 debug 问题。我想在 Catalyst 开启 DBIx::Class 的 debug, 这样我用 perl server.pl 的时候能看到所有的 SQL 语句。这个其实很简单。只要设置
$ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} = 1;
将这个写在 Root.pm 的 sub auto 里就可以了。

第二个是 update_or_create 的问题。因为 update_or_create 很好用。我们 new 或 edit 的时候就能采用同一的代码。new 是 create 而 edit 是 update, 但是我想知道什么时候是 create 什么时候是 update, 因为我要针对不同的 create 还是 update 写一点不同的代码。不过解决方案未知。也在问中。mailing list 的帖子在:http://lists.rawmode.org/pipermail/dbix-class/2006-April/thread.html#1192
Friday, April 07, 2006

my first full-time paid salary

ok, I have gotten more than once part-time salaries before, yet it's my first time to get a full-time salary. It's 4000 HKD, maybe not as much as what you thought. but I feel deeply grateful.

ya, things will be better. God bless me.
Wednesday, April 05, 2006

job stuff

I quit one of my part-time job(EuropeanServers) since I'm very busy with the full time job with Zorpia.com
I must admit that Pierre is a nice person to be working with. yet I'm not cheating on anyone that I even have no time to read my subscribed blogs when working at Zorpia.com 's new project based on Catalyst.

I just setup the LAN in the rent house today so that I can write this blog. :)
God bless me.

Template Plugin HtmlToText

It's a TT plugin for format html to text, a plugin interface to HTML::FormatText.

将 HTML 用 HTML::FormatText 转为 Text 文本。

Template::Plugin::HtmlToText is a easy plugin, all code is here:
package Template::Plugin::HtmlToText;

use strict;
use vars qw( @ISA $VERSION );
use base qw( Template::Plugin );
use Template::Plugin;

$VERSION = '0.01';

sub new {
my ($class, $context, $arg) = @_;
$context->define_filter('html2text', [ \&html2text => 1 ]);
return \&tt_wrap;
}

sub html2text {
my ($context, $args) = @_;
return sub {
my $html = shift;
return $html unless ($html =~ m#(<|>)#s);

require HTML::TreeBuilder;
my $tree = HTML::TreeBuilder->new->parse($html);
require HTML::FormatText;
my $formatter = HTML::FormatText->new(%{$args});
my $text = $formatter->format($tree);
return $text;
}
}

1;
Tuesday, April 04, 2006

Date Manip and Template Plugin FillInForm

今天用 Date::Manip 的时候碰到 Date::Manip unable to determine TimeZone 这样的错误。
后来通过 perldoc Date::Manip 设置了环境变量 TZ 为 +0800 就可以了。

另一个是用 Template::Plugin::FillInForm 的时候。
很多时候用户输入错误后,我们会跳转到用户输入的界面,然后填充用户输入的字段。一般来说对于 input/text 这样可以设置 value='[% c.req.param('name') %], 但是对于 radio checkbox select 这样就比较复杂了。而 HTML::FillInForm 用 HTML::Parser 分析字段并填充,很方便。用法很简单:
[% USE FillInForm %]
[% FILTER fillinform fdat => journal_date || c.req.params %]
<form>
<input type='radio'
[% END %]

啥都不用写,就前面一句 [% USE 后面一句 [% END %]
但是这种情况在以 DBIx::Class 情况下会失效。因为 FillInForm 用 $journal->{title} 来填充,而 DBIx::Class 是用 $journal->title 来获取的。这在 TT 下没关系,因为都可以用 [% journal.text %] 来获取的。但是对于 FillInForm Plugin 就会失效。我目前的折中方法是多添加一句:
[% USE FillInForm %]
[% IF journal;
journal_date = {
title => journal.title,
};
END; %]
[% FILTER fillinform fdat => journal_date || c.req.params %]

而不是用这段失效的:
[% USE FillInForm %]
[% FILTER fillinform fdat => journal || c.req.params %]