はじめに
よくrubyを電卓代わりにしているんですが、計算結果を確認するために次のようなコードをしょっちゅう書きます。
length = 100.0
time = 5.0
speed = length / time
puts "speed = #{speed}"
この一番最後の行、puts
のところ、変数名が2回出てきてRepeat yourself感がしてとても嫌です。変数名に意味をもたせているのだから、それをそのまま表示してくれればいいのにーと思います。
ちょっと電卓叩いて結果表示するだけの目的なのだから、もっとタイプ数減らして楽したいです。
なのでDon't repeat yourselfなメソッドを書きました。ついでにgemにしました。
インストール&使い方
$ gem install print_variable
でインストールできます。
こんな感じに使います。表示したい変数のSymbolを返すブロックを渡します。
Symbolの配列にすれば複数可です。その場合、一番長い変数名に合わせて変数名を左詰めで表示します。
require 'pv'
var = 1
var2, var_foo, v = 2, 3, 4
pv{:var} #=> var = 1
pv{%i(var2 var_foo v)} #=> var2 = 2
# var_foo = 3
# v = 4
せつめい
変数とその値を表示するだけなんだから、変数のSymbolでも渡してやれば簡単にできる!そう思っていた時期がありました。
def pv(symbol)
puts "#{symbol} = #{eval(symbol.to_s)}"
end
var = 1
pv :var
# => undefined local variable or method `var' for main:Object
pvメソッドのスコープの中ではvarが定義されていないので、エラーになりました。
つまりeval(symbol.to_s)
は、メソッドを呼び出した場所のスコープで実行する必要があります。スコープの情報を渡すときに使うものといえば、そうKernel#binding
です。
def pv(symbol, bind)
puts "#{symbol} = #{bind.eval(symbol.to_s)}"
end
var = 1
pv :var, binding
# => var = 1
期待通りに動きました。でもいちいちbindingとか渡してやるのはクソ面倒です。
なんかもっとこう、書きやすく出来ないものか考えました。
…そういえば、rubyのブロック付きメソッドを呼び出す時、ブロックのスコープは呼び出した場所になっていたような?
def pv(symbol, &block)
bind = block.binding
puts "#{symbol} = #{bind.eval(symbol.to_s)}"
end
var = 1
pv(:var){}
# => var = 1
期待通りです!タイプ数が少し減りました!黒魔術感が増しました!
もっと括弧を減らしていきましょう。
def pv(&block)
symbol = block.call
bind = block.binding
puts "#{symbol} = #{bind.eval(symbol.to_s)}"
end
var = 1
pv{:var}
# => var = 1
だいぶ楽になったような気がします。
これに例外処理や、Symbolを複数渡せるように少し弄ったものがgemになっています。
print_variableと言いつつ、定数やメソッド名も表示できます。
CONST = 2
pv{:CONST} #=> CONST = 2
def mthd; 3 end
pv{:mthd} #=> mthd = 3
おわりに
これ以上タイプ数減らす方法あったらコメントください。
(2014/12/05追記)
binding_of_caller
@pasela さまに教えていただきました!ありがとうございます!
binding_of_callerというgemを使うともっと簡単に出来ました。
require 'binding_of_caller'
def pv(symbol)
puts "#{symbol} = #{binding.of_caller(1).eval(symbol.to_s)}"
end
var = 1
pv :var
# => var = 1
READMEを見ると
Recommended for use only in debugging situations. Do not use this in production apps.
Only works in MRI Ruby 1.9.2, 1.9.3, 2.0, 2.1 and RBX (Rubinius)
とかなんか怖いこと書いてありますけど気にしない(゚ε゚)
怖いのが嫌な場合は、私の作ったgemを使ってくださるといいと思います。