3

$を他の通貨に変換するためのmethod_missingを実装しようとしています。たとえば、5.dollarsは5を生成し、5.yenは0.0655.euro6.56を生成します。これは私が今できることです。今、私はそれを実装する必要がありますが、例えば5.dollars.in(:yen)を実行します。

これは私が今持っているものです:

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

誰かが私がこれを行う方法を説明できますか?

PS:コードではなく説明を教えてほしいので、それがどのように行われるかを自分で判断できます。

4

9 に答える 9

10

通貨「dollar」をメソッドに追加:

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

  def in(currency)
    singular_currency = currency.to_s.gsub(/s$/, '')
    self / @@currencies[singular_currency]
  end
end
于 2012-03-13T17:28:04.927 に答える
5

おそらく、これはもっと役立つでしょう。これは実用的な例です(注:ActiveSupport[Railsの一部]とRuby1.9.2+が必要です):

require 'rubygems'

# This is allowing us to do the `pluralize` calls below
require 'active_support/inflector'

module Currency
  CONVERSION_TABLE = { dollars: { dollars: 1, euros: 0.75 }, euros: { dollars: 1.3333334, euros: 1 } }.freeze
  attr_accessor :currency

  def method_missing(method_name, *args, &block)
    # standardize on pluralized currency names internally so both singular
    # and plural methods are handled
    method_name = method_name.to_s.pluralize.to_sym

    # Use the "from" keys in the conversion table to verify this is a valid 
    # source currency
    if CONVERSION_TABLE.key?(method_name)
      @currency = method_name
      self # return self so a call to `1.dollar` returns `1` and not `:dollars`
    else
      super
    end
  end

  # Convert `self` from type of `@currency` to type of `destination_currency`, mark the result with
  # the appropriate currency type, and return. Example:
  def to(destination_currency)
    # Again, standardize on plural currency names internally
    destination_currency = destination_currency.to_s.pluralize.to_sym

    # Do some sanity checking
    raise UnspecifiedSourceCurrency unless defined?(@currency)
    raise UnsupportedDestinationCurrency unless CONVERSION_TABLE.key?(destination_currency)

    # Do the actual conversion, and round for sanity, though a better
    # option would be to use BigDecimal which is more suited to handling money
    result = (self * CONVERSION_TABLE[@currency][destination_currency]).round(2)

    # note that this is setting @currency through the accessor that
    # was created by calling `attr_accessor :currency` above
    result.currency = destination_currency
    result
  end
end

class Numeric
  # Take all the functionality from Currency and mix it into Numeric
  # 
  # Normally this would help us encapsulate, but right now it's just making
  # for cleaner reading. My original example contained more encapsulation
  # that avoided littering the Numeric clas, but it's harder for a beginner
  # to understand. For now, just start here and you will learn more later.
  include Currency
end

p 5.euros.to(:dollars)                #=> 6.67
p 0.25.dollars.to(:euro)              #=> 0.19
p 1.dollar.to(:euros).to(:dollar)     #=> 1.0
于 2012-03-11T03:45:46.043 に答える
3

これは、計算上の問題というよりも数学的な問題です。

@@currenciesハッシュ値は「ドル」に正規化されます。単位は円/ドルユーロ/ドルルピー/ドルです。の場合、ユーロ/ドル円/ドル5.euro.in(:yen)で割るだけで、ユーロを円で表すことができます。

Rubyを使用してこれを計算するには、method_missingメソッドを変更せずに、クラス定数を更新してを含めます'dollar' => 1Numeric#inこの問題を解決するには、単一行の計算を使用するメソッドを追加します。その計算では、浮動小数点数に正しい順序で除算を適用する必要があります。

たとえば5.euro.in(:yen)5.euroが最初に計算されますが、単位はユーロ/ドルであることに注意してください。次に来るin(:yen)メソッドは、この数値の逆数に適用する必要があります。これにより、希望する結果の逆数である円/ユーロの単位で数値が得られます。

于 2012-03-20T00:40:09.413 に答える
2

inシンボル パラメータを に送り返すと呼ばれるメソッドを定義するだけではありませんselfか?

irb(main):057:0> 5.dollar.in(:euro)
=> 6.46
irb(main):065:0> 5.euro.in(:dollar)
=> 6.46 # Which is wrong, by the way

つまり、現在の金額が何を表しているかわからないため、そうではなくてmethod_missingも、すべてがドルであると想定しているからです。

それがお金の宝石がある理由です:)

于 2012-03-11T01:22:33.840 に答える
1

これに対する私のアプローチは、提起された問題の制限を受け入れることに基づいています (@coreyward が示しているように、Numeric で method_missing の実装を拡張しますが、これは宿題の問題以外では実際には間違ったアプローチです)は次のとおりです。

5.euros.in(:yen)次のように翻訳できる理解:

eur = 5.send(:euros)
eur.send( :in, yen )

基本的に何が起こっているかというと、ユーロ メッセージを Numeric 5 に送信し、inメソッドを :yen のパラメーターを使用して 5.euros の Numeric 結果に送信しています。

method_missing では、euros呼び出しに応答し、ユーロからドルへの変換の結果を返す必要があります。次に、(method_missing 内でも)inドルを (前の呼び出しから) として渡されたシンボルに変換した結果を呼び出しに応答する必要があります。パラメータをin呼び出しに追加します。これにより、適切な値が返されます。

もちろん、換算係数が正しい限り、任意の通貨との間で両替することができます。

于 2012-03-15T02:43:31.093 に答える
1

私もこのコースを行っており、タスクを達成する方法の例をいくつか見ました. ある時点で self.send が言及され、他の誰かがこれも実装していると思いますが、この解決策が私のために働くことがわかりました:

https://gist.github.com/2065412

于 2012-03-18T13:15:28.540 に答える
1

ここで使用するよりもmethod_missing、各通貨を繰り返し処理し、変換方法に委譲する単数形および複数形の方法を定義する方が簡単です。

便宜上、ここに ActiveSupport があると仮定しています。あなたはこれなしでこれを行うことができますがconstantize、懸念事項のようなものはそれをより簡単にします.

module DavesMoney
  class BaseMoney
    # your implementation
  end

  class DollarConverter < BaseMoney
    def initialize(value)
      @value = value
    end

    def to(:currency)
      # implemented in `BaseMoney` that gets extended (or included)
    end
  end
end

module CurrencyExtension
  extend ActiveSupport::Concern

  SUPPORTED_CURRENCIES = %w{ dollar yen euro rupee }

  included do
    SUPPORTED_CURRENCIES.each do |currency|
      define_method :"#{currency}" do
        return "#{currency}_converter".constantize.new(self)
      end
      alias :"#{currency.pluralize}" :"#{currency}"
    end
  end
end

# extension
class Numeric
  include CurrencyExtension
end
于 2012-03-11T01:29:29.313 に答える
0

まず、ユニット ライブラリをインストールします: gem install sy. 次に、次のように定義します。

require 'sy'
Money = SY::Quantity.dimensionless      #=> #<Quantity:Money>
USD = SY::Unit.standard of: Money       #=> #<Unit:USD of Money >
YEN = SY::Unit.of Money, amount: 0.013  #=> #<Unit:YEN of Money >
EUR = SY::Unit.of Money, amount: 1.292  #=> #<Unit:EUR of Money >
INR = SY::Unit.of Money, amount: 0.019  #=> #<Unit:INR of Money >

そして今、あなたは計算することができます:

10 * 10.usd => #<Magnitude: 100 >
100.yen.in :usd #=> #<Magnitude: 1.3 >
1.eur + 1.usd #=> #<Magnitude: 2.29 >

定義することもできます

CENT = SY::Unit.of Money, amount: 0.01.usd
EUROCENT = SY::Unit.of Money, amount: 0.01.eur

その後

12.usd + 90.cent #=> #<Magnitude: 12.9 >
于 2013-06-13T03:20:32.127 に答える
0

これが私がしたことです...

http://pastebin.com/DpE8VAH4

    クラス数値
      @@currencies = {'円' => 0.013, 'ユーロ' => 1.292, 'ルピー' => 0.019, 'ドル' => 1}
      def method_missing(メソッド, *arg)
        singular_currency = method.to_s.gsub(/s$/,'')
        if @@currencies.has_key?(singular_currency)
          自分 * @@currencies[singular_currency]
        そうしないと
          素晴らしい
        終わり
      終わり
      デフイン(引数)
        singular_currency = arg.to_s.gsub(/s$/,'')
        if @@currencies.has_key?(singular_currency)
          自分 * @@currencies[singular_currency]
        終わり
      終わり
    終わり

    puts "5.euro = "+5.euro.to_s
    puts "5.euros = "+5.euros.to_s
    puts "5.dollars.in(:euros) = "+5.dollars.in(:euros).to_s
    puts "10.euros.in(:ルピー) = "+10.euros.in(:ルピー).to_s
  • 通貨に「'dollar' => 1」を追加
  • method_missing メソッド ", *args" に新しい引数を追加します
  • Numeric クラスに新しいメソッド「in(arg)」を追加します。
  • このメソッドは、self に引数「arg」で指定された通貨を乗算します。
于 2012-05-30T05:09:08.467 に答える