Rubyは括弧をつけなくてもメソッドを呼び出せます。メソッド名は普通は英小文字で始まります。ローカル変数も英小文字で始まります。
こんなRubyプログラムを実行すると(ifの条件部で代入しているのはtypoではありません)、
def hoge 123 end p hoge x = 456 if hoge = x p hoge end p hoge
こういう出力が得られます。
123 456 456
途中でhogeがメソッド呼び出しから変数参照に変わったのがわかります。 変数宣言後は括弧「()」をつけない場合はメソッド呼び出しではなく変数参照になります。
def hoge 123 end p hoge # hogeメソッド呼び出しなので123 x = 456 if hoge = x # hogeにx(456)を代入。その結果は真なのでif内を実行 p hoge # ここでのhogeはローカル変数参照なので456 end p hoge # ここもローカル変数参照なので456
ところでRubyはif内が1行なら後置ifで記述できます。
if 条件 式 end
は
式 if 条件
と記述できます。
さっきのプログラムのifを後置ifで書き直してみます。
def hoge 123 end p hoge x = 456 p hoge if hoge = x p hoge
実行すると
123 123 456
結果が変わった!
Rubyがプログラムをどのようにパースしているかを見てみます。
最初の例では :var_ref
で変数hogeを参照していますが、
# ruby -rpp -rripper -e 'pp Ripper.sexp(File.read("a.rb"))' [:program, [[:def, [:@ident, "hoge", [1, 4]], [:params, nil, nil, nil, nil, nil, nil, nil], [:bodystmt, [[:@int, "123", [2, 2]]], nil, nil, nil]], [:command, [:@ident, "p", [4, 0]], [:args_add_block, [[:vcall, [:@ident, "hoge", [4, 2]]]], false]], [:assign, [:var_field, [:@ident, "x", [5, 0]]], [:@int, "456", [5, 4]]], [:if, [:assign, [:var_field, [:@ident, "hoge", [6, 3]]], [:var_ref, [:@ident, "x", [6, 10]]]], [[:command, [:@ident, "p", [7, 2]], ★ [:args_add_block, [[:var_ref, [:@ident, "hoge", [7, 4]]]], false]]], nil], [:command, [:@ident, "p", [9, 0]], [:args_add_block, [[:var_ref, [:@ident, "hoge", [9, 2]]]], false]]]]
後置ifの場合は :vcall
でメソッド呼び出しをしています。
# ruby -rpp -rripper -e 'pp Ripper.sexp(File.read("b.rb"))' [:program, [[:def, [:@ident, "hoge", [1, 4]], [:params, nil, nil, nil, nil, nil, nil, nil], [:bodystmt, [[:@int, "123", [2, 2]]], nil, nil, nil]], [:command, [:@ident, "p", [4, 0]], [:args_add_block, [[:vcall, [:@ident, "hoge", [4, 2]]]], false]], [:assign, [:var_field, [:@ident, "x", [5, 0]]], [:@int, "456", [5, 4]]], [:if_mod, [:assign, [:var_field, [:@ident, "hoge", [6, 10]]], [:var_ref, [:@ident, "x", [6, 17]]]], [:command, [:@ident, "p", [6, 0]], ★ [:args_add_block, [[:vcall, [:@ident, "hoge", [6, 2]]]], false]]], [:command, [:@ident, "p", [7, 0]], [:args_add_block, [[:var_ref, [:@ident, "hoge", [7, 2]]]], false]]]]
Rubyのパース処理はよく理解してませんけど、
p hoge if hoge = x
この行は実行時には if の条件が先に評価されるけど、パース時は左から処理するため、hoge変数はまだ宣言されてないとみなしhogeメソッドを呼ぶようにパースされる感じでしょうか。
Rubyおもしろい!