Documentation
¶
Overview ¶
Package money is a pure-Go (CGO-free), MRI-faithful reimplementation of the Ruby `money` gem (RubyMoney). It models an amount of a specific currency as an integer number of minor units (cents) plus a *Currency, and reproduces the gem's arithmetic, allocate/split penny distribution, ISO 4217 currency table, formatting, and variable-exchange bank — byte-for-byte where the gem is deterministic — without any Ruby runtime.
The rate source for currency exchange is a host seam: a *VariableExchange bank holds rates injected by the host (Money.add_rate / bank.add_rate), and the exchange math is implemented here. A *SingleCurrency bank refuses any exchange.
Value model ¶
A Money value is (fractional int64 minor units, currency, bank). A host such as go-embedded-ruby maps its own Money objects to and from this shape:
Ruby Go
---- --
Money.new(100, "USD") money.New(100, money.MustCurrency("USD"))
m.fractional / m.cents m.Fractional() (int64)
m.amount / m.to_d m.Amount() (*big.Rat)
m.currency m.Currency() (*Currency)
Money::Currency.new("USD") money.Currency(...) / money.MustCurrency(...)
Index ¶
- Variables
- func AddRate(from, to *Currency, rate *big.Rat) *big.Rat
- func DisallowCurrencyConversion()
- func RegisterCurrency(c Currency)
- func SetDefaultBank(b Bank)
- func UnregisterCurrency(id string) bool
- type Bank
- type Currency
- type DifferentCurrencyError
- type Money
- func (m *Money) Abs() *Money
- func (m *Money) Add(other *Money) (*Money, error)
- func (m *Money) Allocate(parts []int64) []*Money
- func (m *Money) Amount() *big.Rat
- func (m *Money) Bank() Bank
- func (m *Money) Cents() int64
- func (m *Money) Cmp(other *Money) (int, error)
- func (m *Money) Currency() *Currency
- func (m *Money) Div(value *big.Rat) (*Money, error)
- func (m *Money) DivInt(value int64) (*Money, error)
- func (m *Money) DivModInt(value int64) (*Money, *Money, error)
- func (m *Money) DivModMoney(other *Money) (int64, *Money, error)
- func (m *Money) DivMoney(other *Money) (*big.Rat, error)
- func (m *Money) Eql(other *Money) bool
- func (m *Money) ExchangeTo(to *Currency) (*Money, error)
- func (m *Money) Format(opts Options) string
- func (m *Money) Fractional() int64
- func (m *Money) Inspect() string
- func (m *Money) ModuloInt(value int64) (*Money, error)
- func (m *Money) ModuloMoney(other *Money) (*Money, error)
- func (m *Money) Mul(value *big.Rat) *Money
- func (m *Money) MulInt(value int64) *Money
- func (m *Money) Neg() *Money
- func (m *Money) Negative() bool
- func (m *Money) Nonzero() *Money
- func (m *Money) Positive() bool
- func (m *Money) RemainderInt(value int64) (*Money, error)
- func (m *Money) Round(mode RoundingMode) *Money
- func (m *Money) Split(n int) []*Money
- func (m *Money) String() string
- func (m *Money) Sub(other *Money) (*Money, error)
- func (m *Money) Symbol() string
- func (m *Money) ToF() float64
- func (m *Money) ToI() int64
- func (m *Money) ToNearestCashValue() (*Money, error)
- func (m *Money) WithCurrency(c *Currency) *Money
- func (m *Money) Zero() bool
- type Options
- type RoundingMode
- type SingleCurrency
- type SymbolRule
- type UnknownCurrencyError
- type UnknownRateError
- type VariableExchange
Constants ¶
This section is empty.
Variables ¶
var DefaultRoundingMode = HalfUp
DefaultRoundingMode is the process-wide rounding mode used when converting a non-integer minor-unit value to an integer (Money.rounding_mode). It defaults to HalfUp, as in the gem.
Functions ¶
func AddRate ¶
AddRate registers a rate on the default bank (which must be a *VariableExchange) and returns it, the analogue of Money.add_rate. It panics if the default bank does not support rates.
func DisallowCurrencyConversion ¶
func DisallowCurrencyConversion()
DisallowCurrencyConversion sets the default bank to a SingleCurrency bank, the analogue of Money.disallow_currency_conversion!.
func RegisterCurrency ¶
func RegisterCurrency(c Currency)
RegisterCurrency adds or replaces a currency keyed by its (lowercased) ISO code, matching Money::Currency.register. A caller that mutates the returned table after registration does not affect the registry.
func SetDefaultBank ¶
func SetDefaultBank(b Bank)
SetDefaultBank sets the process-wide default bank, the analogue of Money.default_bank=.
func UnregisterCurrency ¶
UnregisterCurrency removes a currency by id / code and reports whether it existed, matching Money::Currency.unregister.
Types ¶
type Bank ¶
type Bank interface {
// ExchangeWith converts from into to, or returns an error when no rate is
// known (or exchange is disallowed).
ExchangeWith(from *Money, to *Currency) (*Money, error)
}
Bank is the currency-exchange seam. The rate source is supplied by the host — VariableExchange holds rates injected via AddRate, and SingleCurrency refuses every exchange. A Bank converts a Money into another currency, the analogue of Money::Bank::Base#exchange_with.
func DefaultBank ¶
func DefaultBank() Bank
DefaultBank returns the process-wide default bank, the analogue of Money.default_bank. It defaults to an empty VariableExchange.
type Currency ¶
type Currency struct {
// ID is the lowercase identifier (e.g. "usd"); it is the canonical key.
ID string
// Priority orders the currency list (lower sorts first).
Priority int
// ISOCode is the upper-case 3-letter ISO 4217 code (e.g. "USD").
ISOCode string
// ISONumeric is the 3-digit ISO 4217 numeric code, zero-padded (e.g. "840").
ISONumeric string
// Name is the currency's human name (e.g. "United States Dollar").
Name string
// Symbol is the currency symbol (e.g. "$"); may be empty.
Symbol string
// DisambiguateSymbol is an alternative symbol used when Symbol is ambiguous
// (e.g. "US$" / "C$").
DisambiguateSymbol string
// HTMLEntity is the HTML entity for the symbol (e.g. "$", "¥").
HTMLEntity string
// AlternateSymbols are other symbols in use for the currency.
AlternateSymbols []string
// Subunit is the name of the fractional unit (e.g. "Cent"); may be empty.
Subunit string
// SubunitToUnit is the proportion between unit and subunit (e.g. 100).
SubunitToUnit int64
// DecimalMark separates the whole part from the subunit (e.g. ".").
DecimalMark string
// ThousandsSeparator groups the whole part (e.g. ",").
ThousandsSeparator string
// SymbolFirst reports whether the symbol precedes the amount.
SymbolFirst bool
// SmallestDenomination is the smallest cash amount, in subunits (e.g. 1, 5).
SmallestDenomination int64
// Format is an optional "%u%n"-style template overriding the default layout.
Format string
}
Currency represents a specific currency unit — the Go analogue of Money::Currency. It is loaded from the embedded ISO 4217 table (with the gem's non-ISO and backwards-compatible additions merged in) and is immutable once registered. Look one up with Currency / MustCurrency / FindCurrency / FindCurrencyByISONumeric, or add your own with RegisterCurrency.
func AllCurrencies ¶
func AllCurrencies() []*Currency
AllCurrencies returns every registered currency sorted by priority then id, matching Money::Currency.all / .each iteration order.
func FindCurrency ¶
FindCurrency looks up a currency by id / code, returning nil (no error) when it is unknown — the analogue of Money::Currency.find.
func FindCurrencyByISONumeric ¶
FindCurrencyByISONumeric looks a currency up by its ISO 4217 numeric code (e.g. 840 or "840"), zero-padding to three digits first, matching Money::Currency.find_by_iso_numeric. It returns nil when unknown.
func MustCurrency ¶
MustCurrency is like NewCurrency but panics on an unknown id; it is convenient for currencies known to exist at call sites (e.g. MustCurrency("USD")).
func NewCurrency ¶
NewCurrency looks up a currency by its id or ISO code (case-insensitive), the analogue of Money::Currency.new. It returns an *UnknownCurrencyError for an unknown id.
func WrapCurrency ¶
WrapCurrency returns c unchanged when non-nil, else looks id up. It mirrors Money::Currency.wrap for the string case and is used internally to accept either a *Currency or a code where the gem does.
func (*Currency) CentsBased ¶
CentsBased reports whether the subunit is hundredths, matching Currency#cents_based?.
func (*Currency) Code ¶
Code returns the symbol, or the ISO code when there is no symbol, matching Currency#code.
func (*Currency) DecimalPlaces ¶
DecimalPlaces is an alias for Currency.Exponent, matching the gem's alias.
func (*Currency) Equal ¶
Equal reports whether two currencies denote the same currency (same id), matching Currency#==. A nil receiver equals only a nil other.
func (*Currency) Exponent ¶
Exponent returns the base-10 exponent relating subunit to unit, i.e. round(log10(subunit_to_unit)), matching Currency#exponent / #decimal_places.
func (*Currency) ISO ¶
ISO reports whether the currency carries an ISO 4217 numeric code, matching Currency#iso?.
func (*Currency) String ¶
String returns the upper-case ISO id (e.g. "USD"), matching Currency#to_s.
func (*Currency) SymbolOrDefault ¶
SymbolOrDefault returns the currency symbol, or the generic "¤" placeholder when the currency has none — the value Money#symbol uses.
type DifferentCurrencyError ¶
type DifferentCurrencyError struct{ From, To string }
DifferentCurrencyError is returned by SingleCurrency when any exchange is attempted, mirroring Money::Bank::DifferentCurrencyError.
func (*DifferentCurrencyError) Error ¶
func (e *DifferentCurrencyError) Error() string
type Money ¶
type Money struct {
// contains filtered or unexported fields
}
Money is an immutable amount of a specific currency, held as an integer number of minor units (cents) plus a *Currency and a Bank. It is the Go analogue of the gem's Money value object.
func FromAmount ¶
FromAmount returns a Money for a decimal amount in the given currency, scaling by the currency's subunit_to_unit and rounding to an integer with the default rounding mode — the analogue of Money.from_amount(amount, currency). The amount is given as a *big.Rat so callers keep exact decimals.
func New ¶
New returns a Money of fractional minor units (cents) in the given currency, using the DefaultBank — the analogue of Money.new(fractional, currency).
func NewWithBank ¶
NewWithBank is like New but binds an explicit bank for currency exchange.
func (*Money) Add ¶
Add returns the sum of m and other. When other has a different currency it is first exchanged to m's currency, matching Money#+. It returns an error only when that exchange fails (no rate / disallowed).
func (*Money) Allocate ¶
Allocate distributes m into parts proportional to the given weights, without losing pennies — the analogue of Money#allocate(parts). The left-over minor units are handed out so that earlier parts receive them first, exactly as the gem does. Passing all-zero weights splits evenly. It panics on an empty parts slice (matching the gem's ArgumentError).
func (*Money) Amount ¶
Amount returns the decimal value as an exact rational — fractional divided by the currency's subunit_to_unit — the analogue of Money#amount / Money#to_d.
func (*Money) Cents ¶
Cents is an alias for Money.Fractional, matching Money#cents.
func (*Money) Cmp ¶
Cmp compares m to other, returning -1, 0 or 1, matching Money#<=>. When either side is zero the raw fractional values are compared directly; otherwise other is exchanged to m's currency first. It returns an error when a needed exchange fails.
func (*Money) Div ¶
Div returns m divided by a scalar, matching Money#/ (Money / Numeric => Money). The quotient is rounded back to an integer number of minor units with the default rounding mode. It returns an error on division by zero.
func (*Money) DivModInt ¶
DivModInt returns the integer quotient and Money remainder of dividing m by an integer scalar, matching Money#divmod(Integer). The quotient is a Money.
func (*Money) DivModMoney ¶
DivModMoney returns the integer quotient and Money remainder of dividing m by another Money, matching Money#divmod(Money). other is first exchanged to m's currency.
func (*Money) DivMoney ¶
DivMoney returns the ratio m / other as an exact rational, matching the Money / Money form of Money#/ (which returns a Float in the gem). other is first exchanged to m's currency. It returns an error on a zero divisor.
func (*Money) Eql ¶
Eql reports whether m and other have the same fractional value and currency, matching Money#eql? with strict comparison (0 USD is not 0 EUR).
func (*Money) ExchangeTo ¶
ExchangeTo converts m into another currency using m's bank, the analogue of Money#exchange_to. It is a no-op when already in the target currency.
func (*Money) Format ¶
Format renders the amount as a price string per the given options, matching Money#format / Money::Formatter. Passing the zero Options{} reproduces the gem's default formatting for the currency.
func (*Money) Fractional ¶
Fractional returns the amount in minor units (cents), the analogue of Money#fractional / Money#cents.
func (*Money) Inspect ¶
Inspect returns the gem's #<Money fractional:… currency:…> debug string, matching Money#inspect.
func (*Money) ModuloInt ¶
ModuloInt returns m modulo an integer scalar, matching Money#modulo(Integer) / Money#%.
func (*Money) ModuloMoney ¶
ModuloMoney returns m modulo another Money, matching Money#modulo(Money).
func (*Money) Mul ¶
Mul returns m multiplied by a scalar, matching Money#*. A non-integer product is rounded back to an integer number of minor units with the default rounding mode (the gem's return_value on the resulting BigDecimal).
func (*Money) MulInt ¶
MulInt is a convenience wrapper for Money.Mul by an integer scalar; the product is always exact.
func (*Money) Negative ¶
Negative reports whether the amount is less than zero, matching Money#negative?.
func (*Money) Positive ¶
Positive reports whether the amount is greater than zero, matching Money#positive?.
func (*Money) RemainderInt ¶
RemainderInt returns the remainder of m and an integer scalar, matching Money#remainder. Unlike modulo it takes the sign of the dividend: when the operands have opposite signs it is modulo(val) - val.
func (*Money) Round ¶
func (m *Money) Round(mode RoundingMode) *Money
Round returns a Money whose fractional value is rounded to an integer with the given mode — a no-op for the already-integer fractional this package holds, but provided for API parity with Money#round.
func (*Money) Split ¶
Split divides m evenly into n parts without losing pennies — the analogue of Money#split(n) (an alias of allocate with equal weights). It panics when n < 1.
func (*Money) String ¶
String returns the amount as a plain decimal string with no symbol and no thousands separator, matching Money#to_s (no_cents_if_whole for zero-decimal currencies).
func (*Money) Sub ¶
Sub returns the difference m - other. When other has a different currency it is first exchanged to m's currency, matching Money#-.
func (*Money) Symbol ¶
Symbol returns the currency symbol, or "¤" when the currency has none — the analogue of Money#symbol.
func (*Money) ToF ¶
ToF returns the amount as a float64, matching Money#to_f. Prefer Money.Amount for exact decimals; floats lose precision.
func (*Money) ToI ¶
ToI returns the whole-unit part of the amount as an integer (truncated toward zero), matching Money#to_i.
func (*Money) ToNearestCashValue ¶
ToNearestCashValue rounds the amount to the nearest multiple of the currency's smallest_denomination, matching Money#to_nearest_cash_value. It returns an error when the currency has no smallest denomination.
func (*Money) WithCurrency ¶
WithCurrency returns a Money with the same fractional value but a new currency, performing no conversion — the analogue of Money#with_currency.
type Options ¶
type Options struct {
// DisplayFree, when set, formats a zero amount as its string (or "free" when
// set to the empty string via DisplayFreeText).
DisplayFree bool
DisplayFreeText *string // custom free text; nil => "free"
// WithCurrency appends the ISO code (e.g. " USD") after the amount.
WithCurrency bool
// NoCents omits the decimal part entirely.
NoCents bool
// NoCentsIfWhole omits the decimal part only when it is all zeros.
NoCentsIfWhole bool
// DropTrailingZeros trims trailing zeros from the decimal part.
DropTrailingZeros bool
// Symbol controls the currency symbol. nil => default (the currency symbol);
// use SymbolOff(), SymbolOn() or SymbolString(s) to build it.
Symbol *SymbolRule
// Disambiguate uses the currency's disambiguate_symbol when available.
Disambiguate bool
// DecimalMark overrides the decimal separator; nil => currency/default ".".
DecimalMark *string
// ThousandsSeparator overrides the grouping separator; nil => currency/
// default. A pointer to "" (or a false-y value) disables grouping.
ThousandsSeparator *string
// SignPositive prefixes a "+" to positive amounts.
SignPositive bool
// SignBeforeSymbol places the sign before the symbol (e.g. "-$1.00").
SignBeforeSymbol bool
// Format overrides the "%u%n" template; nil => currency/symbol-position
// default.
Format *string
// SouthAsianNumberFormatting groups with the Indian lakh/crore pattern.
SouthAsianNumberFormatting bool
// IgnoreDefaults skips merging Money's process-wide default rules (used by
// Money#to_s). This package has no process-wide default rules, so it only
// affects nothing today, but is kept for API parity.
IgnoreDefaults bool
}
Options are the formatting rules for Money.Format, the analogue of the hash Money#format accepts. Tri-state fields (String / Symbol / …) use pointers so a nil pointer means "not supplied" (fall back to defaults) and a non-nil pointer carries an explicit value — matching how the gem distinguishes an absent key from a false/empty value.
type RoundingMode ¶
type RoundingMode int
RoundingMode selects how a non-integer number of minor units is rounded back to an integer, mirroring the BigDecimal::ROUND_* modes the gem uses. The gem's default is HalfUp (round half away from zero).
const ( // HalfUp rounds to the nearest neighbour; ties round away from zero // (BigDecimal::ROUND_HALF_UP — the gem default). HalfUp RoundingMode = iota // HalfDown rounds to the nearest neighbour; ties round toward zero. HalfDown // HalfEven rounds to the nearest neighbour; ties round to the even neighbour // (banker's rounding). HalfEven // Up rounds away from zero (ceil in magnitude). Up // Down truncates toward zero. Down // Ceiling rounds toward positive infinity. Ceiling // Floor rounds toward negative infinity. Floor )
type SingleCurrency ¶
type SingleCurrency struct{}
SingleCurrency is a bank that refuses every exchange, the analogue of Money::Bank::SingleCurrency — useful for apps that operate in one currency.
func NewSingleCurrency ¶
func NewSingleCurrency() *SingleCurrency
NewSingleCurrency returns a single-currency bank.
func (*SingleCurrency) ExchangeWith ¶
func (b *SingleCurrency) ExchangeWith(from *Money, to *Currency) (*Money, error)
ExchangeWith always returns a *DifferentCurrencyError unless from and to are the same currency, matching SingleCurrency#exchange_with.
type SymbolRule ¶
type SymbolRule struct {
// contains filtered or unexported fields
}
SymbolRule is the tri-state for the :symbol option: off, on (currency symbol), or a fixed string.
func SymbolOn ¶
func SymbolOn() *SymbolRule
SymbolOn selects the currency's own symbol (:symbol => true).
func SymbolString ¶
func SymbolString(s string) *SymbolRule
SymbolString forces a specific symbol string (:symbol => "ƒ").
type UnknownCurrencyError ¶
type UnknownCurrencyError struct{ ID string }
UnknownCurrencyError is returned when a currency id / code cannot be resolved, mirroring Money::Currency::UnknownCurrency.
func (*UnknownCurrencyError) Error ¶
func (e *UnknownCurrencyError) Error() string
type UnknownRateError ¶
type UnknownRateError struct{ From, To string }
UnknownRateError is returned when a bank has no rate for a currency pair, mirroring Money::Bank::UnknownRate.
func (*UnknownRateError) Error ¶
func (e *UnknownRateError) Error() string
type VariableExchange ¶
type VariableExchange struct {
// contains filtered or unexported fields
}
VariableExchange is a bank that exchanges using rates injected by the host, the analogue of Money::Bank::VariableExchange with the in-memory rate store. Rates are keyed by ISO-code pair and each direction is independent.
func NewVariableExchange ¶
func NewVariableExchange() *VariableExchange
NewVariableExchange returns an empty variable-exchange bank.
func (*VariableExchange) AddRate ¶
AddRate registers the rate for converting from -> to and returns it, matching VariableExchange#add_rate / #set_rate. Only this direction is set.
func (*VariableExchange) ExchangeWith ¶
func (b *VariableExchange) ExchangeWith(from *Money, to *Currency) (*Money, error)
ExchangeWith converts from into to using the stored rate, matching VariableExchange#exchange_with. The fractional amount is first rescaled for the two currencies' subunit_to_unit, multiplied by the rate, then rounded back to an integer number of minor units with the default rounding mode.
