Cannot define method_missing in top Object

749 views Asked by At

When I try define(by loading script&just typing in the pry) method_missing in pry it just exit to console(cmd on windows xp).
When I try typing it on the IRB, it goes into infinite loop or when I try loading the script(irb m.rb) it shows something like this:

D:\programowanie\Ruby>irb m.rb
m.rb(main):001:0> def method_missing name, *args, &block
m.rb(main):002:1>   puts 'method is missing'
m.rb(main):003:1> end
=> nil
m.rb(main):004:0>
m.rb(main):005:0* some_missing_method("lol")method is missing
m.rb(main):005:0*
method is missing
method is missing
method is missing
m.rb(main):005:0>
method is missing
method is missing
method is missing
method is missing 

and it exits to the console(cmd)
Here is my code:

def method_missing name, *args, &block
  puts 'method is missing'
  nil
end

some_missing_method("lol")

When I return something else it doesn't go into infinite loop but shows error instead(only first few lines are changing):
Number:

method is missing
method is missing
C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/readline.rb:45:in `raise': can't convert TypeError to String (TypeError#to_str gives Fixnum) (Typ
eError)
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/readline.rb:45:in `rescue in readline'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/readline.rb:39:in `readline'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/input-method.rb:115:in `gets'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:139:in `block (2 levels) in eval_input'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:273:in `signal_status'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:138:in `block in eval_input'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:188:in `call'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:188:in `buf_input'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:103:in `getc'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/slex.rb:205:in `match_io'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/slex.rb:75:in `match'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:286:in `token'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:262:in `lex'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:233:in `block (2 levels) in each_top_level_statement'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `loop'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:229:in `block in each_top_level_statement'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `catch'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb/ruby-lex.rb:228:in `each_top_level_statement'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:155:in `eval_input'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:70:in `block in start'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:69:in `catch'
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/1.9.1/irb.rb:69:in `start'
        from C:/RailsInstaller/Ruby1.9.3/bin/irb:12:in `<main>'

String:

method is missing
method is missing
C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/readline.rb:45:in `rescue in readline': this_is_string (RuntimeError)
        from C:/RailsInstaller/Ruby1.9.3/lib/ruby/site_ruby/1.9.1/readline.rb:39:in `readline'
        (..)
1

There are 1 answers

3
bioneuralnet On

So this requires some understanding of Ruby's class/object/module hierarchy, as well as some understanding of how tools like IRB and Pry work. Take a look at this, which may blow your mind as it did mine - https://web.archive.org/web/20160319051340/http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html.

As for IRB and Pry, I don't know much about their code, but I know they basically work by reading your input and eval'ing + lots of magic.

As you seem to already know, when you're in irb/pry, you're inside the Object scope, from which nearly everything else inherits, including IRB and Pry themselves. So overriding something in Object, like method_missing, might change the behavior of everything that descends from it (i.e. Everything) including IRB/Pry. Pry is probably overriding method_missing itself to do something very important, and your change is breaking that.

You might try this as an interesting experiment:

def method_missing name, *args, &block
  puts "method '#{name}' is missing"
end

That might give you some idea why it's happening, but the short answer is don't do it. Encapsulate your code into its own Module so that it doesn't interfere with anything else.

And I might be confusing myself here, but this might get things working again. It should restore whatever expectations Pry has about Object#method_missing:

def method_missing name, *args, &block
  puts "method '#{name}' is missing"
  super
end

Edit

True, I don't think BasicObject#method_missing exists. But that's okay, because the above super will raise an error like "NoMethodError: undefined method missing_method' for #". That more or less restores the behavior that pry/irb seem to be expecting: that Object#method_missing should ultimately raise a NoMethodError. That should fix the infinite recursive loop.

However, a better solution (aside from not overwriting Object#method_missing in the first place) might be to raise a NoMethodError yourself after doing whatever else you have to do:

def method_missing(name, *args, &block)
  puts "method '#{name}' is missing"
  # important stuff
  raise NoMethodError, name
end

My guess is that pry is rescuing from a NoMethodError in some loop. So if it's never raised, the loop continues forever. If that's right, then the above should fix it. Not that I recommend it.