lang.IndexTemplateObject()
(template API)Returns element(s) from a data structure
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.
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{}
, err := p.Stdin.ReadAll()
bif err != nil {
return err
}
= json.Unmarshal(b, &jInterface)
err if err != nil {
return err
}
:= func(iface interface{}) ([]byte, error) {
marshaller return json.Marshal(iface, p.Stdout.IsTTY())
}
return lang.IndexTemplateObject(p, params, &jInterface, marshaller)
}
package lang
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/lmorg/murex/lang/types"
)
type indexValueT interface {
~string | ~bool | ~int | ~float64 | any
}
// 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 *any, marshaller func(any) ([]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 *any, marshaller func(any) ([]byte, error)) error {
switch v := (*object).(type) {
case []any:
return itoIndexArray(p, params, v, marshaller)
case map[string]any:
return itoIndexMap(p, params, v, marshaller)
case map[any]any:
return itoIndexMap(p, params, v, marshaller)
default:
return errors.New("object cannot be indexed")
}
}
func itoIndexArray[V indexValueT](p *Process, params []string, v []V, marshaller func(any) ([]byte, error)) error {
var objArray []V
for _, key := range params {
, err := strconv.Atoi(key)
iif err != nil {
return err
}
if i < 0 {
+= len(v)
i }
if i >= len(v) {
return fmt.Errorf("key '%s' greater than number of items in array", key)
}
if len(params) > 1 {
= append(objArray, v[i])
objArray continue
}
switch value := any(v[i]).(type) {
case nil:
.Stdout.SetDataType(types.Null)
pcase bool:
.Stdout.SetDataType(types.Boolean)
pif value {
.Stdout.Write(types.TrueByte)
p} else {
.Stdout.Write(types.FalseByte)
p}
case int:
.Stdout.SetDataType(types.Integer)
p:= strconv.Itoa(value)
s .Stdout.Write([]byte(s))
pcase float64:
.Stdout.SetDataType(types.Number)
p:= types.FloatToString(value)
s .Stdout.Write([]byte(s))
pcase string:
.Stdout.SetDataType(types.String)
p.Stdout.Write([]byte(value))
pdefault:
, err := marshaller(value)
bif err != nil {
return err
}
.Stdout.Writeln(b)
p}
}
if len(objArray) > 0 {
, err := marshaller(objArray)
bif err != nil {
return err
}
.Stdout.Writeln(b)
p}
return nil
}
func itoIndexMap[K comparable, V indexValueT](p *Process, params []string, v map[K]V, marshaller func(any) ([]byte, error)) error {
var (
[]any
objArray any
obj error
err )
for i := range params {
if len(params[i]) > 2 && params[i][0] == '[' && params[i][len(params[i])-1] == ']' {
, err = ElementLookup(v, params[i][1:len(params[i])-1])
objif err != nil {
return err
}
} else {
var (
int
iString any
key bool
ok )
for {
switch iString {
case 0:
= params[i]
key case 1:
= strings.Title(params[i])
key case 2:
= strings.ToLower(params[i])
key case 3:
= strings.ToUpper(params[i])
key default:
return fmt.Errorf("key '%s' not found", params[i])
}
, ok = v[key.(K)]
objif ok {
break
}
++
iString}
}
if len(params) > 1 {
= append(objArray, obj)
objArray
} else {
switch obj := obj.(type) {
case nil:
.Stdout.SetDataType(types.Null)
pcase bool:
.Stdout.SetDataType(types.Boolean)
pif obj {
.Stdout.Write(types.TrueByte)
p} else {
.Stdout.Write(types.FalseByte)
p}
case int:
.Stdout.SetDataType(types.Integer)
p:= strconv.Itoa(obj)
s .Stdout.Write([]byte(s))
pcase float64:
.Stdout.SetDataType(types.Number)
p:= types.FloatToString(obj)
s .Stdout.Write([]byte(s))
pcase string:
.Stdout.SetDataType(types.String)
p.Stdout.Write([]byte(obj))
pdefault:
, err := marshaller(obj)
bif err != nil {
return err
}
.Stdout.Writeln(b)
p}
}
}
if len(objArray) > 0 {
, err := marshaller(objArray)
bif err != nil {
return err
}
.Stdout.Writeln(b)
p}
return nil
}
// itoNot requires the indexes to be explicit
func itoNot(p *Process, params []string, object *any, marshaller func(any) ([]byte, error)) error {
switch v := (*object).(type) {
case []any:
return itoNotArray(p, params, v, marshaller)
case map[string]any:
return itoNotMap(p, params, v, marshaller)
case map[any]any:
return itoNotMap(p, params, v, marshaller)
default:
return errors.New("object cannot be !indexed")
}
}
func itoNotArray[V indexValueT](p *Process, params []string, v []V, marshaller func(any) ([]byte, error)) error {
var objArray []any
:= make(map[int]bool)
not for _, key := range params {
, err := strconv.Atoi(key)
iif err != nil {
return err
}
if i < 0 {
return errors.New("cannot have negative keys in array")
}
if i >= len(v) {
return fmt.Errorf("key '%s' greater than number of items in array", key)
}
[i] = true
not}
for i := range v {
if !not[i] {
= append(objArray, v[i])
objArray }
}
, err := marshaller(objArray)
bif err != nil {
return err
}
, err = p.Stdout.Writeln(b)
_
return err
}
func itoNotMap[K comparable, V indexValueT](p *Process, params []string, v map[K]V, marshaller func(any) ([]byte, error)) error {
:= make(map[K]any)
objMap := make(map[K]bool)
not var key any
for _, key = range params {
[key.(K)] = true
not
= strings.Title(key.(string))
key [key.(K)] = true
not
= strings.ToLower(key.(string))
key [key.(K)] = true
not
= strings.ToUpper(key.(string))
key [key.(K)] = true
not}
for s := range v {
if !not[s] {
[s] = v[s]
objMap}
}
, err := marshaller(objMap)
bif err != nil {
return err
}
.Stdout.Writeln(b)
p
return nil
}
*lang.Process
: Process’s runtime state. Typically
expressed as the variable p
[]string
: slice of parameters used in [
/
![
*interface{}
: a pointer to the data structure being
indexedfunc(interface{}) ([]byte, error)
: data type marshaller
functionReadArray()
(type): Read from a data type one array element at a timeReadArrayWithType()
(type): Read from a data type one array element at a time and return
the elements contents and data typeReadIndex()
(type): Data type handler for the index, [
,
builtinReadMap()
(type):
Treat data type as a key/value structure and read its contentsReadNotIndex()
(type): Data type handler for the bang-prefixed index,
![
, builtinWriteArray()
(type): Write a data type, one array element at a timelang.IndexTemplateTable()
(template API): Returns element(s) from a tableThis document was generated from lang/stdio/interface_doc.yaml.
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 Wed Jan 15 23:07:50 UTC 2025 against commit b4c4296b4c429617fd41527ea0efef33c52c15ef2b64972.
Current version is 6.4.2063 (develop) which has been verified against tests cases.