Merge pull request #8 from pascaldekloe/flag-binding
New flag integration
diff --git a/README.md b/README.md
index da3af46..b3b2e5c 100644
--- a/README.md
+++ b/README.md
@@ -30,7 +30,10 @@
---------------
```go
-import "github.com/magiconair/properties"
+import (
+ "flag"
+ "github.com/magiconair/properties"
+)
func main() {
p := properties.MustLoadFile("${HOME}/config.properties", properties.UTF8)
@@ -39,7 +42,7 @@
host := p.MustGetString("host")
port := p.GetInt("port", 8080)
- // or via decode
+ // or via decode
type Config struct {
Host string `properties:"host"`
Port int `properties:"port,default=9000"`
@@ -50,6 +53,9 @@
if err := p.Decode(&cfg); err != nil {
log.Fatal(err)
}
+
+ // or via flags
+ p.MustFlag(flag.CommandLine)
}
```
diff --git a/doc.go b/doc.go
index 6bca5cb..1d3fb86 100644
--- a/doc.go
+++ b/doc.go
@@ -102,6 +102,16 @@
// v = p.GetString("key", "def")
// v = p.GetDuration("key", 999)
//
+// As an alterantive properties may be applied with the standard
+// library's flag implementation at any time.
+//
+// # Standard configuration
+// v = flag.Int("key", 999, "help message")
+// flag.Parse()
+//
+// # Merge p into the flag set
+// p.MustFlag(flag.CommandLine)
+//
// 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
diff --git a/integrate.go b/integrate.go
new file mode 100644
index 0000000..1e97290
--- /dev/null
+++ b/integrate.go
@@ -0,0 +1,30 @@
+package properties
+
+import "flag"
+
+// MustFlag sets flags that are skipped by dst.Parse when p contains
+// the respective key for flag.Flag.Name.
+//
+// It's use is recommended with command line arguments as in:
+// flag.Parse()
+// p.MustFlag(flag.CommandLine)
+func (p *Properties) MustFlag(dst *flag.FlagSet) {
+ m := make(map[string]*flag.Flag)
+ dst.VisitAll(func(f *flag.Flag) {
+ m[f.Name] = f
+ })
+ dst.Visit(func(f *flag.Flag) {
+ delete(m, f.Name) // overridden
+ })
+
+ for name, f := range m {
+ v, ok := p.Get(name)
+ if !ok {
+ continue
+ }
+
+ if err := f.Value.Set(v); err != nil {
+ ErrorHandler(err)
+ }
+ }
+}
diff --git a/integrate_test.go b/integrate_test.go
new file mode 100644
index 0000000..90daaa2
--- /dev/null
+++ b/integrate_test.go
@@ -0,0 +1,70 @@
+package properties
+
+import (
+ "flag"
+ "fmt"
+ "testing"
+)
+
+// TestFlag verifies Properties.MustFlag without flag.FlagSet.Parse
+func TestFlag(t *testing.T) {
+ f := flag.NewFlagSet("src", flag.PanicOnError)
+ gotS := f.String("s", "?", "string flag")
+ gotI := f.Int("i", -1, "int flag")
+
+ p := NewProperties()
+ p.Set("s", "t")
+ p.Set("i", "9")
+ p.MustFlag(f)
+
+ if want := "t"; *gotS != want {
+ t.Errorf("Got string s=%q, want %q", *gotS, want)
+ }
+ if want := 9; *gotI != want {
+ t.Errorf("Got int i=%d, want %d", *gotI, want)
+ }
+}
+
+// TestFlagOverride verifies Properties.MustFlag with flag.FlagSet.Parse.
+func TestFlagOverride(t *testing.T) {
+ f := flag.NewFlagSet("src", flag.PanicOnError)
+ gotA := f.Int("a", 1, "remain default")
+ gotB := f.Int("b", 2, "customized")
+ gotC := f.Int("c", 3, "overridden")
+
+ f.Parse([]string{"-c", "4"})
+
+ p := NewProperties()
+ p.Set("b", "5")
+ p.Set("c", "6")
+ p.MustFlag(f)
+
+ if want := 1; *gotA != want {
+ t.Errorf("Got remain default a=%d, want %d", *gotA, want)
+ }
+ if want := 5; *gotB != want {
+ t.Errorf("Got customized b=%d, want %d", *gotB, want)
+ }
+ if want := 4; *gotC != want {
+ t.Errorf("Got overriden c=%d, want %d", *gotC, want)
+ }
+}
+
+func ExampleProperties_MustFlag() {
+ x := flag.Int("x", 0, "demo customize")
+ y := flag.Int("y", 0, "demo override")
+
+ // Demo alternative for flag.Parse():
+ flag.CommandLine.Parse([]string{"-y", "10"})
+ fmt.Printf("flagged as x=%d, y=%d\n", *x, *y)
+
+ p := NewProperties()
+ p.Set("x", "7")
+ p.Set("y", "42") // note discard
+ p.MustFlag(flag.CommandLine)
+ fmt.Printf("configured to x=%d, y=%d\n", *x, *y)
+
+ // Output:
+ // flagged as x=0, y=10
+ // configured to x=7, y=10
+}