ダメ人間オンライン

あまり信用しないほうがいい技術メモとか備忘録とかその他雑記

すぐに超エキサイティンになれるGoogle Chromeの拡張をシュウウウウウウウウウウウウ

生きていればつらいことがある。
しかし、つらいからと言って簡単に投げ出す事は出来ないということも多い。

みなさんもつらまってる時、よくなんとかドームで遊ぶと思う。
当然のごとく僕もそうである。

最近つらい事がよくある。
そんな時のために、なんとかドームを素早くプレイできる必要があった。
なので、なんとかドームをすぐプレイできるGoogle Chromeの拡張を作った。

「だめだ。もうやってらねー」って時は、右にあるアイコンをクリックすればすぐなんとかドームをプレイできる。最高。超エキサイティン。

f:id:dameninngenn_owata:20130312005330p:plain
dameninngenn/chrome-ext-nanntoka-dome · GitHub

まんをじしてneobundle.vimに乗り換えてみた

今までpathogen.vimを使っていたのをneobundle.vimに乗り換えてみました。
Vundleとかneobundle.vim使ってなかったのはpathogenで今そんな困ってないしなーって思ってたうえに、試しにやってみよっかなーって思った時になんかめんどくさそうだったからですね。

でneobundleの解説とか読んだりしてると今の環境より恩恵得られそうだったので重い腰をあげて移行した。

移行作業

~/.vim/bundle/ 下を全部消して、.vimrcのpathogenの設定消して、~/.vim/bundle/ の下にneobundle.vimもってきて、.vimrcにneobundleの設定書いて:NeoBundleInstallでフィニッシュした。

変わったこと

pluginインストールの管理がgit submoduleから.vimrcへの記述になった。これがなにげに嬉しい。
.vim/以下もgithubで管理してるのですがpublicなプラグイン以外に社内だけで使うプラグインとかもあって、もちろん公開できないのでそこのリポジトリに含めることができない。今まではローカル環境でブランチ分けて更新があったらうまい具合にマージしてとかなんかそんなめんどくさいやり方で運用してた。

この運用は間違ってgithubに社内用のプラグインとか含めてしまってコミットとかしたらいけないとか考えつつの精神的負担が結構大きかった。結局社内で使う分にはsshじゃなくてgitプロトコルのにしたからその心配はなくなったけど。

でneobundleだと個別環境用の.vimrc.local(.vimrcから読み込むやつ)に社内用のプラグインを書いておくだけで綺麗に分けられるのでだいぶシュッとした。管理部分に無駄なコスト払わなくて済むようになったので嬉しい。

あと~/.vim/bundle/下をリポジトリに含めないようにした。環境毎にupdateして使えば良い。

困ったこと

neobundle自体の管理をどうしようか少し考えた。

というのもまっさらなとこに環境構築する時に最初にneobundleが入ってないと他のプラグインはインストールすることができない。bundleの下はリポジトリに含めないようにしたので違うpathにsubmoduleとして入れておこうかなと思ったけど、neobundle自体もbundle下に入れてupdateとかできるようにしときたい。問題はこの初回時のみ。

で結局この問題は.vim/とか.vimrcで解決するのではなくて.vimのセットアップ用スクリプトのほうで解決するようにした。いつもdot_filesまわりの設定とか.vim/やらvim本体のインストールとかを簡単にできるようにするために用意してるスクリプト。

.vim/のセットアップ部分だと

#!/bin/sh

cd
if [ -d ./.vim ]; then
    echo "already exists! $HOME/.vim"
    exit;
fi
git clone git://github.com/dameninngenn/.vim.git

cd .vim
git submodule init
git submodule update

mkdir bundle
cd bundle
git clone git://github.com/Shougo/neobundle.vim ~/.vim/bundle/neobundle.vim
vim +NeoBundleInstall +q

cd
if [ ! -d ./tmp ]; then
    mkdir tmp
fi
echo "finished setup vim plugins"

こんな感じでとりあえず初回時にneobundleをbundleの下に放り込んでNeoBundleInstall走らせる。

他の人がどうしてるのかは気になる。

ニッコリ

submoduleでの管理だとプラグインのupdateとかなんか気が進まない感じだったけど何か解放された感がある。

色々気楽になった感じがするので捗りそう。

Amon2::Plugin::Web::PageCacheというのを書いた

レスポンスのHTMLをまるっとキャッシュするplugin書いた。書いたというか別のWAFで使ってたやつをAmon2用に書き直した。キャッシュ先はmemcachedです。

dameninngenn/p5-Amon2-Plugin-Web-PageCache · GitHub

やりたかったこと

  • requestのpath毎にキャッシュするか否か設定できるようにしたい
  • requestのpath毎にキャッシュのexpire設定できるようにしたい
  • /path/to?p=1 と /path/to?p=2 は別のものとしてキャッシュしたい
    • 想定してないクエリがついてきた場合はスルーしてクエリがついてないものと同じ扱いにしたい
  • requestのpath毎にキャッシュ削除ができるようにしたい
  • HTMLだけじゃなくてJSON返してる場合もキャッシュしたい
  • そこそこお手軽に使えるようにしたい

使い方

モジュールをインストールして、pluginを読み込んで、config.plに設定書くだけです。

    package MyApp::Web;
    use Amon2::Web;

    __PACKAGE__->load_plugin('Web::PageCache');
# config.pl

'PAGE_CACHE' => +{
    enable => 1,
    memcached => +{
        servers => [
            '127.0.0.1:11211'
        ],
        namespace => 'page_cache:',
    },
    path => +{
        'MyApp::Web' => +{
            '/'                         => { expire => 60 },
            '/detail'                   => { expire => 300, query_keys => [qw/p/] },
            '/member/{id:[0-9]+}'       => { expire => 60 },
            '/list'                     => { expire => 60, query_keys => [qw/p rows/] },
        },
        'MyApp::Mobile' => +{
            '/'                         => { expire => 60 },
        },
    },
},
enable

pluginを有効にするか無効にするか指定します。1だと有効0だと無効。
開発環境とかでサッと有効無効を切り替えられるように。

memcached

memcachedの設定です。Cache::Memcached::Fastを使ってるのでそれに渡す設定を書きます。

path

path毎の設定です。
context名とpathとそれに対する設定項目を書きます。PC用とスマートフォン用とかで分けててもそれぞれ設定できるようにしてます。

pathに指定できるフォーマットは Amon2::Web::Dispatcher::RouterSimple(Router::Simple::Route) で使えるものと同じです。

/blog/{year:\d{4}}
/blog/:year
/blog/*/*
normal string

/blog/:year と指定した場合 /blog/2012 と /blog/2013 は当然ですが別のものとしてキャッシュされます。
ここで指定していないpathはキャッシュの対象外になります。あと200番以外のステータスコードだった場合キャッシュしません。

expireはキャッシュが切れるまでの時間を秒で指定します。
expire => 60 と指定するとキャッシュが作られてから60秒間は同じ内容のものが返ります。

query_keysに何も指定しなければどんなクエリがついてこようとも同じ内容を返します。
query_keysに何か指定されていれば指定されたクエリについては別物として扱います。
例えば query_keys => [qw/p/] と指定した場合 /path/to?p=1 と /path/to?p=2 でそれぞれキャッシュされます。
指定したクエリ以外がついてきた場合 /path/to と /path/to?unknown=1 は区別されません。

キャッシュの削除

pluginを読み込むと delete_page_cache というメソッドが生えるのでこれを使います。
例えば

sub edit {
    my ($self, $c) = @_;

    # 何かupdateとかするやつ
    $c->nanika_update_suruyatu( $c->req );

    # 該当部分のキャッシュを削除してすぐ反映されるように
    $c->delete_page_cache({ name => 'MyApp::Web', path => '/detail' });

    $c->redirect('/dokoka');
}

こんな感じでpath毎にキャッシュを削除できます。/detail?p=2 /detail?p=3 みたいにクエリがついてる場合も上記の書き方で全部キャッシュ消してくれます。
ここらへんの仕組みは Catalyst::Plugin::PageCache を参考にしました。

Amon2標準で用意されている BEFORE_DISPATCH と AFTER_DISPATCH トリガーで動きます。なので特に書き換えない限りはキャッシュを返すだけの時も AFTER_DISPATCH のやつは動くので他になんか AFTER_DISPATCH のとこでやっててそこを通らせたくないって時はなんやかんやして下さい。

あとページキャッシュをpathによらず全消ししたい時は普通にflush_allすればいいと思ってるので全消しのメソッドは用意してません。pageキャッシュ用のmemcachedは他のと共用じゃなく別portとかで立てておけばめんどくさいこと考えなくていいんじゃないでしょうか。

モヤモヤ

あまりめんどくさいことせずに誰でもパッと使えるようにしたかったのでconfig.plに設定もろもろ書くようにしたけど、設定したいpathが増えてきた時にconfig.plの見通しが非常に悪くなるのでどうしたもんかなと。

delete_page_cacheは delete_page_cache('MyApp::Web', '/detail') にするかとか迷ったけど今の指定の仕方にした。

ドキュメントの英語がひどい。writing力低すぎて泣きそう。

Solrで「undefined field text」って言われた時の対処

Solr弱者なもんで設定でハマったのでメモ。

カラムを横断して検索するために問い合わせるクエリを q=field:value ではなく q=value で問い合わせて(dismax|edismax)で処理しようとしたら一生「undefined field text」って言われて困った。

textって名前のフィールドなんてないよ!って言われてるんだけど、schema.xmlを見てもtextなんてフィールド名は指定してない。

ググって出てきた解決方法は大概、exampleからコピーして編集したschema.xmlの中に元々サンプルで書いてあったtextとか残ってる気がするからそれを消せ!って感じだったけどschema.xmlの中にはなかった。

結論を言うとschema.xmlではなくてsolrconfig.xmlのほうに問題があった。

これもsolr/example/の下にあるやつをベースにして編集したんだけど、その中の

<requestHandler name="/select" class="solr.SearchHandler">

の中に

<str name="df">text</str>

てのがあってそれを消したら直った。

サンプルの設定でカラムの名前が"text"だとわかり辛いし、それでsolrconfig.xmlもすごく長くてどこをどう環境に合わせて変更すべきなのかがいまいちわかり辛い気がした。

東京Ruby会議10に行ってきた&黒Ruby会議で話してきた

1/13,14の2日間に渡って開催された東京Ruby会議10に行ってきました。

f:id:dameninngenn_owata:20130116020001j:plain

色々仕掛けがあってその中にノベルティのバッジをみんなと交換して全種類(全4種)コンプしよう!みたいなのがあったんですが、人気・不人気なバッジが当然あって僕は一番不人気なささたつバッジx4からのスタートでした。

交換を断られ続けるという中学生の頃のトラウマを呼び起こすかのような体験ができて懐かしかったです。バッジのデザインが何か変な浜辺に寝そべってる写真だったんですが、これ普通にささたつさんのアイコンにしとけば大人気になっていたと思うのは僕だけでしょうか?

黒Ruby会議

で、1日目の最後に黒Ruby会議というのがあったのですがそこで話してきました。LT形式の5分枠です。

黒い話か面白い話をしてくださいというざっくりとしたお題だったのですが、僕はとてもホワイトな人間なので黒い話もなかなか思いつかず年末あたりからずっとうんうん唸り続けてました。

一週間ぐらい前から謎の緊張感がすごくてゲロ吐きそうになりながら当日を迎えたわけですが、発表前に他の発表者の方々と黒い儀式を行ったことにより緊張も多少ほぐれて良い感じに。

# 黒い儀式(ゆーすけべーさん撮影)


話した内容はRubyのルの字も出てこないような内容だったのですが、暖かく見ていただけて石を投げられることなく楽しく話をすることができました。

しかし残念ながら話終えた直後に発表資料が謎の爆発に巻き込まれて消滅してしまったので公開することができなくなってしまいました。ざんねんだわー。

あと舞台袖でやんややんやしながら発表を見たりするのがだいぶ楽しかったですね。舞台袖マジックや!

なんし

2日目は特に雪のせいで運営の方々はとても大変だったかと思います。本当にお疲れ様でした。

素晴らしい地域Ruby会議をありがとうございました。とても楽しかったです!!