github.com/lmorg/murex@v0.0.0-20240217211045-e081c89cd4ef/docs/apis/lang.IndexTemplateObject.md (about) 1 # `lang.IndexTemplateObject()` (template API) 2 3 > Returns element(s) from a data structure 4 5 ## Description 6 7 This is a template API you can use for your custom data types. 8 9 It should only be called from `ReadIndex()` and `ReadNotIndex()` functions. 10 11 This function ensures consistency with the index, `[`, builtin when used with 12 different Murex data types. Thus making indexing a data type agnostic 13 capability. 14 15 16 17 ## Examples 18 19 Example calling `lang.IndexTemplateObject()` function: 20 21 ```go 22 package json 23 24 import ( 25 "github.com/lmorg/murex/lang" 26 "github.com/lmorg/murex/utils/json" 27 ) 28 29 func index(p *lang.Process, params []string) error { 30 var jInterface interface{} 31 32 b, err := p.Stdin.ReadAll() 33 if err != nil { 34 return err 35 } 36 37 err = json.Unmarshal(b, &jInterface) 38 if err != nil { 39 return err 40 } 41 42 marshaller := func(iface interface{}) ([]byte, error) { 43 return json.Marshal(iface, p.Stdout.IsTTY()) 44 } 45 46 return lang.IndexTemplateObject(p, params, &jInterface, marshaller) 47 } 48 ``` 49 50 ## Detail 51 52 ### API Source: 53 54 ```go 55 package lang 56 57 import ( 58 "errors" 59 "fmt" 60 "strconv" 61 "strings" 62 63 "github.com/lmorg/murex/lang/types" 64 ) 65 66 // IndexTemplateObject is a handy standard indexer you can use in your custom data types for structured object types. 67 // The point of this is to minimize code rewriting and standardising the behavior of the indexer. 68 func IndexTemplateObject(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 69 if p.IsNot { 70 return itoNot(p, params, object, marshaller) 71 } 72 return itoIndex(p, params, object, marshaller) 73 } 74 75 // itoIndex allow 76 func itoIndex(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 77 var objArray []interface{} 78 switch v := (*object).(type) { 79 case []interface{}: 80 for _, key := range params { 81 i, err := strconv.Atoi(key) 82 if err != nil { 83 return err 84 } 85 if i < 0 { 86 //i = len(v) + i 87 i += len(v) 88 } 89 if i >= len(v) { 90 return errors.New("key '" + key + "' greater than number of items in array") 91 } 92 93 if len(params) > 1 { 94 objArray = append(objArray, v[i]) 95 96 } else { 97 switch v[i].(type) { 98 case nil: 99 p.Stdout.SetDataType(types.Null) 100 case bool: 101 p.Stdout.SetDataType(types.Boolean) 102 if v[i].(bool) { 103 p.Stdout.Write(types.TrueByte) 104 } else { 105 p.Stdout.Write(types.FalseByte) 106 } 107 case int: 108 p.Stdout.SetDataType(types.Integer) 109 s := strconv.Itoa(v[i].(int)) 110 p.Stdout.Write([]byte(s)) 111 case float64: 112 p.Stdout.SetDataType(types.Number) 113 s := types.FloatToString(v[i].(float64)) 114 p.Stdout.Write([]byte(s)) 115 case string: 116 p.Stdout.SetDataType(types.String) 117 p.Stdout.Write([]byte(v[i].(string))) 118 default: 119 b, err := marshaller(v[i]) 120 if err != nil { 121 return err 122 } 123 p.Stdout.Writeln(b) 124 } 125 } 126 } 127 if len(objArray) > 0 { 128 b, err := marshaller(objArray) 129 if err != nil { 130 return err 131 } 132 p.Stdout.Writeln(b) 133 } 134 return nil 135 136 case map[string]interface{}: 137 var ( 138 obj interface{} 139 err error 140 ) 141 142 for i := range params { 143 if len(params[i]) > 2 && params[i][0] == '[' && params[i][len(params[i])-1] == ']' { 144 obj, err = ElementLookup(v, params[i][1:len(params[i])-1]) 145 if err != nil { 146 return err 147 } 148 149 } else { 150 151 switch { 152 case v[params[i]] != nil: 153 obj = v[params[i]] 154 case v[strings.Title(params[i])] != nil: 155 obj = v[strings.Title(params[i])] 156 case v[strings.ToLower(params[i])] != nil: 157 obj = v[strings.ToLower(params[i])] 158 case v[strings.ToUpper(params[i])] != nil: 159 obj = v[strings.ToUpper(params[i])] 160 default: 161 return errors.New("key '" + params[i] + "' not found") 162 } 163 } 164 165 if len(params) > 1 { 166 objArray = append(objArray, obj) 167 168 } else { 169 switch obj := obj.(type) { 170 case nil: 171 p.Stdout.SetDataType(types.Null) 172 case bool: 173 p.Stdout.SetDataType(types.Boolean) 174 if obj { 175 p.Stdout.Write(types.TrueByte) 176 } else { 177 p.Stdout.Write(types.FalseByte) 178 } 179 case int: 180 p.Stdout.SetDataType(types.Integer) 181 s := strconv.Itoa(obj) 182 p.Stdout.Write([]byte(s)) 183 case float64: 184 p.Stdout.SetDataType(types.Number) 185 s := types.FloatToString(obj) 186 p.Stdout.Write([]byte(s)) 187 case string: 188 p.Stdout.SetDataType(types.String) 189 p.Stdout.Write([]byte(obj)) 190 default: 191 b, err := marshaller(obj) 192 if err != nil { 193 return err 194 } 195 p.Stdout.Writeln(b) 196 } 197 } 198 } 199 if len(objArray) > 0 { 200 b, err := marshaller(objArray) 201 if err != nil { 202 return err 203 } 204 p.Stdout.Writeln(b) 205 } 206 return nil 207 208 case map[interface{}]interface{}: 209 for i := range params { 210 //if v[key] == nil { 211 // return errors.New("key '" + key + "' not found.") 212 //} 213 switch { 214 case v[params[i]] != nil: 215 case v[strings.Title(params[i])] != nil: 216 params[i] = strings.Title(params[i]) 217 case v[strings.ToLower(params[i])] != nil: 218 params[i] = strings.ToLower(params[i]) 219 case v[strings.ToUpper(params[i])] != nil: 220 params[i] = strings.ToUpper(params[i]) 221 //case v[strings.ToTitle(params[i])] != nil: 222 // params[i] = strings.ToTitle(params[i]) 223 default: 224 return errors.New("key '" + params[i] + "' not found") 225 } 226 227 if len(params) > 1 { 228 objArray = append(objArray, v[params[i]]) 229 230 } else { 231 switch v[params[i]].(type) { 232 case nil: 233 p.Stdout.SetDataType(types.Null) 234 case bool: 235 p.Stdout.SetDataType(types.Boolean) 236 if v[params[i]].(bool) { 237 p.Stdout.Write(types.TrueByte) 238 } else { 239 p.Stdout.Write(types.FalseByte) 240 } 241 case int: 242 p.Stdout.SetDataType(types.Integer) 243 s := strconv.Itoa(v[params[i]].(int)) 244 p.Stdout.Write([]byte(s)) 245 case float64: 246 p.Stdout.SetDataType(types.Number) 247 s := types.FloatToString(v[params[i]].(float64)) 248 p.Stdout.Write([]byte(s)) 249 case string: 250 p.Stdout.SetDataType(types.String) 251 p.Stdout.Write([]byte(v[params[i]].(string))) 252 default: 253 b, err := marshaller(v[params[i]]) 254 if err != nil { 255 return err 256 } 257 p.Stdout.Writeln(b) 258 } 259 } 260 } 261 if len(objArray) > 0 { 262 b, err := marshaller(objArray) 263 if err != nil { 264 return err 265 } 266 p.Stdout.Writeln(b) 267 } 268 return nil 269 270 default: 271 return errors.New("object cannot be indexed") 272 } 273 } 274 275 // itoNot requires the indexes to be explicit 276 func itoNot(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error { 277 switch v := (*object).(type) { 278 case []interface{}: 279 var objArray []interface{} 280 not := make(map[int]bool) 281 for _, key := range params { 282 i, err := strconv.Atoi(key) 283 if err != nil { 284 return err 285 } 286 if i < 0 { 287 return errors.New("cannot have negative keys in array") 288 } 289 if i >= len(v) { 290 return errors.New("Key '" + key + "' greater than number of items in array") 291 } 292 293 not[i] = true 294 } 295 296 for i := range v { 297 if !not[i] { 298 objArray = append(objArray, v[i]) 299 } 300 } 301 302 //if len(objArray) > 0 { 303 b, err := marshaller(objArray) 304 if err != nil { 305 return err 306 } 307 _, err = p.Stdout.Writeln(b) 308 //} 309 return err 310 311 case map[string]interface{}: 312 objMap := make(map[string]interface{}) 313 not := make(map[string]bool) 314 for _, key := range params { 315 not[key] = true 316 not[strings.Title(key)] = true 317 not[strings.ToLower(key)] = true 318 not[strings.ToUpper(key)] = true 319 //not[strings.ToTitle(key)] = true 320 } 321 322 for s := range v { 323 if !not[s] { 324 objMap[s] = v[s] 325 } 326 } 327 328 //if len(objMap) > 0 { 329 b, err := marshaller(objMap) 330 if err != nil { 331 return err 332 } 333 p.Stdout.Writeln(b) 334 //} 335 return nil 336 337 case map[interface{}]interface{}: 338 objMap := make(map[interface{}]interface{}) 339 not := make(map[string]bool) 340 for _, key := range params { 341 not[key] = true 342 not[strings.Title(key)] = true 343 not[strings.ToLower(key)] = true 344 not[strings.ToUpper(key)] = true 345 //not[strings.ToTitle(key)] = true 346 } 347 348 for iface := range v { 349 s := fmt.Sprint(iface) 350 if !not[s] { 351 objMap[iface] = v[iface] 352 } 353 } 354 355 //if len(objMap) > 0 { 356 b, err := marshaller(objMap) 357 if err != nil { 358 return err 359 } 360 _, err = p.Stdout.Writeln(b) 361 //} 362 return err 363 364 default: 365 return errors.New("object cannot be !indexed") 366 } 367 } 368 ``` 369 370 ## Parameters 371 372 1. `*lang.Process`: Process's runtime state. Typically expressed as the variable `p` 373 2. `[]string`: slice of parameters used in `[` / `![` 374 3. `*interface{}`: a pointer to the data structure being indexed 375 4. `func(interface{}) ([]byte, error)`: data type marshaller function 376 377 ## See Also 378 379 * [apis/`ReadArray()` (type)](../apis/ReadArray.md): 380 Read from a data type one array element at a time 381 * [apis/`ReadArrayWithType()` (type)](../apis/ReadArrayWithType.md): 382 Read from a data type one array element at a time and return the elements contents and data type 383 * [apis/`ReadIndex()` (type)](../apis/ReadIndex.md): 384 Data type handler for the index, `[`, builtin 385 * [apis/`ReadMap()` (type)](../apis/ReadMap.md): 386 Treat data type as a key/value structure and read its contents 387 * [apis/`ReadNotIndex()` (type)](../apis/ReadNotIndex.md): 388 Data type handler for the bang-prefixed index, `: 390 Write a data type, one array element at a time 391 * [apis/`lang.IndexTemplateTable()` (template API)](../apis/lang.IndexTemplateTable.md): 392 Returns element(s) from a table 393 * [parser/index](../parser/item-index.md): 394 Outputs an element from an array, map or table 395 396 <hr/> 397 398 This document was generated from [lang/stdio/interface_doc.yaml](https://github.com/lmorg/murex/blob/master/lang/stdio/interface_doc.yaml).