Posted at 2007/09/14 13:01
in Ruby
/ Comments (0)
Ruby(や Perl)の範囲式 .. は、if 等の条件文内(やスカラーコンテキスト)で使うと、条件1でONになり条件2でOFFになるという、フリップフロップのような動作をする:
% ruby -e '10.times do |i| print i if i == 3 .. i == 6 end'
3456
しかし、範囲式をメソッドに追い出してしまうと、期待する動作をしなくなる:
% ruby -e 'def foo(i) print i if i == 3 .. i == 6 end; 10.times do |i| foo(i) end'
3
おそらく、範囲式の状態はローカルスコープになっているため、メソッドを抜けたところで消えてしまうんじゃないかと思う(フリップフロップだけに「揮発」か?)。利にはかなってるかもしれないけど使いづらい。
ちなみに Perl の場合はというと:
% perl -e 'for (1 .. 10) { print if $_ == 3 .. $_ == 6 };'
3456
% perl -e 'sub foo { print if $_ == 3 .. $_ == 6 }; for (1 .. 10) { foo };'
3456
といった具合で、実に期待通りに動く(多分 closure 的に状態保持してるんだろう)。
じゃあ Ruby でも closure にしてみればいけそうかな?:
% ruby -e 'foo = Proc.new do |i| print i if i == 3 .. i == 6 end; 10.times do |i| foo[i] end'
3456
めでたしめでたし……?
Posted at 2007/07/30 19:28
in Ruby
/ Comments (0)
Ruby で設定ファイルを読み込む定番は Kernel.load だけど、なんとなく設定項目をローカル変数にしたら何も読み込まれなくて、きょとん。
~./someconf:
someconf = 'is in HOME'
p local_variables
p self
some.rb:
somerb = 'is in somewhere'
load '~/.someconf'
p local_variables
p self
実行結果:
/path/to/somewhere>ruby some.rb
["someconf"]
main
["somerb"]
main
/home>
どうやら load 元と load 先ではスコープが違うらしい(load 先が別メソッド内にあるような感じ?)。self は共通なので、インスタンス変数にするのが正解なのかな(@someconf みたいに)。
Posted at 2007/04/18 12:24
in Diary|Ruby
/ Comments (0)
* 12:55 mistral
内部データの保存を Marshal.dump から YAML.dump に変更したら、文字コード指定付き Regexp の復元でこけたorz
あと、素の文字列と(YAML化に伴って)\ でエスケープされた文字列それぞれから作った Regexp は hash が違うので(String のままなら一致するのにー)、それぞれを Hash に突っ込んだら重複してしまう。むーん。
可読形式で保存したほうがいろいろ楽かなーと思ってたんだけど、ますますめんどくさくなりそうなので Marshal に戻そう(しくしく)\。
Posted at 2007/04/10 21:13
in Ruby
/ Comments (0)
404 Blog Not Found:perl|javascript - 文字列じゃないhash key
JavaScript や Perl の場合ハッシュのキーは文字列限定なので、オブジェクト(Perl はそのリファレンス)をハッシュのキーとして使った場合、ハッシュからキーを取り出したらもはやオブジェクトではなくなってしまう、という話かな(Tie::RefHash なんてあるのね……)。
Ruby の場合、データはすべてオブジェクトであり、ハッシュは「オブジェクトとオブジェクトを関連付ける入れ物」なので、キーにしたオブジェクトをハッシュから取り出しても元のオブジェクトのまま。そのため、以下のような破廉恥(?)なコードがごく自然に書けてしまう:
input = [ 'hogehoge', 'foooooooo', 'nyoron' ]
reply = { 'hoge' => 'fuga', /fo+o/ => 'bar' }
input.each do |instr|
reply.each do |key, val|
puts "#{instr} -> #{val}" if instr[key]
end
end
このコードは、配列 input の各文字列に対して、ハッシュ reply のキー(文字列または正規表現オブジェクト)を引数に [] 演算子を適用し、結果が FALSE/nil でなければハッシュの値を表示する。文字列の演算子 [] は、[] の中身が文字列なら普通の比較、正規表現オブジェクトなら正規表現にマッチする文字列を返す(一致・マッチしなければ FALSE/nil を返す)。実行するとこんな感じ:
> ruby test.rb
hogehoge -> fuga
foooooooo -> bar
>
ちなみにこれ、最近遊びで書いてる IRC bot "mistral" の自動応答機能の心臓部の抜粋なのだけど、Ruby のこの性質のおかげで、特に工夫するでもなくキーワードに文字列だけでなく正規表現も使えてしまうので便利(キーワード登録時には正規表現であることを明記する I/F は必要だけど)。
Posted at 2007/04/05 10:33
in Diary|Programming|Ruby
/ Comments (0)
* 10:30 mistral
たいぷちゃんの nak にインスパイアされた IRC bot を作り中。といっても nadoka の plugin なのでたいして難しいことはしてないのだけど。
とりあえず、発言の URL から TITLE 拾ってくる機能は実装したので、某香港チャンネルに放流。