Skip to content

Commit

Permalink
Add basic functions.
Browse files Browse the repository at this point in the history
  • Loading branch information
leekchan committed Aug 10, 2015
1 parent d1eaeda commit 8eca1cf
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 1 deletion.
9 changes: 9 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
language: go
go:
- tip
before_install:
- go get github.com/axw/gocov/gocov
- go get github.com/mattn/goveralls
- if ! go get code.google.com/p/go.tools/cmd/cover; then go get golang.org/x/tools/cmd/cover; fi
script:
- $HOME/gopath/bin/goveralls -service=travis-ci
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2015 Kyoung-chan Lee
Copyright (c) 2015 Kyoung-chan Lee ([email protected])

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
73 changes: 73 additions & 0 deletions accounting.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package accounting

import (
"strings"
)

type Accounting struct {
Symbol string
Precision int
Thousand string
Decimal string
Format string
FormatNegative string
FormatZero string
}

func (accounting *Accounting) init() {
if accounting.Thousand == "" {
accounting.Thousand = ","
}

if accounting.Decimal == "" {
accounting.Decimal = "."
}

if accounting.Format == "" {
accounting.Format = "%s%v"
}

if accounting.FormatNegative == "" {
accounting.FormatNegative = strings.Replace(strings.Replace(accounting.Format, "-", "", -1), "%v", "-%v", -1)
}

if accounting.FormatZero == "" {
accounting.FormatZero = "0"
}
}

func (accounting *Accounting) formatMoneyString(formattedNumber string) string {
var format string

if formattedNumber[0] == '-' {
format = accounting.FormatNegative
formattedNumber = formattedNumber[1:]
} else if formattedNumber == "0" {
format = accounting.FormatZero
} else {
format = accounting.Format
}

result := strings.Replace(format, "%s", accounting.Symbol, -1)
result = strings.Replace(result, "%v", formattedNumber, -1)

return result
}

func (accounting *Accounting) FormatMoney(value interface{}) string {
accounting.init()
formattedNumber := FormatNumber(value, accounting.Precision, accounting.Thousand, accounting.Decimal)
return accounting.formatMoneyString(formattedNumber)
}

func (accounting *Accounting) FormatMoneyInt(value int) string {
accounting.init()
formattedNumber := FormatNumberInt(value, accounting.Precision, accounting.Thousand, accounting.Decimal)
return accounting.formatMoneyString(formattedNumber)
}

func (accounting *Accounting) FormatMoneyFloat64(value float64) string {
accounting.init()
formattedNumber := FormatNumberFloat64(value, accounting.Precision, accounting.Thousand, accounting.Decimal)
return accounting.formatMoneyString(formattedNumber)
}
66 changes: 66 additions & 0 deletions accounting_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package accounting

import (
"testing"
)

func AssertEqual(t *testing.T, x, y string) {
if x != y {
t.Error("Expected ", y, ", got ", x)
}
}

func TestFormatMoney(t *testing.T) {
accounting := Accounting{Symbol: "$", Precision: 2}
AssertEqual(t, accounting.FormatMoney(123456789.213123), "$123,456,789.21")
AssertEqual(t, accounting.FormatMoney(12345678), "$12,345,678.00")

accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","}
AssertEqual(t, accounting.FormatMoney(4999.99), "€4.999,99")
AssertEqual(t, accounting.FormatMoney(-4999.99), "€-4.999,99")

accounting = Accounting{Symbol: "£ ", Precision: 0}
AssertEqual(t, accounting.FormatMoney(-500000), "£ -500,000")

accounting = Accounting{Symbol: "GBP", Precision: 0,
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"}
AssertEqual(t, accounting.FormatMoney(1000000), "GBP 1,000,000")
AssertEqual(t, accounting.FormatMoney(-5000), "GBP (5,000)")
AssertEqual(t, accounting.FormatMoney(0), "GBP --")
}

func TestFormatMoneyInt(t *testing.T) {
accounting := Accounting{Symbol: "$", Precision: 2}
AssertEqual(t, accounting.FormatMoneyInt(12345678), "$12,345,678.00")

accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","}
AssertEqual(t, accounting.FormatMoneyInt(4999), "€4.999,00")
AssertEqual(t, accounting.FormatMoneyInt(-4999), "€-4.999,00")

accounting = Accounting{Symbol: "£ ", Precision: 0}
AssertEqual(t, accounting.FormatMoneyInt(-500000), "£ -500,000")

accounting = Accounting{Symbol: "GBP", Precision: 0,
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"}
AssertEqual(t, accounting.FormatMoneyInt(1000000), "GBP 1,000,000")
AssertEqual(t, accounting.FormatMoneyInt(-5000), "GBP (5,000)")
AssertEqual(t, accounting.FormatMoneyInt(0), "GBP --")
}

func TestFormatMoneyFloat64(t *testing.T) {
accounting := Accounting{Symbol: "$", Precision: 2}
AssertEqual(t, accounting.FormatMoneyFloat64(123456789.213123), "$123,456,789.21")

accounting = Accounting{Symbol: "€", Precision: 2, Thousand: ".", Decimal: ","}
AssertEqual(t, accounting.FormatMoneyFloat64(4999.99), "€4.999,99")
AssertEqual(t, accounting.FormatMoneyFloat64(-4999.99), "€-4.999,99")

accounting = Accounting{Symbol: "£ ", Precision: 0}
AssertEqual(t, accounting.FormatMoneyFloat64(-500000.0), "£ -500,000")

accounting = Accounting{Symbol: "GBP", Precision: 0,
Format: "%s %v", FormatNegative: "%s (%v)", FormatZero: "%s --"}
AssertEqual(t, accounting.FormatMoneyFloat64(1000000.0), "GBP 1,000,000")
AssertEqual(t, accounting.FormatMoneyFloat64(-5000.0), "GBP (5,000)")
AssertEqual(t, accounting.FormatMoneyFloat64(0.0), "GBP --")
}
105 changes: 105 additions & 0 deletions formatnumber.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package accounting

import (
"bytes"
"fmt"
"math"
"reflect"
"strings"
)

func formatNumberString(x string, precision int, thousand string, decimal string) string {
lastIndex := strings.Index(x, ".") - 1

if lastIndex < 0 {
lastIndex = len(x) - 1
}

var buffer []byte
var strBuffer bytes.Buffer

j := 0
for i := lastIndex; i >= 0; i-- {
j++
buffer = append(buffer, x[i])

if j == 3 && i > 0 && !(i == 1 && x[0] == '-') {
buffer = append(buffer, ',')
j = 0
}
}

for i := len(buffer) - 1; i >= 0; i-- {
strBuffer.WriteByte(buffer[i])
}
result := strBuffer.String()

if thousand != "," {
result = strings.Replace(result, ",", thousand, -1)
}

extra := x[lastIndex+1:]
if decimal != "." {
extra = strings.Replace(extra, ".", decimal, 1)
}

return result + extra
}

func FormatNumber(value interface{}, precision int, thousand string, decimal string) string {
v := reflect.ValueOf(value)

var x string
switch v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
x = fmt.Sprintf("%d", v.Int())
if precision > 0 {
x += "." + strings.Repeat("0", precision)
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
x = fmt.Sprintf("%d", v.Uint())
if precision > 0 {
x += "." + strings.Repeat("0", precision)
}
case reflect.Float32, reflect.Float64:
x = fmt.Sprintf(fmt.Sprintf("%%.%df", precision), v.Float())
default:
return ""
}

return formatNumberString(x, precision, thousand, decimal)
}

func FormatNumberInt(x int, precision int, thousand string, decimal string) string {
var result string
var minus bool

if x == math.MinInt64 {
return FormatNumber(x, precision, thousand, decimal)
}

if x < 0 {
minus = true
x *= -1
}

for x >= 1000 {
result = fmt.Sprintf("%s%03d%s", thousand, x%1000, result)
x /= 1000
}
result = fmt.Sprintf("%d%s", x, result)

if minus {
result = "-" + result
}

if precision > 0 {
result += decimal + strings.Repeat("0", precision)
}

return result
}

func FormatNumberFloat64(x float64, precision int, thousand string, decimal string) string {
return formatNumberString(fmt.Sprintf(fmt.Sprintf("%%.%df", precision), x), precision, thousand, decimal)
}
65 changes: 65 additions & 0 deletions formatnumber_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package accounting

import (
"math"
"testing"
)

func TestFormatNumber(t *testing.T) {
AssertEqual(t, FormatNumber(123456789.213123, 3, ",", "."), "123,456,789.213")
AssertEqual(t, FormatNumber(123456789.213123, 3, ".", ","), "123.456.789,213")
AssertEqual(t, FormatNumber(-12345.123123, 5, ",", "."), "-12,345.12312")
AssertEqual(t, FormatNumber(-1234.123123, 5, ",", "."), "-1,234.12312")
AssertEqual(t, FormatNumber(-123.123123, 5, ",", "."), "-123.12312")
AssertEqual(t, FormatNumber(-12.123123, 5, ",", "."), "-12.12312")
AssertEqual(t, FormatNumber(-1.123123, 5, ",", "."), "-1.12312")
AssertEqual(t, FormatNumber(math.MaxInt64, 10, ",", "."), "9,223,372,036,854,775,807.0000000000")
AssertEqual(t, FormatNumber(math.MinInt64, 10, ",", "."), "-9,223,372,036,854,775,808.0000000000")
AssertEqual(t, FormatNumber(-1, 3, ",", "."), "-1.000")
AssertEqual(t, FormatNumber(-10, 3, ",", "."), "-10.000")
AssertEqual(t, FormatNumber(-100, 3, ",", "."), "-100.000")
AssertEqual(t, FormatNumber(-1000, 3, ",", "."), "-1,000.000")
AssertEqual(t, FormatNumber(-10000, 3, ",", "."), "-10,000.000")
AssertEqual(t, FormatNumber(-100000, 3, ",", "."), "-100,000.000")
AssertEqual(t, FormatNumber(-1000000, 3, ",", "."), "-1,000,000.000")
AssertEqual(t, FormatNumber(1, 3, ",", "."), "1.000")
AssertEqual(t, FormatNumber(10, 3, ",", "."), "10.000")
AssertEqual(t, FormatNumber(100, 3, ",", "."), "100.000")
AssertEqual(t, FormatNumber(1000, 3, ",", "."), "1,000.000")
AssertEqual(t, FormatNumber(10000, 3, ",", "."), "10,000.000")
AssertEqual(t, FormatNumber(100000, 3, ",", "."), "100,000.000")
AssertEqual(t, FormatNumber(1000000, 3, ",", "."), "1,000,000.000")
AssertEqual(t, FormatNumber(1000000, 10, " ", "."), "1 000 000.0000000000")
AssertEqual(t, FormatNumber(1000000, 10, " ", "."), "1 000 000.0000000000")
}

func TestFormatNumberInt(t *testing.T) {
AssertEqual(t, FormatNumberInt(math.MaxInt64, 10, ",", "."), "9,223,372,036,854,775,807.0000000000")
AssertEqual(t, FormatNumberInt(math.MinInt64+1, 10, ",", "."), "-9,223,372,036,854,775,807.0000000000")
AssertEqual(t, FormatNumberInt(math.MinInt64, 10, ",", "."), "-9,223,372,036,854,775,808.0000000000")
AssertEqual(t, FormatNumberInt(-1, 3, ",", "."), "-1.000")
AssertEqual(t, FormatNumberInt(-10, 3, ",", "."), "-10.000")
AssertEqual(t, FormatNumberInt(-100, 3, ",", "."), "-100.000")
AssertEqual(t, FormatNumberInt(-1000, 3, ",", "."), "-1,000.000")
AssertEqual(t, FormatNumberInt(-10000, 3, ",", "."), "-10,000.000")
AssertEqual(t, FormatNumberInt(-100000, 3, ",", "."), "-100,000.000")
AssertEqual(t, FormatNumberInt(-1000000, 3, ",", "."), "-1,000,000.000")
AssertEqual(t, FormatNumberInt(1, 3, ",", "."), "1.000")
AssertEqual(t, FormatNumberInt(10, 3, ",", "."), "10.000")
AssertEqual(t, FormatNumberInt(100, 3, ",", "."), "100.000")
AssertEqual(t, FormatNumberInt(1000, 3, ",", "."), "1,000.000")
AssertEqual(t, FormatNumberInt(10000, 3, ",", "."), "10,000.000")
AssertEqual(t, FormatNumberInt(100000, 3, ",", "."), "100,000.000")
AssertEqual(t, FormatNumberInt(1000000, 3, ",", "."), "1,000,000.000")
AssertEqual(t, FormatNumberInt(1000000, 10, " ", "."), "1 000 000.0000000000")
AssertEqual(t, FormatNumberInt(1000000, 10, " ", "."), "1 000 000.0000000000")
}

func TestFormatNumberFloat64(t *testing.T) {
AssertEqual(t, FormatNumber(123456789.213123, 3, ",", "."), "123,456,789.213")
AssertEqual(t, FormatNumber(-12345.123123, 5, ",", "."), "-12,345.12312")
AssertEqual(t, FormatNumber(-1234.123123, 5, ",", "."), "-1,234.12312")
AssertEqual(t, FormatNumber(-123.123123, 5, ",", "."), "-123.12312")
AssertEqual(t, FormatNumber(-12.123123, 5, ",", "."), "-12.12312")
AssertEqual(t, FormatNumber(-1.123123, 5, ",", "."), "-1.12312")
}

0 comments on commit 8eca1cf

Please sign in to comment.