ruby- method_missing返回没有方法错误

时间:2014-06-01 05:31:27

标签: ruby

我正在尝试使用method_missing将美元转换为不同的货币。

class Numeric
    @@currency={"euro"=>2, "yen"=>6}
    def method_missing(method_id,*args,&block)
        method_id.to_s.gsub!(/s$/,'') #get rid of s in order to handle "euros"
        @@currency.has_key?(method_id) ? self*@@currency[method_id] : super             
    end
end

> 3.euro   #expect to return 6
NoMethodError: undefined method 'euro' for 3:Fixnum
from (pry):24:in 'method_missing'

> 3.euros  #expect to return 6
NoMethodError: undefined method 'euros' for 3:Fixnum
from (pry):24:in 'method_missing'

我猜3.euro无效,因为:euro.to_s.gsub!(/s$/,'')会返回nil。我不确定为什么它不会返回方法错误。

感谢您的帮助。

2 个答案:

答案 0 :(得分:4)

method_missing 被调用时,euro将作为符号分配给method_id。但是,您的@@currency哈希将所有键都保存为字符串,您需要将它们转换为符号

method_id.to_s.gsub!(/s$/,'')无法改变实际对象method_id。由于method_id.to_s会为您提供一个新的字符串对象,因此#gsub!仅对此有用。你无法改变method_id,它仍然保持原样。最好使用 non-bang ,因为如果没有做出更改,它将为您提供实际对象,或者如果进行了更改,则会更改对象,那么您需要将此返回值分配给新变量。

通过@@currency@@currency.has_key?(method_id)评估为falsesupermethod_missing已被调用。为什么?由于method_id未转换为字符串,您可能会发生这种情况。

但是,如果你想回复euroeuros,那么

class Numeric
    @@currency={"euro" => 2, "yen" => 6}
    def method_missing(method_id,*args,&block)
        #get rid of s in order to handle "euros"
        new_method_id = method_id.to_s.gsub(/s$/,'') 
        @@currency.has_key?(new_method_id) ? self*@@currency[new_method_id] : super             
    end
end

3.euros # => 6
3.euro  # => 6

答案 1 :(得分:1)

gsub!修改字符串并返回nil。对于您正在使用的字符串,它不会很好地工作,这是to_s创建的临时字符串,并且永远不会存储在变量中。此外,您甚至无法将结果存储在任何地方。为什么字符串上的gsub!应该修改符号,这些符号无论如何都是不可变的?

尝试使用gsub代替,它返回修改后的字符串并让调用者独自离开。您还需要存储返回值。

real_method_name = method_id.to_s.gsub(/s$/, "")

另外:3.euro无效的原因是因为您的哈希使用字符串作为键,但method_id作为符号传递给方法。如果您不必进行字符串操作(在这种情况下删除s后缀),我建议只使用符号作为您的哈希键。但实际上,你需要进行字符串操作,所以我的答案是使用字符串。