【问题标题】:method_missing with unquoted string arguments in Ruby - possible?在 Ruby 中带有不带引号的字符串参数的 method_missing - 可能吗?
【发布时间】:2013-05-03 17:33:16
【问题描述】:

我正在学习 Ruby,并希望能够做到这一点:

Printer.hi there

并有 Ruby 输出

"hi there"   

到目前为止,我有以下实现

class Printer
  def method_missing(name, *args)
     puts "#{name} #{args.join(',')}"
  end
end

但这只能让我做

Printer.hi "there"

如果我尝试

Printer.hi there

我得到一个

NameError: undefined local variable or method `there' for main:Object

这是有道理的,因为我从未定义过“那里”。有没有办法让这项工作?

【问题讨论】:

  • 如果有可能并且你做到了,那么它会弄乱整个代码。这样做没有实际意义。
  • 不,没有,除非您想办法自动创建未定义的变量。但是,IMO 无论如何都不是一个好的语法,因为它违反直觉。最好创建一个迷你 DSL。
  • 虽然我已尽我所能回答,但请注意您的标题不正确。 Ruby 中没有“不带引号的字符串”之类的东西。正如 NameError 所揭示的那样,它们要么是局部变量,要么是方法。

标签: ruby metaprogramming method-missing


【解决方案1】:

不,这在给定的形式中是不可能的(据我所知)。

您不是在寻找缺少的方法,而是在 Ruby 解释器中寻找当它找不到给定符号时捕获的等效方法。所以虽然你不能在那里拦截它,但你可以在一个块内进行:

def hi(&block)
  begin
    yield
  rescue NameError => e
    e.message =~ /variable or method `(.+)'/
    puts "hi #{$1}"
  end
end

hi { there } # => hi there

请注意,向您展示这一点让我感觉自己是个糟糕的世界公民。请永远不要在任何地方使用它。

【讨论】:

    【解决方案2】:

    是的,有办法。当您编写 there 而没有明确的接收者时,接收者是该范围的 self 对象。在这种情况下,它是main。在main 上下文中定义methods_missing

    def method_missing(name, *args)
      puts "#{name} was called with arguments: #{args.join(',')}"
    end
    

    但是,如果您这样做,那可能会弄乱您的其余代码。我认为这样做没有意义。

    由于puts的返回值是nil,如果你做Printer.hi there,它的计算结果是Printer.hi(nil)。所以为了让它输出"hi there",你需要定义:

    class Printer
      def self.hi _; puts "hi there" end
    end
    

    【讨论】:

    • 这似乎不起作用...用一个参数调用 Print.hi 确实会使其打印“hi there”,但您仍然不能在那里说 Print.hi 并让它工作.
    • 问题中没有提到。
    • 问题是如何让代码 Printer.hi there 导致打印字符串“hi there”。所以是的,它在问题中。
    • 我误会了您的第一条评论。实际上,这对我来说没有意义。 Print.hi there 工作。
    【解决方案3】:

    否,因为字符串需要被引用,所以它们不被视为变量。

    否则there 等变量将需要某种特殊类型的字符来表明它是一个字符串。然而,这仍然不能很好地工作,因为需要处理空间。

    使用单引号或双引号。
    这就是语言的运作方式。接受这个并继续下一个挑战:)

    【讨论】:

    • 这里没有写错,但我不明白这是如何回答问题的。
    • @boulder 我认为答案是“是的,有可能”,这可能值得商榷,但迈克尔的回答是自相矛盾的说“是”,然后写出指向相反方向的东西.
    • 程序员过度分析,好吧,所以我改成“否,因为字符串需要被引用,所以它们不被视为变量。”而不是“是的,因为字符串需要被引用......”我希望每个人都对此感到高兴:)
    【解决方案4】:

    有趣的是,您可以在 ruby​​ 1.8.7 中使用以下代码执行此操作:

    def method_missing(*args)
      puts args.join ' '
    end
    

    我从 Gary Bernhardt 的演讲中了解到这一点,Wat。在 1.9 中,这会给你一个堆栈级别太深的错误,除非你在一个类中这样做。谷歌把我带到了Aurthur's tech blog thing 上的这篇文章,它声称你可以在 JRuby 1.9 模式下做类似的事情:

    def method_missing(*args)
      puts [method.to_s, args].flatten.join ' '
    end
    

    但是,当我在 MRI 1.9.3 上尝试此操作时,它也不起作用。所以在 1.9 中你不能完全做你想做的事。这是我能来的最接近的:

    class Printer
      def self.hi(message)
        puts "hi #{message}"
      end
      def self.method_missing(m, *args)
        [m.to_s, args].flatten.join ' '
      end
    
      def self.bare
        hi there
      end
    end
    
    Printer.bare
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-02
      • 1970-01-01
      • 1970-01-01
      • 2012-06-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多