Ruby のメソッド間では、ふつうは変数は共有されません。
def counter_set x = 0 end def inc x += 1 end def counter_value x end counter_set inc inc counter_value
は最初の inc 呼び出しのところで
undefined method `+' for nil:NilClass (NoMethodError)
のエラーが出ます。これは Ruby の仕様で、却ってメソッドは安全ともいえるわけです。もし変数を共有したければ、メソッドではなく、クロージャである proc を使えば事足ります。
x = 0 inc = proc do x += 1 end inc.call inc.call x #=>2
という具合に。
しかし、これでは「イヤだ」、メソッドを使いたいと仰るわがままな方もおられましょう。これはじつは、Ruby のメタプログラミングを使えば可能です。
def counter_set x = 0 define_method(:inc) do x += 1 end define_method(:counter_value) do x end end counter_set inc inc counter_value #=>2
こんな具合ですね。Module#define_method のメソッド定義がブロック(Ruby のブロックはクロージャです)で行われているために、変数 x が透過して保持されます。
同様のことは、メソッドだけでなくクラスやモジュールでも可能です。
- 作者: Paolo Perrotta,角征典
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/10/10
- メディア: 大型本
- この商品を含むブログ (2件) を見る
なお、上のはなんちゃってメソッドですが、もし冗談にせよ使うなら、こんな感じの方がいいかも知れません。
module Kernel def counter_set x = 0 Kernel.send(:define_method, :inc) do x += 1 end Kernel.send(:define_method, :counter_value) do x end end end
これなら、クラスの中でなど、どこでも使えます。例えばこんな感じ。
counter_set class A inc def initialize inc end end counter_value #=>1 A.new counter_value #=>2