Added support for custom error handlers for MustXXX() functions.
Changed default from panic to log fatal.
diff --git a/README.md b/README.md
index c457fd7..aca7dbf 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,11 @@
Filenames can also contain environment variables like in
`/home/${USER}/myapp.properties`.
+Starting from version 1.3.0 the behavior of the MustXXX() functions is
+configurable by providing a custom ErrorHandler function. The default has
+changed from panic to log.Fatal but this is configurable and custom
+error handling functions can be provided.
+
The properties library supports both ISO-8859-1 and UTF-8 encoded data.
Getting Started
@@ -38,6 +43,12 @@
History
-------
+v1.3.0, 18 Mar 2014
+-------------------
+* Added support for time.Duration
+* Made MustXXX() failure behavior configurable (log.Fatal, panic, custom)
+* Changed default of MustXXX() failure from panic to log.Fatal
+
v1.2.0, 05 Mar 2014
-------------------
* Added MustGet... functions
diff --git a/doc.go b/doc.go
index 01f22e0..c1304bc 100644
--- a/doc.go
+++ b/doc.go
@@ -92,6 +92,30 @@
// v = p.GetUint64("key", 999)
// v = p.GetFloat64("key", 123.0)
// v = p.GetString("key", "def")
+// v = p.GetDuration("key", 999)
+//
+// Properties provides several MustXXX() convenience functions
+// which will terminate the app if an error occurs. The behavior
+// of the failure is configurable and the default is to call
+// log.Fatal(err). To have the MustXXX() functions panic instead
+// of logging the error set a different ErrorHandler before
+// you use the Properties package.
+//
+// properties.ErrorHandler = properties.PanicHandler
+//
+// # Will panic instead of logging an error
+// p := properties.MustLoadFile("config.properties")
+//
+// You can also provide your own ErrorHandler function. The only requirement
+// is that the error handler function must exit after handling the error.
+//
+// properties.ErrorHandler = func(err error) {
+// fmt.Println(err)
+// os.Exit(1)
+// }
+//
+// # Will write to stdout and then exit
+// p := properties.MustLoadFile("config.properties")
//
// The following documents provide a description of the properties
// file format.
diff --git a/load.go b/load.go
index 757c077..7afd436 100644
--- a/load.go
+++ b/load.go
@@ -54,7 +54,7 @@
if err != nil {
return nil, err
}
-
+
return p, p.check()
}
@@ -87,7 +87,7 @@
func mustLoadFiles(filenames []string, enc Encoding, ignoreMissing bool) *Properties {
p, err := loadFiles(filenames, enc, ignoreMissing)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return p
}
@@ -114,6 +114,7 @@
}
return string(runes)
default:
- panic(fmt.Sprintf("Unsupported encoding %v", enc))
+ ErrorHandler(fmt.Errorf("Unsupported encoding %v", enc))
}
+ panic("ErrorHandler should exit")
}
diff --git a/properties.go b/properties.go
index 52e9248..07fef2c 100644
--- a/properties.go
+++ b/properties.go
@@ -10,6 +10,7 @@
import (
"fmt"
"io"
+ "log"
"os"
"strconv"
"strings"
@@ -17,6 +18,27 @@
"unicode/utf8"
)
+// ErrorHandlerFunc defines the type of function which handles failures
+// of the MustXXX() functions. An error handler function must exit
+// the application after handling the error.
+type ErrorHandlerFunc func(error)
+
+// ErrorHandler is the function which handles failures of the MustXXX()
+// functions. The default is LogFatalHandler.
+var ErrorHandler ErrorHandlerFunc = LogFatalHandler
+
+// LogFatalHandler handles the error by logging a fatal error and exiting.
+func LogFatalHandler(err error) {
+ log.Fatal(err)
+}
+
+// PanicHandler handles the error by panicking.
+func PanicHandler(err error) {
+ panic(err)
+}
+
+// -----------------------------------------------------------------------------
+
type Properties struct {
// Pre-/Postfix for property expansion.
Prefix string
@@ -49,7 +71,7 @@
// circular references and malformed expressions
// so we panic if we still get an error here.
if err != nil {
- panic(fmt.Errorf("%s in %q", err, key+" = "+v))
+ ErrorHandler(fmt.Errorf("%s in %q", err, key+" = "+v))
}
return expanded, true
@@ -61,7 +83,8 @@
if v, ok := p.Get(key); ok {
return v
}
- panic(invalidKeyError(key))
+ ErrorHandler(invalidKeyError(key))
+ panic("ErrorHandler should exit")
}
// ----------------------------------------------------------------------------
@@ -83,7 +106,7 @@
func (p *Properties) MustGetBool(key string) bool {
v, err := p.getBool(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return v
}
@@ -114,7 +137,7 @@
func (p *Properties) MustGetDuration(key string) time.Duration {
v, err := p.getInt64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return time.Duration(v)
}
@@ -137,7 +160,7 @@
func (p *Properties) MustGetFloat64(key string) float64 {
v, err := p.getFloat64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return v
}
@@ -174,7 +197,7 @@
func (p *Properties) MustGetInt(key string) int {
v, err := p.getInt64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return intRangeCheck(key, v)
}
@@ -197,7 +220,7 @@
func (p *Properties) MustGetInt64(key string) int64 {
v, err := p.getInt64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return v
}
@@ -234,7 +257,7 @@
func (p *Properties) MustGetUint(key string) uint {
v, err := p.getUint64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return uintRangeCheck(key, v)
}
@@ -257,7 +280,7 @@
func (p *Properties) MustGetUint64(key string) uint64 {
v, err := p.getUint64(key)
if err != nil {
- panic(err)
+ ErrorHandler(err)
}
return v
}
@@ -290,7 +313,8 @@
if v, ok := p.Get(key); ok {
return v
}
- panic(invalidKeyError(key))
+ ErrorHandler(invalidKeyError(key))
+ panic("ErrorHandler should exit")
}
// ----------------------------------------------------------------------------
diff --git a/properties_test.go b/properties_test.go
index fc86dd4..d3555f6 100644
--- a/properties_test.go
+++ b/properties_test.go
@@ -19,13 +19,28 @@
func Test(t *testing.T) { TestingT(t) }
-type TestSuite struct{}
+type TestSuite struct {
+ prevHandler ErrorHandlerFunc
+}
var (
_ = Suite(&TestSuite{})
verbose = flag.Bool("verbose", false, "Verbose output")
)
+// --------------------------------------------------------------------
+
+func (s *TestSuite) SetUpSuite(c *C) {
+ s.prevHandler = ErrorHandler
+ ErrorHandler = PanicHandler
+}
+
+// --------------------------------------------------------------------
+
+func (s *TestSuite) TearDownSuite(c *C) {
+ ErrorHandler = s.prevHandler
+}
+
// ----------------------------------------------------------------------------
// define test cases in the form of