concisetree

package
v0.0.0-...-d31700d Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2022 License: MIT Imports: 6 Imported by: 0

README

English | 简体中文

concise_tree

A concise way to define a concise tree. Only used for static tree, that means tree structure is frozed at compile time.

Feature

  • A tree is constructed from a struct type, all need to do is define a struct. No struct value assignment is required, so you don't need to write every field name twice.
  • All tree nodes are defined and referenced by struct fields. So node reference is ensured right at compile time.
  • No intermediate "Children" fields. So tree definition and node reference are more concise.
  • concisetree.Setup() set up path and tags of all tree nodes automatically. Path is generated by concating field names of ancestor nodes and self node by "." ; Tags is parsed from struct field's tag;
  • Convert a concise tree to a normal tree with Children slice.

Example

import (
	"fmt"

	tree "gitee.com/go-better/dev/concisetree"
)

type Modules struct {
	*tree.Node

	Bill *struct {
		*tree.Node
		List   *tree.Node `name:"列表" desc:"单据列表"`
		Detail *tree.Node `name:"详情" desc:"单据详情"`
	} `name:"单据" desc:"各种单据"`

	Goods *struct {
		*tree.Node
		Create *tree.Node `name:"创建" desc:"商品创建"`
		Update *tree.Node `name:"更新" desc:"商品更新"`
		Delete *tree.Node `name:"删除" desc:"商品删除"`
	} `name:"商品" desc:"商品(含库存)"`
}

func ExampleSetup() {
	modules := &Modules{}
	tree.Setup(modules, "权限树", "", "根节点")

	var n tree.ConciseTree
	n = modules
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Bill
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Bill.List
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Bill.Detail
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Goods
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Goods.Create
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Goods.Update
	fmt.Println(n.Name(), n.Code(), n.Desc())

	n = modules.Goods.Delete
	fmt.Println(n.Name(), n.Code(), n.Desc())

	// Output:
	// 权限树  根节点
	// 单据 bill 各种单据
	// 列表 bill.list 单据列表
	// 详情 bill.detail 单据详情
	// 商品 goods 商品(含库存)
	// 创建 goods.create 商品创建
	// 更新 goods.update 商品更新
	// 删除 goods.delete 商品删除
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Belongs

func Belongs(path string, pathsMap map[string]struct{}) bool

Belongs return true if path or any ancestor of path is included in pathsMap.

Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

func main() {
	var m = map[string]struct{}{
		"A":     struct{}{},
		"B.1":   struct{}{},
		"C.1.1": struct{}{},
	}
	fmt.Println(tree.Belongs("A", m), tree.Belongs("A.1", m), tree.Belongs("A.1.1", m), tree.Belongs("A1", m))
	fmt.Println(tree.Belongs("B", m), tree.Belongs("B.1", m), tree.Belongs("B.1.1", m), tree.Belongs("B.2", m))
	fmt.Println(tree.Belongs("C", m), tree.Belongs("C.1", m), tree.Belongs("C.1.1", m), tree.Belongs("C.1.2", m))
	fmt.Println(tree.Belongs("D", m), tree.Belongs("D.1", m), tree.Belongs("D.1.1", m), tree.Belongs("D.1.2", m))

}
Output:

true true true false
false true true false
false false true false
false false false false

func Contains

func Contains(path, subpath string) bool

Contains return true if path equal subpath or path is ancestor of subpath.

func RemoveDuplicatePaths

func RemoveDuplicatePaths(paths []string) []string

remove duplicate paths that belongs to another one in paths.

Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

func main() {
	fmt.Println(tree.RemoveDuplicatePaths([]string{
		"B.1", "A", "A.1", "B.2", "A.2", "B.1.2", "C",
	}))
	fmt.Println(tree.RemoveDuplicatePaths([]string{
		"B.1", "A", "B.2", "C",
	}))
}
Output:

[A B.1 B.2 C]
[A B.1 B.2 C]

func Setup

func Setup(tree ConciseTree, path string, tags map[string]string)

设置树的所有节点的path、tags

Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

type cud struct {
	Create *tree.Node `name:"创建" desc:"商品创建"`
	Update *tree.Node `name:"更新" desc:"商品更新"`
	Delete *tree.Node `name:"删除" desc:"商品删除"`
}

type Modules struct {
	*tree.Node

	Bill *struct {
		*tree.Node
		List   *tree.Node `name:"列表" desc:"单据列表"`
		Detail *tree.Node `name:"详情" desc:"单据详情"`
	} `name:"单据" desc:"各种单据"`

	Goods *struct {
		tree.Node
		cud
	} `name:"商品" desc:"商品(含库存)"`
}

func main() {
	modules := &Modules{}
	tree.Setup(modules, "", map[string]string{"name": "根节点"})

	var n tree.ConciseTree
	n = modules
	fmt.Println(n.Path(), n.Tags())

	n = modules.Bill
	fmt.Println(n.Path(), n.Tags())

	n = modules.Bill.List
	fmt.Println(n.Path(), n.Tags())

	n = modules.Bill.Detail
	fmt.Println(n.Path(), n.Tags())

	n = modules.Goods
	fmt.Println(n.Path(), n.Tags())

	n = modules.Goods.Create
	fmt.Println(n.Path(), n.Tags())

	n = modules.Goods.Update
	fmt.Println(n.Path(), n.Tags())

	n = modules.Goods.Delete
	fmt.Println(n.Path(), n.Tags())

}
Output:

map[name:根节点]
bill map[desc:各种单据 name:单据]
bill.list map[desc:单据列表 name:列表]
bill.detail map[desc:单据详情 name:详情]
goods map[desc:商品(含库存) name:商品]
goods.create map[desc:商品创建 name:创建]
goods.update map[desc:商品更新 name:更新]
goods.delete map[desc:商品删除 name:删除]
Example (Panic)
defer func() {
	fmt.Println(recover())
}()
Setup(struct{ *Node }{}, "", nil)
Output:

tree should be a pointer, not struct

Types

type ConciseTree

type ConciseTree interface {
	Path() string
	Tags() map[string]string
}

ConciseTree use an interface that describe `Node` to represent a concise tree.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node 代表ConciseTree的一个节点,用来构造结一棵ConciseTree。 所有非叶子节点都应该嵌入此类型,所有叶子节点都应该直接使用此类型。

Node represents a node of ConciseTree,and is used to construct a ConciseTree. All nonleaf nodes should embed this type, all leaf nodes should use this type directly.

func (*Node) Path

func (n *Node) Path() string

func (*Node) Set

func (n *Node) Set(path string, tags map[string]string)

func (*Node) Tags

func (n *Node) Tags() map[string]string

type NormalTree

type NormalTree struct {
	NormalTreeNode
	// contains filtered or unexported fields
}

NormalTree是一个正规形式的树结构。它经常被用在很多常见情况下。

NormalTree is a tree structure in normal form. It's commonly used in most common cases.

func ToNormal

func ToNormal(node ConciseTree) NormalTree

ToNormal converts a ConciseTree to a NormalTree.

Example
package main

import (
	"encoding/json"
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

var normalTree tree.NormalTree

func main() {
	if b, err := json.MarshalIndent(normalTree, "", "  "); err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(string(b))
	}
}
Output:

{
  "path": "",
  "tags": {
    "name": "根节点"
  },
  "children": [
    {
      "path": "bill",
      "tags": {
        "desc": "各种单据",
        "name": "单据"
      },
      "children": [
        {
          "path": "bill.list",
          "tags": {
            "desc": "单据列表",
            "name": "列表"
          }
        },
        {
          "path": "bill.detail",
          "tags": {
            "desc": "单据详情",
            "name": "详情"
          }
        }
      ]
    },
    {
      "path": "goods",
      "tags": {
        "desc": "商品(含库存)",
        "name": "商品"
      },
      "children": [
        {
          "path": "goods.create",
          "tags": {
            "desc": "商品创建",
            "name": "创建"
          }
        },
        {
          "path": "goods.update",
          "tags": {
            "desc": "商品更新",
            "name": "更新"
          }
        },
        {
          "path": "goods.delete",
          "tags": {
            "desc": "商品删除",
            "name": "删除"
          }
        }
      ]
    }
  ]
}

func (*NormalTree) CheckPaths

func (t *NormalTree) CheckPaths(paths []string) error

CheckPaths return an error if has unknown path

Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

var normalTree tree.NormalTree

func main() {
	fmt.Println(normalTree.CheckPaths([]string{"bill", "goods", "goods.create"}))
	fmt.Println(normalTree.CheckPaths([]string{"goods", "goods.create", "goods.insert"}))

}
Output:

<nil>
unknown path: goods.insert

func (*NormalTree) ChildrenPaths

func (t *NormalTree) ChildrenPaths() []string
Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

var normalTree tree.NormalTree

func main() {
	fmt.Println(normalTree.ChildrenPaths())

}
Output:

[bill goods]

func (*NormalTree) CleanPaths

func (t *NormalTree) CleanPaths(paths []string) []string

CleanPaths remove paths that's not in the normal tree.

Example
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

var normalTree tree.NormalTree

func main() {
	fmt.Println(normalTree.CleanPaths([]string{"goods", "goods.create", "goods.insert"}))

}
Output:

[goods goods.create]

func (*NormalTree) ExcludingPaths

func (t *NormalTree) ExcludingPaths() []string

func (*NormalTree) ExpandPaths

func (t *NormalTree) ExpandPaths(paths []string) (result []string)

ExpandPaths expand paths so that they are not ancestor of any excluding path.

func (*NormalTree) ExpandedChildrenPaths

func (t *NormalTree) ExpandedChildrenPaths() []string

func (*NormalTree) Keep

func (t *NormalTree) Keep(fn func(NormalTreeNode) bool) NormalTree

Keep return a new tree, keep only nodes that fn returns true. If fn returns false, the node and its decendants are all removed from the new tree.

Example (Remove_root)
package main

import (
	"fmt"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

func main() {
	r := (&tree.NormalTree{
		NormalTreeNode: tree.NormalTreeNode{Path: "root"},
	}).Keep(func(node tree.NormalTreeNode) bool {
		return node.Path != "root"
	})
	fmt.Printf("%+v\n", r)

}
Output:

{pathsMap:map[] excludingPaths:[] childrenPaths:[] expandedChildrenPaths:[] NormalTreeNode:{Path: Tags:map[] Children:[]}}

func (*NormalTree) PathsMap

func (t *NormalTree) PathsMap() map[string]*NormalTreeNode
Example
package main

import (
	"fmt"
	"sort"

	tree "gitee.com/go-better/dev/type/tree/concisetree"
)

var normalTree tree.NormalTree

func main() {
	var pathNames = []string{}
	for path, node := range normalTree.PathsMap() {
		pathNames = append(pathNames, path+":"+node.Tags["name"])
	}
	sort.Strings(pathNames)
	fmt.Println(pathNames)

}
Output:

[:根节点 bill.detail:详情 bill.list:列表 bill:单据 goods.create:创建 goods.delete:删除 goods.update:更新 goods:商品]

type NormalTreeNode

type NormalTreeNode struct {
	Path     string            `json:"path"`
	Tags     map[string]string `json:"tags,omitempty"`
	Children []NormalTreeNode  `json:"children,omitempty"`
}

func (NormalTreeNode) ChildrenPaths

func (t NormalTreeNode) ChildrenPaths() []string

func (*NormalTreeNode) Contains

func (t *NormalTreeNode) Contains(excludingPaths []string) bool

func (*NormalTreeNode) ExpandPath

func (t *NormalTreeNode) ExpandPath(excludingPaths []string) []string

ExpandPath expand path so that it is not ancestor of any excluding path.

Jump to

Keyboard shortcuts

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