Search code examples
rubyexceptionmessagemethod-missing

How can I get Ruby 2.1.5 to report an object's class for a missing method error?


This line:

@page = @page.launch_profile(@profile_name)

is causing this error:

undefined method `launch_profile' for #<Object:0x007f9013d785e8> (NoMethodError)

If I add puts "Page = #{@page} "{@page.class}" immediately before the call that complains, I get

Page = #<OwnProfilePage:0x007f9013bf5e78> OwnProfilePage

What's weird is that on the command-line, the same version of Ruby (2.1.5) does this:

$ ruby -le 'class Dog; end; Dog.new.foo'
-e:1:in `<main>': undefined method `foo' for #<Dog:0x007fb64120c6d8> (NoMethodError)

so I know it usually works.

I've tried adding a method_missing() method to Object, but it affected nothing, so I presume someone else, somewhere else, is monkey-patching or overriding or otherwise meta-buggering things. I even patched NoMethodError.new() to print a stack trace to try to locate the errant code.

Further, is there a reasonably general to work out which bit of a Ruby system is doing what, when there's potentially so much voodoo and other poorly-conceived global-change nonsense going on in far flung and random gems? (In another case, 'fail' started reporting the previous rescued exception's message, instead of the string I supplied it with.)


Solution

  • OK, I found out what's going on:

    It's calabash-android's ABase class, whose method_missing 'helpfully' delegates to its world object, which also doesn't know about my method (unsurprisingly). Unfortunately, its author failed to think about catching exceptions when his/her surprising implementation detail failed, so it's reporting not my page object but the world object and making Ruby look broken.

    Had I looked at my logging's hexagibberish carefully, I'd have noticed it wasn't Ruby misreporting my page object's class, but correctly reporting a completely different object (although the object's class isn't Object, but Object+Test::Unit::Assertions+half+a+million+other+mixins which would have more rapidly clued me in that it was reporting about the wrong thing).

    I've wrapped that method_missing's body in a try/catch that reports the real object and also mentions that nothing in world knows about it either.

    This is one of the main reasons I dislike magic: people generally fail to provide proper diagnostics. The other main reason is because magic used to implement surprising behaviour transparently is evil.