humanci

package module
v0.0.0-...-74fc9e1 Latest Latest
Warning

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

Go to latest
Published: Sep 15, 2021 License: Apache-2.0 Imports: 6 Imported by: 0

README

humanci 👉 🤖 👈

First things first

humanci is most likely not a CLI-Framework to realistically replace any of the current ones. Why? Well because in humanci we don't know anything about flags, args nor sub-commands. Welll kind of. With humanci you can build CLI-Tools which commands can be spelled in a fluent language. Let me give you an example. I sometimes need to check which web-server I forgot to stop and is now block port 8080. However, I takes me 3 google searches and 4 Safari tabs to find the lsof -i tcp:8080 command to release my pain. humanci should allow you to build something where you can just type in which process is listening on 8080.

This whole thing is meant to be a fun project rather than a project to build the most efficient and performant CLI-Framework. If you are looking for one of those go check out cobra, pretty awesome!

I'd like to quote my roommate how said:

"It might be slow, maybe quite slow - but humans, humans are super slow"

Example

func main() {
    // create a new cli which is a singelton
    // humanci.New() can be called multiple times returning the current
    // instance if one exists else creates one
	cli := humanci.New()

	cli.RootNOP("who", "what"). // set the root "command". Sentence can start with "who" or "what"
		WithNOP("is"). // well this is a fill word/node to allow a correct sentence
		WithRegex(HandleAction, "listening|receiving"). // here we can apply a regex on the current token and execute a function with that knowledge 
		WithNOP("on", "at"). // again fill word/node but sentence can now be "who/what is listening/receiving on/at"
		WithNOP("port"). // fill word/node
		WithRegex(HandlePort, "[0-9]{2,4}") // match the user input port (dont use this regex for ports - just used for this example but is not generally correct!)

    // run the command
	if err := cli.Execute(); err != nil {
		log.Fatal(err)
	}
}

WithRegex requires a ValueFunc which can be used to modify the current state of the command. Here the HandlerAction is used to add meta data to the command which can be used in the next nodes.

func HandleAction(meta humanci.MetaData) error {
	switch meta.LastToken() {
	case "listening":
		meta.Value("cmd", "lsof")
		meta.Value("type", "LISTENING")
	case "receiving":
		meta.Value("cmd", "lsof")
		meta.Value("type", "RECEIVING")
	}
	return nil
}

The last ValueFunc in WithRegex(HandlePort, "[0-9]{2,4}") is the handler which executes the correct shell commands using the meta data from the previous steps.

func HandlePort(meta humanci.MetaData) error {
	port := meta.LastToken()

	switch meta.Return("type") {
	case "LISTENING":
		cmd := exec.Command(meta.Return("cmd").(string), "-i", "tcp:"+port)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err := cmd.Run(); err != nil {
			return err
		}
	case "RECEIVING":
		cmd := exec.Command(meta.Return("cmd").(string), "-nPi", "tcp:"+port)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr

		if err := cmd.Run(); err != nil {
			return err
		}
	default:
		fmt.Println("Mhm..sorry I am not sure what to do with this.")
	}
	return nil
}
Output

go run main.go what is listening on port 8080 output for command

go run main.go who is receiving at port 8080 output for command

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func NewRegexNode

func NewRegexNode(fn ValueFunc) func(MetaData) Node

func SliceToString

func SliceToString(edges []string) string

Types

type CLI

type CLI interface {
	// Help prints all possible commands as given by the trie
	// as tree to the standrard output
	Help()

	// RootNOP creates and NOPNode as one root node for the
	// cli
	RootNOP(keys ...string) Node
	Execute() error
}

func New

func New() CLI

New create new CLI

type ExecNode

type ExecNode struct{}

type IntNode

type IntNode struct{}

type MetaData

type MetaData map[string]interface{}

func (MetaData) LastToken

func (meta MetaData) LastToken() string

func (MetaData) Return

func (meta MetaData) Return(k string) interface{}

func (MetaData) Value

func (meta MetaData) Value(k string, v interface{})

type NOPNode

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

func (*NOPNode) Add

func (node *NOPNode) Add(addFn func(meta MetaData) Node, keys ...string) Node

func (*NOPNode) AddToken

func (node *NOPNode) AddToken(v string)

func (*NOPNode) Ctx

func (node *NOPNode) Ctx() MetaData

func (*NOPNode) Exec

func (node *NOPNode) Exec(cmd []string) error

func (*NOPNode) Func

func (node *NOPNode) Func(v interface{}, token string) error

Func on NOPNode does nothing since NOPNodes don't have any ValueFunc/NodeFunc mapped to it

func (*NOPNode) Nexts

func (node *NOPNode) Nexts() map[Node][]string

func (*NOPNode) Print

func (node *NOPNode) Print(tree treeprint.Tree)

func (*NOPNode) Token

func (node *NOPNode) Token() []string

func (*NOPNode) Values

func (node *NOPNode) Values() map[string]interface{}

func (*NOPNode) WithExec

func (node *NOPNode) WithExec(fn NodeFunc, keys ...string) Node

func (*NOPNode) WithInt

func (node *NOPNode) WithInt(fn ValueFunc) Node

func (*NOPNode) WithKeys

func (node *NOPNode) WithKeys(fn ValueFunc, keys ...string) Node

func (*NOPNode) WithNOP

func (node *NOPNode) WithNOP(keys ...string) Node

func (*NOPNode) WithRegex

func (node *NOPNode) WithRegex(fn func(MetaData) error, patterns ...string) Node

func (*NOPNode) WithStr

func (node *NOPNode) WithStr(fn ValueFunc) Node

type Node

type Node interface {
	// WithNOP creates and adds a NOPNode
	// to the command which only exists so that
	// a sentence is grammarly correct. It has no
	// functionality, but to allow clean and correct english/german/world
	// sentences.
	WithNOP(keys ...string) Node

	// WithKeys returns a Node which ValueFunc will be executed when the
	// Node is reached in the trie. This allows to add custom data to
	// the overall context of the command.
	WithKeys(fn ValueFunc, keys ...string) Node

	// WithRegex returns a Node which key is a regex.
	// The node will allow to match every token which
	// matches the pattern.
	// The ValueFunc can be used to add the value with a custom key and
	// will be executed if the Node is reached in the trie.
	WithRegex(fn func(meta MetaData) error, patterns ...string) Node

	// WithInt returns a Node which does not specifiys a key.
	// However, an IntNode matches every token which can be parsed as
	// and int64 and adds the value to the overall data.
	// The ValueFunc can be used to add the value with a custom key and
	// will be executed if the Node is reached in the trie.
	WithInt(fn ValueFunc) Node

	// WithStr returns a Node which does not specifiys a key.
	// However, an StrNode matches EVERY next token and adds
	// the value to the overall data.
	// The ValueFunc can be used to add the value with a custom key and
	// will be executed if the Node is reached in the trie.
	WithStr(fn ValueFunc) Node

	// WithExec adds a ExecNode to the cmd which when reached will execute the
	// node's NodeFunc. The NodeFunc gets the full context of
	// the run a CMD with all the stored data.
	// Tipically this node would be used as the last node of an CMD
	WithExec(fn NodeFunc, keys ...string) Node

	// Values returns the current state of the Cmd's data
	Values() map[string]interface{}

	AddToken(v string)
	Token() []string
	Ctx() MetaData
	// Nexts returns all nodes which can be reached from a node
	// and its edges over which the node can be reached
	Nexts() map[Node][]string

	// Func executes the mapped ValueFunc or NodeFunc on a node
	// NOPNodes don't have any function, a call to NOPNode.Func() will
	// to nothing
	Func(v interface{}, token string) error

	// Print appends the treeprint.Tree with the node's keys
	// in the form of [key | key]. If the node has nexts Print
	// will be called on each next node.
	Print(tree treeprint.Tree)

	Exec(cmd []string) error
}

func NewNOPNode

func NewNOPNode(meta MetaData) Node

type NodeFunc

type NodeFunc func(Node) error

NodeFunc is a function which recevied the current Node as an argument allowing the caller to perform a veraity of action. Propably only useful for the "last" node to execute the final command, while having access to all the stored data

type RegexNode

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

func (*RegexNode) Add

func (node *RegexNode) Add(addFn func(MetaData) Node, patterns ...string) Node

func (*RegexNode) AddToken

func (node *RegexNode) AddToken(v string)

func (*RegexNode) Ctx

func (node *RegexNode) Ctx() MetaData

func (*RegexNode) Exec

func (node *RegexNode) Exec(cmd []string) error

func (*RegexNode) Func

func (node *RegexNode) Func(v interface{}, token string) error

Func on RegexNode does nothing since RegexNodes don't have any ValueFunc/NodeFunc mapped to it

func (*RegexNode) Nexts

func (node *RegexNode) Nexts() map[Node][]string

func (*RegexNode) Print

func (node *RegexNode) Print(tree treeprint.Tree)

func (*RegexNode) Token

func (node *RegexNode) Token() []string

func (*RegexNode) Values

func (node *RegexNode) Values() map[string]interface{}

func (*RegexNode) WithExec

func (node *RegexNode) WithExec(fn NodeFunc, keys ...string) Node

func (*RegexNode) WithInt

func (node *RegexNode) WithInt(fn ValueFunc) Node

func (*RegexNode) WithKeys

func (node *RegexNode) WithKeys(fn ValueFunc, keys ...string) Node

func (*RegexNode) WithNOP

func (node *RegexNode) WithNOP(keys ...string) Node

func (*RegexNode) WithRegex

func (node *RegexNode) WithRegex(fn func(MetaData) error, patterns ...string) Node

func (*RegexNode) WithStr

func (node *RegexNode) WithStr(fn ValueFunc) Node

type StrNode

type StrNode struct{}

type ValueFunc

type ValueFunc func(meta MetaData) error // (string, interface{})

ValueFunc describes any function which recevies some data from the current node it gets exectuted on. Example:

-> RegexNode, matches regex: ValueFunc(matched_regex_value)
-> ValueNode, passed the node's token into the ValueFunc: ValueFunc("foo")

type ValueNode

type ValueNode struct{}

Directories

Path Synopsis
examples
simple command
structured command

Jump to

Keyboard shortcuts

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