metaflector

package module
v0.0.0-...-d098812 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 17, 2018 License: MIT Imports: 3 Imported by: 2

README

metaflector

Documentation Build Status Report Card

About

Go (golang) package which provides reflection abstractions beyond the Go standard library.

Metaflector makes it easy to inspect objects and structs, and programmatically access structural data.

To be precise, this package currently provides:

  • Generating a dot-separated list of struct hierarchical properties
metaflector.TerminalFields(&http.Server{})
// Output: []string{"Addr", "IdleTimeout", "MaxHeaderBytes", "ReadHeaderTimeout", "ReadTimeout", "WriteTimeout"}
  • Iterating over a struct or slice or array objects' fields
metaflector.EachField(http.Server{}, func(obj interface{}, name string, kind reflect.Kind) {
    fmt.Printf("obj=%v name=%v kind=%v\n", obj, name, kind)
})

// Output:
// obj= name=Addr kind=string
// obj=<nil> name=TLSConfig kind=struct
// obj=0 name=ReadTimeout kind=int64
// obj=0 name=ReadHeaderTimeout kind=int64
// obj=0 name=WriteTimeout kind=int64
// obj=0 name=IdleTimeout kind=int64
// obj=0 name=MaxHeaderBytes kind=int
// obj=map[] name=TLSNextProto kind=map
// obj=<nil> name=ErrorLog kind=struct
  • Dynamic property extraction based on dot-paths

e.g.

Get(myVar, "A.Nested.Property")

I've found this functionality useful for automatically applying user input as search filters against arbitrary structs in command-line progreams.

See the docs for more info.

Created by Jay Taylor and used by Gigawatt.

A word about current limitations
  • For heterogeneous collections (i.e. this is possible via []interface{}), only the structure of the first non-nil slice or array element will be considered.

  • No maps support [yet].

Requirements
  • Go version 1.6 or newer
Running the test suite
go test ./...
Example Usage

examples/basic.go

package main

import (
    "fmt"
    "reflect"

    "github.com/gigawattio/metaflector"
)

type (
    Foo struct {
        Bar  Bar
        Name string
    }

    Bar struct {
        ID      string
        private string
    }
)

var foo = &Foo{
    Bar: Bar{
        ID:      "2017",
        private: "this isn't exported",
    },
    Name: "meta",
}

func main() {
    fmt.Printf("foo TerminalFields: %# v\n", metaflector.TerminalFields(foo))
    fmt.Printf("Bar.ID resolved to: %v\n", metaflector.Get(foo, "Bar.ID"))

    metaflector.EachField(foo, func(obj interface{}, name string, kind reflect.Kind) {
        fmt.Printf("obj=%v == Get(obj, %q) ? %v\n", obj, name, reflect.DeepEqual(obj, metaflector.Get(foo, name)))
    })

    fmt.Printf("Get()=%v\n", metaflector.Get(foo, "Name"))
}

// Output:
// foo TerminalFields: []string{"Bar.ID", "Name"}
// Bar.ID resolved to: 2017
// obj={2017 this isn't exported} == Get(obj, "Bar") ? true
// obj=meta == Get(obj, "Name") ? true
// Get()=meta

See the tests for more examples.

The reflections package is related and complementary.

License

Permissive MIT license, see the LICENSE file for more information.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var Separator = "."

Separator is the string to use as the delimiter between field names.

Functions

func EachField

func EachField(obj interface{}, fn IterFunc) (ok bool)

EachField invokes a callback with the value, name, and kind for each field in a struct. The function returns false if the passed object cannot be resolved to a struct or non-empty slice / array (i.e. if must be a non-terminal type).

func Get

func Get(obj interface{}, dotPath string) interface{}

Get the specified dot-path value by digging down and extracting from each component of the dot-path.

func ResolveUnderlying

func ResolveUnderlying(obj interface{}) (resolved interface{}, ok bool)

ResolveUnderlying takes an interface{} (object) and resolves it to an instance of the underlying type through 3 varieties of resolution mutation:

1. Pointers are resolved to whatever they're referencing.

2. Slices and arrays, when not empty, are resolved to the type of the first element.

3. Test if the end result is a struct.

func TerminalFields

func TerminalFields(obj interface{}) []string

TerminalFields returns a slice of strings representing the full path in dot notation for each "terminal" field, where a terminal field is defined as a primitive type (and without additional sub-fields, e.g. an int).

This implementation uses a BFS queue-based traversal to minimize stack depth.

Important note: Circular references aren't supported yet and will blow up.

Types

type IterFunc

type IterFunc func(child interface{}, name string, kind reflect.Kind)

IterFunc is the type signature of callbacks sent to `EachField`.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL