1

当我尝试定义(通过加载脚本&只输入撬)方法_missing在撬它只是退出到控制台(在windows xp上的cmd)。
当我尝试在 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'
        (..)
4

1 回答 1

2

因此,这需要对 Ruby 的类/对象/模块层次结构有所了解,以及对 IRB 和 Pry 等工具的工作原理有所了解。看看这个,它可能会让你大吃一惊 - https://web.archive.org/web/20160319051340/http://madebydna.com/all/code/2011/06/24/eigenclasses-揭秘.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某个循环中解救出来。因此,如果它从未引发,则循环将永远继续。如果这是正确的,那么上面应该解决它。不是我推荐它。

于 2013-08-28T21:32:14.870 回答