アーカイブ
Sinatra+Haml+jQuery入門
研究室の後輩にSinatraとhamlとjQueryを教えるために作ったテンプレートについて、ここにも書いておく
ソースコード https://github.com/shokai/sinatra-template
実際動いているもの http://masui.sfc.keio.ac.jp/sinatra-template/
git clone git://github.com/shokai/sinatra-template.git
■Sinatraを何に使うか
Sinatra+haml+jQueryが便利。
Railsと似てるけど、ちょっと違う。
個人的には
Rails → HTMLのページをいっぱい作るのに便利
Sinatra → 画面遷移あまりしなくて、同じURLのままjsonのAPIをjQueryのajaxで取得して動的に表示を変えるwebページを作るのには便利
に感じる。
でもSinatra自由すぎるので、ある程度実装パターンを知らないとメチャクチャになるのでこのテンプレートを参考にすると良いよ
個人的にはserial-http-gatewayと一緒に使ってデバイスと連動したwebページを作る、とかが手軽にできてよく使う。
■動かし方
gemでsinatra入れて、ruby development.ru
詳しくはREADME嫁
■テンプレートの解説
最低限の動作するおみくじアプリです
おみくじ結果をJSONで返すAPIがある
jQueryでajaxでJSON読んで表示する
hamlでhtmlを作る
開発用とデプロイ用の2種類のRackUp(*.ru)ファイル付き
■ファイルの説明
・README.md
まず読め
・development.ru
開発サーバーを起動し、main.rbとhelper.rbを読み込んでSinatraアプリを実行するスクリプト
・config.ru
本番サーバーのapacheやnginxでsinatraアプリを実行するためのPassenger用スクリプト
・config.yaml
”やむる”形式の設定ファイルです。アプリのタイトルしか書いてない。
ここに設定値を書くようにするとアプリを配布するのに便利
(必要になったら)DBの接続設定などを書くと良い。
・Gemfile
アプリで使うgemを書いておく
bundlerでgemを管理する時に使う
・helper.rb
起動時に一回だけ読み込まれる
必要なライブラリをロードするコードはここに書く
(必要になったら)データベースへの接続などをここで行うと良い。
app_rootという関数が定義されている(重要)
これにより、開発サーバー・サブドメインでの運用・サブディレクトリでの運用でも内部のURLがズレない
jsからサーバーのAPIにアクセスする時、hamlでcssを読み込む時などに便利
・main.rb
Sinatraアプリ本体
HTTPでアクセスしてきた時のresponseを書く
app_root/omikuji.json でアクセスしてきた時に、ランダムなおみくじを返す
・views/
hamlを置くディレクトリ
・views/index.haml
http://(app_root)/ にアクセスした時に表示されるhamlファイル
index.hamlをどのURLの時に表示するかは、main.rbで指定している
main.js, main.cssを読み込んでいる
rubyの変数のapp_rootをjsの変数app_rootに渡している(重要)
・public/
画像やjavascriptなどの静的ファイルを置くディレクトリ
・public/js/jquery.js
最新版のjquery
・public/js/main.js
index.hamlから読み込まれるJavaScript
・public/css/main.css
index.hamlから読み込まれるcss
SinatraやjQueryの基本的な使い方についてはググる。ライブラリの入門サイトとかを頭から読むよりも既に動いているアプリのソースを読んでわからない所を調べるのが一番速い。
■工夫しているところ
そんなに多いわけでもないけど、
・config.ruとdevelopment.ruを分ける。developmentから起動した時だけsinatra/reloaderを使ってアプリを毎回リロードさせている
・helper.rbの中身は1プロセス毎に1回しか呼ばれないので、DBとの接続や設定ファイルの読み込みはmain.rbと分けてここに書いておくといい
・app_rootという関数を定義してあって、開発環境や本番環境でAPIのURLがずれないようにしている
・haml内に書かれたRubyコードの動作についてはここにまとめた
■アプリの動作
ruby development.ruする→helper.rb読む→helperがyamlの設定ファイルを読む、app_rootという関数を作る→port8080でサーバーがthinに設定される→Sinatraアプリ(main.rb)を起動→main.rbは”/”へのアクセスにindex.hamlを返す、”/omikuji.json”にはランダムなおみくじと時刻を返す
ブラウザで”/”にアクセスする→cssとjsを読む、ajaxでおみくじを取得する関数がボタンに関連付けられる→ボタン押す毎におみくじ表示される
こんな感じで、ajaxでデータ取ってきてhtmlを書き換えるアプリの最低限のテンプレートを用意しました。
意外とDB無くてもglitchtweetやTweetButtonや増井研オーディオAPIのようなものは作れるので、まずはDBなしでSinatra+Haml+jQueryで何か作ってみるのが良い。
DB使うときは、SQL系ならActiveRecordsかSequelかDataMapperあたりがメジャーなのかな?多分。そのへんをまず単体で使ってみて、適当にtwitterのクローラーとか作ってみると良い。
それからSinatraの中に混ぜて使ってみる。いきなりjsで画面が書き換えて、Sinatraもいじって、DBも使うとかやると確実に破滅するので一つずつやるのオススメします
glitchtweet.com作った
2ヶ月ぐらい前に作った。blog書くのめんどくさくて放置してた。
http://glitchtweet.com
俺がやっているような素敵な装飾がついたツイートがだれでもできるwebサービスです。しかも気に入ったのがでるまで何度でもやりなおせる。
iPhoneやAndroidから使うことを想定している。

ライブラリ以外のコードを数えたら、286行しかなかった。
その他は以前作ったテキストに文字装飾を行うglitchtext.jsが500行ぐらい。sinatra、haml、jqueryのおかげでシンプルに書けた。
ソースはここにある
shokai/glitchtweet-web-app – GitHub
以下細かいことなどを書く
■ファイルサイズ
でかい。glitchtext.jsが辞書が巨大すぎて300kb以上ある。けどしょうがないし、まあキャッシュ効くからいいか
■サーバー
さくらVPSのdev.shokai.orgに、virtualhostでglitchtweet.com割り当てて使ってる。
■開発環境
まずglitchtext.jsはv8とRakeで単体でテストをしている。前に書いた。
glitchtweet.comのwebアプリ自体はローカルでwebrickで起動して、chromeの開発パネルでjsなどのデバッグをした。あとはiPhoneとAndroidのsafariのブラウザで開いて、見た目を調整した。
■なるべく画面遷移しない
jquery mobileやjQTouchを使うとネイティブアプリ風に外見で、横にスライドして表示を切り替えるwebアプリを作れるけど
面倒だったので使わなかった。visibleをon/offしてtweetボタンを表示したりしなかったり等している。
なのでviewのテンプレートは1つしかない。
■twitterログイン
生成したglitchテキストはoAuthでログインしてtweetされるが、ユーザ情報管理にDBは使っていない。
cookieにtwitterのoauth tokenとsecretを保存している。
最初の画面でログイン済みかどうかは、haml template上でtokenとsecretがあるかどうかだけで表示を分岐しているので、実際glitchtweet.com側では誰がどんなtweetをしているかは把握していない(しようと思えばできる)
■cookieでsession
sinatraでcookieベースのsessionを使うようにしている。
Rack::Session::Cookieを使う – 橋本詳解に書いた。
glitchtweet.comでは2週間cookieで保存するようにしている。
use Rack::Sessioin::Cookieしたらsinatraのsession関数がcookieを使うようになってくれた。
(これで大丈夫ですよね?)
■ホーム画面アイコン
<link href='http://glitchtweet.com/img/icon.png' rel='apple-touch-icon' />これをheadに書いておくと、iPhoneのホーム画面にブックマーク保存するとアイコンが付く。
Android2.3でもホーム画面にブックマークショートカットを作ったらアイコンが出るようになった。しかも角丸化される。apple-touch-iconって名前なのに処理してくれるAndroidえらい。
■テスト環境にwebrick使うようにした
開発中にSinatra1.2.1が出たのでupdateしたら、thinを使うとhttpリクエスト送った瞬間に問答無用で強制終了するようになった。
webrick使うようにした。
Sinatra1.2.1とthin1.2.10を同時に使うと死ぬ – 橋本詳解
■viewport
@hitoriblogさんに教えてもらった。
適当なhtml/cssを書いていてもiPhoneではそれなりに正しいサイズで表示されるんだけど、Androidではテキストエリアをクリックした瞬間にものすごいズームをされてしまう。
これはviewportをheadに指定しておくとなんとかなる。Androidはデバイスがたくさんあるので、画面サイズが微妙に違うのでwebサービス作ってる人は大変そう。
<meta content='width=device-width, user-scalable=no' name='viewport' />このへんも参考になる。
■shakeイベント
ネイティブアプリではshakeのイベント、つまりiPhone本体を振ったイベントを取得して、undoに使われている。
全く、操作と実行内容の関連付けが最も意味不明な機能だと思う。
でもiOS4.2からsafariでも加速度センサーが使えるようになったので、せっかくだからshakeイベントを取れるjsライブラリを作った。
shokai/js-iphone-shake-event – GitHub
glitchtweet.comでも使っている。tweet後に、もう一度同じソースからglitchしたい時にshakeすると消えた文字が復元される。
これについてはあとで書く。
■iphone-js-console
shokai/iphone-js-console – GitHub
iphone-shake-event.jsを作っている時に、iPhone実機でのデバッグをする為に作った。
パソコンのterminal上でjsを書くと、iPhone上で実行されたり、パソコン上でiPhoneのブラウザ上のjsの値を読み出したりできて便利。
これについてもあとで書く。
Macのsaykanaをhttpから使えるようにした
saykanaをリモートから使いたかったので作った。Macをterminalから喋らせれるアレ。
sinatraで作っていて、http postされた文字列をsaykanaで読み上げる。これが研究室のMacProのpassengerで動いているので、他のマシンからでも研究室のMacしゃべらせれて大変楽しい。
なんか説明書こうかと思ったけどgithubのreadmeに書いたからいいや
rb-mecabが必要。saykanaがひらがな・カタカナしか読めないので、漢字をかなに変換するのに使っている。
http-postでsaykanaさせるAPIが使える。/sayにpostパラメータ message で送ればいい
/ にHTMLで書いたformがあってそこからもsayさせれる。
sayやsaykanaやafplayをsshからログインしたmacで使ったり、apache+passengerで使うと
ConnectPort: can’t find mach server port name = jackdmp_entry.502_default err = unknown error code
というエラーが出て音がならないんだけど、解決方法があった
とりあえず一旦どのユーザでもいいのでGUIでログインすれば使えるようになる。
すぐログアウトしていいので、適当なユーザーを作ってパスワードなしで起動時にログインするように設定しておいて.bashrcにlogoutとか書いておけばいいんじゃないかと思う(まだ試してない)
gyaazzというアウトラインエディタ風wikiを作っている
増井先生が作ってるgyazzが元ネタ。JavaScriptの勉強がしたくてN村ヒロユキっていう人と作った。
ダブルクリックした行から編集できる。方向キーか、ctrlキーを押しながらemacs的操作でカーソル移動できる。
一応アウトラインエディタなので、ctrlやshiftを押しながらキー操作するとブロック毎移動したりインデントしたり、ブロックまるごと入れ替えたりできる。
[[ と ]]で囲んだ部分がURLならリンクに、画像へのURLだったらimgタグに、URLでなければ新しいwikiページへのリンクになる。
しばらく操作しないで置いておくと、右下に「saved!」と表示されて編集が保存される。
あと他の人が編集するとsyncする。
UIはjQueryを使ったので、JSよくわからないけど2、3日でエディタ的機能は実装できた。
サーバー側はSinatraを使っている。ページのデータをJSONで返す簡単なAPIが用意されている。なので一番上の階層に小文字で「api」というページは作れない。
データベースにはTokyoCabinetを使ってる。
ソースコードとインストール方法はhttp://github.com/shokai/gyaazzにある。
でもmongodb使って作り直そうかな
あと、
- ページ名の変更
- ページのコピー
- 認証付きページを作れる機能
エディタ保存したらブラウザリロードするsinatra/auto-reloadを作った
エディタを保存したらブラウザを自動リロードするsinatraプラグインを作った。
これでサブモニタにchromeとJavaScriptコンソール置いておくと幸せになれる。
ソースはgithubに。
Google ChromeもしくはFirefox+Greasemonkeyで動作する。エディタには依存しない。
sinatraアプリをローカルではなくサーバーで実行していてもリロードできる。
■インストール
sudo gem install sinatra-auto-reloadrubygems.orgに置いたので、gemコマンドでインストールできる
■使う
sinatraアプリ内で読み込む
require 'sinatra/auto-reloader' if development?if development? すると、shotgunか -e development オプションを付けて起動した時だけ有効になる。production環境には影響を与えない。
■ブラウザ拡張をインストール
localhost:4567 でアプリを起動しているとして、
http://localhost:4567/sinatra_auto_reload.user.js にgreasemonkeyスクリプトが生成される。
Firefox 3.5+Greasemonkey、もしくはChrome 5.0のuserscriptとしてインストールできる。
スクリーンショット

ホスト名ごとに違うuserscriptとしてインストールされるので、調べ物して同じブラウザで他のページを開いても大丈夫

■監視しないファイルを定義
sinatraアプリ内でauto_reload_ignoresという関数を定義しておく
def auto_reload_ignores配列内に正規表現で書いたファイルは、更新されてもリロードしない。logとかpidに反応しても困るので。
[/db.*/, /config.yaml/, /log.*/, /pid.*/]
end
ところでプラグインに変数を渡すのは、こういう方法でいいんですかね?もっとまともなやり方がある気がするんだけど。
■しくみ
sinatra/baseに新しくgetでアクセスできるページを追加し、 http://hostname:port/sinatra_auto_reload にファイルの最終更新日時が出るようにした。
これをuserscriptからsetIntervalで監視して、更新があればリロードする。
■参考
JavaScript部分はこれを参考にした
最速インターフェース研究会 :: Firefoxでの開発を高速化する自動リロードスクリプト
■オススメ
sinatra-reloader か shotgun と一緒に使うのをおすすめします
sinatraはサーバーを再起動しないとrubyのコードの変更を読み込んでくれないんだけど、こいつらを使うと毎回読み込み直してくれるようになる。
■今後
よく考えたらSub URIで動かしている場合に動かなそうだ。あとで修正する。

最近のコメント