【问题标题】:Cannot define method_missing in top Object无法在顶级对象中定义 method_missing
【发布时间】:2013-08-28 21:04:51
【问题描述】:

当我尝试定义(通过加载脚本&只需键入 pry)时,pry 中的 method_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'
        (..)

【问题讨论】:

  • 无法复制。对我来说很好。 1.9.3p392
  • 可能是 windows 环境?
  • @SergioTulentsev 对我来说也是的......工作......
  • @SergioTulentsev windows env 如何破坏我的代码?你 2 使用的是什么操作系统?

标签: ruby method-missing


【解决方案1】:

因此,这需要对 Ruby 的类/对象/模块层次结构有所了解,以及对 IRB 和 Pry 等工具的工作原理有所了解。看看这个,它可能会让你大吃一惊 - https://web.archive.org/web/20160319051340/http://madebydna.com/all/code/2011/06/24/eigenclasses-demystified.html

至于 IRB 和 Pry,我对他们的代码了解不多,但我知道他们基本上是通过阅读您的输入和评估 + 很多魔法来工作的。

您似乎已经知道,当您在 irb/pry 中时,您处于 Object 范围内,几乎所有其他内容都继承自该范围,包括 IRB 和 Pry 本身。因此,覆盖Object 中的某些内容,例如method_missing,可能会改变从它继承的所有内容(即所有内容)的行为,包括 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 中解救出来。因此,如果它从未引发,则循环将永远继续。如果这是正确的,那么上面应该解决它。不是我推荐的。

【讨论】:

  • 如果你覆盖了method_missing,那么super 对你没有帮助。 super 委托给 overridden 方法,overwritten 方法就消失了。您的代码将委托给Object 的超类中的method_missing 实现。好吧,在 1.8 中,没有超类,而在 1.9+ 中,BasicObject 没有实现 method_missing
  • @JörgWMittag 但我可以这样做: b=BasicObject.new #<0x1cbb3c4>&lt;&gt;
  • &
猜你喜欢
  • 2013-06-23
  • 2020-11-18
  • 2020-08-13
  • 1970-01-01
  • 1970-01-01
  • 2015-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多