[2011-11-20 追記] stub を使えば戻し忘れの問題はないみたい。こんでいいのかな?
Rails 3.0.10 + RSpec 2.6.0 のお話。
すごく当たり前なんだけど、RSpec の block で区切れる書き方を見慣れてたら忘れてしまっていたこと。
Rails.env 変更したら spec の実行全体に影響します。
そらそうだ。
ダメな例
具体的には
module FooHelper
def bar
if ( Rails.env.production? )
...
end
end
end
こんな感じのヘルパーメソッドをテストするために
desribe FooHelper do
context 'production' do
before {
Rails.env = 'production'
}
it {
bar.should == baz
}
end
context 'development' do
before {
Rails.env = 'development'
}
it {
bar.should == qux
}
end
end
なんてことをしてたんだけど、他のspecが落ちちゃう。なんでかなーと悩んでたんだけど、何のことはない。
after(:all) {
Rails.env = 'test'
}
で戻しておきましょうっていうだけだった。
もう一度。
そらそうだ。
stub にするのが正解かな?
stub にすれば block 内だけ変更されるみたい。自分の場合は RR を使っているので
stub(Rails.env).production? { true }
とすれば本番環境用の動作に切り替えることができる。これであれば RSpec の作る block 内でだけ影響するみたい。少なくとも戻し忘れて他の spec が落ちるような動作はしないように見える。
まずは Rakefile を作る
先日の準備からサクッと一ヶ月以上経過してようやく作業を開始。まずは作業の流れを整理する。
- styles.xml をいじる
- styles.xml を含むファイルを styles.odt という名前で zip アーカイブに仕立て直す
- styles.odt を –stylesheet に与えて rst2odt.py で reST ファイルから .odt ファイルを生成
- できあがった .odt ファイルを(Macなので)open を使って OOo で開く
これを気に入ったスタイルができあがるまで延々くり返す。
同じ作業を延々くり返す…。
Rakefile を書きましょう。
今回は初めてまともに file タスクを作った。これを使うと変更があったときにだけ生成や変換が行われるようになる。task タスクだと毎回愚直に実行される。
cf. Rake
ここまでできた
wtnabe's rst2odt_stylesheet at master - GitHub
この日記を書いている段階で
- ページを A4 に
- フォントを IPAex に
- IPAex は日本語を monospace で欧文を proportional で表現してくれるので細かくフォント指定せずにそのまま書き連ねるのに向いている
- 日本語では不自然なイタリックを除去
- 箇条書きの記号を大人しく
できた。
また styles.xml じゃなくて command line argument –table-border-thickness で border-width を設定。
諦めたのは
- table cell の padding 調整
- 見出しに prefix を付ける。
辺り。
table の border もそうなんだけど、table-cell への style を指定する方法がないみたい。table-cell は一つ一つに名前が付いて細かく style を指定するから stylesheet としてデフォルトを当てるのは無理っていう設計なのかな。
見出しの prefix はこれは恐らく個人的な要望で、どういうことかというと、見出しって普通文字を大きくしてボールドにして…とかやるんだけど、日本語の「普通の文書」だとこの見出しってあんまり大きくしない方がバランスいいと思う。なんだけど、やっぱちょっと目立ちにくい。そこでいつもやってるのは
行頭にそれっぽい記号を入れる
方法。これで文字サイズを極端に変えずに見出しとしての attention を維持しようという考え。
で、その prefix の挿入を自動でできないかと思ったんだけど、とりあえず CSS の
h1:before {
content: '■ '
}
みたいなことはできないっぽいので手で入れることにして逃げました。そこにこだわって時間掛けても仕方ない。
あとは地の文だけ(table 内のテキストなどは対象外)にインデントが設定できればほぼ満足かなぁ。
良い副作用
[2010-10-23 追記]
この方法で .odt を作ったら思わぬ副作用があった。できあがったファイルを OOo で開いて PDF にエクスポートするとちゃんとアウトラインを保持した PDF を作ることができる。
当たり前っちゃ当たり前なんだけど、これはなかなか感動的。そんなに長い文章を書くことは多くないけど、やっぱり構造が見やすいのは良い。とても良い。
注意とか疑問まとめ
- table の border を stylesheet で指定する方法はない。コマンドラインオプションで与える。
- list の indent は Emacs の rst-mode が正しくサポートできていない。上の階層から 3文字下げるとちゃんとレベルが下がるが、rst-mode は 2文字下げで止まってしまう。
- indent を含む list の変換が微妙。
* 上のレベル
* 次のレベル
これは OK
* 上のレベル
* 次のレベル
これは NG
違いは行頭の空白。reST では bullet の前に space は置かない方が良いらしい。ただし indent がない場合は行頭に空白があってもなくてもよい。
うーん難しいわ。特に Trac の Wiki と併用していると混乱必死。Trac も基本的に reST で書くようにしちゃえばいいのかなぁ。
関連エントリ
心の叫び
Ruby 製のプロセス監視ツール、God を試してみた。(書いてる時点より5ヶ月前…。)
モダンに監視したい
なぜなら TIG が落ちるから(笑)
実は Un*x 系の OS なら素朴な監視は割と簡単にできる。
- ps
- grep
- /etc/rc.d/* とか /etc/init.d/* とか
- sendmail
辺りで事足りる。要するに
定期的に ps を叩いて、この文字列のパターンがない場合はこのプロセスが落ちてるから mail 投げて起動スクリプトを呼ぼう
ってだけ1。これだけでプロセスが落ちてたらまた起動し直すということが可能なので、知らん間にサーバ落ちててオレ涙目っていう状態を減らすことはできる。少なくともすでに上の道具が使えているなら新しいことを覚える手間はないので、どうしてもすぐ監視を始めたい場合にはこれだけでも十分有効だと思う。
でも効率が良くない。ちょっと複雑なことを考え始めると fork の嵐になって2地球に優しくないし、cron で回すのもタイミングによっては大きな負荷になる。(朝方とか。)
それに sh スクリプトは処理の部品化も一苦労。できれば凝ったものはあまり書きたくない。
なんで daemontools や runit, monit じゃないの?
- どれも知らない
- どれも独自の文法で設定を書かなきゃいけない
- djbware はメンドウというもっぱらの噂
だったらどれ使っても一緒。でも
ツールに入っていない機能(通知方法とか)を使いたいと思うときがきっときて、そのときの拡張しやすさは Ruby 製の God の方が上だと思う
というか
Ruby が好き
だから。使ってみての比較ではないのでそういう意味では参考にならない。
参考
なぜ daemontools を使うのか - kazuhoのメモ置き場
こんな意見もある。これと比べると
- ログのローテート機能はない
んだけど、それは logrotate や rotatelogs を使えばいいんじゃないかという気がしている。特に困ったことがないのはヌルい使い方しかしてないからかもしれないので鵜呑みにはしないでね。
Ruby でやって、重くないの?
kqueue や netlink_handler を使っているので監視部分のコストは高くないっぽい。Ruby 本体とスクリプト分メモリを食うのはしょうがない。
Windows には対応していないので悪しからず。
サイト
- God - A Process Monitoring Framework in Ruby
- 「クックパッド」の裏側にいってきた
- 自分が God を初めて知ったのはこの記事
インストール
拡張ライブラリがあるので ruby-devel や ruby-dev とかのパッケージも入れておこう3
$ sudo gem install god
で ok.
使ってみる
god の gem にも example はあるんだけど、もうちょっと試しやすいように
を git clone するか Download Source のリンクから丸ごと取得する。
どれでもいいんだけど、leaky.god を試してみる。leaky.god の中身はこんな感じになっている。
God.watch do |w|
w.name = "leaky"
w.interval = 5.second
w.start = 'ruby ' + File.dirname(__FILE__) + '/scripts/leaky.rb'
w.start_if do |start|
start.condition(:process_running) do |c|
c.running = false
end
end
w.restart_if do |restart|
restart.condition(:memory_usage) do |c|
c.above = 2.megabytes
end
end
end
細かい説明はしないけど、
- leaky.rb が起動していなかったら起動する
- 消費メモリが2MBに達したら再起動する
という動作をする。
god -c leaky.god
と打って god を起動し、Activity Monitor や後述の topless, watch などを使って Ruby プロセスの様子を確認してみると、God 自身が使っているプロセスと、どんどんメモリが増えていって 2MB に達したら再起動するプロセスを確認することができる。
試しに再起動をくり返しているプロセスを手動で強制終了してもやはり帰ってくる。
設定を変える
手動で強制終了と言っても2MBにはあっという間に達してしまうので、あっという間に再起動が掛かって強制終了できない、と思うかもしれない。そこで God が監視する interval を延ばしてみよう。先ほどの leaky.god の
w.interval = 5.second
ここを書き換える。15.second くらいあれば十分だろう。書き換えたら leaky.god を保存して
god load leaky.god
すると今の変更が反映される。これで手動で強制終了しやすくなった。
当然監視の間隔が延びたので、設定容量である 2MB を越えてしまったり、強制終了後の再起動までに掛かる時間も延びてしまうが、そこは仕方がない。あくまで実験なので。
終了する
さてこれで leaky.rb は普通の方法では終了することができなくなった。じゃあどうやって終了するのかというと、
god stop leaky
と打つ。この leaky は watch のところで定義してある name を反映している。god ファイルの名前じゃないので注意。God そのものを終了したければ
god quit
ただし監視しているプロセスのことは気にせず終了してしまうので、
god terminate
を使うようにしておいた方がいいと思う。詳しくは
god --help
と打てば確認できる。
Growl への通知を追加してみる
God は標準でも mail だけでなく twitter や各種 webhook への通知が可能になっているが、試しに Growl への通知を追加してみた。動いたときの Twitter への POST がこれ。
Twitter / wtnabe: できたできた。http://bit.ly/bD38Z …
まずは
gem install ruby-growl
で
RubyForge: ruby-growl: Project Info
をインストール。そして
god_extension/
|-- god_growl.rb <-- 追加
god_examples/
|-- README.textile
|-- leaky.god
|-- lib/
|-- pids/
|-- rails/
|-- scripts/
| |-- crashy.rb
| |-- leaky.rb
| `-- stable.rb
|-- simple.god
`-- sinatra.god
ディレクトリの構造はこんな感じで、god_gworl.rb というファイルを以下の内容で作る。
simple.god を以下のように Growl を利用するように書き換えて、
Growl がネットワーク越しに通知を受け取れるようにして
god -c simple.god
で実行。
ここから実行される crashy.rb は次々 crash するんだけど、それが God に捕捉されるたびに Growl に通知が来る。なかなか面白い。
その他、気づいたこと
基本的に God 1プロセスで複数のプロセスを監視することになる。その場合、当然監視対象ごとに設定ファイルを分けた方が読みやすいので
God.load /path/to/GOD_CONFIG
で設定ファイルを読み込む処理を書いた設定ファイルを
god -c
で指定して立ち上げることになる。
もし監視する God そのものを増やす場合は God と通信するためのポートもその分必要になる。
監視対象プロセスの起動順に関する疑問
例えば TIG のあとに tiarra、といった具合に起動する順番が大切になっているものを希望通りに立ち上げるにはどうしたらいいんだろう。
- 順番に load を書いていく
- よくある感じで設定ファイルの名前を数字始まりにしてまとめて読む
やっぱ 2 なのかな。
さて。以前からチェックだけしておいた Rails を今月に入ってちょこちょこいじり始めている。
春先に PHP でオレオレフレームワークのかけらほどを作ってみた経験があったので、以前のようにあまりにぼんやりと「なんか便利らしい。ふーん。」程度の認識ではなくなっており、半ばなんぼのもんじゃいという奢った気持ちで手を出してみたら、これが全然訳分かんない。
いや正確には手順に従えばいいっていうのは分かっていて、従った場合には何が起きているのかは分かる。でもなぜその動作をするのかと、示された手順から踏み外した場合にどうすればいいのかがよく分からない。甘く見てました。
そもそも手元のがすでに古くなってきている。1.0 前の記述であり、migration は付録扱いだし、migration は 1.1 で generate model とうまい具合に統合されているし、rake migrate は deprecated だし、この段階でかなり話が噛み合ない。おぉう。もちろん基本の構成は変わっていないので十分通用するんだけど、いちいち出てくる手順で mysql のコマンドを直叩きしてくれちゃっているので、雰囲気が結構違う。やばい、早くやっつけてしまわなければ。
以下、思ったこと。
- 最初のうちはまず model を generate しろ
- migrate のひな形も作ってくれるので Rails の「意図」を理解しやすい
- model は単数形
- てことはやはり modeling がかなり重要な予感
- 失敗した!と思ったら destroy model Modelname で ok
- 逆に要るものをうっかり destroy すると結構悲しいのである程度の形になったらさっさとバージョン管理する
- scaffold は migration を書いて rake db:migrate してから
- でないと旨味半減
- どういう便利メソッドがあるのかよく分からねぇ
- script/console チョー素敵
- helper って特異クラスなのねチョーかっこいい
- でも model の方は ActiveRecord::Base を、controller は ActionController の方を覗いて行く必要あり。まぁそれでいいか。
- database.yml の adapter は require するものを書く
- sqlite3 が使いたければ sqlite3 と書く。sqlite だと使えない
- この設定はサーバを再起動しないと反映されない
- migration の際には ruby がゼロから起動するので反映される。気づきにくい。
- model でデータの絡む処理を、controller で URI の定義を行う
- flash にしびれるぅ、あこがれるぅ
- 次のリクエストでサクっと使えるっつーのはニクいなぁ、こうきたか。
- 録っとくように言われていたドラマを DVD-R に焼いてレコーダの空き容量を確保
- 最初のうち面白がって録画していた世界遺産とかどうせ見ないものをばばっと早送りしながら削除
などの作業完了。
テレビね、見ないんですよね。最初の頃は見る時間が自由に設定できるから喜んで録画してたんだけど、意外とダラダラしたいときに、その場で流れている番組をなんとなく眺めているだけでオッケーで、例えばじっくり腰を据えて見たい番組(世界遺産とかNHKスペシャルとか)をね、そもそもじっくり見る体力がないというか。テンションが保たなくて見続けられない。レコーダがいちばん活躍しているのはナガラで見れるものと、とりあえずの追っかけ再生だな。
なんつーか、そもそも情報や知識のもととして自分は映像を使いこなせないみたいだ。でもこれは特に最近顕著な話で、例えば本なんかもちょっと読み切れないことが増えている。Web どっぷりで短時間に大量のテキストを浴びる、しかもある程度「ついていかなきゃ感」がある生活をくりかえして、自分で自分の首を絞めている感じ。
いつも「もう少しスキルや知識量が上がったらちょっと余裕ができるんじゃないか」と思いながら必死で情報収集して試して租借して、ってやってるつもりなんだけど、思いのほか自分のものになるまで時間が掛かり1、そうこうしているうちに新しい情報がどんどん手に入ってしまい、焦る。
それでも「楽するための努力」の部類なのは間違いないから、いつかある程度報われるんじゃないかなと楽観もしている。それまで、ちょっと教養を磨いたりする時間は削るしかないかなとも思っている。睡眠時間が削れないタイプ2なので、いちばん削りやすい時間はその辺の時間なのだ。食事の時間とかダラダラする時間とか酒飲む時間とかあんまり削りたくないし、そういうの削ると荒んじゃうので。
もう!
PukiWiki と言い、どうなってんのよ!
……と書いてしばらく待ったら繋がるようになった :-P
http://scl.littlestar.jp/revwiki/
へー。
トランスレータ API のページの中身がないのが残念だけど、setext が好きだったし、PukiWiki のデータが放り込めるかもしれないし1、履歴管理にも期待。
別に DNS 騒ぎで逃げ出したくなったわけではない。 ↩