无法在top对象中定义method_missing

时间:2013-08-28 21:04:52

标签: ruby method-missing

当我尝试定义(通过加载脚本和只是输入p​​ry)method_missing in pry时它只是退出到控制台(cmd on windows xp)。
当我尝试在IRB上键入它时,它会进入无限循环或当我尝试加载脚本时(irb m.rb)它会显示如下内容:

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 

然后它退出到控制台(cmd)
这是我的代码:

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

some_missing_method("lol")

当我返回其他内容时,它不会进入无限循环但显示错误(仅前几行正在改变):
号:

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>'

字符串:

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 个答案:

答案 0 :(得分:2)

因此,这需要对Ruby的类/对象/模块层次结构有所了解,以及对IRB和Pry等工具的工作方式有所了解。看看这个,这可能会像我一样打击你的思绪 - http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html

至于IRB和Pry,我对他们的代码知之甚少,但我知道他们基本上是通过阅读你的输入和评估+大量的魔法来工作。

正如你似乎已经知道的那样,当你处于irb / pry时,你就在Object范围内,几乎所有其他东西都继承,包括IRB和Pry自己 。所以覆盖Object中的某些内容,如method_missing,可能会改变从它下降的所有内容(即Everything)的行为,包括IRB / Pry。 Pry可能会覆盖method_missing本身做一些非常重要的事情,而你的改变正在打破这一点。

你可以尝试这个有趣的实验:

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

这可能会让你一些想法为什么会这样,但简短的回答是不要这样做。将您的代码封装到自己的模块中,这样它就不会干扰其他任何内容。

我可能会在这里混淆自己,但这个可能让事情再次发挥作用。它应该恢复Pry对Object#method_missing的所有期望:

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

修改

是的,我认为BasicObject#method_missing不存在。但是没关系,因为上面的super会引发一个错误,例如“NoMethodError:undefined method missing_method'for#”。这或多或少会恢复pry / irb似乎期待的行为:Object#method_missing应最终提升NoMethodError。这应该可以修复无限递归循环。

然而,更好的解决方案(除了首先不覆盖Object#method_missing)可能是在做了你必须做的其他事情之后自己筹集NoMethodError

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

我的猜测是,pry正在某个循环中从NoMethodError中抢救。因此,如果它永远不会被提升,那么循环将永远持续下去。如果这是对的,那么上面应该解决它。不是我推荐它。