LoginSignup
4
3

More than 5 years have passed since last update.

変数の名前と値を表示するメソッド

Last updated at Posted at 2014-12-03

はじめに

よく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でも渡してやれば簡単にできる!そう思っていた時期がありました。

pv1.rb
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です。

pv2.rb
def pv(symbol, bind)
  puts "#{symbol} = #{bind.eval(symbol.to_s)}"
end

var = 1
pv :var, binding
#=> var = 1

期待通りに動きました。でもいちいちbindingとか渡してやるのはクソ面倒です。
なんかもっとこう、書きやすく出来ないものか考えました。

…そういえば、rubyのブロック付きメソッドを呼び出す時、ブロックのスコープは呼び出した場所になっていたような?

pv3.rb
def pv(symbol, &block)
  bind = block.binding
  puts "#{symbol} = #{bind.eval(symbol.to_s)}"
end

var = 1
pv(:var){}
#=> var = 1

期待通りです!タイプ数が少し減りました!黒魔術感が増しました!

もっと括弧を減らしていきましょう。

pv4.rb
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を使うともっと簡単に出来ました。

pv5.rb
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を使ってくださるといいと思います。

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3