2013-07-24 85 views
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 

這個擴展到數字類允許執行以下操作:

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

5.dollars.in(:euros)

如果我有dollars作爲我第一個缺失的方法,它工作得很好。 @previous_currency在第一次拍攝時獲得值dollar,然後在缺少方法in的調用中,它保留了它的值並進行了轉換。但是,如果我嘗試其他任何代替dollarsdollar@previous_currency不知何故在in通話失去了它的價值,成爲nil再次,導致下面的錯誤

NoMethodError: undefined method ` for nil:NilClass 

我試着改用美元發生在@@currencies哈希,但同樣的行爲再次發生。

Ruby是否更喜歡美元?

+0

這是一個超級馬虎的寫作這btw的方式。爲什麼不直接定義'in'方法,而不是依賴'method_missing'?正如所寫,你可以做'5.dollars.viugdkaugehtkauge(:euros)'。 – meagar

回答

1

問題是你想維護一個數字的狀態,然後返回一些完全不同的數字。

隨着美元,5.dollars回報5,因爲你天真地假設爲「1」的真正含義「1元」,(那爲什麼還要使用1.dollar時,你可以只使用1.in(:euros)?),所以5具有dollar@previous_currency5.dollars返回相同的對象,5,以及您附加的額外狀態。

With euros5.euros返回6.46,這是一個完全不同的對象。它與對象5不共享狀態,所以@previous_currency尚未設置。

爲了使這項工作,你需要停下來保持狀態,只是始終返回結果以美元,以同樣的方式5.weeks5.months,並5.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