Added support for unparseable sections. (#72)

* Added support for unparseable sections.

* Add write support for unparseable sections.

* Slightly changed test files to make test results clearer with tools/platforms that handle whitespace differently.
This commit is contained in:
George Vilches
2016-12-21 06:26:37 -05:00
committed by 无闻
parent c2daada740
commit 4b84ed0055
6 changed files with 107 additions and 1 deletions
+17
View File
@@ -164,6 +164,9 @@ type LoadOptions struct {
// AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing.
// This type of keys are mostly used in my.cnf.
AllowBooleanKeys bool
// Some INI formats allow group blocks that store a block of raw content that doesn't otherwise
// conform to key/value pairs. Specify the names of those blocks here.
UnparseableSections []string
}
func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) {
@@ -233,6 +236,13 @@ func (f *File) NewSection(name string) (*Section, error) {
return f.sections[name], nil
}
// NewRawSection creates a new section as an unparseable body.
func (f *File) NewRawSection(name string, body string) (*Section, error) {
section, err := f.NewSection(name)
section.rawBody = body
return section, err
}
// NewSections creates a list of sections.
func (f *File) NewSections(names ...string) (err error) {
for _, name := range names {
@@ -386,6 +396,13 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) {
}
}
if sec.rawBody != "" {
if _, err = buf.WriteString(sec.rawBody); err != nil {
return 0, err
}
continue
}
// Count and generate alignment length and buffer spaces using the
// longest key. Keys may be modifed if they contain certain characters so
// we need to take that into account in our calculation.
+26
View File
@@ -357,6 +357,32 @@ NotFound, State, 50000"""
})
}
func Test_File_WriteTo_SectionRaw(t *testing.T) {
Convey("Write a INI with a raw section", t, func() {
var buf bytes.Buffer
cfg, err := LoadSources(
LoadOptions{
UnparseableSections: []string{"CORE_LESSON", "COMMENTS"},
},
"testdata/aicc.ini")
So(err, ShouldBeNil)
So(cfg, ShouldNotBeNil)
cfg.WriteToIndent(&buf, "\t")
So(buf.String(), ShouldEqual, `[Core]
Lesson_Location = 87
Lesson_Status = C
Score = 3
Time = 00:02:30
[CORE_LESSON]
my lesson state data – 1111111111111111111000000000000000001110000
111111111111111111100000000000111000000000 – end my lesson state data
[COMMENTS]
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>
`)
})
}
// Helpers for slice tests.
func float64sEqual(values []float64, expected ...float64) {
So(values, ShouldHaveLength, len(expected))
+17
View File
@@ -250,6 +250,7 @@ func (f *File) parse(reader io.Reader) (err error) {
section, _ := f.NewSection(DEFAULT_SECTION)
var line []byte
var inUnparseableSection bool
for !p.isEOF {
line, err = p.readUntil('\n')
if err != nil {
@@ -295,6 +296,22 @@ func (f *File) parse(reader io.Reader) (err error) {
// Reset aotu-counter and comments
p.comment.Reset()
p.count = 1
inUnparseableSection = false
if len(f.options.UnparseableSections) > 0 {
for _, sectionName := range f.options.UnparseableSections {
if sectionName == name ||
(f.options.Insensitive && strings.ToLower(sectionName) == strings.ToLower(name)) {
inUnparseableSection = true
continue
}
}
}
continue
}
if inUnparseableSection {
section.rawBody += string(line)
continue
}
+8 -1
View File
@@ -28,10 +28,11 @@ type Section struct {
keys map[string]*Key
keyList []string
keysHash map[string]string
rawBody string
}
func newSection(f *File, name string) *Section {
return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string)}
return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string), ""}
}
// Name returns name of Section.
@@ -39,6 +40,12 @@ func (s *Section) Name() string {
return s.name
}
// Body returns rawBody of Section if the section was marked as unparseable.
// It still follows the other rules of the INI format surrounding leading/trailing whitespace.
func (s *Section) Body() string {
return strings.TrimSpace(s.rawBody)
}
// NewKey creates a new key to given section.
func (s *Section) NewKey(name, val string) (*Key, error) {
if len(name) == 0 {
+28
View File
@@ -45,3 +45,31 @@ func Test_Section(t *testing.T) {
})
})
}
func Test_SectionRaw(t *testing.T) {
Convey("Test section raw string", t, func() {
cfg, err := LoadSources(
LoadOptions{
Insensitive: true,
UnparseableSections: []string{"core_lesson", "comments"},
},
"testdata/aicc.ini")
So(err, ShouldBeNil)
So(cfg, ShouldNotBeNil)
Convey("Get section strings", func() {
So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,core,core_lesson,comments")
})
Convey("Validate non-raw section", func() {
val, err := cfg.Section("core").GetKey("lesson_status")
So(err, ShouldBeNil)
So(val.String(), ShouldEqual, "C")
})
Convey("Validate raw section", func() {
So(cfg.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000
111111111111111111100000000000111000000000 – end my lesson state data`)
})
})
}
+11
View File
@@ -0,0 +1,11 @@
[Core]
Lesson_Location = 87
Lesson_Status = C
Score = 3
Time = 00:02:30
[CORE_LESSON]
my lesson state data – 1111111111111111111000000000000000001110000
111111111111111111100000000000111000000000 – end my lesson state data
[COMMENTS]
<1><L.Slide#2> This slide has the fuel listed in the wrong units <e.1>