├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── go.mod ├── go.sum ├── helper └── util │ └── get_paths.go ├── simpleyaml.go └── simpleyaml_test.go /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | 3 | go: 4 | - 1.5 5 | - 1.6 6 | - 1.7 7 | 8 | install: 9 | - go get -v gopkg.in/yaml.v2 10 | - go get -v github.com/smallfish/simpleyaml 11 | 12 | script: 13 | - go test -v -cover -race 14 | 15 | notifications: 16 | email: false 17 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, 陈小玉 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | * Neither the name of simpleyaml nor the names of its 15 | contributors may be used to endorse or promote products derived from 16 | this software without specific prior written permission. 17 | 18 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | 29 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## simpleyaml 2 | 3 | a Go package to interact with arbitrary YAML, similar as [go-simplejson](https://github.com/bitly/go-simplejson). 4 | 5 | [![GoDoc](https://godoc.org/github.com/smallfish/simpleyaml?status.svg)](http://godoc.org/github.com/smallfish/simpleyaml) [![Build Status](https://travis-ci.org/smallfish/simpleyaml.png)](https://travis-ci.org/smallfish/simpleyaml) 6 | 7 | #### INSTALL 8 | 9 | ```bash 10 | $ go get -u -v github.com/smallfish/simpleyaml 11 | ``` 12 | 13 | #### EXAMPLE 14 | 15 | ```go 16 | var data = []byte(` 17 | name: smallfish 18 | age: 99 19 | float: 3.14159 20 | bool: true 21 | emails: 22 | - xxx@xx.com 23 | - yyy@yy.com 24 | bb: 25 | cc: 26 | dd: 27 | - 111 28 | - 222 29 | - 333 30 | ee: aaa 31 | `) 32 | 33 | y, err := NewYaml(data) 34 | if err != nil { 35 | // ERROR 36 | } 37 | 38 | name, err := y.Get("name").String() 39 | if err != nil { 40 | // ERROR 41 | } 42 | fmt.Println("name:", name) 43 | 44 | // y.Get("age").Int() 45 | // y.Get("float").Float() 46 | // y.Get("bool").Bool() 47 | // y.Get("bb").Get("cc").Get("ee").String() 48 | // y.Get("bb").Get("cc").Get("ee").GetIndex(1).Int() 49 | // y.GetPath("bb", "cc", "ee").String() 50 | ``` 51 | 52 | __END__ 53 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/smallfish/simpleyaml 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/stretchr/testify v1.7.0 // indirect 7 | gopkg.in/yaml.v2 v2.4.0 8 | ) 9 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 4 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 5 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 6 | github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= 7 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 8 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 10 | gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= 11 | gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 12 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= 13 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 14 | -------------------------------------------------------------------------------- /helper/util/get_paths.go: -------------------------------------------------------------------------------- 1 | package util 2 | 3 | import ( 4 | "bytes" 5 | "errors" 6 | "strconv" 7 | 8 | "github.com/smallfish/simpleyaml" 9 | ) 10 | 11 | var ( 12 | ArrayOfPaths = make([]string, 0) 13 | ) 14 | 15 | func GetAllExistingPaths(y *simpleyaml.Yaml, PathSlice []string) ([]string, error) { 16 | if y.IsMap() { 17 | keys, err := y.GetMapKeys() 18 | if err != nil { 19 | return nil, errors.New("Retrieving map keys failed") 20 | } 21 | 22 | for k, _ := range keys { 23 | if k != 0 { 24 | PathSlice = PathSlice[:len(PathSlice)-1] 25 | } 26 | 27 | PathSlice = append(PathSlice, keys[k]) 28 | GetAllExistingPaths(y.Get(keys[k]), PathSlice) 29 | } 30 | } else if y.IsArray() { 31 | arr, err := y.Array() 32 | if err != nil { 33 | return nil, errors.New("Retrieving array failed") 34 | } 35 | 36 | for k, _ := range arr { 37 | if k != 0 { 38 | PathSlice = PathSlice[:len(PathSlice)-1] 39 | } 40 | 41 | PathSlice = append(PathSlice, strconv.Itoa(k)) 42 | GetAllExistingPaths(y.GetIndex(k), PathSlice) 43 | } 44 | } else { 45 | var buffer bytes.Buffer 46 | for k, _ := range PathSlice { 47 | if k == len(PathSlice)-1 { 48 | buffer.WriteString(PathSlice[k]) 49 | } else { 50 | buffer.WriteString(PathSlice[k] + "/") 51 | } 52 | } 53 | 54 | ArrayOfPaths = append(ArrayOfPaths, buffer.String()) 55 | } 56 | 57 | return ArrayOfPaths, nil 58 | } 59 | 60 | // GetAllPaths retrieves all possible paths in the YAML file 61 | // 62 | // Example: 63 | // util.GetAllPaths(*Yaml) 64 | func GetAllPaths(y *simpleyaml.Yaml) ([]string, error) { 65 | InitialPath := make([]string, 0) 66 | AllPaths, err := GetAllExistingPaths(y, InitialPath) 67 | if err != nil { 68 | return nil, errors.New("Retrieving paths failed") 69 | } 70 | 71 | return AllPaths, nil 72 | } 73 | -------------------------------------------------------------------------------- /simpleyaml.go: -------------------------------------------------------------------------------- 1 | // Package simpleyaml: a Go package to interact with arbitrary YAML. 2 | // 3 | // Example: 4 | // var data = []byte(` 5 | // name: smallfish 6 | // age: 99 7 | // bool: true 8 | // bb: 9 | // cc: 10 | // dd: 11 | // - 111 12 | // - 222 13 | // - 333 14 | // ` 15 | // 16 | // y, err := simpleyaml.NewYaml(data) 17 | // if err != nil { 18 | // // ERROR 19 | // } 20 | // 21 | // if v, err := y.Get("name").String(); err == nil { 22 | // fmt.Println("value:", v) 23 | // } 24 | // 25 | // // y.Get("age").Int() 26 | // // y.Get("bool").Bool() 27 | // // y.Get("bb").Get("cc").Get("dd").Array() 28 | // // y.Get("bb").Get("cc").Get("dd").GetIndex(1).Int() 29 | // // y.GetPath("bb", "cc", "ee").String() 30 | 31 | package simpleyaml 32 | 33 | import ( 34 | "errors" 35 | 36 | "gopkg.in/yaml.v2" 37 | ) 38 | 39 | type Yaml struct { 40 | data interface{} 41 | } 42 | 43 | // NewYaml returns a pointer to a new `Yaml` object after unmarshaling `body` bytes 44 | func NewYaml(body []byte) (*Yaml, error) { 45 | var val interface{} 46 | if err := yaml.Unmarshal(body, &val); err != nil { 47 | return nil, errors.New("unmarshal []byte to yaml failed: " + err.Error()) 48 | } 49 | 50 | return &Yaml{val}, nil 51 | } 52 | 53 | // IsFound Check if the given branch was found 54 | func (y *Yaml) IsFound() bool { 55 | return y.data != nil 56 | } 57 | 58 | // Get returns a pointer to a new `Yaml` object for `key` in its `map` representation 59 | // 60 | // Example: 61 | // y.Get("xx").Get("yy").Int() 62 | func (y *Yaml) Get(key interface{}) *Yaml { 63 | m, err := y.Map() 64 | if err == nil { 65 | if val, ok := m[key]; ok { 66 | return &Yaml{val} 67 | } 68 | } 69 | 70 | return &Yaml{nil} 71 | } 72 | 73 | // GetPath searches for the item as specified by the branch 74 | // 75 | // Example: 76 | // y.GetPath("bb", "cc").Int() 77 | func (y *Yaml) GetPath(branch ...interface{}) *Yaml { 78 | yin := y 79 | for _, p := range branch { 80 | yin = yin.Get(p) 81 | } 82 | 83 | return yin 84 | } 85 | 86 | // Array type asserts to an `array` 87 | func (y *Yaml) Array() ([]interface{}, error) { 88 | if a, ok := (y.data).([]interface{}); ok { 89 | return a, nil 90 | } 91 | 92 | return nil, errors.New("type assertion to []interface{} failed") 93 | } 94 | 95 | func (y *Yaml) IsArray() bool { 96 | _, err := y.Array() 97 | return err == nil 98 | } 99 | 100 | // GetArraySize return the size of array 101 | func (y *Yaml) GetArraySize() (int, error) { 102 | a, err := y.Array() 103 | if err != nil { 104 | return 0, err 105 | } 106 | 107 | return len(a), nil 108 | } 109 | 110 | // GetIndex returns a pointer to a new `Yaml` object. 111 | // for `index` in its `array` representation 112 | // 113 | // Example: 114 | // y.Get("xx").GetIndex(1).String() 115 | func (y *Yaml) GetIndex(index int) *Yaml { 116 | a, err := y.Array() 117 | if err == nil { 118 | if len(a) > index { 119 | return &Yaml{a[index]} 120 | } 121 | } 122 | 123 | return &Yaml{nil} 124 | } 125 | 126 | // Int type asserts to `int` 127 | func (y *Yaml) Int() (int, error) { 128 | if v, ok := (y.data).(int); ok { 129 | return v, nil 130 | } 131 | 132 | return 0, errors.New("type assertion to int failed") 133 | } 134 | 135 | // Bool type asserts to `bool` 136 | func (y *Yaml) Bool() (bool, error) { 137 | if v, ok := (y.data).(bool); ok { 138 | return v, nil 139 | } 140 | 141 | return false, errors.New("type assertion to bool failed") 142 | } 143 | 144 | // String type asserts to `string` 145 | func (y *Yaml) String() (string, error) { 146 | if v, ok := (y.data).(string); ok { 147 | return v, nil 148 | } 149 | 150 | return "", errors.New("type assertion to string failed") 151 | } 152 | 153 | func (y *Yaml) Float() (float64, error) { 154 | if v, ok := (y.data).(float64); ok { 155 | return v, nil 156 | } 157 | 158 | return 0, errors.New("type assertion to float64 failed") 159 | } 160 | 161 | // Map type asserts to `map` 162 | func (y *Yaml) Map() (map[interface{}]interface{}, error) { 163 | if m, ok := (y.data).(map[interface{}]interface{}); ok { 164 | return m, nil 165 | } 166 | 167 | return nil, errors.New("type assertion to map[interface]interface{} failed") 168 | } 169 | 170 | // IsMap Check if it is a map 171 | func (y *Yaml) IsMap() bool { 172 | _, err := y.Map() 173 | return err == nil 174 | } 175 | 176 | // GetMapKeys Get all the keys of the map 177 | func (y *Yaml) GetMapKeys() ([]string, error) { 178 | m, err := y.Map() 179 | 180 | if err != nil { 181 | return nil, err 182 | } 183 | 184 | keys := make([]string, 0) 185 | for k, _ := range m { 186 | if s, ok := k.(string); ok { 187 | keys = append(keys, s) 188 | } 189 | } 190 | 191 | return keys, nil 192 | } 193 | -------------------------------------------------------------------------------- /simpleyaml_test.go: -------------------------------------------------------------------------------- 1 | package simpleyaml_test 2 | 3 | import ( 4 | "testing" 5 | 6 | "github.com/smallfish/simpleyaml" 7 | "github.com/smallfish/simpleyaml/helper/util" 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | var ( 12 | data = []byte(` 13 | name: smallfish 14 | age: 99 15 | float: 3.14159 16 | bool: true 17 | 0: IntKey 18 | emails: 19 | - xxx@xx.com 20 | - yyy@yy.com 21 | bb: 22 | cc: 23 | dd: 24 | - 111 25 | - 222 26 | - 333 27 | ee: aaa 28 | `) 29 | ) 30 | 31 | func TestBool(t *testing.T) { 32 | y, err := simpleyaml.NewYaml(data) 33 | assert.NoError(t, err) 34 | 35 | v, err := y.Get("bool").Bool() 36 | assert.NoError(t, err) 37 | 38 | t.Logf("result: %v", v) 39 | assert.True(t, v) 40 | } 41 | 42 | func TestString(t *testing.T) { 43 | y, err := simpleyaml.NewYaml(data) 44 | assert.NoError(t, err) 45 | 46 | v, err := y.Get("name").String() 47 | assert.NoError(t, err) 48 | 49 | t.Logf("result: %v", v) 50 | assert.Equal(t, v, "smallfish") 51 | } 52 | 53 | func TestStringFromIntKey(t *testing.T) { 54 | y, err := simpleyaml.NewYaml(data) 55 | assert.NoError(t, err) 56 | 57 | v, err := y.Get(0).String() 58 | assert.NoError(t, err) 59 | 60 | t.Logf("result: %v", v) 61 | 62 | assert.Equal(t, v, "IntKey") 63 | } 64 | 65 | func TestFloat(t *testing.T) { 66 | y, err := simpleyaml.NewYaml(data) 67 | assert.NoError(t, err) 68 | 69 | v, err := y.Get("float").Float() 70 | assert.NoError(t, err) 71 | 72 | t.Logf("result: %v", v) 73 | 74 | assert.Equal(t, v, 3.14159) 75 | } 76 | 77 | func TestInt(t *testing.T) { 78 | y, err := simpleyaml.NewYaml(data) 79 | assert.NoError(t, err) 80 | 81 | v, err := y.Get("age").Int() 82 | assert.NoError(t, err) 83 | 84 | t.Logf("result: %v", v) 85 | 86 | assert.Equal(t, v, 99) 87 | } 88 | 89 | func TestGetIndex(t *testing.T) { 90 | y, err := simpleyaml.NewYaml(data) 91 | assert.NoError(t, err) 92 | 93 | v, err := y.Get("bb").Get("cc").Get("dd").GetIndex(1).Int() 94 | assert.NoError(t, err) 95 | 96 | t.Logf("result: %v", v) 97 | } 98 | 99 | func TestString2(t *testing.T) { 100 | y, err := simpleyaml.NewYaml(data) 101 | assert.NoError(t, err) 102 | 103 | v, err := y.Get("bb").Get("cc").Get("ee").String() 104 | assert.NoError(t, err) 105 | 106 | t.Logf("result: %v", v) 107 | 108 | assert.Equal(t, v, "aaa") 109 | } 110 | 111 | func TestGetPath(t *testing.T) { 112 | y, err := simpleyaml.NewYaml(data) 113 | assert.NoError(t, err) 114 | 115 | v, err := y.GetPath("bb", "cc", "ee").String() 116 | assert.NoError(t, err) 117 | 118 | t.Logf("result: %v", v) 119 | 120 | assert.Equal(t, v, "aaa") 121 | } 122 | 123 | func TestGetAllPaths(t *testing.T) { 124 | y, err := simpleyaml.NewYaml(data) 125 | assert.NoError(t, err) 126 | 127 | v, err := util.GetAllPaths(y) 128 | assert.NoError(t, err) 129 | 130 | t.Logf("result: %v", v) 131 | 132 | assert.Equal(t, len(v), 10) 133 | } 134 | 135 | func TestArray(t *testing.T) { 136 | y, err := simpleyaml.NewYaml(data) 137 | assert.NoError(t, err) 138 | 139 | v, err := y.Get("emails").Array() 140 | assert.NoError(t, err) 141 | 142 | t.Logf("result: %v", v) 143 | 144 | assert.Equal(t, len(v), 2) 145 | } 146 | 147 | func TestMap(t *testing.T) { 148 | y, err := simpleyaml.NewYaml(data) 149 | assert.NoError(t, err) 150 | assert.True(t, y.IsMap()) 151 | 152 | keys, err := y.GetMapKeys() 153 | assert.NoError(t, err) 154 | 155 | t.Logf("result: %v", keys) 156 | 157 | assert.Equal(t, len(keys), 6) 158 | } 159 | 160 | func TestIsFound(t *testing.T) { 161 | y, err := simpleyaml.NewYaml(data) 162 | assert.NoError(t, err) 163 | 164 | assert.True(t, y.Get("name").IsFound()) 165 | assert.False(t, y.Get("xx").IsFound()) 166 | } 167 | --------------------------------------------------------------------------------