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