[ruby-core:66747] [ruby-trunk - Bug #10564] DelegateClass, method_missing, and instance_eval -- different behavior in ruby 2.1

From: jonathan@...
Date: 2014-12-08 20:20:36 UTC
List: ruby-core #66747
Issue #10564 has been updated by jonathan rochkind.


Okay, thanks. 

What I don't understand is, if `method_missing` is not defined in the `< DelegateClass(Object)` class, then I can still do:

~~~
my_lambda = o.instance_eval do 
   lambda {|a| a}
end
my_lambda #=> Proc object
~~~

And it works, and no method_missing on a superclass is called. 

But if `method_missing` is defined on the subclass, then it gets called.    Why is method_missing even being called, for a line that would work fine without calling superclass method_missing?

If not a bug, I still predict it's definitely going to be unexpected behavior for other developers that use DelegateClass, instance_eval, and method_missing together. 

----------------------------------------
Bug #10564: DelegateClass, method_missing, and instance_eval -- different behavior in ruby 2.1
https://bugs.ruby-lang.org/issues/10564#change-50336

* Author: jonathan rochkind
* Status: Closed
* Priority: Normal
* Assignee: 
* Category: 
* Target version: 
* ruby -v: 2.1.3p242
* Backport: 2.0.0: UNKNOWN, 2.1: UNKNOWN
----------------------------------------
This is an odd one, I don't completely understand. But there is different behavior in ruby 2.0 vs 2.1, and the 2.0 behavior is what I'd expect. Not sure if it's a bug, expected difference in behavior, or something else. 

Here is a minimized reproduction:

~~~
require 'delegate'

class DelegateWithMethodMissing < DelegateClass(Object)    

  def method_missing sym, *args, &block
    if sym == :lambda
      Kernel.raise Exception.new("Why is it catching lambda?")
    end
          
    Kernel.puts "Caught method missing for `#{sym}` with args: #{args}"
  end
  
end

o = DelegateWithMethodMissing.new( Object.new )

o.instance_eval do 
  missing_method "value"
  missing_method_with_lambda_value lambda {|a| a}
end  
~~~

On 2.0.0p576, this produces:

Caught method missing for `missing_method` with args: ["value"]
Caught method missing for `missing_method_with_lambda_value` with args: [#<Proc:0x007fa8532b3330@./spec/confstruct/test.rb:19 (lambda)>]

On 2.1.3p242, this instead raises the exception:

Caught method missing for `missing_method` with args: ["value"]
.test.rb:7:in `method_missing': Why is it catching lambda? (Exception)

Somehow the `lambda` inside the `instance_eval` is being caught by `method_missing`, instead of accessing the ordinary lambda keyword. If I remove the `method_missing` definition, then `lambda` can work as expected again, which is even more confusing. 



-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next