Rubyのdefの中で更にdefをするコードの挙動

defの中にdefを書いたらどうなるのか? そんな実験。

class Nanoha
  def starlight_breaker
    puts "魔力が足りません"
  end

  def battle!
    def starlight_breaker
      puts "全力全開、スターライトブレイカー!"
    end
  end
end

user = Nanoha.new

user.starlight_breaker
#=> (1)

user.battle!
user.starlight_breaker
#=> (2)

other = Nanoha.new
other.starlight_breaker
#=> (3)

battle! を実行したら、 starlight_breaker のメソッドが上書きされて収束砲を発射できそうなコードです。

さて、このコードを実行すると、(1)〜(3)では何が出力されるでしょう?

自信ある人は一度考えてみてください。回答はスペースを空けた下の方に書いてあります。

.
.
.
.
.
.
.
.
.
.
.
.

出力結果

実行結果は下記の通りです。

$ ruby nanoha.rb
魔力が足りません
全力全開、スターライトブレイカー!
全力全開、スターライトブレイカー!

新しいインスタンスを作っているのに、(3)でも「スターライトブレイカー!」になってしまいました!

解説

Rubyのレキシカルスコープの話なので、ちゃんと理解したい人は「Rubyのしくみ」を読むと良いです。

Rubyのしくみ -Ruby Under a Microscope-

Rubyのしくみ -Ruby Under a Microscope-

もしインスタンスの特異メソッドにしたいのであれば、 def self.starlight_breakerself をつけると下記のような挙動になります。

class Nanoha
  def starlight_breaker
    puts "魔力が足りません"
  end

  def battle!
    def self.starlight_breaker
      puts "全力全開、スターライトブレイカー!"
    end
  end
end

user = Nanoha.new

user.starlight_breaker
#=> 魔力が足りません

user.battle!
user.starlight_breaker
#=> 全力全開、スターライトブレイカー!

other = Nanoha.new
other.starlight_breaker
#=> 魔力が足りません

いや、defの中にdef書くコードとかプロダクトでは書いたらダメですよ?