-> 12 { 01 / 20 }
Ruby 1.9 で起動オプションで外部エンコーディングを指定する
1.9 をよく解ってないオールドタイプの secondlife ですこんばんは。Ruby 1.9 では外部エンコーディングの Encoding.default_external はロケール( $LANG )によて変化する。
$ echo $LANG ja_JP.UTF-8 $ ruby -e "puts Encoding.default_external" UTF-8
$ echo $LANG C $ ruby -e "puts Encoding.default_external" US-ASCII
外部エンコーディングを考慮してない、かつ UTF-8 を扱うスクリプトだとエラーになったりする。そんなときは
ruby -EUTF-8 script
で起動オプションで指定してやると良い。gem ライブラリのような場合
ruby -EUTF-8 -S command
とすると path から探索してくれる便利!後ろの席の Ruby コミッターに教えていただきました。
-> 12 { 01 / 17 }
Ruby で解りにくい例外の発生元を調べる
例えばインテグレーションテストで
Failure/Error:
expected there to be content Internal Server Error undefined method `name' for #<Hash:0x11b7d7578> WEBrick/1.3.1 (Ruby/1.8.7/2011-12-28) at 127.0.0.1:62045"
# ./spec/integration/foo_spec.rb:174
みたいな例外が起きたとき、ぱっと見どこから呼び出させるのか解らなくて生きるのが辛い。name ぐらい汎用的な名前だと grep で引っかからないし。そんなときは
class Hash
def name
require 'pp'; pp caller.to_a
end
end
みたいにオーバーライドしてメソッド定義しちゃうとあら簡単に解ります!特にこの場合なら spec/integration/foo_spec.rb の該当行らへんにかけば影響範囲も単体テストなら少なく探しやすい!
なんか泥沼っぽいですけど知っておくと便利!!同僚に教えて貰った。
-> 12 { 01 / 16 }
AWS のリージョン/エンドポイント一覧と aws-sdk での設定
AWS の各種サービスの API を叩こうとするとエンドポイントの指定が必要。いつも探すときググったりして面倒だったんだけど一覧ページあったんですね便利!!(なかなかたどり着けなかった…)
s3 のエンドポイントはサブドメイン区切りじゃなくて - (ハイフン) 区切りだったりしてカオスな…。
で、ruby のオフィシャルライブラリの aws-sdk でこのエンドポイントを設定するんですが、こいつの設定方法もソースの読み方解らないとハマリがちで、例えば SimpleDB だったら SimpleDB のライブラリの何処かに書いてあるかと思いきや、最上位のコンフィグで指定するので SimpleDB 以下のコードを読んでも解らない。正解は aws/core.rb か aws/core/configuration.rb にのってるので、それらの apidoc かソース見ればおkな感じ。うーん。
-> 12 { 01 / 04 }
Ruby 1.8.7 の hashdos 対応による挙動の変更点
Ruby 1.8.7-p356 以前の人は p357 もしくは 1.9 にとっととあげよう、という話しなんだけど p357 にしたら一部テストがこけた。p357 ではハッシュの seed が起動毎に異なる*1ので
for i in {1..10}; do ruby-1.8.7-p357 -e 'p ({"fooooo"=>1,"baaaaar"=>2}).keys'; done
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["baaaaar", "fooooo"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["baaaaar", "fooooo"]
["baaaaar", "fooooo"]
["baaaaar", "fooooo"]
という結果になる。これが以前だと
for i in {1..10}; do ruby-1.8.7-p334 -e 'p ({"fooooo"=>1,"baaaaar"=>2}).keys'; done
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
["fooooo", "baaaaar"]
なため、Hash#keys の戻り値の順序が一定だ、と書いていたテストがこけるようになった。(そもそも順序が一定前提のテストが悪いんだけど)
うっかりダメな実装してる人はこれで挙動が事なり出したりするんじゃないかなぁ。
-> 11 { 12 / 20 }
mongodb で capped と capped でないコレクションの変換
現状ふつうには出来ないぽいので、いったんテンポラリテーブルをつくって、そこに書き込み、最後 rename する、みたいな。昔の RDB を思い出す感じ…。
たとえば capped な DB にしたい場合は
db.noncapped.validate(); // validate で size, max がどれぐらい必要か見積もっておく change_collection_type(db.noncapped, {capped: true, size: 1000000000}); db.noncapped.validate(); // capped:1 になってる
change_collection_type はこれ。ほんと JS すな〜。bulk insert じゃないので速度遅いけど、500Mぐらいのオンメモリなデータなら10秒ぐらいで終わった。だれか bulk insert 版書いて下さい。あとこのコレクションに CRUD の操作が走ってる場合、アップデート中その操作は失われると思います。(ロックされないので)
function change_collection_type(collection, options) { var collection_name = collection.getName(); var tmp_name = 'tmp_change_collection.' + collection_name; var remove_name = 'tmp_change_collection.remove.' + collection_name; var collection = db[collection_name]; db.createCollection(tmp_name, options); var tmp = db[tmp_name]; collection.find().forEach(function (d) { tmp.insert(d) }); collection.renameCollection(remove_name); tmp.renameCollection(collection_name); db[remove_name].drop(); }
1.8 系は順序保障なし。1.9 系は順序保障ありだと勝手に思ってました。
順序保障が必要な場合、1.8 でも 1.9 でも動くように Hash ではなく Array(偶数がキー、奇数が値) を使っています。格納数が小さい場合だけですが。
たまたまそういう挙動になっていて、その挙動前提で書かれたコードが問題になるかなぁと。