Этот коммит содержится в:
Christopher Speller
2017-05-17 16:51:25 -04:00
коммит произвёл GitHub
родитель cd23b8139a
Коммит d103ed6ca9
1001 изменённых файлов: 191052 добавлений и 5192 удалений

6
vendor/github.com/pelletier/go-toml/README.md сгенерированный поставляемый
Просмотреть файл

@@ -16,9 +16,9 @@ This library supports TOML version
Go-toml provides the following features for using data parsed from TOML documents:
* Load TOML documents from files and string data
* Easily navigate TOML structure using TomlTree
* Easily navigate TOML structure using Tree
* Line & column position data for all parsed elements
* Query support similar to JSON-Path
* [Query support similar to JSON-Path](query/)
* Syntax errors contain line and column numbers
Go-toml is designed to help cover use-cases not covered by reflection-based TOML parsing:
@@ -61,7 +61,7 @@ if err != nil {
password := config.Get("postgres.password").(string)
// or using an intermediate object
configTree := config.Get("postgres").(*toml.TomlTree)
configTree := config.Get("postgres").(*toml.Tree)
user = configTree.Get("user").(string)
password = configTree.Get("password").(string)
fmt.Println("User is ", user, ". Password is ", password)

6
vendor/github.com/pelletier/go-toml/clean.sh сгенерированный поставляемый
Просмотреть файл

@@ -1,6 +0,0 @@
#!/bin/bash
# fail out of the script if anything here fails
set -e
# clear out stuff generated by test.sh
rm -rf src test_program_bin toml-test

6
vendor/github.com/pelletier/go-toml/cmd/test_program.go сгенерированный поставляемый
Просмотреть файл

@@ -41,16 +41,16 @@ func translate(tomlData interface{}) interface{} {
typed[k] = translate(v)
}
return typed
case *toml.TomlTree:
case *toml.Tree:
return translate(*orig)
case toml.TomlTree:
case toml.Tree:
keys := orig.Keys()
typed := make(map[string]interface{}, len(keys))
for _, k := range keys {
typed[k] = translate(orig.GetPath([]string{k}))
}
return typed
case []*toml.TomlTree:
case []*toml.Tree:
typed := make([]map[string]interface{}, len(orig))
for i, v := range orig {
typed[i] = translate(v).(map[string]interface{})

2
vendor/github.com/pelletier/go-toml/cmd/tomljson/main.go сгенерированный поставляемый
Просмотреть файл

@@ -57,7 +57,7 @@ func reader(r io.Reader) (string, error) {
return mapToJSON(tree)
}
func mapToJSON(tree *toml.TomlTree) (string, error) {
func mapToJSON(tree *toml.Tree) (string, error) {
treeMap := tree.ToMap()
bytes, err := json.MarshalIndent(treeMap, "", " ")
if err != nil {

184
vendor/github.com/pelletier/go-toml/doc.go сгенерированный поставляемый
Просмотреть файл

@@ -13,14 +13,14 @@
// // load TOML data stored in a string
// tree, err := toml.Load(stringContainingTomlData)
//
// Either way, the result is a TomlTree object that can be used to navigate the
// Either way, the result is a Tree object that can be used to navigate the
// structure and data within the original document.
//
//
// Getting data from the TomlTree
// Getting data from the Tree
//
// After parsing TOML data with Load() or LoadFile(), use the Has() and Get()
// methods on the returned TomlTree, to find your way through the document data.
// methods on the returned Tree, to find your way through the document data.
//
// if tree.Has("foo") {
// fmt.Println("foo is:", tree.Get("foo"))
@@ -50,11 +50,11 @@
// tree.GetPath([]string{"foo","bar","baz"})
//
// Note that this is distinct from the heavyweight query syntax supported by
// TomlTree.Query() and the Query() struct (see below).
// Tree.Query() and the Query() struct (see below).
//
// Position Support
//
// Each element within the TomlTree is stored with position metadata, which is
// Each element within the Tree is stored with position metadata, which is
// invaluable for providing semantic feedback to a user. This helps in
// situations where the TOML file parses correctly, but contains data that is
// not correct for the application. In such cases, an error message can be
@@ -75,176 +75,10 @@
// return fmt.Errorf("%v: Expected 'bar' element", tree.GetPosition(""))
// }
//
// Query Support
// JSONPath-like queries
//
// The TOML query path implementation is based loosely on the JSONPath specification:
// http://goessner.net/articles/JsonPath/
//
// The idea behind a query path is to allow quick access to any element, or set
// of elements within TOML document, with a single expression.
//
// result, err := tree.Query("$.foo.bar.baz")
//
// This is roughly equivalent to:
//
// next := tree.Get("foo")
// if next != nil {
// next = next.Get("bar")
// if next != nil {
// next = next.Get("baz")
// }
// }
// result := next
//
// err is nil if any parsing exception occurs.
//
// If no node in the tree matches the query, result will simply contain an empty list of
// items.
//
// As illustrated above, the query path is much more efficient, especially since
// the structure of the TOML file can vary. Rather than making assumptions about
// a document's structure, a query allows the programmer to make structured
// requests into the document, and get zero or more values as a result.
//
// The syntax of a query begins with a root token, followed by any number
// sub-expressions:
//
// $
// Root of the TOML tree. This must always come first.
// .name
// Selects child of this node, where 'name' is a TOML key
// name.
// ['name']
// Selects child of this node, where 'name' is a string
// containing a TOML key name.
// [index]
// Selcts child array element at 'index'.
// ..expr
// Recursively selects all children, filtered by an a union,
// index, or slice expression.
// ..*
// Recursive selection of all nodes at this point in the
// tree.
// .*
// Selects all children of the current node.
// [expr,expr]
// Union operator - a logical 'or' grouping of two or more
// sub-expressions: index, key name, or filter.
// [start:end:step]
// Slice operator - selects array elements from start to
// end-1, at the given step. All three arguments are
// optional.
// [?(filter)]
// Named filter expression - the function 'filter' is
// used to filter children at this node.
//
// Query Indexes And Slices
//
// Index expressions perform no bounds checking, and will contribute no
// values to the result set if the provided index or index range is invalid.
// Negative indexes represent values from the end of the array, counting backwards.
//
// // select the last index of the array named 'foo'
// tree.Query("$.foo[-1]")
//
// Slice expressions are supported, by using ':' to separate a start/end index pair.
//
// // select up to the first five elements in the array
// tree.Query("$.foo[0:5]")
//
// Slice expressions also allow negative indexes for the start and stop
// arguments.
//
// // select all array elements.
// tree.Query("$.foo[0:-1]")
//
// Slice expressions may have an optional stride/step parameter:
//
// // select every other element
// tree.Query("$.foo[0:-1:2]")
//
// Slice start and end parameters are also optional:
//
// // these are all equivalent and select all the values in the array
// tree.Query("$.foo[:]")
// tree.Query("$.foo[0:]")
// tree.Query("$.foo[:-1]")
// tree.Query("$.foo[0:-1:]")
// tree.Query("$.foo[::1]")
// tree.Query("$.foo[0::1]")
// tree.Query("$.foo[:-1:1]")
// tree.Query("$.foo[0:-1:1]")
//
// Query Filters
//
// Query filters are used within a Union [,] or single Filter [] expression.
// A filter only allows nodes that qualify through to the next expression,
// and/or into the result set.
//
// // returns children of foo that are permitted by the 'bar' filter.
// tree.Query("$.foo[?(bar)]")
//
// There are several filters provided with the library:
//
// tree
// Allows nodes of type TomlTree.
// int
// Allows nodes of type int64.
// float
// Allows nodes of type float64.
// string
// Allows nodes of type string.
// time
// Allows nodes of type time.Time.
// bool
// Allows nodes of type bool.
//
// Query Results
//
// An executed query returns a QueryResult object. This contains the nodes
// in the TOML tree that qualify the query expression. Position information
// is also available for each value in the set.
//
// // display the results of a query
// results := tree.Query("$.foo.bar.baz")
// for idx, value := results.Values() {
// fmt.Println("%v: %v", results.Positions()[idx], value)
// }
//
// Compiled Queries
//
// Queries may be executed directly on a TomlTree object, or compiled ahead
// of time and executed discretely. The former is more convienent, but has the
// penalty of having to recompile the query expression each time.
//
// // basic query
// results := tree.Query("$.foo.bar.baz")
//
// // compiled query
// query := toml.CompileQuery("$.foo.bar.baz")
// results := query.Execute(tree)
//
// // run the compiled query again on a different tree
// moreResults := query.Execute(anotherTree)
//
// User Defined Query Filters
//
// Filter expressions may also be user defined by using the SetFilter()
// function on the Query object. The function must return true/false, which
// signifies if the passed node is kept or discarded, respectively.
//
// // create a query that references a user-defined filter
// query, _ := CompileQuery("$[?(bazOnly)]")
//
// // define the filter, and assign it to the query
// query.SetFilter("bazOnly", func(node interface{}) bool{
// if tree, ok := node.(*TomlTree); ok {
// return tree.Has("baz")
// }
// return false // reject all other node types
// })
//
// // run the query
// query.Execute(tree)
// The package github.com/pelletier/go-toml/query implements a system
// similar to JSONPath to quickly retrive elements of a TOML document using a
// single expression. See the package documentation for more information.
//
package toml

54
vendor/github.com/pelletier/go-toml/doc_test.go сгенерированный поставляемый
Просмотреть файл

@@ -6,52 +6,6 @@ import (
"fmt"
)
func ExampleNodeFilterFn_filterExample() {
tree, _ := Load(`
[struct_one]
foo = "foo"
bar = "bar"
[struct_two]
baz = "baz"
gorf = "gorf"
`)
// create a query that references a user-defined-filter
query, _ := CompileQuery("$[?(bazOnly)]")
// define the filter, and assign it to the query
query.SetFilter("bazOnly", func(node interface{}) bool {
if tree, ok := node.(*TomlTree); ok {
return tree.Has("baz")
}
return false // reject all other node types
})
// results contain only the 'struct_two' TomlTree
query.Execute(tree)
}
func ExampleQuery_queryExample() {
config, _ := Load(`
[[book]]
title = "The Stand"
author = "Stephen King"
[[book]]
title = "For Whom the Bell Tolls"
author = "Ernest Hemmingway"
[[book]]
title = "Neuromancer"
author = "William Gibson"
`)
// find and print all the authors in the document
authors, _ := config.Query("$.book.author")
for _, name := range authors.Values() {
fmt.Println(name)
}
}
func Example_comprehensiveExample() {
config, err := LoadFile("config.toml")
@@ -63,7 +17,7 @@ func Example_comprehensiveExample() {
password := config.Get("postgres.password").(string)
// or using an intermediate object
configTree := config.Get("postgres").(*TomlTree)
configTree := config.Get("postgres").(*Tree)
user = configTree.Get("user").(string)
password = configTree.Get("password").(string)
fmt.Println("User is ", user, ". Password is ", password)
@@ -71,11 +25,5 @@ func Example_comprehensiveExample() {
// show where elements are in the file
fmt.Printf("User position: %v\n", configTree.GetPosition("user"))
fmt.Printf("Password position: %v\n", configTree.GetPosition("password"))
// use a query to gather elements without walking the tree
results, _ := config.Query("$..[user,password]")
for ii, item := range results.Values() {
fmt.Printf("Query result %d: %v\n", ii, item)
}
}
}

63
vendor/github.com/pelletier/go-toml/marshal.go сгенерированный поставляемый
Просмотреть файл

@@ -1,6 +1,7 @@
package toml
import (
"bytes"
"errors"
"fmt"
"reflect"
@@ -9,14 +10,14 @@ import (
)
/*
TomlTree structural types and corresponding marshal types
Tree structural types and corresponding marshal types
-------------------------------------------------------------------------------
*TomlTree (*)struct, (*)map[string]interface{}
[]*TomlTree (*)[](*)struct, (*)[](*)map[string]interface{}
*Tree (*)struct, (*)map[string]interface{}
[]*Tree (*)[](*)struct, (*)[](*)map[string]interface{}
[]interface{} (as interface{}) (*)[]primitive, (*)[]([]interface{})
interface{} (*)primitive
TomlTree primitive types and corresponding marshal types
Tree primitive types and corresponding marshal types
-----------------------------------------------------------
uint64 uint, uint8-uint64, pointers to same
int64 int, int8-uint64, pointers to same
@@ -35,7 +36,7 @@ type tomlOpts struct {
var timeType = reflect.TypeOf(time.Time{})
var marshalerType = reflect.TypeOf(new(Marshaler)).Elem()
// Check if the given marshall type maps to a TomlTree primitive
// Check if the given marshall type maps to a Tree primitive
func isPrimitive(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
@@ -57,7 +58,7 @@ func isPrimitive(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a TomlTree slice
// Check if the given marshall type maps to a Tree slice
func isTreeSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Slice:
@@ -67,7 +68,7 @@ func isTreeSlice(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a non-TomlTree slice
// Check if the given marshall type maps to a non-Tree slice
func isOtherSlice(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Ptr:
@@ -79,7 +80,7 @@ func isOtherSlice(mtype reflect.Type) bool {
}
}
// Check if the given marshall type maps to a TomlTree
// Check if the given marshall type maps to a Tree
func isTree(mtype reflect.Type) bool {
switch mtype.Kind() {
case reflect.Map:
@@ -133,11 +134,11 @@ func Marshal(v interface{}) ([]byte, error) {
}
// Convert given marshal struct or map value to toml tree
func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) {
func valueToTree(mtype reflect.Type, mval reflect.Value) (*Tree, error) {
if mtype.Kind() == reflect.Ptr {
return valueToTree(mtype.Elem(), mval.Elem())
}
tval := newTomlTree()
tval := newTree()
switch mtype.Kind() {
case reflect.Struct:
for i := 0; i < mtype.NumField(); i++ {
@@ -165,8 +166,8 @@ func valueToTree(mtype reflect.Type, mval reflect.Value) (*TomlTree, error) {
}
// Convert given marshal slice to slice of Toml trees
func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*TomlTree, error) {
tval := make([]*TomlTree, mval.Len(), mval.Len())
func valueToTreeSlice(mtype reflect.Type, mval reflect.Value) ([]*Tree, error) {
tval := make([]*Tree, mval.Len(), mval.Len())
for i := 0; i < mval.Len(); i++ {
val, err := valueToTree(mtype.Elem(), mval.Index(i))
if err != nil {
@@ -224,24 +225,15 @@ func valueToToml(mtype reflect.Type, mval reflect.Value) (interface{}, error) {
}
}
/*
Unmarshal parses the TOML-encoded data and stores the result in the value
pointed to by v. Behavior is similar to the Go json encoder, except that there
is no concept of an Unmarshaler interface or UnmarshalTOML function for
sub-structs, and currently only definite types can be unmarshaled to (i.e. no
`interface{}`).
*/
func Unmarshal(data []byte, v interface{}) error {
// Unmarshal attempts to unmarshal the Tree into a Go struct pointed by v.
// Neither Unmarshaler interfaces nor UnmarshalTOML functions are supported for
// sub-structs, and only definite types can be unmarshaled.
func (t *Tree) Unmarshal(v interface{}) error {
mtype := reflect.TypeOf(v)
if mtype.Kind() != reflect.Ptr || mtype.Elem().Kind() != reflect.Struct {
return errors.New("Only a pointer to struct can be unmarshaled from TOML")
}
t, err := Load(string(data))
if err != nil {
return err
}
sval, err := valueFromTree(mtype.Elem(), t)
if err != nil {
return err
@@ -250,8 +242,21 @@ func Unmarshal(data []byte, v interface{}) error {
return nil
}
// Unmarshal parses the TOML-encoded data and stores the result in the value
// pointed to by v. Behavior is similar to the Go json encoder, except that there
// is no concept of an Unmarshaler interface or UnmarshalTOML function for
// sub-structs, and currently only definite types can be unmarshaled to (i.e. no
// `interface{}`).
func Unmarshal(data []byte, v interface{}) error {
t, err := LoadReader(bytes.NewReader(data))
if err != nil {
return err
}
return t.Unmarshal(v)
}
// Convert toml tree to marshal struct or map, using marshal type
func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) {
func valueFromTree(mtype reflect.Type, tval *Tree) (reflect.Value, error) {
if mtype.Kind() == reflect.Ptr {
return unwrapPointer(mtype, tval)
}
@@ -290,7 +295,7 @@ func valueFromTree(mtype reflect.Type, tval *TomlTree) (reflect.Value, error) {
}
// Convert toml value to marshal struct/map slice, using marshal type
func valueFromTreeSlice(mtype reflect.Type, tval []*TomlTree) (reflect.Value, error) {
func valueFromTreeSlice(mtype reflect.Type, tval []*Tree) (reflect.Value, error) {
mval := reflect.MakeSlice(mtype, len(tval), len(tval))
for i := 0; i < len(tval); i++ {
val, err := valueFromTree(mtype.Elem(), tval[i])
@@ -322,9 +327,9 @@ func valueFromToml(mtype reflect.Type, tval interface{}) (reflect.Value, error)
}
switch {
case isTree(mtype):
return valueFromTree(mtype, tval.(*TomlTree))
return valueFromTree(mtype, tval.(*Tree))
case isTreeSlice(mtype):
return valueFromTreeSlice(mtype, tval.([]*TomlTree))
return valueFromTreeSlice(mtype, tval.([]*Tree))
case isOtherSlice(mtype):
return valueFromOtherSlice(mtype, tval.([]interface{}))
default:

17
vendor/github.com/pelletier/go-toml/marshal_test.go сгенерированный поставляемый
Просмотреть файл

@@ -177,6 +177,23 @@ func TestDocUnmarshal(t *testing.T) {
}
}
func TestDocPartialUnmarshal(t *testing.T) {
result := testDocSubs{}
tree, _ := LoadFile("marshal_test.toml")
subTree := tree.Get("subdoc").(*Tree)
err := subTree.Unmarshal(&result)
expected := docData.Subdocs
if err != nil {
t.Fatal(err)
}
if !reflect.DeepEqual(result, expected) {
resStr, _ := json.MarshalIndent(result, "", " ")
expStr, _ := json.MarshalIndent(expected, "", " ")
t.Errorf("Bad partial unmartial: expected\n-----\n%s\n-----\ngot\n-----\n%s\n-----\n", expStr, resStr)
}
}
type tomlTypeCheckTest struct {
name string
item interface{}

38
vendor/github.com/pelletier/go-toml/parser.go сгенерированный поставляемый
Просмотреть файл

@@ -14,7 +14,7 @@ import (
type tomlParser struct {
flow chan token
tree *TomlTree
tree *Tree
tokensBuffer []token
currentTable []string
seenTableKeys []string
@@ -106,18 +106,18 @@ func (p *tomlParser) parseGroupArray() tomlParserStateFn {
}
p.tree.createSubTree(keys[:len(keys)-1], startToken.Position) // create parent entries
destTree := p.tree.GetPath(keys)
var array []*TomlTree
var array []*Tree
if destTree == nil {
array = make([]*TomlTree, 0)
} else if target, ok := destTree.([]*TomlTree); ok && target != nil {
array = destTree.([]*TomlTree)
array = make([]*Tree, 0)
} else if target, ok := destTree.([]*Tree); ok && target != nil {
array = destTree.([]*Tree)
} else {
p.raiseError(key, "key %s is already assigned and not of type table array", key)
}
p.currentTable = keys
// add a new tree to the end of the table array
newTree := newTomlTree()
newTree := newTree()
newTree.position = startToken.Position
array = append(array, newTree)
p.tree.SetPath(p.currentTable, array)
@@ -183,11 +183,11 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
}
// find the table to assign, looking out for arrays of tables
var targetNode *TomlTree
var targetNode *Tree
switch node := p.tree.GetPath(tableKey).(type) {
case []*TomlTree:
case []*Tree:
targetNode = node[len(node)-1]
case *TomlTree:
case *Tree:
targetNode = node
default:
p.raiseError(key, "Unknown table type for path: %s",
@@ -212,7 +212,7 @@ func (p *tomlParser) parseAssign() tomlParserStateFn {
var toInsert interface{}
switch value.(type) {
case *TomlTree, []*TomlTree:
case *Tree, []*Tree:
toInsert = value
default:
toInsert = &tomlValue{value, key.Position}
@@ -289,8 +289,8 @@ func tokenIsComma(t *token) bool {
return t != nil && t.typ == tokenComma
}
func (p *tomlParser) parseInlineTable() *TomlTree {
tree := newTomlTree()
func (p *tomlParser) parseInlineTable() *Tree {
tree := newTree()
var previous *token
Loop:
for {
@@ -360,22 +360,22 @@ func (p *tomlParser) parseArray() interface{} {
p.getToken()
}
}
// An array of TomlTrees is actually an array of inline
// An array of Trees is actually an array of inline
// tables, which is a shorthand for a table array. If the
// array was not converted from []interface{} to []*TomlTree,
// array was not converted from []interface{} to []*Tree,
// the two notations would not be equivalent.
if arrayType == reflect.TypeOf(newTomlTree()) {
tomlArray := make([]*TomlTree, len(array))
if arrayType == reflect.TypeOf(newTree()) {
tomlArray := make([]*Tree, len(array))
for i, v := range array {
tomlArray[i] = v.(*TomlTree)
tomlArray[i] = v.(*Tree)
}
return tomlArray
}
return array
}
func parseToml(flow chan token) *TomlTree {
result := newTomlTree()
func parseToml(flow chan token) *Tree {
result := newTree()
result.position = Position{1, 1}
parser := &tomlParser{
flow: flow,

10
vendor/github.com/pelletier/go-toml/parser_test.go сгенерированный поставляемый
Просмотреть файл

@@ -9,7 +9,7 @@ import (
"github.com/davecgh/go-spew/spew"
)
func assertSubTree(t *testing.T, path []string, tree *TomlTree, err error, ref map[string]interface{}) {
func assertSubTree(t *testing.T, path []string, tree *Tree, err error, ref map[string]interface{}) {
if err != nil {
t.Error("Non-nil error:", err.Error())
return
@@ -20,12 +20,12 @@ func assertSubTree(t *testing.T, path []string, tree *TomlTree, err error, ref m
// NOTE: directly access key instead of resolve by path
// NOTE: see TestSpecialKV
switch node := tree.GetPath([]string{k}).(type) {
case []*TomlTree:
case []*Tree:
t.Log("\tcomparing key", nextPath, "by array iteration")
for idx, item := range node {
assertSubTree(t, nextPath, item, err, v.([]map[string]interface{})[idx])
}
case *TomlTree:
case *Tree:
t.Log("\tcomparing key", nextPath, "by subtree assestion")
assertSubTree(t, nextPath, node, err, v.(map[string]interface{}))
default:
@@ -37,14 +37,14 @@ func assertSubTree(t *testing.T, path []string, tree *TomlTree, err error, ref m
}
}
func assertTree(t *testing.T, tree *TomlTree, err error, ref map[string]interface{}) {
func assertTree(t *testing.T, tree *Tree, err error, ref map[string]interface{}) {
t.Log("Asserting tree:\n", spew.Sdump(tree))
assertSubTree(t, []string{}, tree, err, ref)
t.Log("Finished tree assertion.")
}
func TestCreateSubTree(t *testing.T) {
tree := newTomlTree()
tree := newTree()
tree.createSubTree([]string{"a", "b", "c"}, Position{})
tree.Set("a.b.c", 42)
if tree.Get("a.b.c") != 42 {

175
vendor/github.com/pelletier/go-toml/query/doc.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,175 @@
// Package query performs JSONPath-like queries on a TOML document.
//
// The query path implementation is based loosely on the JSONPath specification:
// http://goessner.net/articles/JsonPath/.
//
// The idea behind a query path is to allow quick access to any element, or set
// of elements within TOML document, with a single expression.
//
// result, err := query.CompileAndExecute("$.foo.bar.baz", tree)
//
// This is roughly equivalent to:
//
// next := tree.Get("foo")
// if next != nil {
// next = next.Get("bar")
// if next != nil {
// next = next.Get("baz")
// }
// }
// result := next
//
// err is nil if any parsing exception occurs.
//
// If no node in the tree matches the query, result will simply contain an empty list of
// items.
//
// As illustrated above, the query path is much more efficient, especially since
// the structure of the TOML file can vary. Rather than making assumptions about
// a document's structure, a query allows the programmer to make structured
// requests into the document, and get zero or more values as a result.
//
// Query syntax
//
// The syntax of a query begins with a root token, followed by any number
// sub-expressions:
//
// $
// Root of the TOML tree. This must always come first.
// .name
// Selects child of this node, where 'name' is a TOML key
// name.
// ['name']
// Selects child of this node, where 'name' is a string
// containing a TOML key name.
// [index]
// Selcts child array element at 'index'.
// ..expr
// Recursively selects all children, filtered by an a union,
// index, or slice expression.
// ..*
// Recursive selection of all nodes at this point in the
// tree.
// .*
// Selects all children of the current node.
// [expr,expr]
// Union operator - a logical 'or' grouping of two or more
// sub-expressions: index, key name, or filter.
// [start:end:step]
// Slice operator - selects array elements from start to
// end-1, at the given step. All three arguments are
// optional.
// [?(filter)]
// Named filter expression - the function 'filter' is
// used to filter children at this node.
//
// Query Indexes And Slices
//
// Index expressions perform no bounds checking, and will contribute no
// values to the result set if the provided index or index range is invalid.
// Negative indexes represent values from the end of the array, counting backwards.
//
// // select the last index of the array named 'foo'
// query.CompileAndExecute("$.foo[-1]", tree)
//
// Slice expressions are supported, by using ':' to separate a start/end index pair.
//
// // select up to the first five elements in the array
// query.CompileAndExecute("$.foo[0:5]", tree)
//
// Slice expressions also allow negative indexes for the start and stop
// arguments.
//
// // select all array elements.
// query.CompileAndExecute("$.foo[0:-1]", tree)
//
// Slice expressions may have an optional stride/step parameter:
//
// // select every other element
// query.CompileAndExecute("$.foo[0:-1:2]", tree)
//
// Slice start and end parameters are also optional:
//
// // these are all equivalent and select all the values in the array
// query.CompileAndExecute("$.foo[:]", tree)
// query.CompileAndExecute("$.foo[0:]", tree)
// query.CompileAndExecute("$.foo[:-1]", tree)
// query.CompileAndExecute("$.foo[0:-1:]", tree)
// query.CompileAndExecute("$.foo[::1]", tree)
// query.CompileAndExecute("$.foo[0::1]", tree)
// query.CompileAndExecute("$.foo[:-1:1]", tree)
// query.CompileAndExecute("$.foo[0:-1:1]", tree)
//
// Query Filters
//
// Query filters are used within a Union [,] or single Filter [] expression.
// A filter only allows nodes that qualify through to the next expression,
// and/or into the result set.
//
// // returns children of foo that are permitted by the 'bar' filter.
// query.CompileAndExecute("$.foo[?(bar)]", tree)
//
// There are several filters provided with the library:
//
// tree
// Allows nodes of type Tree.
// int
// Allows nodes of type int64.
// float
// Allows nodes of type float64.
// string
// Allows nodes of type string.
// time
// Allows nodes of type time.Time.
// bool
// Allows nodes of type bool.
//
// Query Results
//
// An executed query returns a Result object. This contains the nodes
// in the TOML tree that qualify the query expression. Position information
// is also available for each value in the set.
//
// // display the results of a query
// results := query.CompileAndExecute("$.foo.bar.baz", tree)
// for idx, value := results.Values() {
// fmt.Println("%v: %v", results.Positions()[idx], value)
// }
//
// Compiled Queries
//
// Queries may be executed directly on a Tree object, or compiled ahead
// of time and executed discretely. The former is more convienent, but has the
// penalty of having to recompile the query expression each time.
//
// // basic query
// results := query.CompileAndExecute("$.foo.bar.baz", tree)
//
// // compiled query
// query, err := toml.Compile("$.foo.bar.baz")
// results := query.Execute(tree)
//
// // run the compiled query again on a different tree
// moreResults := query.Execute(anotherTree)
//
// User Defined Query Filters
//
// Filter expressions may also be user defined by using the SetFilter()
// function on the Query object. The function must return true/false, which
// signifies if the passed node is kept or discarded, respectively.
//
// // create a query that references a user-defined filter
// query, _ := query.Compile("$[?(bazOnly)]")
//
// // define the filter, and assign it to the query
// query.SetFilter("bazOnly", func(node interface{}) bool{
// if tree, ok := node.(*Tree); ok {
// return tree.Has("baz")
// }
// return false // reject all other node types
// })
//
// // run the query
// query.Execute(tree)
//
package query

Просмотреть файл

@@ -3,13 +3,14 @@
// Written using the principles developed by Rob Pike in
// http://www.youtube.com/watch?v=HxaD_trXwRE
package toml
package query
import (
"fmt"
"strconv"
"strings"
"unicode/utf8"
"github.com/pelletier/go-toml"
)
// Lexer state function
@@ -54,7 +55,7 @@ func (l *queryLexer) nextStart() {
func (l *queryLexer) emit(t tokenType) {
l.tokens <- token{
Position: Position{l.line, l.col},
Position: toml.Position{Line:l.line, Col:l.col},
typ: t,
val: l.input[l.start:l.pos],
}
@@ -63,7 +64,7 @@ func (l *queryLexer) emit(t tokenType) {
func (l *queryLexer) emitWithValue(t tokenType, value string) {
l.tokens <- token{
Position: Position{l.line, l.col},
Position: toml.Position{Line:l.line, Col:l.col},
typ: t,
val: value,
}
@@ -91,7 +92,7 @@ func (l *queryLexer) backup() {
func (l *queryLexer) errorf(format string, args ...interface{}) queryLexStateFn {
l.tokens <- token{
Position: Position{l.line, l.col},
Position: toml.Position{Line:l.line, Col:l.col},
typ: tokenError,
val: fmt.Sprintf(format, args...),
}

Просмотреть файл

@@ -1,7 +1,8 @@
package toml
package query
import (
"testing"
"github.com/pelletier/go-toml"
)
func testQLFlow(t *testing.T, input string, expectedFlow []token) {
@@ -36,143 +37,143 @@ func testQLFlow(t *testing.T, input string, expectedFlow []token) {
func TestLexSpecialChars(t *testing.T) {
testQLFlow(t, " .$[]..()?*", []token{
{Position{1, 2}, tokenDot, "."},
{Position{1, 3}, tokenDollar, "$"},
{Position{1, 4}, tokenLeftBracket, "["},
{Position{1, 5}, tokenRightBracket, "]"},
{Position{1, 6}, tokenDotDot, ".."},
{Position{1, 8}, tokenLeftParen, "("},
{Position{1, 9}, tokenRightParen, ")"},
{Position{1, 10}, tokenQuestion, "?"},
{Position{1, 11}, tokenStar, "*"},
{Position{1, 12}, tokenEOF, ""},
{toml.Position{1, 2}, tokenDot, "."},
{toml.Position{1, 3}, tokenDollar, "$"},
{toml.Position{1, 4}, tokenLeftBracket, "["},
{toml.Position{1, 5}, tokenRightBracket, "]"},
{toml.Position{1, 6}, tokenDotDot, ".."},
{toml.Position{1, 8}, tokenLeftParen, "("},
{toml.Position{1, 9}, tokenRightParen, ")"},
{toml.Position{1, 10}, tokenQuestion, "?"},
{toml.Position{1, 11}, tokenStar, "*"},
{toml.Position{1, 12}, tokenEOF, ""},
})
}
func TestLexString(t *testing.T) {
testQLFlow(t, "'foo\n'", []token{
{Position{1, 2}, tokenString, "foo\n"},
{Position{2, 2}, tokenEOF, ""},
{toml.Position{1, 2}, tokenString, "foo\n"},
{toml.Position{2, 2}, tokenEOF, ""},
})
}
func TestLexDoubleString(t *testing.T) {
testQLFlow(t, `"bar"`, []token{
{Position{1, 2}, tokenString, "bar"},
{Position{1, 6}, tokenEOF, ""},
{toml.Position{1, 2}, tokenString, "bar"},
{toml.Position{1, 6}, tokenEOF, ""},
})
}
func TestLexStringEscapes(t *testing.T) {
testQLFlow(t, `"foo \" \' \b \f \/ \t \r \\ \u03A9 \U00012345 \n bar"`, []token{
{Position{1, 2}, tokenString, "foo \" ' \b \f / \t \r \\ \u03A9 \U00012345 \n bar"},
{Position{1, 55}, tokenEOF, ""},
{toml.Position{1, 2}, tokenString, "foo \" ' \b \f / \t \r \\ \u03A9 \U00012345 \n bar"},
{toml.Position{1, 55}, tokenEOF, ""},
})
}
func TestLexStringUnfinishedUnicode4(t *testing.T) {
testQLFlow(t, `"\u000"`, []token{
{Position{1, 2}, tokenError, "unfinished unicode escape"},
{toml.Position{1, 2}, tokenError, "unfinished unicode escape"},
})
}
func TestLexStringUnfinishedUnicode8(t *testing.T) {
testQLFlow(t, `"\U0000"`, []token{
{Position{1, 2}, tokenError, "unfinished unicode escape"},
{toml.Position{1, 2}, tokenError, "unfinished unicode escape"},
})
}
func TestLexStringInvalidEscape(t *testing.T) {
testQLFlow(t, `"\x"`, []token{
{Position{1, 2}, tokenError, "invalid escape sequence: \\x"},
{toml.Position{1, 2}, tokenError, "invalid escape sequence: \\x"},
})
}
func TestLexStringUnfinished(t *testing.T) {
testQLFlow(t, `"bar`, []token{
{Position{1, 2}, tokenError, "unclosed string"},
{toml.Position{1, 2}, tokenError, "unclosed string"},
})
}
func TestLexKey(t *testing.T) {
testQLFlow(t, "foo", []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 4}, tokenEOF, ""},
{toml.Position{1, 1}, tokenKey, "foo"},
{toml.Position{1, 4}, tokenEOF, ""},
})
}
func TestLexRecurse(t *testing.T) {
testQLFlow(t, "$..*", []token{
{Position{1, 1}, tokenDollar, "$"},
{Position{1, 2}, tokenDotDot, ".."},
{Position{1, 4}, tokenStar, "*"},
{Position{1, 5}, tokenEOF, ""},
{toml.Position{1, 1}, tokenDollar, "$"},
{toml.Position{1, 2}, tokenDotDot, ".."},
{toml.Position{1, 4}, tokenStar, "*"},
{toml.Position{1, 5}, tokenEOF, ""},
})
}
func TestLexBracketKey(t *testing.T) {
testQLFlow(t, "$[foo]", []token{
{Position{1, 1}, tokenDollar, "$"},
{Position{1, 2}, tokenLeftBracket, "["},
{Position{1, 3}, tokenKey, "foo"},
{Position{1, 6}, tokenRightBracket, "]"},
{Position{1, 7}, tokenEOF, ""},
{toml.Position{1, 1}, tokenDollar, "$"},
{toml.Position{1, 2}, tokenLeftBracket, "["},
{toml.Position{1, 3}, tokenKey, "foo"},
{toml.Position{1, 6}, tokenRightBracket, "]"},
{toml.Position{1, 7}, tokenEOF, ""},
})
}
func TestLexSpace(t *testing.T) {
testQLFlow(t, "foo bar baz", []token{
{Position{1, 1}, tokenKey, "foo"},
{Position{1, 5}, tokenKey, "bar"},
{Position{1, 9}, tokenKey, "baz"},
{Position{1, 12}, tokenEOF, ""},
{toml.Position{1, 1}, tokenKey, "foo"},
{toml.Position{1, 5}, tokenKey, "bar"},
{toml.Position{1, 9}, tokenKey, "baz"},
{toml.Position{1, 12}, tokenEOF, ""},
})
}
func TestLexInteger(t *testing.T) {
testQLFlow(t, "100 +200 -300", []token{
{Position{1, 1}, tokenInteger, "100"},
{Position{1, 5}, tokenInteger, "+200"},
{Position{1, 10}, tokenInteger, "-300"},
{Position{1, 14}, tokenEOF, ""},
{toml.Position{1, 1}, tokenInteger, "100"},
{toml.Position{1, 5}, tokenInteger, "+200"},
{toml.Position{1, 10}, tokenInteger, "-300"},
{toml.Position{1, 14}, tokenEOF, ""},
})
}
func TestLexFloat(t *testing.T) {
testQLFlow(t, "100.0 +200.0 -300.0", []token{
{Position{1, 1}, tokenFloat, "100.0"},
{Position{1, 7}, tokenFloat, "+200.0"},
{Position{1, 14}, tokenFloat, "-300.0"},
{Position{1, 20}, tokenEOF, ""},
{toml.Position{1, 1}, tokenFloat, "100.0"},
{toml.Position{1, 7}, tokenFloat, "+200.0"},
{toml.Position{1, 14}, tokenFloat, "-300.0"},
{toml.Position{1, 20}, tokenEOF, ""},
})
}
func TestLexFloatWithMultipleDots(t *testing.T) {
testQLFlow(t, "4.2.", []token{
{Position{1, 1}, tokenError, "cannot have two dots in one float"},
{toml.Position{1, 1}, tokenError, "cannot have two dots in one float"},
})
}
func TestLexFloatLeadingDot(t *testing.T) {
testQLFlow(t, "+.1", []token{
{Position{1, 1}, tokenError, "cannot start float with a dot"},
{toml.Position{1, 1}, tokenError, "cannot start float with a dot"},
})
}
func TestLexFloatWithTrailingDot(t *testing.T) {
testQLFlow(t, "42.", []token{
{Position{1, 1}, tokenError, "float cannot end with a dot"},
{toml.Position{1, 1}, tokenError, "float cannot end with a dot"},
})
}
func TestLexNumberWithoutDigit(t *testing.T) {
testQLFlow(t, "+", []token{
{Position{1, 1}, tokenError, "no digit in that number"},
{toml.Position{1, 1}, tokenError, "no digit in that number"},
})
}
func TestLexUnknown(t *testing.T) {
testQLFlow(t, "^", []token{
{Position{1, 1}, tokenError, "unexpected char: '94'"},
{toml.Position{1, 1}, tokenError, "unexpected char: '94'"},
})
}

Просмотреть файл

@@ -1,27 +1,10 @@
package toml
package query
import (
"fmt"
"github.com/pelletier/go-toml"
)
// support function to set positions for tomlValues
// NOTE: this is done to allow ctx.lastPosition to indicate the start of any
// values returned by the query engines
func tomlValueCheck(node interface{}, ctx *queryContext) interface{} {
switch castNode := node.(type) {
case *tomlValue:
ctx.lastPosition = castNode.position
return castNode.value
case []*TomlTree:
if len(castNode) > 0 {
ctx.lastPosition = castNode[0].position
}
return node
default:
return node
}
}
// base match
type matchBase struct {
next pathFn
@@ -45,15 +28,7 @@ func (f *terminatingFn) setNext(next pathFn) {
}
func (f *terminatingFn) call(node interface{}, ctx *queryContext) {
switch castNode := node.(type) {
case *TomlTree:
ctx.result.appendResult(node, castNode.position)
case *tomlValue:
ctx.result.appendResult(node, castNode.position)
default:
// use last position for scalars
ctx.result.appendResult(node, ctx.lastPosition)
}
ctx.result.appendResult(node, ctx.lastPosition)
}
// match single key
@@ -67,16 +42,18 @@ func newMatchKeyFn(name string) *matchKeyFn {
}
func (f *matchKeyFn) call(node interface{}, ctx *queryContext) {
if array, ok := node.([]*TomlTree); ok {
if array, ok := node.([]*toml.Tree); ok {
for _, tree := range array {
item := tree.values[f.Name]
item := tree.Get(f.Name)
if item != nil {
ctx.lastPosition = tree.GetPosition(f.Name)
f.next.call(item, ctx)
}
}
} else if tree, ok := node.(*TomlTree); ok {
item := tree.values[f.Name]
} else if tree, ok := node.(*toml.Tree); ok {
item := tree.Get(f.Name)
if item != nil {
ctx.lastPosition = tree.GetPosition(f.Name)
f.next.call(item, ctx)
}
}
@@ -93,8 +70,13 @@ func newMatchIndexFn(idx int) *matchIndexFn {
}
func (f *matchIndexFn) call(node interface{}, ctx *queryContext) {
if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok {
if arr, ok := node.([]interface{}); ok {
if f.Idx < len(arr) && f.Idx >= 0 {
if treesArray, ok := node.([]*toml.Tree); ok {
if len(treesArray) > 0 {
ctx.lastPosition = treesArray[0].Position()
}
}
f.next.call(arr[f.Idx], ctx)
}
}
@@ -111,7 +93,7 @@ func newMatchSliceFn(start, end, step int) *matchSliceFn {
}
func (f *matchSliceFn) call(node interface{}, ctx *queryContext) {
if arr, ok := tomlValueCheck(node, ctx).([]interface{}); ok {
if arr, ok := node.([]interface{}); ok {
// adjust indexes for negative values, reverse ordering
realStart, realEnd := f.Start, f.End
if realStart < 0 {
@@ -125,6 +107,11 @@ func (f *matchSliceFn) call(node interface{}, ctx *queryContext) {
}
// loop and gather
for idx := realStart; idx < realEnd; idx += f.Step {
if treesArray, ok := node.([]*toml.Tree); ok {
if len(treesArray) > 0 {
ctx.lastPosition = treesArray[0].Position()
}
}
f.next.call(arr[idx], ctx)
}
}
@@ -140,8 +127,10 @@ func newMatchAnyFn() *matchAnyFn {
}
func (f *matchAnyFn) call(node interface{}, ctx *queryContext) {
if tree, ok := node.(*TomlTree); ok {
for _, v := range tree.values {
if tree, ok := node.(*toml.Tree); ok {
for _, k := range tree.Keys() {
v := tree.Get(k)
ctx.lastPosition = tree.GetPosition(k)
f.next.call(v, ctx)
}
}
@@ -174,21 +163,25 @@ func newMatchRecursiveFn() *matchRecursiveFn {
}
func (f *matchRecursiveFn) call(node interface{}, ctx *queryContext) {
if tree, ok := node.(*TomlTree); ok {
var visit func(tree *TomlTree)
visit = func(tree *TomlTree) {
for _, v := range tree.values {
originalPosition := ctx.lastPosition
if tree, ok := node.(*toml.Tree); ok {
var visit func(tree *toml.Tree)
visit = func(tree *toml.Tree) {
for _, k := range tree.Keys() {
v := tree.Get(k)
ctx.lastPosition = tree.GetPosition(k)
f.next.call(v, ctx)
switch node := v.(type) {
case *TomlTree:
case *toml.Tree:
visit(node)
case []*TomlTree:
case []*toml.Tree:
for _, subtree := range node {
visit(subtree)
}
}
}
}
ctx.lastPosition = originalPosition
f.next.call(tree, ctx)
visit(tree)
}
@@ -197,11 +190,11 @@ func (f *matchRecursiveFn) call(node interface{}, ctx *queryContext) {
// match based on an externally provided functional filter
type matchFilterFn struct {
matchBase
Pos Position
Pos toml.Position
Name string
}
func newMatchFilterFn(name string, pos Position) *matchFilterFn {
func newMatchFilterFn(name string, pos toml.Position) *matchFilterFn {
return &matchFilterFn{Name: name, Pos: pos}
}
@@ -211,17 +204,22 @@ func (f *matchFilterFn) call(node interface{}, ctx *queryContext) {
panic(fmt.Sprintf("%s: query context does not have filter '%s'",
f.Pos.String(), f.Name))
}
switch castNode := tomlValueCheck(node, ctx).(type) {
case *TomlTree:
for _, v := range castNode.values {
if tv, ok := v.(*tomlValue); ok {
if fn(tv.value) {
f.next.call(v, ctx)
}
} else {
if fn(v) {
f.next.call(v, ctx)
switch castNode := node.(type) {
case *toml.Tree:
for _, k := range castNode.Keys() {
v := castNode.Get(k)
if fn(v) {
ctx.lastPosition = castNode.GetPosition(k)
f.next.call(v, ctx)
}
}
case []*toml.Tree:
for _, v := range castNode {
if fn(v) {
if len(castNode) > 0 {
ctx.lastPosition = castNode[0].Position()
}
f.next.call(v, ctx)
}
}
case []interface{}:

Просмотреть файл

@@ -1,8 +1,9 @@
package toml
package query
import (
"fmt"
"testing"
"github.com/pelletier/go-toml"
)
// dump path tree to a string
@@ -194,8 +195,8 @@ func TestPathFilterExpr(t *testing.T) {
"$[?('foo'),?(bar)]",
buildPath(
&matchUnionFn{[]pathFn{
newMatchFilterFn("foo", Position{}),
newMatchFilterFn("bar", Position{}),
newMatchFilterFn("foo", toml.Position{}),
newMatchFilterFn("bar", toml.Position{}),
}},
))
}

Просмотреть файл

@@ -5,7 +5,7 @@
https://code.google.com/p/json-path/
*/
package toml
package query
import (
"fmt"

Просмотреть файл

@@ -1,4 +1,4 @@
package toml
package query
import (
"fmt"
@@ -7,19 +7,18 @@ import (
"strings"
"testing"
"time"
"github.com/pelletier/go-toml"
)
type queryTestNode struct {
value interface{}
position Position
position toml.Position
}
func valueString(root interface{}) string {
result := "" //fmt.Sprintf("%T:", root)
switch node := root.(type) {
case *tomlValue:
return valueString(node.value)
case *QueryResult:
case *Result:
items := []string{}
for i, v := range node.Values() {
items = append(items, fmt.Sprintf("%s:%s",
@@ -37,7 +36,7 @@ func valueString(root interface{}) string {
}
sort.Strings(items)
result = "[" + strings.Join(items, ", ") + "]"
case *TomlTree:
case *toml.Tree:
// workaround for unreliable map key ordering
items := []string{}
for _, k := range node.Keys() {
@@ -78,13 +77,13 @@ func assertValue(t *testing.T, result, ref interface{}) {
}
}
func assertQueryPositions(t *testing.T, toml, query string, ref []interface{}) {
tree, err := Load(toml)
func assertQueryPositions(t *testing.T, tomlDoc string, query string, ref []interface{}) {
tree, err := toml.Load(tomlDoc)
if err != nil {
t.Errorf("Non-nil toml parse error: %v", err)
return
}
q, err := CompileQuery(query)
q, err := Compile(query)
if err != nil {
t.Error(err)
return
@@ -101,7 +100,7 @@ func TestQueryRoot(t *testing.T) {
queryTestNode{
map[string]interface{}{
"a": int64(42),
}, Position{1, 1},
}, toml.Position{1, 1},
},
})
}
@@ -112,7 +111,7 @@ func TestQueryKey(t *testing.T) {
"$.foo.a",
[]interface{}{
queryTestNode{
int64(42), Position{2, 1},
int64(42), toml.Position{2, 1},
},
})
}
@@ -123,7 +122,7 @@ func TestQueryKeyString(t *testing.T) {
"$.foo['a']",
[]interface{}{
queryTestNode{
int64(42), Position{2, 1},
int64(42), toml.Position{2, 1},
},
})
}
@@ -134,7 +133,7 @@ func TestQueryIndex(t *testing.T) {
"$.foo.a[5]",
[]interface{}{
queryTestNode{
int64(6), Position{2, 1},
int64(6), toml.Position{2, 1},
},
})
}
@@ -145,19 +144,19 @@ func TestQuerySliceRange(t *testing.T) {
"$.foo.a[0:5]",
[]interface{}{
queryTestNode{
int64(1), Position{2, 1},
int64(1), toml.Position{2, 1},
},
queryTestNode{
int64(2), Position{2, 1},
int64(2), toml.Position{2, 1},
},
queryTestNode{
int64(3), Position{2, 1},
int64(3), toml.Position{2, 1},
},
queryTestNode{
int64(4), Position{2, 1},
int64(4), toml.Position{2, 1},
},
queryTestNode{
int64(5), Position{2, 1},
int64(5), toml.Position{2, 1},
},
})
}
@@ -168,13 +167,13 @@ func TestQuerySliceStep(t *testing.T) {
"$.foo.a[0:5:2]",
[]interface{}{
queryTestNode{
int64(1), Position{2, 1},
int64(1), toml.Position{2, 1},
},
queryTestNode{
int64(3), Position{2, 1},
int64(3), toml.Position{2, 1},
},
queryTestNode{
int64(5), Position{2, 1},
int64(5), toml.Position{2, 1},
},
})
}
@@ -188,13 +187,13 @@ func TestQueryAny(t *testing.T) {
map[string]interface{}{
"a": int64(1),
"b": int64(2),
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(3),
"b": int64(4),
}, Position{4, 1},
}, toml.Position{4, 1},
},
})
}
@@ -207,19 +206,19 @@ func TestQueryUnionSimple(t *testing.T) {
map[string]interface{}{
"a": int64(1),
"b": int64(2),
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(3),
"b": int64(4),
}, Position{4, 1},
}, toml.Position{4, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(5),
"b": int64(6),
}, Position{7, 1},
}, toml.Position{7, 1},
},
})
}
@@ -249,7 +248,7 @@ func TestQueryRecursionAll(t *testing.T) {
"b": int64(6),
},
},
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
@@ -257,19 +256,19 @@ func TestQueryRecursionAll(t *testing.T) {
"a": int64(1),
"b": int64(2),
},
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(1),
"b": int64(2),
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
int64(1), Position{2, 1},
int64(1), toml.Position{2, 1},
},
queryTestNode{
int64(2), Position{3, 1},
int64(2), toml.Position{3, 1},
},
queryTestNode{
map[string]interface{}{
@@ -277,19 +276,19 @@ func TestQueryRecursionAll(t *testing.T) {
"a": int64(3),
"b": int64(4),
},
}, Position{4, 1},
}, toml.Position{4, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(3),
"b": int64(4),
}, Position{4, 1},
}, toml.Position{4, 1},
},
queryTestNode{
int64(3), Position{5, 1},
int64(3), toml.Position{5, 1},
},
queryTestNode{
int64(4), Position{6, 1},
int64(4), toml.Position{6, 1},
},
queryTestNode{
map[string]interface{}{
@@ -297,19 +296,19 @@ func TestQueryRecursionAll(t *testing.T) {
"a": int64(5),
"b": int64(6),
},
}, Position{7, 1},
}, toml.Position{7, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(5),
"b": int64(6),
}, Position{7, 1},
}, toml.Position{7, 1},
},
queryTestNode{
int64(5), Position{8, 1},
int64(5), toml.Position{8, 1},
},
queryTestNode{
int64(6), Position{9, 1},
int64(6), toml.Position{9, 1},
},
})
}
@@ -325,31 +324,31 @@ func TestQueryRecursionUnionSimple(t *testing.T) {
"a": int64(1),
"b": int64(2),
},
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(3),
"b": int64(4),
}, Position{4, 1},
}, toml.Position{4, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(1),
"b": int64(2),
}, Position{1, 1},
}, toml.Position{1, 1},
},
queryTestNode{
map[string]interface{}{
"a": int64(5),
"b": int64(6),
}, Position{7, 1},
}, toml.Position{7, 1},
},
})
}
func TestQueryFilterFn(t *testing.T) {
buff, err := ioutil.ReadFile("example.toml")
buff, err := ioutil.ReadFile("../example.toml")
if err != nil {
t.Error(err)
return
@@ -359,16 +358,16 @@ func TestQueryFilterFn(t *testing.T) {
"$..[?(int)]",
[]interface{}{
queryTestNode{
int64(8001), Position{13, 1},
int64(8001), toml.Position{13, 1},
},
queryTestNode{
int64(8001), Position{13, 1},
int64(8001), toml.Position{13, 1},
},
queryTestNode{
int64(8002), Position{13, 1},
int64(8002), toml.Position{13, 1},
},
queryTestNode{
int64(5000), Position{14, 1},
int64(5000), toml.Position{14, 1},
},
})
@@ -376,32 +375,32 @@ func TestQueryFilterFn(t *testing.T) {
"$..[?(string)]",
[]interface{}{
queryTestNode{
"TOML Example", Position{3, 1},
"TOML Example", toml.Position{3, 1},
},
queryTestNode{
"Tom Preston-Werner", Position{6, 1},
"Tom Preston-Werner", toml.Position{6, 1},
},
queryTestNode{
"GitHub", Position{7, 1},
"GitHub", toml.Position{7, 1},
},
queryTestNode{
"GitHub Cofounder & CEO\nLikes tater tots and beer.",
Position{8, 1},
toml.Position{8, 1},
},
queryTestNode{
"192.168.1.1", Position{12, 1},
"192.168.1.1", toml.Position{12, 1},
},
queryTestNode{
"10.0.0.1", Position{21, 3},
"10.0.0.1", toml.Position{21, 3},
},
queryTestNode{
"eqdc10", Position{22, 3},
"eqdc10", toml.Position{22, 3},
},
queryTestNode{
"10.0.0.2", Position{25, 3},
"10.0.0.2", toml.Position{25, 3},
},
queryTestNode{
"eqdc10", Position{26, 3},
"eqdc10", toml.Position{26, 3},
},
})
@@ -421,7 +420,7 @@ func TestQueryFilterFn(t *testing.T) {
"organization": "GitHub",
"bio": "GitHub Cofounder & CEO\nLikes tater tots and beer.",
"dob": tv,
}, Position{5, 1},
}, toml.Position{5, 1},
},
queryTestNode{
map[string]interface{}{
@@ -429,7 +428,7 @@ func TestQueryFilterFn(t *testing.T) {
"ports": []interface{}{int64(8001), int64(8001), int64(8002)},
"connection_max": int64(5000),
"enabled": true,
}, Position{11, 1},
}, toml.Position{11, 1},
},
queryTestNode{
map[string]interface{}{
@@ -441,19 +440,19 @@ func TestQueryFilterFn(t *testing.T) {
"ip": "10.0.0.2",
"dc": "eqdc10",
},
}, Position{17, 1},
}, toml.Position{17, 1},
},
queryTestNode{
map[string]interface{}{
"ip": "10.0.0.1",
"dc": "eqdc10",
}, Position{20, 3},
}, toml.Position{20, 3},
},
queryTestNode{
map[string]interface{}{
"ip": "10.0.0.2",
"dc": "eqdc10",
}, Position{24, 3},
}, toml.Position{24, 3},
},
queryTestNode{
map[string]interface{}{
@@ -461,7 +460,7 @@ func TestQueryFilterFn(t *testing.T) {
[]interface{}{"gamma", "delta"},
[]interface{}{int64(1), int64(2)},
},
}, Position{28, 1},
}, toml.Position{28, 1},
},
})
@@ -469,7 +468,7 @@ func TestQueryFilterFn(t *testing.T) {
"$..[?(time)]",
[]interface{}{
queryTestNode{
tv, Position{9, 1},
tv, toml.Position{9, 1},
},
})
@@ -477,7 +476,7 @@ func TestQueryFilterFn(t *testing.T) {
"$..[?(bool)]",
[]interface{}{
queryTestNode{
true, Position{15, 1},
true, toml.Position{15, 1},
},
})
}

Просмотреть файл

@@ -1,7 +1,9 @@
package toml
package query
import (
"time"
"github.com/pelletier/go-toml"
)
// NodeFilterFn represents a user-defined filter function, for use with
@@ -15,50 +17,43 @@ import (
// to use from multiple goroutines.
type NodeFilterFn func(node interface{}) bool
// QueryResult is the result of Executing a Query.
type QueryResult struct {
// Result is the result of Executing a Query.
type Result struct {
items []interface{}
positions []Position
positions []toml.Position
}
// appends a value/position pair to the result set.
func (r *QueryResult) appendResult(node interface{}, pos Position) {
func (r *Result) appendResult(node interface{}, pos toml.Position) {
r.items = append(r.items, node)
r.positions = append(r.positions, pos)
}
// Values is a set of values within a QueryResult. The order of values is not
// Values is a set of values within a Result. The order of values is not
// guaranteed to be in document order, and may be different each time a query is
// executed.
func (r QueryResult) Values() []interface{} {
values := make([]interface{}, len(r.items))
for i, v := range r.items {
o, ok := v.(*tomlValue)
if ok {
values[i] = o.value
} else {
values[i] = v
}
}
return values
func (r Result) Values() []interface{} {
return r.items
}
// Positions is a set of positions for values within a QueryResult. Each index
// Positions is a set of positions for values within a Result. Each index
// in Positions() corresponds to the entry in Value() of the same index.
func (r QueryResult) Positions() []Position {
func (r Result) Positions() []toml.Position {
return r.positions
}
// runtime context for executing query paths
type queryContext struct {
result *QueryResult
result *Result
filters *map[string]NodeFilterFn
lastPosition Position
lastPosition toml.Position
}
// generic path functor interface
type pathFn interface {
setNext(next pathFn)
// it is the caller's responsibility to set the ctx.lastPosition before invoking call()
// node can be one of: *toml.Tree, []*toml.Tree, or a scalar
call(node interface{}, ctx *queryContext)
}
@@ -88,17 +83,17 @@ func (q *Query) appendPath(next pathFn) {
next.setNext(newTerminatingFn()) // init the next functor
}
// CompileQuery compiles a TOML path expression. The returned Query can be used
// to match elements within a TomlTree and its descendants.
func CompileQuery(path string) (*Query, error) {
// Compile compiles a TOML path expression. The returned Query can be used
// to match elements within a Tree and its descendants. See Execute.
func Compile(path string) (*Query, error) {
return parseQuery(lexQuery(path))
}
// Execute executes a query against a TomlTree, and returns the result of the query.
func (q *Query) Execute(tree *TomlTree) *QueryResult {
result := &QueryResult{
// Execute executes a query against a Tree, and returns the result of the query.
func (q *Query) Execute(tree *toml.Tree) *Result {
result := &Result{
items: []interface{}{},
positions: []Position{},
positions: []toml.Position{},
}
if q.root == nil {
result.appendResult(tree, tree.GetPosition(""))
@@ -107,11 +102,21 @@ func (q *Query) Execute(tree *TomlTree) *QueryResult {
result: result,
filters: q.filters,
}
ctx.lastPosition = tree.Position()
q.root.call(tree, ctx)
}
return result
}
// CompileAndExecute is a shorthand for Compile(path) followed by Execute(tree).
func CompileAndExecute(path string, tree *toml.Tree) (*Result, error) {
query, err := Compile(path)
if err != nil {
return nil, err
}
return query.Execute(tree), nil
}
// SetFilter sets a user-defined filter function. These may be used inside
// "?(..)" query expressions to filter TOML document elements within a query.
func (q *Query) SetFilter(name string, fn NodeFilterFn) {
@@ -127,7 +132,7 @@ func (q *Query) SetFilter(name string, fn NodeFilterFn) {
var defaultFilterFunctions = map[string]NodeFilterFn{
"tree": func(node interface{}) bool {
_, ok := node.(*TomlTree)
_, ok := node.(*toml.Tree)
return ok
},
"int": func(node interface{}) bool {

157
vendor/github.com/pelletier/go-toml/query/query_test.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,157 @@
package query
import (
"fmt"
"testing"
"github.com/pelletier/go-toml"
)
func assertArrayContainsInAnyOrder(t *testing.T, array []interface{}, objects ...interface{}) {
if len(array) != len(objects) {
t.Fatalf("array contains %d objects but %d are expected", len(array), len(objects))
}
for _, o := range objects {
found := false
for _, a := range array {
if a == o {
found = true
break
}
}
if !found {
t.Fatal(o, "not found in array", array)
}
}
}
func TestQueryExample(t *testing.T) {
config, _ := toml.Load(`
[[book]]
title = "The Stand"
author = "Stephen King"
[[book]]
title = "For Whom the Bell Tolls"
author = "Ernest Hemmingway"
[[book]]
title = "Neuromancer"
author = "William Gibson"
`)
authors, err := CompileAndExecute("$.book.author", config)
if err != nil {
t.Fatal("unexpected error:", err)
}
names := authors.Values()
if len(names) != 3 {
t.Fatalf("query should return 3 names but returned %d", len(names))
}
assertArrayContainsInAnyOrder(t, names, "Stephen King", "Ernest Hemmingway", "William Gibson")
}
func TestQueryReadmeExample(t *testing.T) {
config, _ := toml.Load(`
[postgres]
user = "pelletier"
password = "mypassword"
`)
query, err := Compile("$..[user,password]")
if err != nil {
t.Fatal("unexpected error:", err)
}
results := query.Execute(config)
values := results.Values()
if len(values) != 2 {
t.Fatalf("query should return 2 values but returned %d", len(values))
}
assertArrayContainsInAnyOrder(t, values, "pelletier", "mypassword")
}
func TestQueryPathNotPresent(t *testing.T) {
config, _ := toml.Load(`a = "hello"`)
query, err := Compile("$.foo.bar")
if err != nil {
t.Fatal("unexpected error:", err)
}
results := query.Execute(config)
if err != nil {
t.Fatalf("err should be nil. got %s instead", err)
}
if len(results.items) != 0 {
t.Fatalf("no items should be matched. %d matched instead", len(results.items))
}
}
func ExampleNodeFilterFn_filterExample() {
tree, _ := toml.Load(`
[struct_one]
foo = "foo"
bar = "bar"
[struct_two]
baz = "baz"
gorf = "gorf"
`)
// create a query that references a user-defined-filter
query, _ := Compile("$[?(bazOnly)]")
// define the filter, and assign it to the query
query.SetFilter("bazOnly", func(node interface{}) bool {
if tree, ok := node.(*toml.Tree); ok {
return tree.Has("baz")
}
return false // reject all other node types
})
// results contain only the 'struct_two' Tree
query.Execute(tree)
}
func ExampleQuery_queryExample() {
config, _ := toml.Load(`
[[book]]
title = "The Stand"
author = "Stephen King"
[[book]]
title = "For Whom the Bell Tolls"
author = "Ernest Hemmingway"
[[book]]
title = "Neuromancer"
author = "William Gibson"
`)
// find and print all the authors in the document
query, _ := Compile("$.book.author")
authors := query.Execute(config)
for _, name := range authors.Values() {
fmt.Println(name)
}
}
func TestTomlQuery(t *testing.T) {
tree, err := toml.Load("[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6")
if err != nil {
t.Error(err)
return
}
query, err := Compile("$.foo.bar")
if err != nil {
t.Error(err)
return
}
result := query.Execute(tree)
values := result.Values()
if len(values) != 1 {
t.Errorf("Expected resultset of 1, got %d instead: %v", len(values), values)
}
if tt, ok := values[0].(*toml.Tree); !ok {
t.Errorf("Expected type of Tree: %T", values[0])
} else if tt.Get("a") != int64(1) {
t.Errorf("Expected 'a' with a value 1: %v", tt.Get("a"))
} else if tt.Get("b") != int64(2) {
t.Errorf("Expected 'b' with a value 2: %v", tt.Get("b"))
}
}

107
vendor/github.com/pelletier/go-toml/query/tokens.go сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -0,0 +1,107 @@
package query
import (
"fmt"
"strconv"
"unicode"
"github.com/pelletier/go-toml"
)
// Define tokens
type tokenType int
const (
eof = -(iota + 1)
)
const (
tokenError tokenType = iota
tokenEOF
tokenKey
tokenString
tokenInteger
tokenFloat
tokenLeftBracket
tokenRightBracket
tokenLeftParen
tokenRightParen
tokenComma
tokenColon
tokenDollar
tokenStar
tokenQuestion
tokenDot
tokenDotDot
)
var tokenTypeNames = []string{
"Error",
"EOF",
"Key",
"String",
"Integer",
"Float",
"[",
"]",
"(",
")",
",",
":",
"$",
"*",
"?",
".",
"..",
}
type token struct {
toml.Position
typ tokenType
val string
}
func (tt tokenType) String() string {
idx := int(tt)
if idx < len(tokenTypeNames) {
return tokenTypeNames[idx]
}
return "Unknown"
}
func (t token) Int() int {
if result, err := strconv.Atoi(t.val); err != nil {
panic(err)
} else {
return result
}
}
func (t token) String() string {
switch t.typ {
case tokenEOF:
return "EOF"
case tokenError:
return t.val
}
return fmt.Sprintf("%q", t.val)
}
func isSpace(r rune) bool {
return r == ' ' || r == '\t'
}
func isAlphanumeric(r rune) bool {
return unicode.IsLetter(r) || r == '_'
}
func isDigit(r rune) bool {
return unicode.IsNumber(r)
}
func isHexDigit(r rune) bool {
return isDigit(r) ||
(r >= 'a' && r <= 'f') ||
(r >= 'A' && r <= 'F')
}

70
vendor/github.com/pelletier/go-toml/query_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,70 +0,0 @@
package toml
import (
"testing"
)
func assertArrayContainsInAnyOrder(t *testing.T, array []interface{}, objects ...interface{}) {
if len(array) != len(objects) {
t.Fatalf("array contains %d objects but %d are expected", len(array), len(objects))
}
for _, o := range objects {
found := false
for _, a := range array {
if a == o {
found = true
break
}
}
if !found {
t.Fatal(o, "not found in array", array)
}
}
}
func TestQueryExample(t *testing.T) {
config, _ := Load(`
[[book]]
title = "The Stand"
author = "Stephen King"
[[book]]
title = "For Whom the Bell Tolls"
author = "Ernest Hemmingway"
[[book]]
title = "Neuromancer"
author = "William Gibson"
`)
authors, _ := config.Query("$.book.author")
names := authors.Values()
if len(names) != 3 {
t.Fatalf("query should return 3 names but returned %d", len(names))
}
assertArrayContainsInAnyOrder(t, names, "Stephen King", "Ernest Hemmingway", "William Gibson")
}
func TestQueryReadmeExample(t *testing.T) {
config, _ := Load(`
[postgres]
user = "pelletier"
password = "mypassword"
`)
results, _ := config.Query("$..[user,password]")
values := results.Values()
if len(values) != 2 {
t.Fatalf("query should return 2 values but returned %d", len(values))
}
assertArrayContainsInAnyOrder(t, values, "pelletier", "mypassword")
}
func TestQueryPathNotPresent(t *testing.T) {
config, _ := Load(`a = "hello"`)
results, err := config.Query("$.foo.bar")
if err != nil {
t.Fatalf("err should be nil. got %s instead", err)
}
if len(results.items) != 0 {
t.Fatalf("no items should be matched. %d matched instead", len(results.items))
}
}

8
vendor/github.com/pelletier/go-toml/test.sh сгенерированный поставляемый
Просмотреть файл

@@ -19,6 +19,9 @@ function git_clone() {
popd
}
# Remove potential previous runs
rm -rf src test_program_bin toml-test
# Run go vet
go vet ./...
@@ -36,13 +39,16 @@ go build -o toml-test github.com/BurntSushi/toml-test
# vendorize the current lib for testing
# NOTE: this basically mocks an install without having to go back out to github for code
mkdir -p src/github.com/pelletier/go-toml/cmd
mkdir -p src/github.com/pelletier/go-toml/query
cp *.go *.toml src/github.com/pelletier/go-toml
cp -R cmd/* src/github.com/pelletier/go-toml/cmd
cp -R query/* src/github.com/pelletier/go-toml/query
go build -o test_program_bin src/github.com/pelletier/go-toml/cmd/test_program.go
# Run basic unit tests
go test github.com/pelletier/go-toml -v -covermode=count -coverprofile=coverage.out
go test github.com/pelletier/go-toml -covermode=count -coverprofile=coverage.out
go test github.com/pelletier/go-toml/cmd/tomljson
go test github.com/pelletier/go-toml/query
# run the entire BurntSushi test suite
if [[ $# -eq 0 ]] ; then

106
vendor/github.com/pelletier/go-toml/toml.go сгенерированный поставляемый
Просмотреть файл

@@ -14,30 +14,35 @@ type tomlValue struct {
position Position
}
// TomlTree is the result of the parsing of a TOML file.
type TomlTree struct {
values map[string]interface{} // string -> *tomlValue, *TomlTree, []*TomlTree
// Tree is the result of the parsing of a TOML file.
type Tree struct {
values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
position Position
}
func newTomlTree() *TomlTree {
return &TomlTree{
func newTree() *Tree {
return &Tree{
values: make(map[string]interface{}),
position: Position{},
}
}
// TreeFromMap initializes a new TomlTree object using the given map.
func TreeFromMap(m map[string]interface{}) (*TomlTree, error) {
// TreeFromMap initializes a new Tree object using the given map.
func TreeFromMap(m map[string]interface{}) (*Tree, error) {
result, err := toTree(m)
if err != nil {
return nil, err
}
return result.(*TomlTree), nil
return result.(*Tree), nil
}
// Position returns the position of the tree.
func (t *Tree) Position() Position {
return t.position
}
// Has returns a boolean indicating if the given key exists.
func (t *TomlTree) Has(key string) bool {
func (t *Tree) Has(key string) bool {
if key == "" {
return false
}
@@ -45,25 +50,27 @@ func (t *TomlTree) Has(key string) bool {
}
// HasPath returns true if the given path of keys exists, false otherwise.
func (t *TomlTree) HasPath(keys []string) bool {
func (t *Tree) HasPath(keys []string) bool {
return t.GetPath(keys) != nil
}
// Keys returns the keys of the toplevel tree.
// Warning: this is a costly operation.
func (t *TomlTree) Keys() []string {
var keys []string
func (t *Tree) Keys() []string {
keys := make([]string, len(t.values))
i := 0
for k := range t.values {
keys = append(keys, k)
keys[i] = k
i++
}
return keys
}
// Get the value at key in the TomlTree.
// Get the value at key in the Tree.
// Key is a dot-separated path (e.g. a.b.c).
// Returns nil if the path does not exist in the tree.
// If keys is of length zero, the current tree is returned.
func (t *TomlTree) Get(key string) interface{} {
func (t *Tree) Get(key string) interface{} {
if key == "" {
return t
}
@@ -76,7 +83,7 @@ func (t *TomlTree) Get(key string) interface{} {
// GetPath returns the element in the tree indicated by 'keys'.
// If keys is of length zero, the current tree is returned.
func (t *TomlTree) GetPath(keys []string) interface{} {
func (t *Tree) GetPath(keys []string) interface{} {
if len(keys) == 0 {
return t
}
@@ -87,9 +94,9 @@ func (t *TomlTree) GetPath(keys []string) interface{} {
return nil
}
switch node := value.(type) {
case *TomlTree:
case *Tree:
subtree = node
case []*TomlTree:
case []*Tree:
// go to most recent element
if len(node) == 0 {
return nil
@@ -109,7 +116,7 @@ func (t *TomlTree) GetPath(keys []string) interface{} {
}
// GetPosition returns the position of the given key.
func (t *TomlTree) GetPosition(key string) Position {
func (t *Tree) GetPosition(key string) Position {
if key == "" {
return t.position
}
@@ -118,7 +125,7 @@ func (t *TomlTree) GetPosition(key string) Position {
// GetPositionPath returns the element in the tree indicated by 'keys'.
// If keys is of length zero, the current tree is returned.
func (t *TomlTree) GetPositionPath(keys []string) Position {
func (t *Tree) GetPositionPath(keys []string) Position {
if len(keys) == 0 {
return t.position
}
@@ -129,9 +136,9 @@ func (t *TomlTree) GetPositionPath(keys []string) Position {
return Position{0, 0}
}
switch node := value.(type) {
case *TomlTree:
case *Tree:
subtree = node
case []*TomlTree:
case []*Tree:
// go to most recent element
if len(node) == 0 {
return Position{0, 0}
@@ -145,9 +152,9 @@ func (t *TomlTree) GetPositionPath(keys []string) Position {
switch node := subtree.values[keys[len(keys)-1]].(type) {
case *tomlValue:
return node.position
case *TomlTree:
case *Tree:
return node.position
case []*TomlTree:
case []*Tree:
// go to most recent element
if len(node) == 0 {
return Position{0, 0}
@@ -159,7 +166,7 @@ func (t *TomlTree) GetPositionPath(keys []string) Position {
}
// GetDefault works like Get but with a default value
func (t *TomlTree) GetDefault(key string, def interface{}) interface{} {
func (t *Tree) GetDefault(key string, def interface{}) interface{} {
val := t.Get(key)
if val == nil {
return def
@@ -169,30 +176,30 @@ func (t *TomlTree) GetDefault(key string, def interface{}) interface{} {
// Set an element in the tree.
// Key is a dot-separated path (e.g. a.b.c).
// Creates all necessary intermediates trees, if needed.
func (t *TomlTree) Set(key string, value interface{}) {
// Creates all necessary intermediate trees, if needed.
func (t *Tree) Set(key string, value interface{}) {
t.SetPath(strings.Split(key, "."), value)
}
// SetPath sets an element in the tree.
// Keys is an array of path elements (e.g. {"a","b","c"}).
// Creates all necessary intermediates trees, if needed.
func (t *TomlTree) SetPath(keys []string, value interface{}) {
// Creates all necessary intermediate trees, if needed.
func (t *Tree) SetPath(keys []string, value interface{}) {
subtree := t
for _, intermediateKey := range keys[:len(keys)-1] {
nextTree, exists := subtree.values[intermediateKey]
if !exists {
nextTree = newTomlTree()
nextTree = newTree()
subtree.values[intermediateKey] = nextTree // add new element here
}
switch node := nextTree.(type) {
case *TomlTree:
case *Tree:
subtree = node
case []*TomlTree:
case []*Tree:
// go to most recent element
if len(node) == 0 {
// create element if it does not exist
subtree.values[intermediateKey] = append(node, newTomlTree())
subtree.values[intermediateKey] = append(node, newTree())
}
subtree = node[len(node)-1]
}
@@ -201,9 +208,9 @@ func (t *TomlTree) SetPath(keys []string, value interface{}) {
var toInsert interface{}
switch value.(type) {
case *TomlTree:
case *Tree:
toInsert = value
case []*TomlTree:
case []*Tree:
toInsert = value
case *tomlValue:
toInsert = value
@@ -221,21 +228,21 @@ func (t *TomlTree) SetPath(keys []string, value interface{}) {
// and tree[a][b][c]
//
// Returns nil on success, error object on failure
func (t *TomlTree) createSubTree(keys []string, pos Position) error {
func (t *Tree) createSubTree(keys []string, pos Position) error {
subtree := t
for _, intermediateKey := range keys {
nextTree, exists := subtree.values[intermediateKey]
if !exists {
tree := newTomlTree()
tree := newTree()
tree.position = pos
subtree.values[intermediateKey] = tree
nextTree = tree
}
switch node := nextTree.(type) {
case []*TomlTree:
case []*Tree:
subtree = node[len(node)-1]
case *TomlTree:
case *Tree:
subtree = node
default:
return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
@@ -245,17 +252,8 @@ func (t *TomlTree) createSubTree(keys []string, pos Position) error {
return nil
}
// Query compiles and executes a query on a tree and returns the query result.
func (t *TomlTree) Query(query string) (*QueryResult, error) {
q, err := CompileQuery(query)
if err != nil {
return nil, err
}
return q.Execute(t), nil
}
// LoadReader creates a TomlTree from any io.Reader.
func LoadReader(reader io.Reader) (tree *TomlTree, err error) {
// LoadReader creates a Tree from any io.Reader.
func LoadReader(reader io.Reader) (tree *Tree, err error) {
defer func() {
if r := recover(); r != nil {
if _, ok := r.(runtime.Error); ok {
@@ -268,13 +266,13 @@ func LoadReader(reader io.Reader) (tree *TomlTree, err error) {
return
}
// Load creates a TomlTree from a string.
func Load(content string) (tree *TomlTree, err error) {
// Load creates a Tree from a string.
func Load(content string) (tree *Tree, err error) {
return LoadReader(strings.NewReader(content))
}
// LoadFile creates a TomlTree from a file.
func LoadFile(path string) (tree *TomlTree, err error) {
// LoadFile creates a Tree from a file.
func LoadFile(path string) (tree *Tree, err error) {
file, err := os.Open(path)
if err != nil {
return nil, err

29
vendor/github.com/pelletier/go-toml/toml_test.go сгенерированный поставляемый
Просмотреть файл

@@ -70,12 +70,12 @@ func TestTomlHasPath(t *testing.T) {
}
func TestTomlGetPath(t *testing.T) {
node := newTomlTree()
node := newTree()
//TODO: set other node data
for idx, item := range []struct {
Path []string
Expected *TomlTree
Expected *Tree
}{
{ // empty path test
[]string{},
@@ -94,31 +94,6 @@ func TestTomlGetPath(t *testing.T) {
}
}
func TestTomlQuery(t *testing.T) {
tree, err := Load("[foo.bar]\na=1\nb=2\n[baz.foo]\na=3\nb=4\n[gorf.foo]\na=5\nb=6")
if err != nil {
t.Error(err)
return
}
result, err := tree.Query("$.foo.bar")
if err != nil {
t.Error(err)
return
}
values := result.Values()
if len(values) != 1 {
t.Errorf("Expected resultset of 1, got %d instead: %v", len(values), values)
}
if tt, ok := values[0].(*TomlTree); !ok {
t.Errorf("Expected type of TomlTree: %T", values[0])
} else if tt.Get("a") != int64(1) {
t.Errorf("Expected 'a' with a value 1: %v", tt.Get("a"))
} else if tt.Get("b") != int64(2) {
t.Errorf("Expected 'b' with a value 2: %v", tt.Get("b"))
}
}
func TestTomlFromMap(t *testing.T) {
simpleMap := map[string]interface{}{"hello": 42}
tree, err := TreeFromMap(simpleMap)

10
vendor/github.com/pelletier/go-toml/tomltree_create.go сгенерированный поставляемый
Просмотреть файл

@@ -51,7 +51,7 @@ func simpleValueCoercion(object interface{}) (interface{}, error) {
case fmt.Stringer:
return original.String(), nil
default:
return nil, fmt.Errorf("cannot convert type %T to TomlTree", object)
return nil, fmt.Errorf("cannot convert type %T to Tree", object)
}
}
@@ -59,7 +59,7 @@ func sliceToTree(object interface{}) (interface{}, error) {
// arrays are a bit tricky, since they can represent either a
// collection of simple values, which is represented by one
// *tomlValue, or an array of tables, which is represented by an
// array of *TomlTree.
// array of *Tree.
// holding the assumption that this function is called from toTree only when value.Kind() is Array or Slice
value := reflect.ValueOf(object)
@@ -70,14 +70,14 @@ func sliceToTree(object interface{}) (interface{}, error) {
}
if insideType.Kind() == reflect.Map {
// this is considered as an array of tables
tablesArray := make([]*TomlTree, 0, length)
tablesArray := make([]*Tree, 0, length)
for i := 0; i < length; i++ {
table := value.Index(i)
tree, err := toTree(table.Interface())
if err != nil {
return nil, err
}
tablesArray = append(tablesArray, tree.(*TomlTree))
tablesArray = append(tablesArray, tree.(*Tree))
}
return tablesArray, nil
}
@@ -120,7 +120,7 @@ func toTree(object interface{}) (interface{}, error) {
}
values[key.String()] = newValue
}
return &TomlTree{values, Position{}}, nil
return &Tree{values, Position{}}, nil
}
if value.Kind() == reflect.Array || value.Kind() == reflect.Slice {

24
vendor/github.com/pelletier/go-toml/tomltree_create_test.go сгенерированный поставляемый
Просмотреть файл

@@ -1,9 +1,9 @@
package toml
import (
"strconv"
"testing"
"time"
"strconv"
)
type customString string
@@ -16,11 +16,11 @@ func (s stringer) String() string {
func validate(t *testing.T, path string, object interface{}) {
switch o := object.(type) {
case *TomlTree:
case *Tree:
for key, tree := range o.values {
validate(t, path+"."+key, tree)
}
case []*TomlTree:
case []*Tree:
for index, tree := range o {
validate(t, path+"."+strconv.Itoa(index), tree)
}
@@ -37,11 +37,11 @@ func validate(t *testing.T, path string, object interface{}) {
t.Logf("validation ok %s as %T", path, object)
}
func validateTree(t *testing.T, tree *TomlTree) {
func validateTree(t *testing.T, tree *Tree) {
validate(t, "", tree)
}
func TestTomlTreeCreateToTree(t *testing.T) {
func TestTreeCreateToTree(t *testing.T) {
data := map[string]interface{}{
"a_string": "bar",
"an_int": 42,
@@ -72,15 +72,15 @@ func TestTomlTreeCreateToTree(t *testing.T) {
validateTree(t, tree)
}
func TestTomlTreeCreateToTreeInvalidLeafType(t *testing.T) {
func TestTreeCreateToTreeInvalidLeafType(t *testing.T) {
_, err := TreeFromMap(map[string]interface{}{"foo": t})
expected := "cannot convert type *testing.T to TomlTree"
expected := "cannot convert type *testing.T to Tree"
if err.Error() != expected {
t.Fatalf("expected error %s, got %s", expected, err.Error())
}
}
func TestTomlTreeCreateToTreeInvalidMapKeyType(t *testing.T) {
func TestTreeCreateToTreeInvalidMapKeyType(t *testing.T) {
_, err := TreeFromMap(map[string]interface{}{"foo": map[int]interface{}{2: 1}})
expected := "map key needs to be a string, not int (int)"
if err.Error() != expected {
@@ -88,17 +88,17 @@ func TestTomlTreeCreateToTreeInvalidMapKeyType(t *testing.T) {
}
}
func TestTomlTreeCreateToTreeInvalidArrayMemberType(t *testing.T) {
func TestTreeCreateToTreeInvalidArrayMemberType(t *testing.T) {
_, err := TreeFromMap(map[string]interface{}{"foo": []*testing.T{t}})
expected := "cannot convert type *testing.T to TomlTree"
expected := "cannot convert type *testing.T to Tree"
if err.Error() != expected {
t.Fatalf("expected error %s, got %s", expected, err.Error())
}
}
func TestTomlTreeCreateToTreeInvalidTableGroupType(t *testing.T) {
func TestTreeCreateToTreeInvalidTableGroupType(t *testing.T) {
_, err := TreeFromMap(map[string]interface{}{"foo": []map[string]interface{}{map[string]interface{}{"hello": t}}})
expected := "cannot convert type *testing.T to TomlTree"
expected := "cannot convert type *testing.T to Tree"
if err.Error() != expected {
t.Fatalf("expected error %s, got %s", expected, err.Error())
}

40
vendor/github.com/pelletier/go-toml/tomltree_write.go сгенерированный поставляемый
Просмотреть файл

@@ -4,11 +4,11 @@ import (
"bytes"
"fmt"
"io"
"reflect"
"sort"
"strconv"
"strings"
"time"
"reflect"
)
// encodes a string to a TOML-compliant string value
@@ -83,14 +83,14 @@ func tomlValueStringRepresentation(v interface{}) (string, error) {
return "", fmt.Errorf("unsupported value type %T: %v", v, v)
}
func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) {
func (t *Tree) writeTo(w io.Writer, indent, keyspace string, bytesCount int64) (int64, error) {
simpleValuesKeys := make([]string, 0)
complexValuesKeys := make([]string, 0)
for k := range t.values {
v := t.values[k]
switch v.(type) {
case *TomlTree, []*TomlTree:
case *Tree, []*Tree:
complexValuesKeys = append(complexValuesKeys, k)
default:
simpleValuesKeys = append(simpleValuesKeys, k)
@@ -129,7 +129,7 @@ func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int6
switch node := v.(type) {
// node has to be of those two types given how keys are sorted above
case *TomlTree:
case *Tree:
tableName := fmt.Sprintf("\n%s[%s]\n", indent, combinedKey)
writtenBytesCount, err := w.Write([]byte(tableName))
bytesCount += int64(writtenBytesCount)
@@ -140,7 +140,7 @@ func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int6
if err != nil {
return bytesCount, err
}
case []*TomlTree:
case []*Tree:
for _, subTree := range node {
if len(subTree.values) > 0 {
tableArrayName := fmt.Sprintf("\n%s[[%s]]\n", indent, combinedKey)
@@ -162,16 +162,16 @@ func (t *TomlTree) writeTo(w io.Writer, indent, keyspace string, bytesCount int6
return bytesCount, nil
}
// WriteTo encode the TomlTree as Toml and writes it to the writer w.
// WriteTo encode the Tree as Toml and writes it to the writer w.
// Returns the number of bytes written in case of success, or an error if anything happened.
func (t *TomlTree) WriteTo(w io.Writer) (int64, error) {
func (t *Tree) WriteTo(w io.Writer) (int64, error) {
return t.writeTo(w, "", "", 0)
}
// ToTomlString generates a human-readable representation of the current tree.
// Output spans multiple lines, and is suitable for ingest by a TOML parser.
// If the conversion cannot be performed, ToString returns a non-nil error.
func (t *TomlTree) ToTomlString() (string, error) {
func (t *Tree) ToTomlString() (string, error) {
var buf bytes.Buffer
_, err := t.WriteTo(&buf)
if err != nil {
@@ -182,32 +182,34 @@ func (t *TomlTree) ToTomlString() (string, error) {
// String generates a human-readable representation of the current tree.
// Alias of ToString. Present to implement the fmt.Stringer interface.
func (t *TomlTree) String() string {
func (t *Tree) String() string {
result, _ := t.ToTomlString()
return result
}
// ToMap recursively generates a representation of the tree using Go built-in structures.
// The following types are used:
// * uint64
// * int64
// * bool
// * string
// * time.Time
// * map[string]interface{} (where interface{} is any of this list)
// * []interface{} (where interface{} is any of this list)
func (t *TomlTree) ToMap() map[string]interface{} {
//
// * bool
// * float64
// * int64
// * string
// * uint64
// * time.Time
// * map[string]interface{} (where interface{} is any of this list)
// * []interface{} (where interface{} is any of this list)
func (t *Tree) ToMap() map[string]interface{} {
result := map[string]interface{}{}
for k, v := range t.values {
switch node := v.(type) {
case []*TomlTree:
case []*Tree:
var array []interface{}
for _, item := range node {
array = append(array, item.ToMap())
}
result[k] = array
case *TomlTree:
case *Tree:
result[k] = node.ToMap()
case *tomlValue:
result[k] = node.value

32
vendor/github.com/pelletier/go-toml/tomltree_write_test.go сгенерированный поставляемый
Просмотреть файл

@@ -40,7 +40,7 @@ func assertErrorString(t *testing.T, expected string, err error) {
}
}
func TestTomlTreeWriteToTomlString(t *testing.T) {
func TestTreeWriteToTomlString(t *testing.T) {
toml, err := Load(`name = { first = "Tom", last = "Preston-Werner" }
points = { x = 1, y = 2 }`)
@@ -63,7 +63,7 @@ points = { x = 1, y = 2 }`)
})
}
func TestTomlTreeWriteToTomlStringSimple(t *testing.T) {
func TestTreeWriteToTomlStringSimple(t *testing.T) {
tree, err := Load("[foo]\n\n[[foo.bar]]\na = 42\n\n[[foo.bar]]\na = 69\n")
if err != nil {
t.Errorf("Test failed to parse: %v", err)
@@ -79,7 +79,7 @@ func TestTomlTreeWriteToTomlStringSimple(t *testing.T) {
}
}
func TestTomlTreeWriteToTomlStringKeysOrders(t *testing.T) {
func TestTreeWriteToTomlStringKeysOrders(t *testing.T) {
for i := 0; i < 100; i++ {
tree, _ := Load(`
foobar = true
@@ -119,7 +119,7 @@ func testMaps(t *testing.T, actual, expected map[string]interface{}) {
}
}
func TestTomlTreeWriteToMapSimple(t *testing.T) {
func TestTreeWriteToMapSimple(t *testing.T) {
tree, _ := Load("a = 42\nb = 17")
expected := map[string]interface{}{
@@ -130,32 +130,32 @@ func TestTomlTreeWriteToMapSimple(t *testing.T) {
testMaps(t, tree.ToMap(), expected)
}
func TestTomlTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
tree := TomlTree{values: map[string]interface{}{"foo": int8(1)}}
func TestTreeWriteToInvalidTreeSimpleValue(t *testing.T) {
tree := Tree{values: map[string]interface{}{"foo": int8(1)}}
_, err := tree.ToTomlString()
assertErrorString(t, "invalid value type at foo: int8", err)
}
func TestTomlTreeWriteToInvalidTreeTomlValue(t *testing.T) {
tree := TomlTree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}}
func TestTreeWriteToInvalidTreeTomlValue(t *testing.T) {
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{int8(1), Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
func TestTomlTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
tree := TomlTree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}}
func TestTreeWriteToInvalidTreeTomlValueArray(t *testing.T) {
tree := Tree{values: map[string]interface{}{"foo": &tomlValue{[]interface{}{int8(1)}, Position{}}}}
_, err := tree.ToTomlString()
assertErrorString(t, "unsupported value type int8: 1", err)
}
func TestTomlTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
func TestTreeWriteToFailingWriterInSimpleValue(t *testing.T) {
toml, _ := Load(`a = 2`)
writer := failingWriter{failAt: 0, written: 0}
_, err := toml.WriteTo(writer)
assertErrorString(t, "failingWriter failed after writting 0 bytes", err)
}
func TestTomlTreeWriteToFailingWriterInTable(t *testing.T) {
func TestTreeWriteToFailingWriterInTable(t *testing.T) {
toml, _ := Load(`
[b]
a = 2`)
@@ -168,7 +168,7 @@ a = 2`)
assertErrorString(t, "failingWriter failed after writting 13 bytes", err)
}
func TestTomlTreeWriteToFailingWriterInArray(t *testing.T) {
func TestTreeWriteToFailingWriterInArray(t *testing.T) {
toml, _ := Load(`
[[b]]
a = 2`)
@@ -181,7 +181,7 @@ a = 2`)
assertErrorString(t, "failingWriter failed after writting 15 bytes", err)
}
func TestTomlTreeWriteToMapExampleFile(t *testing.T) {
func TestTreeWriteToMapExampleFile(t *testing.T) {
tree, _ := LoadFile("example.toml")
expected := map[string]interface{}{
"title": "TOML Example",
@@ -217,7 +217,7 @@ func TestTomlTreeWriteToMapExampleFile(t *testing.T) {
testMaps(t, tree.ToMap(), expected)
}
func TestTomlTreeWriteToMapWithTablesInMultipleChunks(t *testing.T) {
func TestTreeWriteToMapWithTablesInMultipleChunks(t *testing.T) {
tree, _ := Load(`
[[menu.main]]
a = "menu 1"
@@ -238,7 +238,7 @@ func TestTomlTreeWriteToMapWithTablesInMultipleChunks(t *testing.T) {
testMaps(t, treeMap, expected)
}
func TestTomlTreeWriteToMapWithArrayOfInlineTables(t *testing.T) {
func TestTreeWriteToMapWithArrayOfInlineTables(t *testing.T) {
tree, _ := Load(`
[params]
language_tabs = [