murex Shell Docs

API Reference: lang.IndexTemplateObject() (template API)

Returns element(s) from a data structure

Description

This is a template API you can use for your custom data types.

It should only be called from ReadIndex() and ReadNotIndex() functions.

This function ensures consistency with the index, [, builtin when used with different murex data types. Thus making indexing a data type agnostic capability.

Examples

Example calling lang.IndexTemplateObject() function:

package json

import (
    "github.com/lmorg/murex/lang"
    "github.com/lmorg/murex/utils/json"
)

func index(p *lang.Process, params []string) error {
    var jInterface interface{}

    b, err := p.Stdin.ReadAll()
    if err != nil {
        return err
    }

    err = json.Unmarshal(b, &jInterface)
    if err != nil {
        return err
    }

    marshaller := func(iface interface{}) ([]byte, error) {
        return json.Marshal(iface, p.Stdout.IsTTY())
    }

    return lang.IndexTemplateObject(p, params, &jInterface, marshaller)
}

Detail

API Source:

package lang

import (
    "errors"
    "fmt"
    "strconv"
    "strings"
)

// IndexTemplateObject is a handy standard indexer you can use in your custom data types for structured object types.
// The point of this is to minimize code rewriting and standardising the behavior of the indexer.
func IndexTemplateObject(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
    if p.IsNot {
        return itoNot(p, params, object, marshaller)
    }
    return itoIndex(p, params, object, marshaller)
}

// itoIndex allow
func itoIndex(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
    var objArray []interface{}
    switch v := (*object).(type) {
    case []interface{}:
        for _, key := range params {
            i, err := strconv.Atoi(key)
            if err != nil {
                return err
            }
            if i < 0 {
                //return errors.New("Cannot have negative keys in array")
                i = len(v) + i
            }
            if i >= len(v) {
                return errors.New("Key '" + key + "' greater than number of items in array")
            }

            if len(params) > 1 {
                objArray = append(objArray, v[i])

            } else {
                switch v[i].(type) {
                case string:
                    p.Stdout.Write([]byte(v[i].(string)))
                default:
                    b, err := marshaller(v[i])
                    if err != nil {
                        return err
                    }
                    p.Stdout.Writeln(b)
                }
            }
        }
        if len(objArray) > 0 {
            b, err := marshaller(objArray)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    case map[string]interface{}:
        for i := range params {
            switch {
            case v[params[i]] != nil:
            case v[strings.Title(params[i])] != nil:
                params[i] = strings.Title(params[i])
            case v[strings.ToLower(params[i])] != nil:
                params[i] = strings.ToLower(params[i])
            case v[strings.ToUpper(params[i])] != nil:
                params[i] = strings.ToUpper(params[i])
            //case v[strings.ToTitle(params[i])] != nil:
            //  params[i] = strings.ToTitle(params[i])
            default:
                return errors.New("Key '" + params[i] + "' not found")
            }

            if len(params) > 1 {
                objArray = append(objArray, v[params[i]])

            } else {
                switch v[params[i]].(type) {
                case string:
                    p.Stdout.Write([]byte(v[params[i]].(string)))
                default:
                    b, err := marshaller(v[params[i]])
                    if err != nil {
                        return err
                    }
                    p.Stdout.Writeln(b)
                }
            }
        }
        if len(objArray) > 0 {
            b, err := marshaller(objArray)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    case map[interface{}]interface{}:
        for i := range params {
            //if v[key] == nil {
            //  return errors.New("Key '" + key + "' not found.")
            //}
            switch {
            case v[params[i]] != nil:
            case v[strings.Title(params[i])] != nil:
                params[i] = strings.Title(params[i])
            case v[strings.ToLower(params[i])] != nil:
                params[i] = strings.ToLower(params[i])
            case v[strings.ToUpper(params[i])] != nil:
                params[i] = strings.ToUpper(params[i])
            //case v[strings.ToTitle(params[i])] != nil:
            //  params[i] = strings.ToTitle(params[i])
            default:
                return errors.New("Key '" + params[i] + "' not found")
            }

            if len(params) > 1 {
                objArray = append(objArray, v[params[i]])

            } else {
                switch v[params[i]].(type) {
                case string:
                    p.Stdout.Write([]byte(v[params[i]].(string)))
                default:
                    b, err := marshaller(v[params[i]])
                    if err != nil {
                        return err
                    }
                    p.Stdout.Writeln(b)
                }
            }
        }
        if len(objArray) > 0 {
            b, err := marshaller(objArray)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    default:
        return errors.New("Object cannot be indexed")
    }
}

// itoNot requires the indexes to be explicit
func itoNot(p *Process, params []string, object *interface{}, marshaller func(interface{}) ([]byte, error)) error {
    switch v := (*object).(type) {
    case []interface{}:
        var objArray []interface{}
        not := make(map[int]bool)
        for _, key := range params {
            i, err := strconv.Atoi(key)
            if err != nil {
                return err
            }
            if i < 0 {
                return errors.New("Cannot have negative keys in array")
            }
            if i >= len(v) {
                return errors.New("Key '" + key + "' greater than number of items in array")
            }

            not[i] = true
        }

        for i := range v {
            if !not[i] {
                objArray = append(objArray, v[i])
            }
        }

        if len(objArray) > 0 {
            b, err := marshaller(objArray)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    case map[string]interface{}:
        objMap := make(map[string]interface{})
        not := make(map[string]bool)
        for _, key := range params {
            not[key] = true
            not[strings.Title(key)] = true
            not[strings.ToLower(key)] = true
            not[strings.ToUpper(key)] = true
            //not[strings.ToTitle(key)] = true
        }

        for s := range v {
            if !not[s] {
                objMap[s] = v[s]
            }
        }

        if len(objMap) > 0 {
            b, err := marshaller(objMap)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    case map[interface{}]interface{}:
        objMap := make(map[interface{}]interface{})
        not := make(map[string]bool)
        for _, key := range params {
            not[key] = true
            not[strings.Title(key)] = true
            not[strings.ToLower(key)] = true
            not[strings.ToUpper(key)] = true
            //not[strings.ToTitle(key)] = true
        }

        for iface := range v {
            s := fmt.Sprint(iface)
            if !not[s] {
                objMap[iface] = v[iface]
            }
        }

        if len(objMap) > 0 {
            b, err := marshaller(objMap)
            if err != nil {
                return err
            }
            p.Stdout.Writeln(b)
        }
        return nil

    default:
        return errors.New("Object cannot be !indexed")
    }
}

Parameters

  1. *lang.Process: Process's runtime state. Typically expressed as the variable p
  2. []string: slice of parameters used in [ / ![
  3. *interface{}: a pointer to the data structure being indexed
  4. func(interface{}) ([]byte, error): data type marshaller function

See Also

This site's content is rebuilt automatically from murex's source code after each merge to the master branch. Downloadable murex binaries are also built with the website.

Last built on Tue Jun 22 08:18:17 UTC 2021 against commit 2235c7b2235c7b18f86f1cf214e246b88b0ea193d87fe80.

Current version is 2.2.1100 BETA which has been verified against tests.