Skip to content

Commit e7bf770

Browse files
committed
Fix jinzhu#34
1 parent f52abb2 commit e7bf770

File tree

2 files changed

+64
-16
lines changed

2 files changed

+64
-16
lines changed

configor_test.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,15 @@ type Anonymous struct {
1717
}
1818

1919
type testConfig struct {
20-
APPName string `default:"configor"`
20+
APPName string `default:"configor" json:",omitempty"`
2121
Hosts []string
2222

2323
DB struct {
2424
Name string
2525
User string `default:"root"`
2626
Password string `required:"true" env:"DBPassword"`
27-
Port uint `default:"3306"`
27+
Port uint `default:"3306" json:",omitempty"`
28+
SSL bool `default:"true" json:",omitempty"`
2829
}
2930

3031
Contacts []struct {
@@ -45,12 +46,14 @@ func generateDefaultConfig() testConfig {
4546
Name string
4647
User string `default:"root"`
4748
Password string `required:"true" env:"DBPassword"`
48-
Port uint `default:"3306"`
49+
Port uint `default:"3306" json:",omitempty"`
50+
SSL bool `default:"true" json:",omitempty"`
4951
}{
5052
Name: "configor",
5153
User: "configor",
5254
Password: "configor",
5355
Port: 3306,
56+
SSL: true,
5457
},
5558
Contacts: []struct {
5659
Name string
@@ -136,6 +139,7 @@ func TestDefaultValue(t *testing.T) {
136139
config := generateDefaultConfig()
137140
config.APPName = ""
138141
config.DB.Port = 0
142+
config.DB.SSL = false
139143

140144
if bytes, err := json.Marshal(config); err == nil {
141145
if file, err := ioutil.TempFile("/tmp", "configor"); err == nil {
@@ -145,6 +149,7 @@ func TestDefaultValue(t *testing.T) {
145149

146150
var result testConfig
147151
Load(&result, file.Name())
152+
148153
if !reflect.DeepEqual(result, generateDefaultConfig()) {
149154
t.Errorf("result should be set default value correctly")
150155
}

utils.go

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,6 @@ func processFile(config interface{}, file string, errorOnUnmatchedKeys bool) err
115115
case strings.HasSuffix(file, ".json"):
116116
return unmarshalJSON(data, config, errorOnUnmatchedKeys)
117117
default:
118-
119118
if err := unmarshalToml(data, config, errorOnUnmatchedKeys); err == nil {
120119
return nil
121120
} else if errUnmatchedKeys, ok := err.(*UnmatchedTomlKeysError); ok {
@@ -188,6 +187,55 @@ func getPrefixForStruct(prefixes []string, fieldStruct *reflect.StructField) []s
188187
return append(prefixes, fieldStruct.Name)
189188
}
190189

190+
func (configor *Configor) processDefaults(config interface{}) error {
191+
configValue := reflect.Indirect(reflect.ValueOf(config))
192+
if configValue.Kind() != reflect.Struct {
193+
return errors.New("invalid config, should be struct")
194+
}
195+
196+
configType := configValue.Type()
197+
for i := 0; i < configType.NumField(); i++ {
198+
var (
199+
fieldStruct = configType.Field(i)
200+
field = configValue.Field(i)
201+
)
202+
203+
if !field.CanAddr() || !field.CanInterface() {
204+
continue
205+
}
206+
207+
if isBlank := reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()); isBlank {
208+
// Set default configuration if blank
209+
if value := fieldStruct.Tag.Get("default"); value != "" {
210+
if err := yaml.Unmarshal([]byte(value), field.Addr().Interface()); err != nil {
211+
return err
212+
}
213+
}
214+
}
215+
216+
for field.Kind() == reflect.Ptr {
217+
field = field.Elem()
218+
}
219+
220+
switch field.Kind() {
221+
case reflect.Struct:
222+
if err := configor.processDefaults(field.Addr().Interface()); err != nil {
223+
return err
224+
}
225+
case reflect.Slice:
226+
for i := 0; i < field.Len(); i++ {
227+
if reflect.Indirect(field.Index(i)).Kind() == reflect.Struct {
228+
if err := configor.processDefaults(field.Index(i).Addr().Interface()); err != nil {
229+
return err
230+
}
231+
}
232+
}
233+
}
234+
}
235+
236+
return nil
237+
}
238+
191239
func (configor *Configor) processTags(config interface{}, prefixes ...string) error {
192240
configValue := reflect.Indirect(reflect.ValueOf(config))
193241
if configValue.Kind() != reflect.Struct {
@@ -244,16 +292,9 @@ func (configor *Configor) processTags(config interface{}, prefixes ...string) er
244292
}
245293
}
246294

247-
if isBlank := reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()); isBlank {
248-
// Set default configuration if blank
249-
if value := fieldStruct.Tag.Get("default"); value != "" {
250-
if err := yaml.Unmarshal([]byte(value), field.Addr().Interface()); err != nil {
251-
return err
252-
}
253-
} else if fieldStruct.Tag.Get("required") == "true" {
254-
// return error if it is required but blank
255-
return errors.New(fieldStruct.Name + " is required, but blank")
256-
}
295+
if isBlank := reflect.DeepEqual(field.Interface(), reflect.Zero(field.Type()).Interface()); isBlank && fieldStruct.Tag.Get("required") == "true" {
296+
// return error if it is required but blank
297+
return errors.New(fieldStruct.Name + " is required, but blank")
257298
}
258299

259300
for field.Kind() == reflect.Ptr {
@@ -267,8 +308,7 @@ func (configor *Configor) processTags(config interface{}, prefixes ...string) er
267308
}
268309

269310
if field.Kind() == reflect.Slice {
270-
arrLen := field.Len()
271-
if arrLen > 0 {
311+
if arrLen := field.Len(); arrLen > 0 {
272312
for i := 0; i < arrLen; i++ {
273313
if reflect.Indirect(field.Index(i)).Kind() == reflect.Struct {
274314
if err := configor.processTags(field.Index(i).Addr().Interface(), append(getPrefixForStruct(prefixes, &fieldStruct), fmt.Sprint(i))...); err != nil {
@@ -327,6 +367,9 @@ func (configor *Configor) load(config interface{}, watchMode bool, files ...stri
327367
}
328368
}
329369

370+
// process defaults
371+
configor.processDefaults(config)
372+
330373
for _, file := range configFiles {
331374
if configor.Config.Debug || configor.Config.Verbose {
332375
fmt.Printf("Loading configurations from file '%v'...\n", file)

0 commit comments

Comments
 (0)