How and why does this dynamic method definition work?

How does the following code work, and more importantly, why does it work this way?

class Example
  def one
    def one
      @value = 99
    end
    puts "Expensive Call"
    @value = 99 # assume its expensive call
  end
end

ex = Example.new
puts ex.one # => "Expensive Call"; 99
puts ex.one # => 99

Here, when the method is first called, oneRuby executes the external onemethod, but in subsequent calls, it only executes the internal method one, completely bypassing the external method one.

I want to know how this happens and why it happens.

+5
source share
3 answers

How it works

Ruby allows you to override classes at runtime because class and def are actually executable code. In your example, the code does the following:

  • Defines example # one method, which (re) defines the method Example # one when invoking the instance method.
  • def , . ( , /, .)
  • "ex."
  • ex, .
  • .

, . :

def my_method
  puts 'Old Method'
  puts  self.method(:my_method).object_id
  def my_method
    puts 'New Method'
    puts  self.method(:my_method).object_id
  end  
end

irb pry, :

> my_method; puts; my_method
Old Method
8998420

New Method
8998360

, ( ), . , , , .

+6

, . one @value = 99, .

+7

, Ruby , .

You define a new method inside a method β€” in this case, since the method being defined has the same name as the existing one, the new definition completely overwrites the original one.

What you have is equivalent (perhaps) to the more obvious:

class Example
  def one
    self.class.send(:define_method, :one) do
      @value = 99
    end
    puts "Expensive Call"
    @value = 99 # assume its expensive call
  end
end

It is clear here that you are defining a method in the context of a class.

+2
source

All Articles