0

看看这个(用更少草率的代码编辑)

class Numeric
    @@currencies = {'dollar' => 1, 'yen' => 0.013, 'euro' => 1.292, 'rupee' => 0.019}
    attr_writer :previous_currency
    def method_missing(method_id)
        singular_currency = method_id.to_s.gsub( /s$/, '')
        if @@currencies.has_key?(singular_currency)
            @previous_currency = singular_currency
            self * @@currencies[singular_currency]
        else
            super
        end
    end

    def in(currency)
        singular_currency = currency.to_s.gsub( /s$/, '')
        rate = @@currencies[singular_currency]
        if @@currencies[@previous_currency] < rate
            self / rate
        else
            self * rate
        end
    end
end

Numeric 类的此扩展允许执行以下操作:

<Number>.<currency>.in(:<other_currency>)

喜欢5.dollars.in(:euros)

如果我有dollars第一个缺失的方法,它就可以了。@previous_currency在第一次拍摄时获取值dollar,然后在调用缺少的方法in时,它保留其值并进行转换就好了。但是如果我尝试其他方法而不是dollarsordollar@previous_currency就会以某种方式失去它的价值,nil在调用时再次成为in,导致以下错误

NoMethodError: undefined method ` for nil:NilClass

我试图改变美元在@@currencies哈希中的位置,但同样的行为再次发生。

Ruby 更喜欢美元吗?

4

1 回答 1

1

问题是你试图保持一个数字的状态,然后返回一些完全不同的数字。

使用美元,5.dollars返回5,因为你天真地假设“1”真的意味着“1 美元”,(那么为什么还要使用1.dollar当你可以使用的时候1.in(:euros)呢?),所以 5 有一个@previous_currencyof dollar5.dollars返回相同的对象,5以及您附加的额外状态。

With euros, 5.eurosreturns 6.46,这是一个完全不同的对象。它与 object 不共享任何状态5,因此@previous_currency尚未设置。

为了完成这项工作,您需要停止维护状态并始终以美元返回结果,以同样的方式5.weeks,5.months5.years返回秒数。然后你就有了一个简单的无国籍号码。您还应该停止依赖method_missing,而只是动态定义方法。这是一个简单的工作版本:

class Numeric
  @@currencies = {dollars: 1, yen: 0.013, euros: 1.292, rupees: 0.019}

  def in(currency)
    self / @@currencies[currency.to_sym]
  end

  @@currencies.keys.each do |method_name|
    define_method method_name do
      self * @@currencies[method_name.to_sym]
    end
  end
end

puts 1.euros # 1.292
puts 1.euros.in(:dollars) # 1.292
puts 1.dollars # 1
puts 1.dollars.in(:euros) # 0.7739938080495355


puts 1.euros.in(:yen) # 99.38461538461539
puts 1.euros.in(:dollars).in(:yen).in(:dollars) 99.38461538461539
于 2013-07-24T19:27:04.960 回答