运算符在ruby块内重载

时间:2013-11-06 17:26:01

标签: ruby operator-overloading block

我有这个问题,我不能在块中使用重载运算符,而不是使用重载运算符,它使用ruby默认运算符并返回:

ArgumentError: comparison of String with 25 failed

用例允许将类用作:

Query.where { age > 25 }

作为一个通知,不要介意下面的method_missing方法,在这个上下文中,它仅用于抛出上面提到的错误消息,这里的代码如下:

class Query
  class << self
    def > arg
      "> #{arg.to_s}"
    end
    def method_missing meth, *args, &block
      "#{meth.to_s} #{args.first.to_s}"
    end
    def where &block
      "SELECT * FROM table WHERE #{class_eval &block}"
    end
  end
end

如果我在块中添加self,则重载的运算符运行正常:

Query.where { age self > 25 }
=> "SELECT * FROM table WHERE age > 25"

取出self,会返回此错误:

Query.where { age > 25 }
=> ArgumentError: comparison of String with 25 failed

3 个答案:

答案 0 :(得分:2)

您的问题是method_missing

def method_missing meth, *args, &block
  "#{meth.to_s} #{args.first.to_s}"
end

在调用age时返回一个字符串。这意味着您的阻止:

{ age > 25 }

看起来像这样:

{ 'age' > 25 }

在调用method_missing来处理age电话后。这是你的ArgumentError

您需要method_missing以正确的字符串形式的方式返回知道如何回复>的内容。例如:

class Query
  class Wrapper
    def initialize str
      @str = str
    end
    def > arg
      @str += "> #{arg.to_s}"
    end
    def to_s
      @str
    end
  end
  class << self
    def method_missing meth, *args, &block
      Wrapper.new("#{meth.to_s} #{args.first.to_s}")
    end
    def where &block
      "SELECT * FROM table WHERE #{class_eval &block}"
    end
  end
end

这将使Query.where { age > 25 }按照您希望的方式运行。当你拨打where时,这仍然会给你留下一个不可束缚的字符串(即Query.where { age > 25 }.where { pancakes < 11 }之类的东西不起作用)但是扩展Query以涵盖这些事情应该会更容易正确的地方。

答案 1 :(得分:1)

在这种情况下:

Query.where { age self > 25 }

对象selfQuery对象,因此它使用您定义的运算符。 但是,在这种情况下:

Query.where { age > 25 }

age25都不是Query个对象,因此它不会使用Query中的运算符

答案 2 :(得分:0)

Query.where {age self > 25}发生了这种情况:

   class_eval {age self > 25}           
=> class_eval {age Query > 25}
=> class_eval {age Query.>(25)}
=> class_eval {age "> #{25.to_s}"}
=> class_eval {age "> 25"}
=> method_missing(age, ["> 25"])
=> "#{age.to_s} #{["> 25"].first.to_s}"
=> "age > 25"

我们拥有Query.where {age > 25}

class_eval {age > 25}           

会引发错误,因为age被认为是v的接收者。

您可以将Query.where { age > 25 }更改为Query.where { age "> 25" }并删除'Query#>'方法。您可能不需要某些to_s