Skip to content

Commit

Permalink
add NewFromString #108
Browse files Browse the repository at this point in the history
  • Loading branch information
npinochet committed Aug 3, 2022
1 parent e9d346f commit a2b580e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 1 deletion.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,10 @@ Initialize Money by using smallest unit value (e.g 100 represents 1 pound). Use
```go
pound := money.New(100, money.GBP)
```
Or initialize Money using the direct amount.
Or initialize Money using the direct amount as float or numeric string.
```go
quarterEuro := money.NewFromFloat(0.25, money.EUR)
twoFiftyDolars := money.NewFromString("2.50", money.USD)
```
Comparison
-
Expand Down
30 changes: 30 additions & 0 deletions money.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"errors"
"fmt"
"math"
"strconv"
"strings"
)

// Injection points for backward compatibility.
Expand Down Expand Up @@ -93,6 +95,34 @@ func NewFromFloat(amount float64, currency string) *Money {
return New(int64(amount*currencyDecimals), currency)
}

// NewFromString creates and returns new instance of Money from a string.
// Can only parse simple float-like strings, like "1.23" USD or "1,5" ARS, not "1.23 USD", "$1.23" or "1,000" USD.
func NewFromString(amount string, currencyCode string) (*Money, error) {
currency := GetCurrency(currencyCode)
fraction := currency.Fraction

toParse := amount
var decimals int
if pointIndex := strings.Index(amount, currency.Decimal); pointIndex != -1 {
decimals = len(amount) - pointIndex - 1
if decimals > fraction {
decimals = fraction
}
toParse = amount[:pointIndex] + amount[pointIndex+1:pointIndex+1+decimals]
}

parsed, err := strconv.ParseInt(toParse, 10, 64)
if err != nil {
return nil, fmt.Errorf("can't parse '%s' to money", amount)
}

for d := decimals; d < fraction; d++ {
parsed *= 10
}

return New(parsed, currencyCode), nil
}

// Currency returns the currency used by Money.
func (m *Money) Currency() *Currency {
return m.currency
Expand Down
32 changes: 32 additions & 0 deletions money_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,38 @@ func TestNewFromFloat(t *testing.T) {
}
}

func TestNewFromString(t *testing.T) {
m, err := NewFromString("12.34", EUR)

if err != nil {
t.Error(err)
}

if m.amount != 1234 {
t.Errorf("Expected %d got %d", 1234, m.amount)
}

if m.currency.Code != EUR {
t.Errorf("Expected currency %s got %s", EUR, m.currency.Code)
}

m, err = NewFromString("-1.12345", EUR)

if err != nil {
t.Error(err)
}

if m.amount != -112 {
t.Errorf("Expected %d got %d", -112, m.amount)
}

_, err = NewFromString("invalid_input", EUR)

if err.Error() != "can't parse 'invalid_input' to money" {
t.Error(err)
}
}

func TestDefaultMarshal(t *testing.T) {
given := New(12345, IQD)
expected := `{"amount":12345,"currency":"IQD"}`
Expand Down

0 comments on commit a2b580e

Please sign in to comment.