-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdoc_test.go
154 lines (131 loc) · 5.46 KB
/
doc_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package cnfg_test
import (
"fmt"
"os"
"time"
"golift.io/cnfg"
)
// Complete working example for ENV.Unmarshal().
func ExampleENV_Unmarshal_simple() {
// Systems is used to show an example of how to access nested slices.
type System struct {
Name string `env:"name"`
Signal *[]int `env:"signal"`
}
// Config represents your application's environment variable based config inputs.
// Works with or without pointers.
type Config struct {
Debug bool `env:"debug"`
Users []string `env:"user"`
Interval *time.Duration `env:"interval"`
Systems []*System `env:"system"`
}
// Make a pointer to your struct with some default data.
// Maybe this data came from a config file? Using ParseFile()!
config := &Config{
Debug: true,
Users: []string{"me", "you", "them"},
Interval: nil,
Systems: nil,
}
// Okay set some ENV variables. Pretend you did this in bash.
os.Setenv("APP_DEBUG", "false") // turn off debug
os.Setenv("APP_USER_1", "dad") // replace "you" with "dad"
os.Setenv("APP_USER_3", "mom") // add "mom"
os.Setenv("APP_INTERVAL", "7m1s") // don't forget the interval!!
// This adds (creates) systems and signals in sub-slices.
os.Setenv("APP_SYSTEM_0_NAME", "SysWon")
os.Setenv("APP_SYSTEM_1_NAME", "SysToo")
os.Setenv("APP_SYSTEM_1_SIGNAL_0", "12")
// You can add as many as you like, as long as they are in numerical order.
os.Setenv("APP_SYSTEM_1_SIGNAL_1", "77")
fmt.Printf("BEFORE => Debug: %v, Interval: %v, Users: %v, Systems: %v\n",
config.Debug, config.Interval, config.Users, config.Systems)
// Make a ENV Decoder with special tag and prefix.
env := &cnfg.ENV{Tag: "env", Pfx: "APP"}
// Run Unmarshal to parse the values into your config pointer:
found, err := env.Unmarshal(config)
if err != nil {
panic(err)
}
// And optionally, do something with the "found" return value.
// If you wanted to overwrite ALL configs if ANY env variables are present
// you could use ok to make and if statement that does that.
if found {
fmt.Println("~ Environment variables were parsed into the config!")
}
// If you don't set an env variable for it, it will stay nil.
// Same for structs and slices.
if config.Interval == nil {
fmt.Printf("You forgot to set an interval!")
return
}
fmt.Printf("AFTER => Debug: %v, Interval: %v, Users: %v\n", config.Debug, *config.Interval, config.Users)
// We added some systems, check them!
for i, s := range config.Systems {
fmt.Printf(" %v: System Name: %v, Signals: %v\n", i, s.Name, s.Signal)
}
// Output: BEFORE => Debug: true, Interval: <nil>, Users: [me you them], Systems: []
// ~ Environment variables were parsed into the config!
// AFTER => Debug: false, Interval: 7m1s, Users: [me dad them mom]
// 0: System Name: SysWon, Signals: <nil>
// 1: System Name: SysToo, Signals: &[12 77]
}
// Complete working example for UnmarshalENV(). Use this method when the "xml"
// struct tag suits your application.
func ExampleUnmarshalENV() {
// Systems is used to show an example of how to access nested slices.
type System struct {
Name string `xml:"name"`
Signal []byte `xml:"signal"`
Ion *map[string]string `xml:"ion"`
}
// Config represents your application's environment variable based config inputs.
// Works with or without pointers.
type Config struct {
Users []struct {
Name string `xml:"name"`
Levels []float64 `xml:"level"`
} `xml:"user"`
Systems []*System `xml:"system"`
}
// Make a pointer to your struct. It may be empty or contain defaults.
// It may contain nested pointers, structs, maps, slices, etc. It all works.
config := &Config{}
// Okay set some ENV variables. Pretend you did this in bash.
// Setting these will overwrite any existing data. If you set a slice that
// does not exist, it has to be the _following_ index number. In other words,
// if your slice is empty, setting APP_USER_1_NAME wont work, you have to start
// with 0. If your slice len is 2, you can append by setting APP_USER_2_NAME
os.Setenv("APP_USER_0_NAME", "Tim")
os.Setenv("APP_USER_0_LEVEL_0", "1")
os.Setenv("APP_USER_0_LEVEL_1", "13")
os.Setenv("APP_USER_1_NAME", "Jon")
os.Setenv("APP_USER_1_LEVEL_0", "1")
// This adds (creates) systems and signals in sub-slices.
os.Setenv("APP_SYSTEM_0_NAME", "SysWon")
os.Setenv("APP_SYSTEM_1_NAME", "SysToo")
// With []byte you can only pass a string, and it's converted.
// You cannot access a byte member directly. Do you need to? Let me know!
os.Setenv("APP_SYSTEM_0_SIGNAL", "123456")
os.Setenv("APP_SYSTEM_1_SIGNAL", "654321")
// Maps inside slices! You can nest all you want, but your variable names may get lengthy.
fmt.Printf("BEFORE => Users: %v, Systems: %v\n", len(config.Users), len(config.Systems))
os.Setenv("APP_SYSTEM_1_ION_reactor-1", "overload")
os.Setenv("APP_SYSTEM_1_ION_reactor-2", "underload")
// Run Unmarshal to parse the values into your config pointer.
// We ignore "ok" here. You may choose to capture and it do something though.
_, err := cnfg.UnmarshalENV(config, "APP")
if err != nil {
panic(err)
}
fmt.Printf("AFTER => Users: %v\n", config.Users)
for i, s := range config.Systems {
fmt.Printf(" %v: System Name: %v, Signals: %v, Ion: %v\n", i, s.Name, s.Signal, s.Ion)
}
// Output:
// BEFORE => Users: 0, Systems: 0
// AFTER => Users: [{Tim [1 13]} {Jon [1]}]
// 0: System Name: SysWon, Signals: [49 50 51 52 53 54], Ion: <nil>
// 1: System Name: SysToo, Signals: [54 53 52 51 50 49], Ion: &map[reactor-1:overload reactor-2:underload]
}