a schedule of mod_perl learning

12 November 2005


It's just a schedule table of mod_perl learning. I'm a bit lost, having no idea but to force myself to learning something I'm longing for. yes, mod_perl comes into my eyes.

Long long ago(more than half a year), I subscribed to the maillist and saw somthing like that(roughly):

mod_perl 有三个层次:

* 第一种是就是用 ModPerl::RegistryModPerl::PerlRun 来运行普通的 Perl 代码。
* 第二种是类如 Apache2::Hello 这样的模块。Catalyst, TT, Mason 等都提供的这种方式。
* 最后一种要涉及到跟 Apache 的内部,即一系列 Perl*Handler 打交道。

可能有一些不对,不过即使不中也不远也。

As follows are what I have done:
* subscribe to the maillist again(it's the fourth time, :> send a blank email to [email protected]).
* download the free book - Practical mod_perl(Under CC license, tarball here)
* download some chapters of mod_perl Developer's Cookbook, it's FREE.
* read several articles on perl.com

I'd like to write some journal through my learning course.
Writing HERE will beat me to read over it and NOT give up halfway.
my plan is to compose more than 1 blog per week.

God bless me.

Update

I unsubscribe the maillist and change to use Outlook Express to subscribe gmane.comp.apache.mod-perl on news.gmane.org. it's more clear to read.

重新写就的 Lingua::Han::PinYin

09 November 2005


最近有位 Tong Sun 兄给我发邮件说 Lingua::Han::PinYin 里有些字的拼音是不对的。比如“小”,旧版本里显示出“shao”。还有类如“幸”等。

我原来的拼音对照表是从 Unicode::Unihan 那里拿来的。仔细读了读它的代码,发现它采用的是 2002 年的 Unihan.txt
比较老。于是从 Unicode.org 下载了比较新的 Unihan 版本。

因为拼音只是 Unihan 里的一部分。所以第一件事要做的就是从中获取 kMandarin 字段。Perl 的老本行,一次性代码:

#!/usr/bin/perl
use strict;

my $unihan_file = 'E:/Downloads/Unihan.txt';

my $i;

open(FH, $unihan_file) or die $!;
open(OUT, '>Mandarin.dat') or die $!;
while (<FH>) {
   chomp;
my ($u, $type, $value) = split(/\t/);
   next if ($type ne 'kMandarin');
   $u =~ s/^U\+//isg;
   print OUT "$u\t$value\n";
   $i++;
}
close(FH);
close(OUT);

print "Totally $i is recorded";

1;

这样所写就的 Mandarin.dat 第一个字段就是汉字的 Unicode 十六进制。而接下来的字段是汉字的拼音。
而这里的汉字的第一字段获取倒把我难了好久。这实在是因为俺水平不太好。

比如说“仱”字,在 Perl 中你可以使用

print "\x{4ef1}";
把它在 utf8 编码下显示出来。或者可以直接用 HTML
将它显示出来。而 Mandarin.dat 所对应的第一字段就是这个。
如果将一个汉字获取到这个东西?后来在 ChinaUnix.net 找到了答案。
use Encode;
my $hanzi = '仱';
my $hanzi = decode ("utf8",$hanzi);
print sprintf("%x",unpack ("U*",$hanzi));
接下来的事就简单了。重新写了下这模块。再做了点测试。就发现那几个拼音错误的都修正了。
最后增加了多个字处理和音标。Enjoy!
Download from http://fayland.org/CPAN/Lingua-Han-PinYin-0.04.tar.gz

POD

head1 NAME

Lingua::Han::PinYin - 获取汉字的拼音

head1 SYNOPSIS


use Lingua::Han::PinYin;

my $h2p = new Lingua::Han::PinYin();
print $h2p->han2pinyin("我"); # wo
my @result = $h2p->han2pinyin("爱你"); # @result = ('ai', 'ni');

# 我需要音标
my $h2p = new Lingua::Han::PinYin(tone => 1);
print $h2p->han2pinyin("我"); #wo3
my @result = $h2p->han2pinyin("爱你"); # @result = ('ai4', 'ni3');
print $h2p->han2pinyin("林道"); #lin2dao4
head1 限制

不能处理多音字。

head1 返回值

正常情况下,返回其拼音。这里总共包括了多于两万个汉字。

万一,(很可能这东西不是汉字),返回它原来的东西;

head1 选项

over 4

item tone => 1|0

默认为 0,需要音标的话设置为 1。

back

Update

修正了一个问题。并且增加了处理中英文混合字。Thank Tong Sun. 已经传到 CPAN 上了。Enjoy!

Template Toolkit && random

07 November 2005


在我的 journal Index 页上往下数四行,会出现 Larry Wall 的一些语言。本来就一句
Call me bored, but don't call me boring. -- Larry Wall
后来想想应该多增加一点,且变成随机出现。一想到随机,我第一个想到的就是 List::Util , 那里面有个 shuffle 函数用以打乱 list 的次序。
当然这不是唯一选择,或许也不是最好的选择。不过或许也算凑巧, CPAN 上还是有它的 Template Plugin: Template::Plugin::ListUtil

放到里面的代码很简单,大致就是:

[% USE ListUtil %]

<style>
.quotes {
   white-space: -moz-pre-wrap; /* Mozilla, supported since 1999 */
   white-space: -pre-wrap; /* Opera 4 - 6 */
   white-space: -o-pre-wrap; /* Opera 7 */
   white-space: pre-wrap; /* CSS3 - Text module (Candidate Recommendation)
http://www.w3.org/TR/css3-text/#white-space */
   word-wrap: break-word; /* IE 5.5+ */
}
</style>

[% quote_words = [
"Call me bored, but don't call me boring. -- Larry Wall",
"I don't know if it's what you want, but it's what you get. :-)
-- Larry Wall in <[email protected]>",
"I think it's a new feature. Don't tell anyone it was an accident. :-)
-- Larry Wall on s/foo/bar/eieio in <[email protected]>",
"Obviously I was either onto something, or on something. -- Larry Wall",
"The following two statements are usually both true:
There's not enough documentation.
There's too much documentation. -- Larry Wall",
"If someone stinks, view it as a reason to help them, not a reason to avoid them. -- Larry Wall",
"In general, if you think something isn't in Perl, try it out, because it usually is. :-)
--Larry Wall in <[email protected]>"
] %]

<div class='quotes'>[% ListUtil.random(quote_words) %]</div>

后来又把右边浮动框的颜色也随机化了一下。

大致也就这样。看了一点 Perl Template Toolkit 的 Chapter 5. Filters


Template Toolkit 的配置选项

24 October 2005


今天用 Catalyst 写一个 RSS 聚合器程序的时候,发现 TT 的配置总是出错。后来才发现原来是配置选项出了点问题。

原来的代码差不多是这样子的:

package Feeder::V::TT;

use strict;
use base 'Catalyst::View::TT';
use Template::Constants qw( :debug );

__PACKAGE__->config({
   # any TT configurations items go here
   INCLUDE_PATH => Feeder->config->{'home'} . '/templates/',
   POST_CHOMP => 1,
   PRE_CHOMP => 1,
   EVAL_PERL => 1,
   PRE_PROCESS => 'header.tt',
   POST_PROCESS => 'footer.tt',
   DEBUG => DEBUG_PARSER | DEBUG_PROVIDER,
   CONTEXT => undef,

   # two optional config items
   CATALYST_VAR => 'Catalyst',
   TIMER => 1,
});

可怎么运行都不行。试了好一会儿,后来才发现原来 Template 的 INCLUDE_PATH 默认是用 : 来分隔多个路径的,比如:
INCLUDE_PATH => '/home/abw/templates:/usr/share/templates',
这样就是两个路径。而我运行在 Win32 下,发现 Template 将 E:/Fayland/Feeder/templates 划分为了两个路径 E 和 /Fayland/Feeder/templates, 所以运行程序总是跳出找不到模版文件。知道原因后查了查 Perl Template Toolkit 一书,在配置里加了一句:
DELIMITER    => ';',
这样就不是用 : 而是用 ; 来划分了。

这只是因为自己不熟悉 Template 的配置选项。于是就复习了一遍,将常用的几个翻译如下:

ABSOLUTE

指出用绝对路径的文件是否被解析。默认为 0.
如 /foo/bar 在 1 时为绝对路径而在 0 时为相对路径。
在 0 时使用类如 [% INSERT /etc/passwd %] 会出错,除非相对路径也有这文件。

ANYCASE

指示性关键字如 INCLUDE 是否允许小写

BLOCKS

此选项用于预先定义一系列模版块。
my $tt = Template->new({
BLOCKS => {
header => 'The Header. [% title %]',
footer => sub { return $some_output_text },
another => Template::Document->new({ ... }),
},
});
Hash 的值可以是模版内容,子程序或是 Template::Document
这样我们就可以在其他模版文件里调用它们。

COMPILE_DIR/COMPILE_EXT

Template 可以将模版文件编译成 Perl 文件保存以便接下来的再次调用。
my $tt1 = Template->new({
COMPILE_DIR => '/tmp/ttc',
COMPILE_EXT => '.ttc1',
});
COMPILE_DIR 是地址,COMPILE_EXT 为后缀名。

DELIMITER

这就是我所碰到的问题解决方案。解释见最前面。
# Win32 only
my $tt = Template->new({
DELIMITER => ';',
INCLUDE_PATH => 'C:/TT2/Templates;D:/My Templates',
});

CONSTANTS

编译时编译一次这些常量,而不是每次运行都编译一次。这样能稍微提高点速度。
my $tt = Template->new({
CONSTANTS => {
title => 'A Demo Page',
author => 'Joe Random Hacker',
version => 3.14,
},
};

CONSTANT_NAMESPACE

所有定义的 CONSTANTS 默认用 [% constants.title %] 来获得。而 CONSTANT_NAMESPACE 用来改变前缀。如:
CONSTANTS_NAMESPACE => 'const',
后,可以用 [% const.title %] 来访问。

NAMESPACE

用来定义多个 CONSTANT_NAMESPACE
my $tt = Template->new({
NAMESPACE => {
site => Template:::Namespace::Constants->new({
title => "Wardley's Widgets",
version => 2.718,
}),

author => Template:::Namespace::Constants->new({
name => 'Andy Wardley',
email => [email protected]',
}),
},
};

这样你就可以分别用 [% site.title %] 和 [% author.name %] 访问不同的常量。

CONTEXT

设置上下文。具体用途有点复杂。略过。

DEBUG

设置哪些地方需要调式。所定义的常量位于 use Template::Constants qw( :debug );
有两种写法:
DEBUG => DEBUG_PARSER | DEBUG_PROVIDER,
# or
DEBUG => 'parser, provider',
具体哪个啥意思查手册。

DEFAULT

当在 INCLUDE_PATH 里找不到模版文件时,默认调用该文件
my $tt = Template->new({
DEFAULT => 'notfound.html',
});

ERROR/ERRORS

定义一些常用的 错误 模版,然后在必要时调用它们。
my $tt = Template->new({
ERROR => {
'user.login' => 'user/login.html',
'user.passwd' => 'user/badpasswd.html',
'user' => 'user/index.html',
'default' => 'error/default',
},
});
必要时通过 [% THROW user.login 'no user id: please login' %] 来调用。
或在当前的 Template::Context 调用: $context->throw('user.passwd', 'Incorrect Password');
或在 Perl 代码中调用: die (Template::Exception->new('user.denied', 'Invalid User ID'));

EVAL_PERL

确定类如 PERL 或 RAWPERL 这样的块是否被执行。默认为 0

FILTERS

自定义自己的 filter, 过滤器。用于处理文件的某一些转换。 Template 默认自带了一些。
$tt = Template->new({
FILTERS => {
'sfilt1' => \&static_filter, # static
'sfilt2' => [ \&static_filter, 0 ], # same as above
'dfilt1' => [ \&dynamic_filter_factory, 1 ],
},
});
而后调用
[% FILTER sfilt1 %]
Blah blah blah.
[% END %]

INCLUDE_PATH

这个前面用了 n 多次了。它就是用于指定你要搜索的模版文件的文件夹。这几乎是用得最多的一个指令。

START_TAG/END_TAG

用以指定 template 指令的起始和终止符号。默认为 %
my $tt = Template->new({ 
START_TAG => quotemeta('<+'),
END_TAG => quotemeta('+>'),
});
这样就用 <+ INCLUDE foobar +> 而不是 [% %] 来调用指令了。

INTERPOLATE

内插。默认为 0
# INTERPOLATE => 0
<a href="http://[% server %]/[% help %]">
<img src="[% images %]/help.gif"></a>
[% myorg.name %]

# INTERPOLATE => 1
<a href="http://$server/$help">
<img src="$images/help.gif"></a>
$myorg.name
# explicit scoping with { }
<img src="$images/${icon.next}.gif">

OUTPUT/OUTPUT_PATH

这个我在老版本的 Eplanet 里是常用的。可以将内容输出到文件。

PRE_CHOMP, POST_CHOMP

是否在 [% %] 指令前后去除空行。默认不去除。这样的话:
<a href='[% address %]'>Click Here</a>
的话产生的最后结果可能是:
<a href='
fayland.html
'>Click Here</a>
我喜欢将它们设置成 1, 即使有时候应该分开的行也并起来了。

PRE_DEFINE, VARIABLES

这两个选项是一样的。用于设置一些默认值。如果 STASH 没有设置的话采用它们,设定的话忽略。
my $tt = Template->new({
PRE_DEFINE => {
title => 'A Demo Page',
author => 'Joe Random Hacker',
version => 3.14,
},
};

PRE_PROCESS, POST_PROCESS

调用一个 process 模版文件时预先调用和后来调用的模版文件。一般用于放置头文件和尾文件。
my $tt = Template->new({
PRE_PROCESS => [ 'config', 'header' ],
POST_PROCESS => 'footer',
};

STASH, process

这些在 Catalyst 没用到所以也不介绍了。

Enjoy!

Share me what u think.

SVN::Web

22 October 2005


安装 SVN::Web 之前要安装 subversion 和它的 pl 文件
将 pl 文件解压缩,拷贝里面的 site/lib 下的 SVN 和 auto 目录到你的 Perl 安装目录的 site/lib 下。
然后启动命令行:

C:\>cpan SVN::Web
C:\>cd cgi-bin\svnweb # 这个是你的 apache2 的 cgi-bin 目录下,建一个 svnweb 目录
C:\>svnweb-install # 这个文件在你的 Perl 安装目录的 bin 下。一般加 $Perl/bin 目录到 PATH
然后修改 cgi-bin\svnweb 目录下的 config.yaml 修改里面的:

repos: # 去掉前面注释
test: 'E:/repos' # 你自己的 repos 目录
# ...
style: 'http://localhost/svnweb/css/common.css' # 可以访问 css 的地址
可以访问: http://localhost/cgi-bin/svnweb/index.cgi/test

最后的截图如下:


AutoSave / 自动存储

14 October 2005


这个功能很常见。是为了防止浏览器崩溃或提交不成功而导致自己辛辛苦苦写就的东西消失掉。Gmail 里也这个东西。
它的原理是将该文本框的东西存储进一个 Cookie. 如果没提交成功(原因可能是浏览器崩溃),下次访问该页面时询问是否导入上次存储的东西。

function AutoSave(it) { // it 指调用的文本框

   var _value = it.value;    // 获得文本框的值
   if (!_value) {
       var _LastContent = GetCookie('AutoSaveContent'); // 获得 cookie 的值,这里的 GetCookie 是个自定义函数,参见源代码
       
       if (!_LastContent) return; // 如果该 cookie 没有值,说明是新的开始
       
       if (confirm("Load Last AutoSave Content?")) { // 否则询问是否导入
           it.value = _LastContent;
           return true;
       }            
   } else {
       
       var expDays = 30;
       var exp = new Date();
       exp.setTime( exp.getTime() + (expDays * 86400000) ); // 24*60*60*1000 = 86400000
       var expires='; expires=' + exp.toGMTString();

       // SetCookie 这里就是设置该 cookie
       document.cookie = "AutoSaveContent=" + escape (_value) + expires;
   }
}

而这 HTML 中应当如此:

<script language=JavaScript src='/javascript/AutoSave.js'></script>
<form action="submit" method="POST" onSubmit="DeleteCookie('AutoSaveContent')">
<textarea rows="5" cols="70" wrap="virtual" onkeyup="AutoSave(this);" onselect="AutoSave(this);" onclick="AutoSave(this);"></textarea>
<input type="submit"></form>
第一句导入 js, 第二句的 onSubmit 指如果提交了就删除该 cookie, 而 DeleteCookie 也是自定义的一个函数。参见源代码
textarea 里的 onkeyup 是指当按键时访问 AutoSave, 用以存储新写入的文字。
而 onselect 和 onclick 用以新访问时确定导入自动保存的文字。

大致就是如此。 Enjoy!

源代码:http://www.fayland.org/javascript/AutoSave.js


DateTime::Calendar::Chinese

13 October 2005


一直想着写一个阴历模块,却因为算法实在太复杂而望而却步。
今天下定决心开始看那长长的算法,没想到去 CPAN 上搜索 Lunar 的时候却找到了 DateTime::Calendar::Chinese
这模块是位日本同行所写,这足以使我羞愧。
国内的 Perl 相比日本而言还是两个层次的。总希望自己能对祖国做出点贡献。我虽不认为自己是个民族主义者。

与诸君共勉之。


Catalyst && XML-RPC

11 October 2005


今天因为用到了这个模块,所以就在这里提一下。如果你有机会碰到同样的问题可以参考一下。

因为 chunzi 有很多工作要做,而我又有点空加上想锻炼下自己。所以就配合他写 member.perlchina 的代码。
代码块中有一功能是用户认证 API, 当然这个很复杂。首先需要一个详细的 SPEC 规格文档。
就目前处于没有文档的情况下,我就先试着用 XMLRPC 来写一个远程验证 API. 待文档确定后再修补。

Catalyst 用于 RPC 有一 plugin 为 Catalyst::Plugin::XMLRPC , 它是以 RPC::XML 为基础的一个插件。
doc 很简单。唯一要注意的是要写在 use Catalyst qw/XMLRPC/; 同一文件里。

以代码为例:

# 主程序模块文件(use Catalyst qw/XMLRPC)那文件,添加

# 这与其他 Catalyst 的 Global 函数一样。定义了一个 rpc 方法。注意函数名不要为 xmlrpc, 这是插件的函数
sub rpc : Global {
my ( $self, $c ) = @_;
$c->xmlrpc;
}

# 所有方法后面带有 : Remote 的都是 XMLRPC 方法
sub auth : Remote {
my ( $self, $c, @args ) = @_;
return 'ERR_ARG_COUNT' if (scalar @args != 2);
my ($username, $password) = @args;

# 这里调用的是模块里自己定义的一个函数 auth, 你可以自己写 CDBI 代码
my $person = Person::M::CDBI::Person->auth( $username, $password );

return 'ERR_LOGIN_FAILED' unless ($person);
return 'ERR_UNACTIVED' unless ($person->has_actived);

return 'SUCCUSS';
}

而验证代码我们可以简单写一下:
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
use RPC::XML;
use RPC::XML::Client;

my $cli = RPC::XML::Client->new('http://fayland:3000/rpc'); # XMLRPC 地址

my $request = RPC::XML::request->new('auth', 'fayland', '123456'); # 方法名和两个参数

my $response = $cli->simple_request($request);

if (!$response) {
print "$RPC::XML::ERROR \n"; # No response
}
else {
print Dumper($response);
}

这是访问的一种方法,其他的可以参考 XML-PRC Client 客户端编写

Enjoy!


我对 Catalyst 的理解和介绍

08 October 2005


昨晚跟 joe jiang, Qiang 和 cnhackTNT 讨论了下成立 Catalyst 学习小组的事。Qiang 还建了个 Livejournal 的 journal. 打算把大家的学习过程之中学到的经验或经历共享下。如果能对初学者有所帮助就再好不过。
因为我也算接触 Catalyst 比较久了,所以打算讲点对它的理解。一家之言,如有错误请批评指正。兴之所致而讲,如不连贯也见谅。

Catalyst 是对最近颇为流行的 MVC 模型或者说是 Ruby on rails 在 Perl 上的实现。在我看来,Perl 其实功能啥都不缺,就缺一组合。而 Catalyst 就是一个快速 Web 开发的漂亮组合拳。

M - Model, 一般用来将数据库对象化,这样能比较容易访问和操作。Perl 中最有名的就是 Class::DBI
V - View, 就是视图,用来处理界面显示。Perl 中比较有名的是 Template-Toolkit 和 Mason
C - Controller, 就是控制器。就是针对不同的 action 或 request, 来执行不同的代码。另外有个名词就是分发/Dispatch

Catalyst 中可以使用很多不同的 Model 和 View/Template. 看个人喜好而定,我一般偏向于使用最流行的 CDBI 和 TT.
Class::DBI 和 TT 本来在 Perl 世界中就很出名。而按一般逻辑思维,视图与模型搞定后就剩下事件处理了。Catalyst 无缝地整合了这两者,而事件处理/Controller 则让我赞不绝口。

首先从目录结构上来说(运行 catalyst MyApp),略过某些东西:

created "MyApp" # 整一目录
created "MyApp\lib"
created "MyApp\root" # 可以将一些静态文件放在这如 CSS/Gif/JS etc.
created "MyApp\lib\MyApp"
created "MyApp\lib\MyApp\M" # 这里就是放置 Model
created "MyApp\lib\MyApp\V" # 一般也就一个文件 TT.pm
created "MyApp\lib\MyApp\C" # 这里比较重要,所有的 Controller 都放这
created "MyApp\lib\MyApp.pm" # 主程序模块
created "MyApp/Build.PL" # 可以用来打包发布模块
created "MyApp\script" # 脚本目录
created "MyApp\script/myapp_cgi.pl" # 普通 CGI 环境下运行
created "MyApp\script/myapp_fastcgi.pl" # FastCGI
created "MyApp\script/myapp_server.pl" # 这个就是我们一般写代码要运行的脚本
created "MyApp\script/myapp_test.pl"
created "MyApp\script/myapp_create.pl" # 这个用来创建新的 C/M/V 模块
对 Controller 来讲,Catalyst 实行 URL-to-Action.
在服务器运行时它将检查 MyApp.pm 和 \M \V \C 这三目录下的所有模块文件。对于 \C 目录下模块文件中实行 URL-Action 匹配。比如我们在 \C 下有一新文件 List.pm (用 perl script/myapp_create.pl controller List 创建)。List.pm 中如果这么写:
sub list : Global { # 这个 Action 自动对应类如 http://fayland:3000/list 这样的 URL

sub view : Regexp('^tag/(.*)') { # 这个对应类如 http://fayland:3000/tag/Catalyst 这样的 URL

sub orderby : Local { # 这个对应 http://fayland:3000/list/orderby 这样的 URL
与 Global 不同的是它在 URL 中多了个模块名

还有其他后缀。这是个非常棒的东西。这样你就不用在一个文件中写哪个模块对应哪个子程序了(以前要用类如 CGI::Application 完成这功能)。很方便。

一般而言,把简单的 \V 和 \M 搞完后(真的很简单,里面一般一个文件十行代码就可以),剩下来的就是 Controller 的编写了。
Controller 一般子程序的第一行是 my ( $self, $c ) = @_;
这里就是引进了一个最重要的 $c, 其实你不必理会它是什么东西(其实是模块的一个实例),只需要知道项目里的所有东西你都可以从这得到。需要什么,找它就是。它又分为很多部件,包括 request, response, stash, config, forward 等。

request 包含你请求(浏览器对服务器的请求)时的所有信息。如 cookies, 参数/params 和其他头/header 信息。可以通过 my $value = $c->req->params->{'foo'}; 当你访问 http://fayland:3000/?foo=bar 时, $value 就是 bar 了。

response 就是服务器对浏览器的反馈。你对浏览器的输出等就是靠这个部件来解决。$c->res->output('Congratulations, NewApp is on Catalyst!'); 一般很少用 output, 因为输出一般用 Template 解决。

config 一般存储项目的配置文件。我一般用 YAML 来配置,然后通过 YAML::LoadFile 来导入该配置文件

forward 这个是很有用的东西。一般用来实现在子程序间的跳转。

stash 所有子程序传递到 TT 模块中的变量都是用这个变量来传递。(用过 TT 的人都应该知道的)

代码片断

package Eplanet::C::Add;

use base 'Catalyst::Base';

sub add : Global {
   my ( $self, $c ) = @_;
   $c->stash->{cates} = [ Eplanet::M::CDBI::Category->retrieve_all ];
}

Eplanet::M::CDBI::Category 这就是对象化后的数据库。retrieve_all 是 CDBI 的一个函数。就是获得所有数据。然后将其放到 $c->stash->{cates} 里,这样模块文件就能访问这数据了。
# add.tt 模版文件
<select name="cms_cat_id">
[% FOREACH cate IN cates -%]
<option value="[% cate.cat_id %]">[% cate.cat_name %]
[% END -%]
</select>
这样就是一个最基本的完整的过程。http://fayland:3000/add 实现 URL-Action, Eplanet::M::CDBI::Category 是数据库,然后通过 $c->stash 传递到模版里。一般的流程就是这样。

学习流程一般这样:

* 看 Catalyst::Manual::Intro
* svn co http://dev.catalyst.perl.org/repos/Catalyst/trunk 里看那文件夹里的 examples
* 订阅 http://lists.rawmode.org/mailman/listinfo/catalyst
* 写代码,做试验,问问题

Enjoy Catalyst.


Catalyst 在 Win32 下的 Session

29 September 2005


昨天拿到 chunzihttp://member.perlchina.org 代码。装了很多依赖的模块,最后就死在了 Cache::FastMmap 上面。
这模块打死也装不起来。说来也很凑巧, Catalystmaillist 正在讨论这个问题。
依照那里的指示


  • Catalyst::Plugin::Session::FastMmap 里用 Cache::FileCache 代替了 Cache::FastMmap
  • 打开 Catalyst/Plugin/Session/FastMmap.pm, 修改
    1. 第六行用 use Cache::FileCache; 来替代 use Cache::FastMmap;
    2. 在一百二十几行 setup 函数里:(+ 的添加, - 的删除)
           $self->config->{session}->{rewrite} ||= 0;

      $self->_session(
      - Cache::FastMmap->new(
      - share_file => $self->config->{session}->{storage},
      - expire_time => $self->config->{session}->{expires}
      - )
      + Cache::FileCache->new( {
      + default_expires_in => $self->config->{session}->{expires}
      + } )
      );
现在 Person 代码已经正常的运行在我的电脑上。(除了邮件,注册验证只好直接打开 databse 来找 code)
昨晚将一些配置资料提出来生成了 YAML ,然后用 YAML::LoadFile 来导入这些配置文件。这样我修改完代码就可以直接在服务器上覆盖了。
打算先好好的看代码。尤其是 Model 部分。我没怎么用过 Class::DBI::Loader::Relationship , 得向 chunzi 兄好好学习。