JSON::XS を実戦投入した
いままでずっと JSON::Syck
を使い続けていたのだけど、いまの JSON::Syck
には
/y|Y
|n|N
|yes|Yes|YES
|no|No|NO
|true|True|TRUE
|false|False|FALSE
|on|On|ON
|off|Off|OFF
|null|Null|NULL
|~
/x
の正規表現にマッチする値はシングルクオートでくくられてしまうという仕様があり、これはJSONの仕様に反するのでパーサーによっては正しく処理できないものがある。
これがFlashから使うJSON APIでもろにはまって、adobe の corelib に入っている JSON のパーサーはこれをパースできない。(rubyのyamlパーサーでもエラーになるようだ)
cho45さんがこれを直すパッチを書いてくれたのだけど、いい機会なので JSON::XS
を試してみた。JSON::Syck
のドキュメントからも言及されてるしね。
Catalyst::View::JSON
から使うには以下のような感じで MyApp::View::JSON
をかけばOK。
package MyApp::View::JSON;
use strict;
use base 'Catalyst::View::JSON';
use JSON::XS ();
sub new {
my $self = shift->NEXT::new(@_);
my $dumper = JSON::XS->new->latin1;
$self->json_dumper(sub { $dumper->encode($_[0]) });
$self;
}
1;
JSON::Any
つかってないのは Any だと環境変数で使用ライブラリを上書きできてしまっていやなので XS を直使用している。
一日くらい社内でテストしたけどだいじょうぶっぽかったのでさっき本番投入してみた。どうだろうな。
コード再利用の話
基本自社サービス or 個人サービスしかつくってないので、本当にcatalystを使っているとコピペ地獄になる。
また同じことかいてるなーってのが多すぎるため、むかついてなるべくコピペを減らす工夫をしている。
codereposにあげたcatstarterってのもそうだし、あとはヘルパーを結構書いてる。
Catalystのヘルパーってまぁ要するにコードジェネレータなんだけど、ユーザー登録とかログイン・ログアウトとかほんとにいつもかいてるのでその辺はヘルパー一発で雛形生成するようにしてたりとか、jsのajax apiのサーバーサイドとかもjson形式を決めうちにしちゃってこれも雛形生成している。
いまの Catalyst::Helper
って新しいコード生成には使えるけど既存のクラスにメソッド追加とかそういうのできないのが不満。なんかつくりたい。
この辺の話はちゃんとまとめたいな。catalyst conやりたい!
Catalyst::Plugin::URI::MtimeQueryとCatalyst::Plugin::Assets - dann@catalyst - Catalystグループ
Catalyst::Plugin::AssetsにCatalyst::Plugin::URI::MtimeQueryのアイデアをインスパイアしたものを加えると、Assetsも結構使えるかも知れないなぁ。export_with_mtimequeryみたいなのがあればいいのかも。
これ今まさに仕事で使おうと思ってかいている。
そのうち公開します!
DBIx::Classで論理削除
DBICで論理削除をしたくなったので調べていたのだが、うまく書く方法がイマイチなかった。
まず、削除フラグを常にチェックするようにするのは簡単で、テーブルクラスに
__PACKAGE__->resultset_attributes({ where => { deleted => undef }});
とか書いてくだけでつねにWHERE句に deleted IS NOT NULL
が入るようになる。これはマニュアルに書いてある通り。
問題は削除するときで、テーブルクラスで delete
定義してそこで update({ deleted => 1 })
とかやればいいかなと思いきや、そうすると cascade delete 効かなくなってしまっていやだ。
DBICのrowに対するdeleteチェーンは大まかに
- ユーザー定義テーブルクラスでのdelete (定義されてる場合)
- DBIx::Class::Relationship::CascadeActions
- DBIx::Class::Row
となっていて、2 で cascade delete の処理が入り。3で実際に row が削除される。
(正確には2ではnextよんでからcascade deleteしてるため 1 -> 2 -> 3 -> 2 という感じである)
それでこの場合は実際に削除するのを update({ deleted => 1 })
に置き換えたいので 3 の直前に自分のメソッドを差し込んでそこでチェーンをとめるという実装がしたいと思った。
のだけどしばらく考えたけどいいやり方が見つからなかったので結局 1 のユーザー定義クラスで
sub delete {
my $self = shift;
$self->update({ deleted => 1 });
my $source = $self->result_source;
$self->search_related($_)->delete_all
for grep { $source->relationship_info($_)->{attrs}{cascade_delete} } $source->relationships;
$self;
}
などと全部詰め込む感じでお茶を濁した。
論理削除を今まで使ってなかったのでいまさら感がありますが、DBICで論理削除ってるひとでいいやり方知ってる人いたら教えてください!
uri_forのやつ
uri_withも同じようにおかしかったのでそっちもなおしてもらった。
uri_forのパッチ
いまどきのperl使いな皆様におかれましては内部ではutf8フラグを立てたutf8 stringとして文字列を扱っていると思いますが、そういった場合は uri_for
は正しく動作します。
そうではなく、utf8 bytes を渡した場合、今の uri_for
では壊れたURIが帰って来るというバグがあります。単純なミスなのだけど。
かなり前からなんだけど誰も気がつかないのか必要ないのか一向に直らないので業を煮やしてメールでパッチ送ったところすぐに反映してくれた。ナイス。
パッチはこんなん。
canonical してないのは仕様らしい。(昔のはしてたよね?)
mst によれば
For RSS/atom feeds etc.
とのこと。どゆこと?
WWW::HatenaDiary
CPANの更新Feedで存在を知った罠。どんだけcoderepos見てないんだよ。。。
Fuse::Hatena
のコードちょっと使ってるみたいなこと書いてあるけど、逆にこれを Fuse::Hatena
で使わせてもらおうw
POE::Component::WWW::Google::Calculator とか
PoCo::Genericってもんを知らないのかなこの人は。。。
DBIx::Class::AsArrayHash - Hatena::Diary::Neko::kak 500 Internal Server Error
うんうん、DBICつかってるとmapまくりよね。僕ならこう書いてるな。
my @rets = map { $_->get_columns }, $rs->all;
DBIC::AsArrayHashいらないってのは同意。
retrieveとかCDBI的なのもあれ。
なんか荒れてるやつ読んだ
論点とは違うけど、ひとつ思ったこと。
自分の書いたコードが module author に気に入られず採用されなかったときには、テストケースにして送ってみるといいと思いますよ。
自分のコーディングポリシーと違うコードだとか、そもそもいけてないとかいう理由で送られてきたパッチをスルーするのはよくある話だと思いますが、そういう場合にはテストケースとして送りつけるというのが作者側としてはありがたいです。
送られてきたパッチを読んでどのようなことがしたいのかを読み取って自分で実装してもいいけれど、やりたいことが明確にわからなかったり、実装したけどこれであってるのかどうかよくわからなかったりして、その結果よくわからないからスルーなどということになるわけですが、テストがあればそれを通るようにするだけなので。