ラベル Perl の投稿を表示しています。 すべての投稿を表示
ラベル Perl の投稿を表示しています。 すべての投稿を表示

2009-01-06

$USE_PARAM_SEMICOLONS か -oldstyle_urls が必要だったけ?

おはようございます。なかじまです。

Perl の CGI モジュールで、QUERY_STRING を含むページの URL を扱う必要があり、次のとおり、CGI::url を使ってみると、パラメータの区切りがセミコロンになってしまうのです。あれ?そうだったけ?

my $cgi = CGI->new();
my $page = $cgi->url( -absolute => 1, -query => 1 );
# $page => /foobar.cgi?foo1=bar1;foo2=bar2;foo3=bar3

ざっと CGI.pm のソースコードを覗いてみたところ、バージョン 2.64 からセミコロンになったようです。ということは、私が CGI::url を使ったのは、ずっと前だったのかもしれません。Perl 5.004 とかそれ以前かもしれません。

アンパサンドに変更する方法は、2とおりありました。

1つ目は $USE_PARAM_SEMICOLONS を 0 とする方法です。

use CGI;
$CGI::USE_PARAM_SEMICOLONS = 0;

2つ目は -oldstyle_urls を指定する方法です。

use CGI qw(-oldstyle_urls);

とすると、次のとおり、アンパサンドで区切られた期待どおりの結果となりました。

my $cgi = CGI->new();
my $page = $cgi->url( -absolute => 1, -query => 1 );
# $page => /foobar.cgi?foo1=bar1&foo2=bar2&foo3=bar3

初期値がセミコロンになった経緯とか知りたかったのですが、ネット(日本語サイト)で検索しても、ほとんど言及されてないんですね。みんな CGI モジュールで QUERY_STRING を吐き出したりしないんでしょうか...。

[を] CGI.pmでのパラメタの調整 がヒントになりました。だんだん。

2008-04-16

サブルーチン末尾の括弧ありなしで振る舞いが変わるなんて知らなかったよ

次のような、よくある Perl のサブルーチンがあったとします。
sub foo {
my ($x) = @_;
print $x;
}
次のように、このサブルーチンを括弧ありで呼び出すのと、
&foo();
括弧なしで呼び出すのとで、その振る舞いが変わるなんて知らなかったよ。
&foo;
前者の括弧ありは、見たまま引数なしの振る舞いをします。が、後者の括弧なしは、引数なしにはなりません。なんと、現在の @_ を引き継ぐではないですか。

この振る舞いの違いに気がつかず、30分ほど悩んでしまいました。そこで『プログラミング Perl』を読んでみると、そのようにサブルーチンが解説されていました。先に仕様を確認すべきだった。

こういうコンテキストに依存することが Perl のやっかいさなんだけど、知ってしまうとこれが自然な感じがしてくるのが興味深いところですね。この振る舞いも今は違和感がありますが、その背景や役立つケースを知ると、また気分が変わって多用しはじめたりするのですね。

2008-04-12

CGI.pm でパラメータではないクエリ文字はキーワードリストになる

次の "新宿 渋谷" の例のように、Perl の CGI.pm で、パラメータ名と値という組み合わせではないクエリ文字列が指定されたとき、
# 新宿 渋谷
http://example.com/foo.cgi?%E6%96%B0%E5%AE%BF+%E6%B8%8B%E8%B0%B7
そのクエリ文字列を取得するとき、次の2とおりの方法があります。
$cgi->keywords;
もしくは、
$cgi->param('keywords');
です。

両サブルーチンともクエリ文字列を1つ以上の空白(\s+)で区切った配列を返します。CGI.pm ではこの配列をキーワードリストと呼んでいます。

違いもあります。後者はコンテキストに依存した振る舞いをします。リストを要求しているときは配列、スカラーを要求するときは配列の先頭要素を返します。

2008-02-10

Perl split は文字列の末尾が分割記号だと省略してしまう

Perl split は、文字列の末尾が分割記号だと、省略してしまうので、不便だなぁと感じ続けてきたのですが、
my @path = split('/', '/users/nakajiman/places/');

('', 'users', 'nakajiman', 'places')
なんと、LIMIT にマイナス値を指定して、省略しないように指示ができたのですね。
my @path = split('/', '/users/nakajiman/places/', -1);

('', 'users', 'nakajiman', 'places', '')
何年もの間、ず~と知らずに過ごしてきました。ちょっと恥ずかしい。

Perl Hacks ―プロが教えるテクニック & ツール101選Perl Hacks ―プロが教えるテクニック & ツール101選
chromatic Damian Conway Curtis "Ovid" Poe

Perlベストプラクティス 実用Perlプログラミング まるごとJavaScript & Ajax ! Vol.1 まるごとPerl! Vol.1 プログラミングPerl〈VOLUME1〉

by G-Tools

2008-02-09

Perl CGI.pm で PUT を POST に見立てる方法?

Perl CGI.pm を使って application/atom+xml;type=entry なデータを POST と PUT で取得しようと思ったら、なんと PUT だと POSTDATA が取得できないじゃないですか。

次のブログを読んでみると、CGI.pm は HEAD、GET、POST にしか対応していないようですね。しかも、外部からコードの振る舞いを変えるような仕組みにはなっていないようです。ちょっと困りました。

CGI.pmでtext/xmlなPOSTデータを読みたい場合 : blog.nomadscafe.jp
CGI.pm の POSTDATA - naoyaのはてなダイアリー

しかたがないので、次のように PUT のときは POST として、CGI.pm を騙す方法で使ってみています。
my $m = $ENV{'REQUEST_METHOD'};
if ($m eq 'PUT') {
$ENV{'REQUEST_METHOD'} = 'POST';
}
my $cgi = CGI->new;
$ENV{'REQUEST_METHOD'} = $m;
なんかイマイチですけれど、CGI.pm のソースコードを見る限り、期待どおり動作してくれるように見えます。また、実際に試行していますが、今のところ不都合はないようです。

CGI.pm のバージョンは、次のとおりでした。ちょっと古めのものかもしれません。
$CGI::revision = '$Id: CGI.pm,v 1.208 2006/04/23 14:25:14 lstein Exp $';
$CGI::VERSION='3.20';
この対策は、バージョンや環境に依存するかもしれませんし、見つけていない不都合があるかもしれません。使おうとするときは、十分な検証をお願いしますね。

RESTful WebサービスRESTful Webサービス
Leonard Richardson Sam Ruby 山本 陽平

WEB+DB PRESS Vol.42 アジャイルプラクティス 達人プログラマに学ぶ現場開発者の習慣 RailsによるアジャイルWebアプリケーション開発 第2版 Statistics Hacks ―統計の基本と世界を測るテクニック WEB+DB PRESS Vol.41

by G-Tools