2011-03-06 [長年日記]
_ JavaScript Url DispatcherとかRouterについて調べた
あるいは kanazawa.js v1.0.1 勉強会 : ATND に参加してきた。(前回と同じパターンの使い回し)
なぜdispatcher(あるいは router)か
実はピンときてなかったけど、なんかこういう手法があるっぽいということだけ知ってた。
pixiv Tech MeetingでpixivのJSの話をしました
から辿れるスライドを見てなるほどなと思った。自分がいちばんなるほどと思ったのは
WAFの不自由さ
というか layout ファイルの <script> を可変にできるように仕組み用意していちいちそこに何か文字送ったりするのってめんどくさいよねというか、要するに
script loading も DRY に
ってことじゃないかな。もっかい整理すると
- layout ファイルで JavaScript のライブラリの読み込みは共通にできる
- でも layout ファイルの中に手を出せるのはサーバサイドだけだし、一部でだけ共通な JS ファイルの読み込みは面倒
- 集中管理できないし、分業してると何かと面倒
という問題を解消するために dispatcher(あるいは router)が有用だよってことだね。なるほどなぁ。
いくつか見つけた
日本語で読めるものもいくつか。kayac と pixiv は手作りで、ライブラリ側にこの機能が統合されているものはまだあまり見かけない。もしかして uupaa が初めて?
kayac バージョン
- そこそこ規模が大きくても何とかなるjavascriptの設計(URL dispatcherの薦め) | tech.kayac.com - KAYAC engineers' blog
- 中規模向けJS設計
pixiv バージョン
先ほどの納得のいった資料の元ですな。
uupaa バージョン
uupaa-js - Project Hosting on Google Code
jsdo.it にサンプルが載ってる。
uu.ready("href:URL Dispatcher", callback...) test code - jsdo.it - Share JavaScript, HTML5 and CSS
jDispatcher(ちょっと意図と違う)
みんな大好き jQuery の plugin であったら便利じゃねーのと思ったので探したんだけど、これは Ajax Request を飛ばすのが目的のものなので除外。
jQuery Router
こっちが今回の目的に合致する jQuery plugin.
複数ページの window.onload をまとめて書ける jQuery プラグインを書きました | Tanablog
jQuery Router を試す
全部のコードを晒すのもアレなので一部だけ。Ruby の WAF だとだいたいこんな感じでまとめられるはず。実際に以下のコードは Sinatra 上で動かして確認した。
これで application.js だけで必要な script の読み込みを制御できるので、サーバサイドの処理には手を加える必要がないし、分業している場合はサーバサイドの人に処理の追加を頼む必要がない。
楽ちん。
ちなみに $LAB.script() は LABjs のメソッド。
感想
個人的にはもっと Sinatra ライクな rouing ができると嬉しいと思う。正規表現のみの routing は罠にハマりやすいんじゃないかな。まぁテスト書けってことなんだろうけど、このままだとテストも書きにくい(というか書ける?)。
制御したい URL のパターンが増えたらテスト書ける router を別に探した方がいいのかもしれない。routing が一カ所に集まっていれば差し替えも楽だし。
※ 今回紹介した中では pixiv バージョンにはテストがついてる。
LABjsはこの辺参照
Loading And Blocking JavaScript だそうで。
非同期 load、同期 load を自在に設定できる便利ライブラリ。JavaScript を細かく分割して必要なものだけロードしたいなら持ってこい。つまり dispatcher, router と相性がよい。はず。
まとめ
kanazawa.js 超かっこよくてオサレなのでみんな来ればいいよ!(えー
LABjs と Sinatra で別エントリ書くと思う。
おまけ
git の bundle ファイル を上げてみた。fetch してから*1 git clone するとどんな風に作業進めたか見れるよ。
*1 bundle ファイルをただ上げただけなので直接 clone できません。
2011-03-07 [長年日記]
_ 今さらSinatra最低限メモ
今度は Sinatra. 次もすぐに動かせるように公式のドキュメントを圧縮する感じで、自分の欲しい情報だけ。アプリを書く以前のレベルで、まずはページを表示できる状態を目指す。
実は昨日の kanazawa.js の成果その2
環境
今回の環境は
- MacOSX 10.5
- Ruby 1.8.7
- Sinatra 1.1.3
- Ruby 1.9.2
- Sinatra 1.2.0
で確認した。Sinatra のバージョンが合ってないことに特に意味はない。
インストール
(ry
動かし方
1ファイルの場合は
$ ruby app.rb
でもよい。例の感じで中に
require 'rubygems' unless defined? ::Gem require 'sinatra' get '/' do 'Hello, World' end
で終了。デフォルトで port 4567 で起きる。
ちなみにこれだけで response header とこの文字列だけの response body が返る。PHPer 的には print や echo で出力したくなるけどそれは間違い。これは
get '/' do return 'Hello, World' end
の return を省略してるだけ。return が response になる。rack の header を省略できると思えばいいはず。
設定とか分離したい
rack の流儀に則って config.ru を用意(別名でもいいけど)。
config.ru
require 'rubygems' unless defined? ::Gem require File.dirname( __FILE__ ) + '/app' run Sinatra::Application
app.rb
require 'sinatra' get '/' do 'Hello, World !' end
この場合は rackup する。*1
$ rackup
デフォルトで port 9292 になる。rack の流儀で変更可能。
$ rackup --port 80
※ ただし Un*x なシステムでは 1024 以下は特権ポート。のはず。
Handler を明示すれば option を与えられるけど、Handler を与えない方針なので以上。
自動でReload
mod_php や Rails の development 環境に慣れてしまったのでこれがないとやってられない。方法は3つ。
- Rack::Reloader
- Shotgun
- Sinatra::Reloader
What happened to reloading in Sinatra 0.9.2? - Sinatra: Frequently Asked Questions
Rack::Reloader
普通の Rack Middleware
use Rack::Reloader
すればオッケー。でもちゃんと動かないらしい。動いてるように見えるけど、そうとは限らないということか。却下。
Shotgun
shotgun の名前がインパクトがあってよく覚えてたんだけど、今 Sinatra のサイトで読むといちばん遅いのと、fork を使うので JRuby や Windows で動かないとのこと。あやや。
インストールはもちろん
gem install shotgun
これは普通のアプリの起動にも使えるし、
shotgun app.rb
rackup 代わりにもそのまま使える。
shotgun [config.ru]
今度は port はデフォルトで 9393 になる。
Sinatra::Reloader
gem install sinatra-reloader
個人的には予想以上に依存が多い。
if development? require 'sinatra/reloader' Sinatra.register Sinatra::Reloader end
で使える。Rack Middleware の要領で use ってやったら怒られた。Sinatra Extension と Rack Middleware は違うのね。
あと当たり前だけど
reloaderに関する書き換えを行うときは再起動した方がいいよ。
ディレクトリ構成とsetによる設定
project/
├── app.rb
├── config.ru
├── public/
│ └── javascripts/
│ ├── LAB.js
│ ├── application.js
│ ├── jquery-1.5.1.min.js
│ └── jquery.Router.js
└── views/
├── hello.erubis
├── index.erubis
└── layout.erubis
Rails流とちょっと違う。
この public, views はそれぞれ以下のように設定できる。
set :public, File.dirname( __FILE__ ) + '/static'
set :views, File.dirname( __FILE__ ) + '/templates'
要するにアプリケーションのファイルを基準にして自分で決めたきゃ決めろと。この設定方法は Capistrano に似てるなぁ。
何が設定できるかはここを見るといい。
root も変更できる。
テンプレートの選択とrender
基本系
get '/' do erb :index end
こんな感じ。これで
- index.erb を探して
- erb でレンダリング
という意味になる。拡張子の変更はできるのかなぁ。できないような気がする。中で render メソッドを読んでるんだけど、ちゃんと追いかけると何か分かるかも。
render は最後に
erb :index
って書き方だけだと index.erb を表示用に使うよ、っていう宣言に見えちゃうんだけど、これはれっきとした render メソッドの呼び出しなので、処理はこの前に書くこと。と言うか
erb :index とかは最後に書け
の方が分かりやすいか。
erubis でHTMLのエスケープをデフォルトに
Rails 3 以降デビューなのでこれがないとやってられない。
require 'erubis' set :erubis, :escape_html => true get '/' do erubis :index end
こんだけ。
オブジェクトの割り当て
これは Rails の View に似ていて(同じ?)、
- インスタンス変数は直接参照可能
- ローカル変数は明示的に :locals で割り当て
という方法を採る。
app.rb
get '/' do
erubis :index, :locals => {:key => value}
end
views/index.erubis
<%= key %>
こんな感じで value が表示できる。
layoutファイル
layout ファイルは
views/layout.#{ENGINE}
になるはず。layout ファイルと個々のテンプレートで種類を変えることができるのかどうか分からない。たぶんしない方がいいと思う。
erubis の「エスケープしない」出力
layout.erubis
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title><%= @title %></title>
</head>
<body>
<h1><%= @title %></h1>
<%== yield %>
</body>
</html>
こういう風にしとくと個々の
erubis :index
などの中身に HTML をそのまま書くことができる。
<%== %>
が決め手。
参考
- Sinatra
- 本家
- Sinatra
- API
- Ruby Freaks Lounge:第41回 Sinatra 1.0の世界にようこそ|gihyo.jp … 技術評論社
- Ruby Freaks Lounge:第42回 実世界のSinatra|gihyo.jp … 技術評論社
- Rack: a Ruby Webserver Interface
- Ruby Freaks Lounge:第23回 Rackとは何か(1)Rackの生まれた背景|gihyo.jp … 技術評論社
- Ruby Freaks Lounge:第24回 Rackとは何か(2)Rackの使い方|gihyo.jp … 技術評論社
- Ruby Freaks Lounge:第25回 Rackとは何か(3)ミドルウェアのすすめ|gihyo.jp … 技術評論社
*1 Handler を直接 config.ru に書く方法もあるんだけど、それだと環境を変えるためにはいちいち書き直さなきゃいけないから嬉しくないと思う。
2011-03-08 [長年日記]
_ 今さらRails3メモ - 番外編その2: gitに入れてないファイルの洗い出し -
- 以下の内容を Rails.root/lib/tasks/git.rake に置く
- Rails.root/.gitignore に cache, tmp など除外したいファイルのパターンを追加
以上。
もっといい方があるような気もするけど、今のところ満足。
rake -s git:untracked | xargs git add
とか、まとめてできる。
2011-03-17 [長年日記]
_ CentOS 5 + Rails 3 + native extensions のメモ
とても今さらな環境の話と Rails 3 が組み合わさってるけど、だからこそのメモ。
まとめ
- 開発環境が Mac OSX 10.5 ( のちに 10.6 )
- staging および production が RHEL 5 ( clone )
で、Rails 3, 特に面倒の多い native extension をどうするかを整理した。最終的には以下のような感じに。
ちなみに DBMS は development, test を SQLite で、それ以外を PostgreSQL で構築している。
できあがったGemfile
gem 'sqlite3-ruby', '< 1.3', :require => 'sqlite3' gem 'rmagick', '< 2' group :production do gem 'pg' end
※ あとで気づいたけど
bundle install --without=production
すれば development 環境で PostgreSQL は要らなかった…。
OSX 10.5
MacPorts を使って必要なバイナリをインストールしている。
- Ruby 1.8.7
- ImageMagick 6.6.7 + rmagick 1.15.17
- SQLite 3.7.4 + sqlite3-ruby 1.2.1
- PostgreSQL 8.1.x + pg 0.10.1
CentOS 5
もちろん yum 管理。Ruby は endpoint の repository を使って REE を利用。
- Ruby Enterprise Edition ( 1.8.7 via endpoind )
- ImageMagick 6.2.8 + rmagick 1.15.17
- SQLite 3.3.6 + sqlite3-ruby 1.2.1
- PostgreSQL 8.1.x + pg 0.10.1
cf.
補足
Ruby 1.8 なら RMagick 1 を入れられる
- ImageMagick 6.3.0 で新機能が加わった
- RMagick 1 は 6.3.0 の新機能が必要なければ使える
- RMagick 1 は Ruby 1.9 はサポートしていない
ということで production で Ruby 1.8 を使う場合、開発環境では rvm で 1.8 を使うことで RMagick 1 をインストールして動作を合わせることができる。最近の開発環境はたぶん Ruby も ImageMagick も工夫しないと新しいものが入ってしまうので注意が必要かも。
今回のケースでは RHEL 5 clone で欲張って Ruby 1.9 を使おうとしてしまった場合にはややこしいことになっていた。
cf.
Which version of RMagick is right for me? - RMagick Download Page
RMagick は root 権限が必要で bundle install できない?
- /usr/share/RMagick とか /opt/local/share/RMagick にファイルを起きたがるため root 権限が必要で bundle install に失敗する
- でもここでインストールするものはドキュメントだけ
- 一度 bundle じゃなくて yum なりで ImageMagick をインストールする、手でディレクトリ掘るなどして permission 周りの問題を解消しておけば gem については root 権限なしで全部 vendor 以下に入れられる
MacPorts には postgresql-devel ないけど?
エラーメッセージを読んだり pg の README.OS_X を読めば分かるけど
--with-pg-config
で pg_config を指定してやれば ok.
自分の場合は
/opt/local/bin/pg_config -> /opt/local/lib/postgresql81/bin/pg_config
と link を張ってごまかした。
2011-03-25 [長年日記]
_ Rubyのif式で気づいたこと
安心してください。とても今さらな話です。
jpmobile を読んでいたら if も式だと
今日 jpmoile 1.0.0.pre を読んでいてふと
lib/jpmobile/mailer.rb
@mobile = if tos.size == 1
# for mobile
(Jpmobile::Email.detect(tos.first) || Jpmobile::Mobile::AbstractMobile).new(nil, nil)
else
# for multi to addresses
Jpmobile::Mobile::AbstractMobile.new(nil, nil)
end
こんなコードが目に留まった。
あーそうか。
Rubyは制御構造も式です
ってこういうことか。あまり意識してなかった。式とか文とか普段あまり意識してなくて、
基本的には値が返るので return を省略できる
程度にしか覚えてなかった。
Ruby は条件演算子をかっこよく書けないけど問題にならない
※ 実際に気づいたのは 4/5 のこと。
PHP を書いているときによく
function funk() {
return ( condition )
? val1
: val2;
}
と、いわゆる三項演算子、厳密には条件演算子を使って if 文を書かずに済むなら書かないようにしていた。そうでないと
function func() {
if ( condition ) {
return val1;
} else {
return val2;
}
}
と書かねばならず*1、とても記述量が増えてしまうから。後置 if も使えないし、とにかく短く書けない PHP での必死の抵抗として条件演算子にはとてもお世話になっている。この場合は単に return するだけなのでそうでもないが、例えば
var = ( condition )
? val1
: val2
となると、もはや条件演算子を使わずにスッキリ書くなど不可能と言ってよい。
ところが Ruby では逆にこの条件演算子を気持ちよく書きにくい。というのも
? を次の行に下ろすことができない
から。なんと syntax error になるのだ。そうすると
( condition ) ? val1 : val2
こう書くのか。しかしこれではとても読みやすいとは言えない。実はこれずーーっと困ったなぁ思っていたんだけど、上のように
var = if ( condiition )
val1
else
val2
end
と書けるんならこれでいいな。いやはや、式とか文とかあまり興味ないんだけど、ちゃんと分かってないとダメだなぁ。
*1 ブレースは必ず書く派なので書いてあるだけ
2011-03-27 [長年日記]
_ kanazawa.js v1.2 に参加します
基本はもくもく会スタイルで勉強している kanazawa.js ですが、今回はセミナー形式ということで
Firebugの使い方を中心にそもそものWebの基礎的な内容
で発表を行う予定です。JavaScript に限りません。
正直自分もフロントエンドの話はもうずいぶんご無沙汰なので Firebug もそれほど使い込んでいるわけではないのですが、何ができるか、言い換えると
どんな働きをさせることが大事だとFirebugや開発者向けツールの作者たちは考えているか
に思いを寄せることができればいいなと考えています。
4/16(土)会場でボクと握手!