Frage

Ich versuche, eine method_missing für die Umrechnung von $ in andere Währungen zu implementieren, da 5 Dollar 5 ergibt, 5 Yen 0,065, 5 Euro 6,56 und so weiter.Das kann ich jetzt tun.Jetzt muss ich es implementieren, aber zum Beispiel 5.dollars.in(:yen) machen.

Das ist es, was ich gerade habe:

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

Kann mir jemand erklären, wie ich das machen kann?

PS:Ich möchte lieber, dass Sie mir nicht den Code geben, sondern eine Erklärung, damit ich selbst bestimmen kann, wie es gemacht wird.

War es hilfreich?

Lösung

Perhaps this will be of more help. It's a working example (note, I'm expecting you to have ActiveSupport [part of Rails] and Ruby 1.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

Andere Tipps

Währung "Dollar" und in Methode hinzugefügt: generasacodicetagpre.

Dies ist eher ein mathematisches als ein rechnerisches Problem.

Jedes von den @@currencies Hash-Werte werden auf „Dollar“ normalisiert:ihre Einheiten sind Yen/Dollar, Euro Dollar, Rupie/Dollar.Für 5.euro.in(:yen), Sie müssen nur dividieren Euro Dollar von Yen/Dollar um die Antwort als Euro in Yen auszudrücken.

Um dies mit Ruby zu berechnen, verlassen Sie die method_missing Methode unverändert und aktualisieren Sie die Klassenkonstante, um sie einzuschließen 'dollar' => 1.Füge hinzu ein Numeric#in Methode mit einer einzeiligen Berechnung zur Lösung dieses Problems.Bei dieser Berechnung muss eine Division in der richtigen Reihenfolge auf eine Gleitkommazahl angewendet werden.

Für 5.euro.in(:yen) Denken Sie zum Beispiel daran 5,-Euro wird zuerst berechnet, hat aber Einheiten von Euro Dollar.Der in(:Yen) Die nächste Methode muss auf den Kehrwert dieser Zahl angewendet werden.Dies ergibt eine Zahl mit Einheiten in Yen/Euro, der Kehrwert Ihres gewünschten Ergebnisses.

Würden Sie nicht einfach eine Methode namens definieren in an den der Symbolparameter zurückgesendet wurde 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

Also nicht ganz, denn Sie wissen nicht, wie hoch der aktuelle Betrag ist – Ihr method_missing geht davon aus, dass alles in Dollar ist, auch wenn das nicht der Fall ist.

Deshalb gibt es das Geldjuwel :)

Anstatt zu benutzen method_missing Hier wäre es einfacher, alle Währungen zu durchlaufen und Singular- und Pluralmethoden zu definieren, um sie an Ihre Umrechnungsmethode zu delegieren.

Der Einfachheit halber gehe ich davon aus, dass Sie hier ActiveSupport haben.Sie könnten auf alles verzichten, aber Dinge wie constantize und Bedenken machen es einfacher.

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

Mein Ansatz hierzu basiert auf der Akzeptanz der Grenzen des gestellten Problems (Erweitern einer method_missing-Implementierung auf Numeric, auch wenn dies, wie @coreyward angibt, für alles wirklich der falsche Ansatz ist nicht eine Hausaufgabenaufgabe) war wie folgt:

Das verstehen 5.euros.in(:yen) kann übersetzt werden als:

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

Was im Wesentlichen passiert, ist, dass wir die Euro-Nachricht an Numeric 5 senden und dann die in Methode zum numerischen Ergebnis von 5, Euro mit einem Parameter von: Yen.

In method_missing sollten Sie auf Folgendes antworten euros Rufen Sie auf und geben Sie das Ergebnis einer Umrechnung von Euro in Dollar zurück, und antworten Sie dann (auch in method_missing) auf die in Aufruf mit den Ergebnissen der Konvertierung der Dollars (aus dem vorherigen Aufruf) in das Symbol, das als Parameter an übergeben wurde in Anruf.Dadurch wird der richtige Wert zurückgegeben.

Natürlich können Sie in jede beliebige Währung umrechnen, solange Ihre Umrechnungsfaktoren korrekt sind. Angesichts der gegebenen Umstände für dieses spezielle Problem schien die Umrechnung in/von Dollar am sinnvollsten zu sein.

Ich mache diesen Kurs auch und ich sah ein paar Beispiele, wie man die Aufgabe erfüllt.In irgendeinem Punkt wurde sich selbst erwähnt und ich glaube, dass jemand anderes dies auch implementiert hat, aber ich fand diese Lösung für mich:

https://gist.github.com/2065412

hier ist das, was ich getan habe ...

http://pastein.com/dpe8vah4 generasacodicetagpre.

    .
  • add "'' dollar '=> 1" in Währungen
  • Fügen Sie ein neues Argument in der Methode_missing-Methode ", * Args" hinzu
  • Fügen Sie eine neue Methode "in (arg)" in die numerische Klasse hinzu
  • Diese Methode multiplizieren sich selbst von der von dem Argument "arg" angegebenen Währung "arg"

Installieren Sie zunächst meine Einheitenbibliothek: gem install sy.Dann definieren Sie:

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 >

Und jetzt können Sie berechnen:

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

Sie können auch definieren

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

Und dann

12.usd + 90.cent #=> #<Magnitude: 12.9 >
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top