drkcore todo

やることリスト

  • trackback ping打てるようにしとく
  • Tagのサジェスト機能をつける
  • 二重投稿を防ぐ

Catalyst::Model::Net::Amazonでキャッシュ

昨日ちょっと気になったので触ってみた。

ヘルパーがあるので

script/myapp_create.pl create model Net::Amazon Net::Amazon

でモデル作成。yamlに

Model::Net::Amazon:
  token: 'amazon_token'
  locale: 'jp'

を設定して、Root.pmに

sub default : Private {
    my ( $self, $c ) = @_;
    my $ua = $c->model('Net::Amazon');

    my $response = $ua->search( asin => '4873112109' );

    if ( $response->is_success ) {
      $c->response->body( $response->as_string );
    } else {
      $c->response->body( $response->message );
    }

}

で、ルートにアクセスすると

[1] マーク ルッツ/デイビッド アスカー, "初めてのPython 第2版", 2004, ¥ 5,040, 4873112109

と表示される。あとは/ASIN/XXXXXXのURLでJSON返すようにすればMochikit(javascript)からいい感じで扱えるはず。うーんナイス!

さらに、Net::Amazonはキャッシュが使えるのでCatalyst::Model::Net::Amazonでもキャッシュを効かせたい。C::M::Net::Amazonに直接書いた。

use Cache::File;

use base qw/ Catalyst::Model::Net::Amazon /;

my $cache = Cache::File->new( 
                         cache_root        => '/tmp/amazon_cache',
                         default_expires   => '30 min',
                            );

__PACKAGE__->config(cache => $cache);

Net::AmazonがCache::Fileオブジェクトをとるので、このようにModelに直接書いたのだけど、cache_rootとかdefault_expiresを設定ファイルに追い出すことはできないのだろうか?

Catalystでamazonアフィリエイト

blosxomでいうところのawsxomみたいなのが欲しいんだけど、コントローラーからNet::Amazonを使ってASIN:XXXXXXっていう部分を直接書き換えるようにするのがいいのか、それともCatalyst::Model::Net::AmazonのModelと適当なクラス名を用意して、Javascript+JSONで扱ったほうがよいのだろうかと考えていた。

後者だとMochikitでいろいろやれそうな感じになってよさげな気がするが、後で試してみよう。

はてなスターつけたヨ

個別のエントリのページでタイトルがエントリータイトルでなくDrkcoreとなっている部分を修正。あと、新規投稿をCtrl-.に変更。ちなみにDrkcoreはDrum'n'Bassのダークコアからとったわけですなこれが。

今回さらに、ピコピコ押す感がちょっと楽しげなはてなスター付けてみた。

はてなスター日記みながら、

Hatena.Star.headerTagAndClassName = ['h2','entry-title'];

で上書きかませばいいらしいんだけど、なんか上書きされてナイっぽい。

ので、Hatena.Star.EntryLoader.loadEntriesを上書きしたらOK。というより、サンプルちょこちょこといじって済ませた。かなりやっつけ。

Hatena.Star.Entry.Drkcore = new Ten.Class({
    initialize: function(doc) {
        this.doc = doc;
        var h2 = doc.getElementsByTagName('h2','title')[0];
        this.title = Ten.DOM.scrapeText(h2);
        var widget = \ 
        Ten.DOM.getElementsByTagAndClassName('div','widget_bottom',doc)[0];
        this.uri = widget.getElementsByTagName('a')[0].href;
        this.comment_container = \
        Hatena.Star.EntryLoader.createCommentContainer();
        h2.appendChild(this.comment_container);
        this.star_container = Hatena.Star.EntryLoader.createStarContainer();
        h2.appendChild(this.star_container);
    }
});

ただ、comment_conteinarとstar_conteinarをDOMの好きなところにぶら下げれば別にタイトルの隣じゃないところに持っていくことができるな(コメント欄とか)。

drkcore

個別のエントリのタイトルのとこが変だ。

あとで直す。

あと、Ctrl-cで新規入力はコピペがしにくくなるので駄目だった。キーの割り当てを変える。

TTでRFC822 Date Format

CatalystでTT使ってRSS2.0のフィードを吐き出したかったんだけど、datetimeのあたりでRFC822のフォーマットで時刻を出力しないといけないらしい。

都合のいいプラグインがみつからなかったので、Template::Plugin::DtFormatterを使って。

[% USE DtFormatter(patterns => { 
    'rfc822' => '%a, %d %b %Y %H:%M:%S %z',
     time_zone => 'Asia/Tokyo' }) -%]
...
<pubDate>[% DtFormatter.format(ub.clip_time, 'rfc822') %]</pubDate>

フォーマットはDateTime::Format::Mailを参考に。

TT使わないでXML::Feedを使ったほうが良いのかな?

わからん。

DBICで集約関数を使ってTTに送る場合に

タグのテーブルなんかでタグをカウントしてtagname(count)とか出力したいときにDBICだとどうやんのかな?と。

とasを指定しておけば、TTのほうで

t.get_column('posts_count')

でカウントが表示できる。

タグの名前とカウント数を表示させたい場合にはこのままTTでいいと思うが、タグクラウドにしたい場合は、コントローラーでHTML::TagCloud::ExtendedとかHTML::TagCloud を使ったほうがいいのかもと。

あとYAPCのチケットとった。DBICネタが密かに楽しみだったり。

DBICでprefetchとjoin

ありがたい。色々勉強になりました。

Hatena::Diary::Neko::kak 500 Internal Server Error - CatはしらんけどSledgeなら

基本コントローラーでRSを作りまくってstashにぶち込みまくって Viewの方で実際にクエリを実行する感じですね。

というわけでcookbookみながら悩んでみた。いじってるのは、こんな感じのテーブルなので、

多対多対多

user_bookmarksテーブルに対してイテレータをまわすことにした。 あとcatlystだとautoっていう最初(のほうに)に呼ばれるメソッドがあるので、そこにユーザーが存在するかどうかのバリデーション書いた。

sub auto : Private {
    my ($self, $c, $action, $username) = @_;

    $c->stash->{user} = 
      $c->model('PblDB::User')->single({name => $username});

    unless (defined($c->stash->{user}) || $c->req->path =~ m!^bookmarks/?$!) {
    $c->response->redirect($c->uri_for('/'));
    return 0;
    }

    return 1;
}

sub default : Private {
    my ( $self, $c ) = @_;

    $c->stash->{user_bookmark_it} = 
    $c->model('PblDB::UserBookmark')->search(
          {user_id => $c->stash->{user}->id},
          {       
             prefetch => [qw/user bookmark/],
             join => [qw/user bookmark/],
             order_by => 'me.id DESC'
           }
           );
}

あと、ユーザーバリデーションしてる件に関しては、

livedoor クリップ - Hatena::Diary::Neko::kak 500 Internal Server Error - CatはしらんけどSledgeなら

個人的には、バリデーションでユーザがいるかどうかはチェックしないなー。 そこでユーザの存在がわかっちゃうとあれかなと。まぁ、場合によるね。

とか

ってやった場合に、ユーザがいない場合にそんなメソッドがないよってエラーになっちゃうので、バリデーションしたというのが経緯なのだが、join使えば、

sub default : Private {
    my ( $self, $c, $action, $username ) = @_;

    $c->model('PblDB::UserBookmark')->search(
          {'user.name' => $username},
          {
             prefetch => [qw/user bookmark/],
             join => [qw/user bookmark/],
             order_by => 'me.id DESC'
          }
          );
}

と書けばよいのでこれでもいいかもしれんと思った。

あと、実際のサービスでそういった場合の処理はどうしてんのかなと気になったので僕が使っているSBSで調べてみた。

  • はてなブックマーク
  • トップページに飛ばされる
  • livedoor clip
  • unregistration.html
  • del.icio.us
  • エラーページ

ふむー。

DBICで多対多の設定を

かなりボケボケだった。

こういうことらしい。

DBIx::Class::Relationship - Inter-table relationships - search.cpan.org

PACKAGE>$method_name('relname', 'Foreign::Class', $cond, $attrs);

というわけで、こんな感じの理解で。

__PACKAGE__->belongs_to(アクセサ名(任意) => 
    '従うクラス','従うクラスのIDを持つ属性名');
__PACKAGE__->has_many(アクセサ名(任意) => 
    'クラス','自分のクラスのIDをもつ属性名');
__PACKAGE__->many_to_many(アクセサ名(任意) => 
    'has_manyでのアクセサ名','belongs_toでのアクセサ名');

データベースを指しているのかクラスを属性を指してるのか良く分かってなかった。というかO/RマッパーでDBのカラム名っておかしいよって何で気づかなかったんだろう。

  • many_to_manyは任意にキー名決められるのにhas_manyはキー値にテーブル名指定しないとエラー吐くのが謎。
  • has_many(アクセサ名(任意) => 'クラス','カラム名')でOK
  • many_to_manyでテーブル名のとこをKzfm::Schema::TagMapってやるのが駄目な理由がよくわからない。
  • has_manyで指定したアクセサ名が必要なのでダメ。

なんとなくこんな感じか。

Catalyst::Plugin::TagCloud

この前書いたのイマイチ かつYAPCのCatalyst話参考になったので、早速書き直してみた。

__PACKAGE__->config(
        tagcloud =>{
                levels => 10,
                limit => 3
                }
);

な感じでレベルとリミット設定できるようにした。

でも、実際に使ってみると、

sub default : Private {
    my ( $self, $c ) = @_;

my $tags = [
        {tag=>"tag1",url=>"url1",count=>5},
        {tag=>"tag2",url=>"url2",count=>15},
        {tag=>"tag3",url=>"url3",count=>8},
        {tag=>"tag4",url=>"url4",count=>20},
        {tag=>"tag5",url=>"url5",count=>3}];

my $html = $c->create_tagcloud($tags,"html_and_css");
    # Hello World
    $c->response->body( $html );
}

みたいに配列のリファレンスを用意しないといけないのが駄目ゲ?セーフゲ?わからん。

  • testとか書いてない(今後覚える、というかやる)
  • blahが多い(blur派だからしょうがない?)
  • Module::Starterつかうべしなのにh2xsではじめてしまった。

な感じで、やりかけだけど、ココから落とせます。もっと、小洒落たやりかたがあれば指摘してもらえると助かります。