gopkg.in/alecthomas/gometalinter.v3@v3.0.0/_linters/src/github.com/stretchr/objx/accessors.go (about) 1 package objx 2 3 import ( 4 "regexp" 5 "strconv" 6 "strings" 7 ) 8 9 const ( 10 // PathSeparator is the character used to separate the elements 11 // of the keypath. 12 // 13 // For example, `location.address.city` 14 PathSeparator string = "." 15 16 // arrayAccesRegexString is the regex used to extract the array number 17 // from the access path 18 arrayAccesRegexString = `^(.+)\[([0-9]+)\]$` 19 ) 20 21 // arrayAccesRegex is the compiled arrayAccesRegexString 22 var arrayAccesRegex = regexp.MustCompile(arrayAccesRegexString) 23 24 // Get gets the value using the specified selector and 25 // returns it inside a new Obj object. 26 // 27 // If it cannot find the value, Get will return a nil 28 // value inside an instance of Obj. 29 // 30 // Get can only operate directly on map[string]interface{} and []interface. 31 // 32 // Example 33 // 34 // To access the title of the third chapter of the second book, do: 35 // 36 // o.Get("books[1].chapters[2].title") 37 func (m Map) Get(selector string) *Value { 38 rawObj := access(m, selector, nil, false) 39 return &Value{data: rawObj} 40 } 41 42 // Set sets the value using the specified selector and 43 // returns the object on which Set was called. 44 // 45 // Set can only operate directly on map[string]interface{} and []interface 46 // 47 // Example 48 // 49 // To set the title of the third chapter of the second book, do: 50 // 51 // o.Set("books[1].chapters[2].title","Time to Go") 52 func (m Map) Set(selector string, value interface{}) Map { 53 access(m, selector, value, true) 54 return m 55 } 56 57 // getIndex returns the index, which is hold in s by two braches. 58 // It also returns s withour the index part, e.g. name[1] will return (1, name). 59 // If no index is found, -1 is returned 60 func getIndex(s string) (int, string) { 61 arrayMatches := arrayAccesRegex.FindStringSubmatch(s) 62 if len(arrayMatches) > 0 { 63 // Get the key into the map 64 selector := arrayMatches[1] 65 // Get the index into the array at the key 66 // We know this cannt fail because arrayMatches[2] is an int for sure 67 index, _ := strconv.Atoi(arrayMatches[2]) 68 return index, selector 69 } 70 return -1, s 71 } 72 73 // access accesses the object using the selector and performs the 74 // appropriate action. 75 func access(current interface{}, selector string, value interface{}, isSet bool) interface{} { 76 selSegs := strings.SplitN(selector, PathSeparator, 2) 77 thisSel := selSegs[0] 78 index := -1 79 80 if strings.Contains(thisSel, "[") { 81 index, thisSel = getIndex(thisSel) 82 } 83 84 if curMap, ok := current.(Map); ok { 85 current = map[string]interface{}(curMap) 86 } 87 // get the object in question 88 switch current.(type) { 89 case map[string]interface{}: 90 curMSI := current.(map[string]interface{}) 91 if len(selSegs) <= 1 && isSet { 92 curMSI[thisSel] = value 93 return nil 94 } 95 96 _, ok := curMSI[thisSel].(map[string]interface{}) 97 if (curMSI[thisSel] == nil || !ok) && index == -1 && isSet { 98 curMSI[thisSel] = map[string]interface{}{} 99 } 100 101 current = curMSI[thisSel] 102 default: 103 current = nil 104 } 105 // do we need to access the item of an array? 106 if index > -1 { 107 if array, ok := current.([]interface{}); ok { 108 if index < len(array) { 109 current = array[index] 110 } else { 111 current = nil 112 } 113 } 114 } 115 if len(selSegs) > 1 { 116 current = access(current, selSegs[1], value, isSet) 117 } 118 return current 119 }