diff --git a/all_test.go b/all_test.go index c02adf1..2f09f0e 100644 --- a/all_test.go +++ b/all_test.go @@ -118,7 +118,7 @@ func TestInMemory(t *testing.T) { } // default section always exists - if c.AddSection(DEFAULT_SECTION) { + if c.AddSection(DefaultSection) { t.Errorf("AddSection failure: true on default section insert") } @@ -187,13 +187,13 @@ func TestInMemory(t *testing.T) { // == Test cycle - c.AddOption(DEFAULT_SECTION, "opt1", "%(opt2)s") - c.AddOption(DEFAULT_SECTION, "opt2", "%(opt1)s") + c.AddOption(DefaultSection, "opt1", "%(opt2)s") + c.AddOption(DefaultSection, "opt2", "%(opt1)s") - _, err = c.String(DEFAULT_SECTION, "opt1") + _, err = c.String(DefaultSection, "opt1") if err == nil { t.Errorf("String failure: no error for cycle") - } else if strings.Index(err.Error(), "cycle") < 0 { + } else if !strings.Contains(err.Error(), "cycle") { t.Errorf("String failure: incorrect error for cycle") } } @@ -218,7 +218,7 @@ func TestReadFile(t *testing.T) { buf.WriteString(" # Let me put another comment\n") buf.WriteString("option3= line1\n line2: \n\tline3=v # Comment multiline with := in value\n") buf.WriteString("; Another comment\n") - buf.WriteString("[" + DEFAULT_SECTION + "]\n") + buf.WriteString("[" + DefaultSection + "]\n") buf.WriteString("variable1=small\n") buf.WriteString("variable2=a_part_of_a_%(variable1)s_test\n") buf.WriteString("[secTION-2]\n") @@ -241,7 +241,7 @@ func TestReadFile(t *testing.T) { } // check number of options 6 of [section-1] plus 2 of [default] - opts, err := c.Options("section-1") + opts, _ := c.Options("section-1") if len(opts) != 8 { t.Errorf("Options failure: wrong number of options: %d", len(opts)) } @@ -266,8 +266,8 @@ func TestWriteReadFile(t *testing.T) { cw.AddOption("First-Section", "option2", "2") cw.AddOption("", "host", "www.example.com") - cw.AddOption(DEFAULT_SECTION, "protocol", "https://") - cw.AddOption(DEFAULT_SECTION, "base-url", "%(protocol)s%(host)s") + cw.AddOption(DefaultSection, "protocol", "https://") + cw.AddOption(DefaultSection, "base-url", "%(protocol)s%(host)s") cw.AddOption("Another-Section", "useHTTPS", "y") cw.AddOption("Another-Section", "url", "%(base-url)s/some/path") @@ -298,8 +298,8 @@ func TestSectionOptions(t *testing.T) { cw.AddOption("First-Section", "option2", "2") cw.AddOption("", "host", "www.example.com") - cw.AddOption(DEFAULT_SECTION, "protocol", "https://") - cw.AddOption(DEFAULT_SECTION, "base-url", "%(protocol)s%(host)s") + cw.AddOption(DefaultSection, "protocol", "https://") + cw.AddOption(DefaultSection, "base-url", "%(protocol)s%(host)s") cw.AddOption("Another-Section", "useHTTPS", "y") cw.AddOption("Another-Section", "url", "%(base-url)s/some/path") @@ -336,7 +336,7 @@ func TestSectionOptions(t *testing.T) { t.Fatalf("SectionOptions reads wrong data: %v", options) } - options, err = cr.SectionOptions(DEFAULT_SECTION) + options, err = cr.SectionOptions(DefaultSection) if err != nil { t.Fatalf("SectionOptions failure: %s", err) @@ -375,18 +375,18 @@ func TestMerge(t *testing.T) { target.Merge(source) // Assert whether a regular option was merged from source -> target - if result, _ := target.String(DEFAULT_SECTION, "one"); result != "source1" { + if result, _ := target.String(DefaultSection, "one"); result != "source1" { t.Errorf("Expected 'one' to be '1' but instead it was '%s'", result) } // Assert that a non-existent option in source was not overwritten - if result, _ := target.String(DEFAULT_SECTION, "five"); result != "5" { + if result, _ := target.String(DefaultSection, "five"); result != "5" { t.Errorf("Expected 'five' to be '5' but instead it was '%s'", result) } // Assert that a folded option was correctly unfolded - if result, _ := target.String(DEFAULT_SECTION, "two_+_three"); result != "source2 + source3" { + if result, _ := target.String(DefaultSection, "two_+_three"); result != "source2 + source3" { t.Errorf("Expected 'two_+_three' to be 'source2 + source3' but instead it was '%s'", result) } - if result, _ := target.String(DEFAULT_SECTION, "four"); result != "4" { + if result, _ := target.String(DefaultSection, "four"); result != "4" { t.Errorf("Expected 'four' to be '4' but instead it was '%s'", result) } diff --git a/config.go b/config.go index b7c17f4..c19518f 100644 --- a/config.go +++ b/config.go @@ -19,16 +19,17 @@ import ( "strings" ) +// config constants const ( // Default section name. - DEFAULT_SECTION = "DEFAULT" + DefaultSection = "DEFAULT" // Maximum allowed depth when recursively substituing variable names. - _DEPTH_VALUES = 200 + DepthValues = 200 - DEFAULT_COMMENT = "# " - ALTERNATIVE_COMMENT = "; " - DEFAULT_SEPARATOR = ":" - ALTERNATIVE_SEPARATOR = "=" + DefaultComment = "# " + AlternativeComment = "; " + DefaultSeparator = ":" + AlternativeSeparator = "=" ) var ( @@ -58,11 +59,11 @@ type Config struct { separator string // Sections order - lastIdSection int // Last section identifier + lastIDSection int // Last section identifier idSection map[string]int // Section : position // The last option identifier used for each section. - lastIdOption map[string]int // Section : last identifier + lastIDOption map[string]int // Section : last identifier // Section -> option : value data map[string]map[string]*tValue @@ -80,16 +81,16 @@ type tValue struct { // // == Arguments // -// comment: has to be `DEFAULT_COMMENT` or `ALTERNATIVE_COMMENT` -// separator: has to be `DEFAULT_SEPARATOR` or `ALTERNATIVE_SEPARATOR` +// comment: has to be `DefaultComment` or `AlternativeComment` +// separator: has to be `DefaultSeparator` or `AlternativeSeparator` // preSpace: indicate if is inserted a space before of the separator // postSpace: indicate if is added a space after of the separator func New(comment, separator string, preSpace, postSpace bool) *Config { - if comment != DEFAULT_COMMENT && comment != ALTERNATIVE_COMMENT { + if comment != DefaultComment && comment != AlternativeComment { panic("comment character not valid") } - if separator != DEFAULT_SEPARATOR && separator != ALTERNATIVE_SEPARATOR { + if separator != DefaultSeparator && separator != AlternativeSeparator { panic("separator character not valid") } @@ -108,17 +109,17 @@ func New(comment, separator string, preSpace, postSpace bool) *Config { c.comment = comment c.separator = separator c.idSection = make(map[string]int) - c.lastIdOption = make(map[string]int) + c.lastIDOption = make(map[string]int) c.data = make(map[string]map[string]*tValue) - c.AddSection(DEFAULT_SECTION) // Default section always exists. + c.AddSection(DefaultSection) // Default section always exists. return c } // NewDefault creates a configuration representation with values by default. func NewDefault() *Config { - return New(DEFAULT_COMMENT, DEFAULT_SEPARATOR, false, true) + return New(DefaultComment, DefaultSeparator, false, true) } // Merge merges the given configuration "source" with this one ("target"). diff --git a/context.go b/context.go index 8d7f57b..340f900 100644 --- a/context.go +++ b/context.go @@ -30,10 +30,12 @@ type Context struct { section string // Check this section first, then fall back to DEFAULT } +// NewContext creates a default section and returns config context func NewContext() *Context { return &Context{config: NewDefault()} } +// LoadContext loads the ini config from gives multiple conf paths func LoadContext(confName string, confPaths []string) (*Context, error) { ctx := NewContext() for _, confPath := range confPaths { @@ -51,18 +53,24 @@ func LoadContext(confName string, confPaths []string) (*Context, error) { return ctx, nil } +// Raw returns raw config instance func (c *Context) Raw() *Config { return c.config } +// SetSection the section scope of ini config +// For e.g.: dev or prod func (c *Context) SetSection(section string) { c.section = section } +// SetOption sets the value for the given key func (c *Context) SetOption(name, value string) { c.config.AddOption(c.section, name, value) } +// Int returns `int` config value and if found returns true +// otherwise false func (c *Context) Int(option string) (result int, found bool) { result, err := c.config.Int(c.section, option) if err == nil { @@ -76,6 +84,8 @@ func (c *Context) Int(option string) (result int, found bool) { return 0, false } +// IntDefault returns `int` config value if found otherwise +// returns given default int value func (c *Context) IntDefault(option string, dfault int) int { if r, found := c.Int(option); found { return r @@ -83,6 +93,8 @@ func (c *Context) IntDefault(option string, dfault int) int { return dfault } +// Bool returns `bool` config value and if found returns true +// otherwise false func (c *Context) Bool(option string) (result, found bool) { result, err := c.config.Bool(c.section, option) if err == nil { @@ -96,6 +108,8 @@ func (c *Context) Bool(option string) (result, found bool) { return false, false } +// BoolDefault returns `bool` config value if found otherwise +// returns given default bool value func (c *Context) BoolDefault(option string, dfault bool) bool { if r, found := c.Bool(option); found { return r @@ -103,6 +117,8 @@ func (c *Context) BoolDefault(option string, dfault bool) bool { return dfault } +// String returns `string` config value and if found returns true +// otherwise false func (c *Context) String(option string) (result string, found bool) { if r, err := c.config.String(c.section, option); err == nil { return stripQuotes(r), true @@ -110,6 +126,8 @@ func (c *Context) String(option string) (result string, found bool) { return "", false } +// StringDefault returns `string` config value if found otherwise +// returns given default string value func (c *Context) StringDefault(option, dfault string) string { if r, found := c.String(option); found { return r @@ -117,6 +135,8 @@ func (c *Context) StringDefault(option, dfault string) string { return dfault } +// HasSection checks if the configuration has the given section. +// (The default section always exists.) func (c *Context) HasSection(section string) bool { return c.config.HasSection(section) } diff --git a/error.go b/error.go index 44296c0..ab8e386 100644 --- a/error.go +++ b/error.go @@ -14,12 +14,14 @@ package config +// SectionError type string type SectionError string func (e SectionError) Error() string { return "section not found: " + string(e) } +// OptionError type string type OptionError string func (e OptionError) Error() string { diff --git a/option.go b/option.go index c3184ed..0f98de3 100644 --- a/option.go +++ b/option.go @@ -27,13 +27,13 @@ func (c *Config) AddOption(section string, option string, value string) bool { c.AddSection(section) // Make sure section exists if section == "" { - section = DEFAULT_SECTION + section = DefaultSection } _, ok := c.data[section][option] - c.data[section][option] = &tValue{c.lastIdOption[section], value} - c.lastIdOption[section]++ + c.data[section][option] = &tValue{c.lastIDOption[section], value} + c.lastIDOption[section]++ return !ok } @@ -59,7 +59,7 @@ func (c *Config) HasOption(section string, option string) bool { return false } - _, okd := c.data[DEFAULT_SECTION][option] + _, okd := c.data[DefaultSection][option] _, oknd := c.data[section][option] return okd || oknd @@ -75,18 +75,18 @@ func (c *Config) Options(section string) (options []string, err error) { // Keep a map of option names we've seen to deduplicate. optionMap := make(map[string]struct{}, - len(c.data[DEFAULT_SECTION])+len(c.data[section])) - for s, _ := range c.data[DEFAULT_SECTION] { + len(c.data[DefaultSection])+len(c.data[section])) + for s := range c.data[DefaultSection] { optionMap[s] = struct{}{} } - for s, _ := range c.data[section] { + for s := range c.data[section] { optionMap[s] = struct{}{} } // Get the keys. i := 0 options = make([]string, len(optionMap)) - for k, _ := range optionMap { + for k := range optionMap { options[i] = k i++ } @@ -104,7 +104,7 @@ func (c *Config) SectionOptions(section string) (options []string, err error) { options = make([]string, len(c.data[section])) i := 0 - for s, _ := range c.data[section] { + for s := range c.data[section] { options[i] = s i++ } diff --git a/section.go b/section.go index c8304c3..d982d43 100644 --- a/section.go +++ b/section.go @@ -22,7 +22,7 @@ package config // It returns true if the new section was inserted, and false if the section // already existed. func (c *Config) AddSection(section string) bool { - // DEFAULT_SECTION + // DefaultSection if section == "" { return false } @@ -34,8 +34,8 @@ func (c *Config) AddSection(section string) bool { c.data[section] = make(map[string]*tValue) // Section order - c.idSection[section] = c.lastIdSection - c.lastIdSection++ + c.idSection[section] = c.lastIDSection + c.lastIDSection++ return true } @@ -46,16 +46,16 @@ func (c *Config) RemoveSection(section string) bool { _, ok := c.data[section] // Default section cannot be removed. - if !ok || section == DEFAULT_SECTION { + if !ok || section == DefaultSection { return false } - for o, _ := range c.data[section] { + for o := range c.data[section] { delete(c.data[section], o) // *value } delete(c.data, section) - delete(c.lastIdOption, section) + delete(c.lastIDOption, section) delete(c.idSection, section) return true @@ -75,7 +75,7 @@ func (c *Config) Sections() (sections []string) { sections = make([]string, len(c.idSection)) pos := 0 // Position in sections - for i := 0; i < c.lastIdSection; i++ { + for i := 0; i < c.lastIDSection; i++ { for section, id := range c.idSection { if id == i { sections[pos] = section diff --git a/type.go b/type.go index 4ca38d2..d938aad 100644 --- a/type.go +++ b/type.go @@ -27,7 +27,7 @@ import ( func (c *Config) computeVar(beforeValue *string, regx *regexp.Regexp, headsz, tailsz int, withVar func(*string) string) (*string, error) { var i int computedVal := beforeValue - for i = 0; i < _DEPTH_VALUES; i++ { // keep a sane depth + for i = 0; i < DepthValues; i++ { // keep a sane depth vr := regx.FindStringSubmatchIndex(*computedVal) if len(vr) == 0 { @@ -37,7 +37,7 @@ func (c *Config) computeVar(beforeValue *string, regx *regexp.Regexp, headsz, ta varname := (*computedVal)[vr[headsz]:vr[headsz+1]] varVal := withVar(&varname) if varVal == "" { - return &varVal, errors.New(fmt.Sprintf("Option not found: %s", varname)) + return &varVal, fmt.Errorf("Option not found: %s", varname) } // substitute by new value and take off leading '%(' and trailing ')s' @@ -47,10 +47,10 @@ func (c *Config) computeVar(beforeValue *string, regx *regexp.Regexp, headsz, ta computedVal = &newVal } - if i == _DEPTH_VALUES { + if i == DepthValues { retVal := "" return &retVal, - fmt.Errorf("Possible cycle while unfolding variables: max depth of %d reached", _DEPTH_VALUES) + fmt.Errorf("Possible cycle while unfolding variables: max depth of %d reached", DepthValues) } return computedVal, nil @@ -111,7 +111,7 @@ func (c *Config) RawString(section string, option string) (value string, err err // // It returns an error if the option does not exist in the DEFAULT section. func (c *Config) RawStringDefault(option string) (value string, err error) { - if tValue, ok := c.data[DEFAULT_SECTION][option]; ok { + if tValue, ok := c.data[DefaultSection][option]; ok { return tValue.v, nil } return "", OptionError(option) @@ -120,7 +120,7 @@ func (c *Config) RawStringDefault(option string) (value string, err error) { // String gets the string value for the given option in the section. // If the value needs to be unfolded (see e.g. %(host)s example in the beginning // of this documentation), then String does this unfolding automatically, up to -// _DEPTH_VALUES number of iterations. +// `DepthValues` number of iterations. // // It returns an error if either the section or the option do not exist, or the // unfolding cycled. @@ -134,7 +134,7 @@ func (c *Config) String(section string, option string) (value string, err error) computedVal, err := c.computeVar(&value, varRegExp, 2, 2, func(varName *string) string { lowerVar := *varName // search variable in default section as well as current section - varVal, _ := c.data[DEFAULT_SECTION][lowerVar] + varVal, _ := c.data[DefaultSection][lowerVar] if _, ok := c.data[section][lowerVar]; ok { varVal = c.data[section][lowerVar] } diff --git a/write.go b/write.go index 68cc8f5..9af6f4e 100644 --- a/write.go +++ b/write.go @@ -34,7 +34,7 @@ func (c *Config) WriteFile(fname string, perm os.FileMode, header string) error if err = c.write(buf, header); err != nil { return err } - buf.Flush() + _ = buf.Flush() return file.Close() } @@ -56,7 +56,7 @@ func (c *Config) write(buf *bufio.Writer, header string) (err error) { if section == orderedSection { // Skip default section if empty. - if section == DEFAULT_SECTION && len(sectionMap) == 0 { + if section == DefaultSection && len(sectionMap) == 0 { continue } @@ -65,7 +65,7 @@ func (c *Config) write(buf *bufio.Writer, header string) (err error) { } // Follow the input order in options. - for i := 0; i < c.lastIdOption[section]; i++ { + for i := 0; i < c.lastIDOption[section]; i++ { for option, tValue := range sectionMap { if tValue.position == i { @@ -82,9 +82,6 @@ func (c *Config) write(buf *bufio.Writer, header string) (err error) { } } - if _, err = buf.WriteString("\n"); err != nil { - return err - } - - return nil + _, err = buf.WriteString("\n") + return err }