git submodule を使わないで vim プラグインを管理する
dot-files を git で管理してるとついつい vim プラグインも submodule 使って管理してしまいたくなるんですが、 submodule を使わないほうが楽なんじゃないかなと思って dot-files の整理と一緒にこんなシェルスクリプトを書いてみた。
整理した dot-files はこちら。 GitHub - punytan/dot-files: dot-files
使い方など
- .gitignore に vim/buldle/* を追加して、bundle以下は管理しないようにする
- 追加したいプラグインのリポジトリを install 部分に追加する
- bundleディレクトリは各自の環境に合わせて書き換えて
- プラグインのアップデートは upgrade を引数に実行するとまとめて git pull してくれる
- pathogen.vim 使ってください(って書けって言われた。常識ですけど!)
build-env/05_vimbundle.sh
#!/usr/bin/env bash if [ ! -d "$HOME/dot-files/vim/bundle" ]; then mkdir -p "$HOME/dot-files/vim/bundle"; fi cd "$HOME/dot-files/vim/bundle"; case $1 in 'install') git clone git://github.com/thinca/vim-guicolorscheme.git; git clone git://github.com/Shougo/neocomplcache.git; git clone git://github.com/thinca/vim-quickrun.git; git clone git://github.com/Shougo/unite.vim.git; git clone git://github.com/thinca/vim-ref.git; ;; 'upgrade') dirlista=`find . -maxdepth 1 -type d -print`; for d in $dirlista; do if [ "$d" != "." ]; then cd "$d"; echo $d; git pull; cd '..'; fi done; ;; *) cat << EOM Usage: $0 install $0 upgrade EOM ;; esac
daemontools メモ
daemontools はめったに設定しないので毎回忘れる!とくにmultilogとか編集中にはダウンさせておくとか。
一連の流れをまとめたメモ。
インストール
$ sudo apt-get install daemontools-run $ cd $ mkdir daemontools
foo ディレクトリをつくり、スティッキービットをたてる
$ cd ~/daemontools $ mkdir foo $ mkdir foo/log $ chmod +t foo
シンボリックリンクを /etc/service 以下につくり、自動で supervise が起動するのでダウンさせておく
$ cd /etc/service $ sudo ln -s /home/hoge/daemontools/foo foo $ sudo svc -d /etc/service/foo $ sudo svc -d /etc/service/foo/log
runを作成
$ cd ~/daemontools/foo
$ vim run
export PATH=/path/to/library cd /home/hoge/app/foo && exec setuidgid hoge executable-file
log/runを作成
$ vim log/run
exec setuidgid hoge multilog t ./main
先ほどダウンさせたサービスを開始する
$ sudo svc -u /etc/service/foo/log $ sudo svc -u /etc/service/foo
$ sudo svstat /etc/service/foo $ sudo svstat /etc/service/foo/log
を実行して up の秒数が増えていれば正常に起動している。
10 seconds 以上にならないときは異常終了しているので環境変数やパスが間違っていないか確認する。
SSHだけでリモートサーバからローカルMacにGrowl通知したい!
Growlしたい!というときは次のようにやってます。
概要
- リモートでgrowl専用のログファイルを準備する。
- ローカルからリモートにsshで接続し、tail -fでログファイルの監視する。
- リモート側では、そのログファイルに対してGrowlさせたい内容をリダイレクトを使って追記する
- 追記された内容が出力されるので、その出力をローカルのLLで行ごとに読み込む。
- 読み込んだ行を growlnotify を起動して通知する
これだけ。
growlnotify が必要なので、 GrowlのディスクイメージのExtrasフォルダから事前にインストールしておくこと。
手順
ステップ1 - リモートで
$ echo 'foo' > $HOME/growler.log
このように、ログファイル(通知させたい内容を追記するファイル)を作成しておく。
ステップ2 - ローカルで
$ ssh example@example.com tail -n 1 -f '$HOME/growler.log' | perl -e 'system "growlnotify", "-m", $_ while (<STDIN>);'
この例では、example.comにsshでログインし、ログファイルをtail -f で監視する。
標準出力がpipeによってperlに流れるので、それを受信してgrowlnotifyを起動する。
これによってファイルの最終行がgrowlされ、接続できているか確認できる。
ステップ3 - リモートで
$ echo 'hoge' >> $HOME/growler.log $ ls >> $HOME/growler.log
このように標準出力をログファイルに追記するだけでgrowl通知ができる!
応用
とても時間のかかる処理をさせている間に別の処理をしたい場合
cpan-outdated -p | cpanm; echo 'upgraded' >> $HOME/growler.log
としておくと、処理が終わったときに通知してくれます。
ログファイルを吐き出すIRCクライアント(この場合はweechat)をリモートのscreen上で実行している場合
ssh example@example.com tail -n 1 -f '$HOME/.weechat/logs/*/*/*.weechatlog' | perl irc_growl.pl &
としてサーバにつなげ、irc_growl.plで処理を加えた上でgrowlさせることもできる。irc_growl.plでは、 --appIcon にLimeChatを指定することでGrowl時のアイコンを変更している。
sshのコマンドが長いと感じたら、.bashrcにaliasを設定しておくと良い。
参考にirc_growl.plを貼りつけておく。
irc_growl.pl
while (<STDIN>) { chomp; next unless $_; next if /^==>/; # ignore tail's output my $attr = parse($_); if ($attr->{type} =~ /(:?NOTICE|PRIVMSG)/) { system("growlnotify", "-m", $attr->{content}, "-t", $attr->{user}, "--appIcon", "LimeChat"); } } sub parse { my ($line) = @_; my ($time, $cmd, @contents) = split /\t/, $line; my $content = join "\t", @contents; my $user; if (not $cmd) { # critical error $cmd = 'ERROR'; } elsif ($cmd eq '-->') { # join $cmd = 'JOIN'; } elsif ($cmd eq '<--') { # part $cmd = 'PART'; } elsif ($cmd eq '--') { # messages from server $cmd = 'SERVER'; } elsif ($cmd eq '*') { # notice $user = $cmd; $cmd = 'NOTICE'; } else { # privmsg $user = $cmd; $cmd = 'PRIVMSG'; } return +{ type => $cmd, time => $time, content => $content, user => $user, }; }
pjax こそが pushState + Ajax の本命
pjaxの前にpushStateとは
AjaxとjQueryの説明は不要として、pushStateとはなんぞや。
pushStateを使ってブラウザの履歴に対する操作をし、HTMLの一部のみを書き換える動作でもブラウザの戻る/進む機能を実現できる方法のひとつ。Ajaxなページを再現し、かつURLを見慣れた方法で自然にpermalinkを表現できる。
有名なところではGitHubで使われてるアレ。
hash fragment (/#!/)
ブラウザの履歴を機能させるため、URL の fragment (#) を使ってAjaxなページを実現する方法。一時期もてはやされた感があるが、さらなる「#!」URL批判 - karasuyamatenguの日記 など合理的な反論があり、これから導入するのはためらわれるところ。
有名なところではTwitterで使われているあの厄介者。
pjaxとは
pjax とは pushState + ajax を合わせた語で、その名のとおり pushState を使いつつ Ajax な処理を行う為の jQuery ライブラリ。GitHubのdefunktが開発していることもあり、今後pushStateを使ったものでは導入が進んでいく可能性がかなり高いのではないかと読んでいる。
また、最近ではページの見た目の面では非クロスブラウザを許容する風潮があるように見受けられ、この流れともpjaxは親和性が高い。
「高機能なWebブラウザでは見栄えよく、そうでないWebブラウザで“も”それなりに」
Webページの見栄えにどこまでこだわるのか | 日経 xTECH(クロステック)
pjaxの振る舞いは、ChromeのようなブラウザではpushStateを使い、IEのようなブラウザでは通常のアクセスと同じように、全く同じpermalinkでアクセスできるようにしてくれる。
「コンテンツがcurlでロードできなければそのサイトは壊れている勢力」の救世主
私もこの勢力のうちのひとりだと内心思っているのでやや傾倒している感はある。
しかし hash fragment を使用したページは curl では取得できない。これはサーバ側にfragment以降は送信されないためであるが、publicなものにcurlやLWP::UserAgentやGoogleのクローラーといったクライアントでアクセスさせるためにURLに細工することは解せない。かと言って自分でゴリゴリとpushStateの実装を書くのも骨が折れる。そういった問題を解決してくれるものになると思われる。
使い方
ここではざっくりとした使い方を書いておく。
細かい使い方はいろいろあるようなので、GitHubにあるREADMEを参照すると良い。GitHub - defunkt/jquery-pjax: pushState + ajax = pjax
クライアントサイド
"js-pjax" クラスのアンカーに対してのみ機能させる場合はこのようにセレクタを書く。
<script src="/jquery.min.js"></script> <script src="/jquery.pjax.js"></script> <script type="text/javascript"> $(function () { $('a.js-pjax').pjax('#main'); }) </script>
実装
サーバをPerlで実装したので
$ cd /tmp $ curl https://gist.github.com/raw/901139/c13279a29cfcca8cc75e63fb9eeb65b3ca2785c7/app.psgi -LO $ plackup
で起動し、リクエスト/レスポンスをチェックできる。
app.psgi
use strict; use warnings; use feature qw/say switch/; use Data::Section::Simple; use Text::Xslate; use Plack::Request; my $tx = Text::Xslate->new( path => [ Data::Section::Simple->new->get_data_section ], ); my $app = sub { my $req = Plack::Request->new(shift); my %data = ( %ENV, TIME => scalar localtime, PJAX => ($req->header('X-PJAX') ? 1 : 0) ); say "----- X-PJAX is " . ($data{PJAX} ? 'TRUE' : 'FALSE'); my $type = $data{PJAX} ? 'pjax' : 'default'; my $res = $req->new_response(200); $res->content_type('text/html; charset=utf-8'); given ($req->path_info) { when ('/') { $data{title} = "root"; $res->body( $tx->render("root-$type.tx", {data => \%data}) ); } when ('/home') { $data{title} = "/home"; $res->body( $tx->render("home-$type.tx", {data => \%data}) ); } when ('/help') { $data{title} = "/help"; $res->body( $tx->render("help-$type.tx", {data => \%data}) ); } when ('/favicon.ico') { $res->redirect("http://www.google.com/favicon.ico", 301); } default { $res->status(404); $res->body('Not Found'); } } return $res->finalize; }; $app; __DATA__ @@ home-pjax.tx <: if $data.PJAX { :> <title><: $data.title :></title> <: } :> <p> Hello, <: $data.USER :> </p> @@ home-default.tx : cascade base; : override main -> { include "home-pjax.tx" } : override title -> { "/home" } @@ help-pjax.tx <: if $data.PJAX { :> <title><: $data.title :></title> <: } :> <pre> <: $data | dump :> </pre> @@ help-default.tx : cascade base; : override main -> { include "help-pjax.tx" } : override title -> { "/help" } @@ root-pjax.tx <: if $data.PJAX { :> <title><: $data.title :></title> <: } :> <p> pjax!! pjax!! pjax!!</p> @@ root-default.tx : cascade base; : override main -> { include "root-pjax.tx" } : override title -> { "root" } @@ base.tx <!DOCTYPE html> <html> <head> <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script> <script src="http://pjax.heroku.com/jquery.pjax.js"></script> <meta charset='utf-8'> <title> <: block title -> { :> hello pjax <: } :> </title> <script type="text/javascript"> $(function () { $('a.js-pjax').pjax('#main'); }) </script> </head> <body> : include "nav.tx" <div> : $data.TIME </div> <div id="main"> : block main -> { } </div> </body> </html> @@ nav.tx <ul id="nav"> <li><a href="/" class="js-pjax">Index</a></li> <li><a href="/home" class="js-pjax">Home</a></li> <li><a href="/help" class="js-pjax">Help</a></li> </ul>
結論
簡単にpushStateによる履歴操作とhash fragment (裏側のURLは汚い)に勝る綺麗なURLを実現できるので流行るといいな。
Perl CPANモジュールガイド
CPAN本の出版おめでとうございます&献本頂きありがとうございます。私がリリースしたもの*1も収録されています。
紹介と感想
CPANモジュールを32のジャンル(ユーティリティ/データ/クラス/日付/アルゴリズム等々)に分け、目的のモジュールと使い方を説明する形式で、まさに書名の通り「CPAN モジュールガイド」と呼ぶにふさわしい本といえるのではないでしょうか。また、400ページ超のこの分量を書くのは相当な苦労だったのだろうと想像できるほどの力作となっています。
多くのPerl入門書ではCPANの記述は最終章近くで存在に触れている程度でしかなく、どれを使えば良いのかわからない状態で先に進めない人が多いのではないかと思いますが、本書はそういった問題を解決するひとつの手段になりうるのではないかと思います。
また、自分の知らないモジュールがたくさんあることを思い知らされました。さらに、モジュール紹介の中にあるtips*2はPerlを使う上で知っておいたほうが良いものが多いです。
モジュールガイドなのにAcme::のnamespaceがないのはうわなにをするやめくぁwせdrftgyふじkl;
ということで、Perl CPANモジュールガイドおすすめです。
TEPCO 電気需要 JSON API 作った
http://linknode.net/tepco.html
Access-Control-Allow-Origin: *
をヘッダーに含めているので、Same Origin Policyを気にせず、サイトをまたがってリクエストを飛ばしてJSONを取ってくることができます。
使用例
次のようなもので簡単に表を出力することができます。
<script> $(function () { $.ajax({ url : 'http://api.linknode.net/tepco/v2/demand.json', dataType : 'json', success : function (data) { //console.log(data.raw); //console.log(data); $('#raw').append(data.raw); $('#last_updated').append(data.last_updated.date + ' ' + data.last_updated.time); for (var i in data.demand) { $('#target > tbody').append( $('<tr>').append( $('<td>').append(data.demand[i].date + ' ' + data.demand[i].time), $('<td>').append(data.demand[i].today), $('<td>').append(data.demand[i].yesterday))); } } }); }); </script>
search.cpan.org で syntax highlighting
最近 search.cpan.org で POD 中のコードに syntax highlight できるようになりました。