1
0
Fork 0
confection/config.go

128 lines
2.4 KiB
Go
Raw Normal View History

2015-01-18 10:50:03 +00:00
package confection
import (
"bytes"
"encoding/json"
"fmt"
"reflect"
"strings"
)
type (
config struct {
config interface{}
}
configField struct {
2015-01-18 11:23:58 +00:00
Path string `json:"path"`
Type string `json:"type"`
Value interface{} `json:"value"`
IsRequired bool `json:"is_required"`
IsReadonly bool `json:"is_readonly"`
Title string `json:"title"`
Options []string `json:"options"`
2015-01-18 10:50:03 +00:00
}
)
const (
2015-01-18 11:23:58 +00:00
tJson = "json"
tTitle = "title"
tAttrs = "attrs"
tOptions = "options"
aRequired = "required"
aReadonly = "readonly"
2015-01-18 11:31:36 +00:00
aIgnored = "ignored"
2015-01-18 11:23:58 +00:00
sep = ","
2015-01-18 10:50:03 +00:00
)
func (c *config) dump() ([]byte, error) {
var (
out bytes.Buffer
b []byte
err error
)
if b, err = json.Marshal(c.config); err != nil {
return nil, err
}
// Indent with empty prefix and four spaces
if err = json.Indent(&out, b, "", " "); err != nil {
return nil, err
}
2015-01-18 11:42:43 +00:00
out.WriteByte('\n')
2015-01-18 10:50:03 +00:00
return out.Bytes(), nil
}
2015-01-19 11:22:45 +00:00
// TODO: function is too heavy, needs refactor
2015-01-18 10:50:03 +00:00
func (c *config) meta(prefix string) []*configField {
var (
fields = []*configField{}
cval = reflect.ValueOf(c.config)
2015-01-18 11:23:58 +00:00
ctyp = reflect.TypeOf(c.config)
ckind = cval.Kind()
2015-01-18 10:50:03 +00:00
)
2015-01-18 11:23:58 +00:00
if ckind != reflect.Struct {
panic(fmt.Errorf("Config is expected to be a Struct, not %s", ckind.String()))
2015-01-18 10:50:03 +00:00
}
2015-01-18 11:31:36 +00:00
loop_over_fields:
2015-01-18 10:50:03 +00:00
for i := 0; i < cval.NumField(); i++ {
var (
2015-01-18 11:23:58 +00:00
field = ctyp.Field(i)
2015-01-18 10:50:03 +00:00
val = cval.Field(i)
2015-01-18 11:23:58 +00:00
kind = val.Kind()
2015-01-18 10:50:03 +00:00
2015-01-18 11:23:58 +00:00
jsonKey = field.Tag.Get(tJson)
path = strings.Join([]string{prefix, jsonKey}, "/")
title = field.Tag.Get(tTitle)
attrs = field.Tag.Get(tAttrs)
options = field.Tag.Get(tOptions)
2015-01-18 10:50:03 +00:00
cf = &configField{
2015-01-18 11:23:58 +00:00
Path: path,
Type: val.Kind().String(),
Title: title,
2015-01-18 10:50:03 +00:00
}
)
if len(attrs) > 0 {
2015-01-18 11:23:58 +00:00
for _, attr := range strings.Split(attrs, sep) {
if attr == aRequired {
cf.IsRequired = true
}
if attr == aReadonly {
cf.IsReadonly = true
}
2015-01-18 11:31:36 +00:00
if attr == aIgnored {
continue loop_over_fields
}
2015-01-18 10:50:03 +00:00
}
2015-01-18 11:23:58 +00:00
}
2015-01-18 10:50:03 +00:00
// Substitute field name for title if none set
if kind != reflect.Struct {
cf.Value = val.Interface()
}
if title == "" {
cf.Title = field.Name
}
if len(options) > 0 {
cf.Options = strings.Split(options, sep)
}
fields = append(fields, cf)
2015-01-18 10:50:03 +00:00
// Recursion here
2015-01-18 11:23:58 +00:00
if kind == reflect.Struct {
2015-01-18 10:50:03 +00:00
subconf := &config{
config: val.Interface(),
}
fields = append(fields, subconf.meta(path)...)
}
}
return fields
}