cookoo

package module
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: Sep 21, 2015 License: MIT Imports: 7 Imported by: 460

README

Cookoo

A chain-of-command framework written in Go

Build Status GoDoc

Usage

$ cd $GOPATH
$ go get github.com/Masterminds/cookoo

Use it as follows (from example/example.go):

package main

import (
	// This is the path to Cookoo
	"fmt"
	"github.com/Masterminds/cookoo"
)

func main() {

	// Build a new Cookoo app.
	registry, router, context := cookoo.Cookoo()

	// Fill the registry.
	registry.AddRoutes(
		cookoo.Route{
			Name: "TEST",
			Help: "A test route",
			Does: cookoo.Tasks{
				cookoo.Cmd{
					Name: "hi",
					Fn:   HelloWorld,
				},
			},
		},
	)

	// Execute the route.
	router.HandleRequest("TEST", context, false)
}

func HelloWorld(cxt cookoo.Context, params *cookoo.Params) (interface{}, cookoo.Interrupt) {
	fmt.Println("Hello World")
	return true, nil
}

Documentation

A Real Example

For a real example of Cookoo, take a look at Skunk.

Here's what Skunk's registry looks like:

	registry.
	Route("scaffold", "Scaffold a new app.").
		Does(LoadSettings, "settings").
			Using("file").WithDefault(homedir + "/settings.json").From("cxt:SettingsFile").
		Does(MakeDirectories, "dirs").
			Using("basedir").From("cxt:basedir").
			Using("directories").From("cxt:directories").
		Does(RenderTemplates, "template").
			Using("tpldir").From("cxt:homedir").
			Using("basedir").From("cxt:basedir").
			Using("templates").From("cxt:templates").
	Route("help", "Print help").
		Does(Usage, "Testing")

This has two routes:

  • scaffold
  • help

The help route just runs the command Usage, which looks like this:

func Usage(cxt cookoo.Context, params *cookoo.Params) interface{} {
	fmt.Println("Usage: skunk PROJECTNAME")
	return true
}

That is a good example of a basic command.

The scaffold route is more complex. It performs the following commands (in order):

  • LoadSettings: Load a settings.json file into the context.
  • MakeDirectories: Make a bunch of directories.
  • RenderTemplates: Perform template conversions on some files.

The MakeDirectories command is an example of a more complex command. It takes two parameters (declared with Using().From()):

  1. basedir: The base directory where the new subdirectories will be created. This comes from the cxt:basedir source, which means Cookoo looks in the Context object for a value named basedir.
  2. directoies: An array of directory names that this command will create. These come from cxt:directories, which means that the Context object is queried for the value of directories. In this case, that value is actually loaded from the settings.json file into the context by the LoadSettings command.`

With that in mind, let's look at the command:

// The MakeDirectories command.
// All commands take a Context and a Params object, and return an
// interface{}
func MakeDirectories(cxt cookoo.Context, params *cookoo.Params) interface{} {

	// This is how we get something out of the Params object. This is the
	// value that was passed in by `Using('basedir').From('cxt:basedir')
	basedir := params.Get("basedir", ".").(string)

	// This is another way to get a parameter value. This form allows us
	// to conveniently check that the parameter exists.
	d, ok := params.Has("directories")
	if !ok {
		// Did nothing. But we don't want to raise an error.
		return false
	}

	// We do have to do an explicit type conversion.
	directories := d.([]interface{})

	// Here we do the work of creating directories.
	for _, dir := range directories {
		dname := path.Join(basedir, dir.(string))
		os.MkdirAll(dname, 0755)
	}

	// We don't really have anything special to return, so we just
	// indicate that the command was successful.
	return true
}

This is a basic example of working with Cookoo. But far more sophisticated workflows can be built inexpensively and quickly, and in a style that encourages building small and re-usable chunks of code.

Documentation

Overview

Package cookoo is a Chain-of-Command (CoCo) framework for writing applications.

Tutorials

* Building Web Apps with Cookoo: https://github.com/Masterminds/cookoo-web-tutorial

* Building CLI Apps with Cookoo: https://github.com/Masterminds/cookoo-cli-tutorial

A chain of command framework works as follows:

  • A "route" is constructed as a chain of commands -- a series of single-purpose tasks that are run in sequence.
  • An application is composed of one or more routes.
  • Commands in a route communicate using a Context.
  • An application Router is used to receive a route name and then execute the appropriate chain of commands.

To create a new Cookoo application, use cookoo.Cookoo(). This will configure and create a new registry, request router, and context. From there, use the Registry to build chains of commands, and then use the Router to execute chains of commands.

Unlike other CoCo implementations (like Pronto.js or Fortissimo), Cookoo commands are just functions.

Interrupts

There are four types of interrupts that you may wish to return:

  1. FatalError: This will stop the route immediately.
  2. RecoverableError: This will allow the route to continue moving.
  3. Stop: This will stop the current request, but not as an error.
  4. Reroute: This will stop executing the current route, and switch to executing another route.

To learn how to write Cookoo applications, you may wish to examine the small Skunk application: https://github.com/technosophos/skunk.

Example
// This is an admittedly contrived example in which we first store a
// "Hello World" message, and then tell the logger to get that stored
// message and write it to the log.
reg, router, cxt := Cookoo()
reg.AddRoute(Route{
	Name: "hello",
	Help: "Sends the log message 'Hello World'",
	Does: Tasks{
		// First, store the message "Hello World" in the context.
		Cmd{
			Name: "message",
			Fn:   AddToContext,
			Using: []Param{
				Param{
					Name:         "hello",
					DefaultValue: "Hello World",
				},
			},
		},
		// Now get that message and write it to the log.
		Cmd{
			Name: "log",
			Fn:   LogMessage,
			Using: []Param{
				Param{
					Name: "msg",
					From: "cxt:message",
				},
			},
		},
	},
})

router.HandleRequest("hello", cxt, false)
Output:

Index

Examples

Constants

View Source
const VERSION = "1.3.0"

VERSION provides the current version of Cookoo.

Variables

This section is empty.

Functions

func Cookoo

func Cookoo() (reg *Registry, router *Router, cxt Context)

Cookoo creates a new Cookoo app.

This is the main progenitor of a Cookoo application. Whether a plain Cookoo app, or a Web or CLI program, this is the function you will use to bootstrap.

The `*Registry` is used to declare new routes, where a "route" may be thought of as a task composed of a series of steps (commands).

The `*Router` is responsible for the actual execution of a Cookoo route. The main method used to call a route is `Router.HandleRequest()`.

The `Context` is a container for passing information down a chain of commands. Apps may insert "global" information to a context at startup and make it available to all commands.

Example
reg, router, cxt := Cookoo()
reg.AddRoute(Route{
	// The name of the route. You execute routes by name. (See router.HandleRequest below)
	Name: "hello",
	// This is for documentation/help tools.
	Help: "Print a message on standard output",

	// This is a list of things you want this route to do. When executed,
	// it will run these commands in order.
	Does: Tasks{
		// Declare a new command.
		Cmd{
			// Give the command a name. Programs reference command output
			// by this name.
			Name: "print",

			// Tell Cookoo what function to execute when we get to this
			// step.
			//
			// Usually we define functions elsewhere so we can re-use them.
			Fn: func(c Context, p *Params) (interface{}, Interrupt) {
				// Print whatever the content of the 'msg' parameter is.
				fmt.Println(p.Get("msg", "").(string))
				return nil, nil
			},
			// Send some parameters into Fn. Here we define the 'msg'
			// parameter that Fn prints. While we just use a default
			// value here, Cookoo can get that information from another
			// source and then send it into Fn.
			Using: []Param{
				Param{
					Name:         "msg",
					DefaultValue: "Hello World",
				},
			},
		},
	},
})

// Now we execute the "hello" chain of commands.
router.HandleRequest("hello", cxt, false)
Output:

Hello World

func GetBool added in v1.2.0

func GetBool(key string, defaultValue bool, source Getter) bool

GetBool gets a boolean value from any Getter.

func GetFloat64 added in v1.2.0

func GetFloat64(key string, defaultVal float64, source Getter) float64

GetFloat64 gets a float64 from any Getter.

func GetInt added in v1.2.0

func GetInt(key string, defaultValue int, source Getter) int

GetInt gets an int from any Getter.

func GetInt32 added in v1.2.0

func GetInt32(key string, defaultValue int32, source Getter) int32

GetInt32 gets an int32 from any Getter.

func GetInt64 added in v1.2.0

func GetInt64(key string, defaultValue int64, source Getter) int64

GetInt64 gets an int64 from any Getter.

func GetString added in v1.2.0

func GetString(key, defaultValue string, source Getter) string

GetString is a convenience function for getting strings.

This simplifies getting strings from a Context, a Params, or a GettableDatasource.

func GetUint64 added in v1.2.0

func GetUint64(key string, defaultVal uint64, source Getter) uint64

GetUint64 gets a uint64 from any Getter.

func HasBool added in v1.2.0

func HasBool(key string, source Getter) (bool, bool)

HasBool returns the value and a flag indicated whether the flag value was found.

Default value is false if ok is false.

func HasFloat64 added in v1.2.0

func HasFloat64(key string, source Getter) (float64, bool)

HasFloat64 returns the float64 value for key, and a flag indicated if it was found.

If ok is false, the float value will be 0

func HasInt added in v1.2.0

func HasInt(key string, source Getter) (int, bool)

HasInt returns the int value for key, and a flag indicated if it was found.

If ok is false, the int value will be 0

func HasInt32 added in v1.2.0

func HasInt32(key string, source Getter) (int32, bool)

HasInt32 returns the int32 value for key, and a flag indicated if it was found.

If ok is false, the int value will be 0

func HasInt64 added in v1.2.0

func HasInt64(key string, source Getter) (int64, bool)

HasInt64 returns the int64 value for key, and a flag indicated if it was found.

If ok is false, the int value will be 0

func HasString added in v1.2.0

func HasString(key string, source Getter) (string, bool)

HasString is a convenience function to perform Has() and return a string.

func HasUint64 added in v1.2.0

func HasUint64(key string, source Getter) (uint64, bool)

HasUint64 returns the uint64 value for key, and a flag indicated if it was found.

If ok is false, the int value will be 0

func Map added in v1.2.0

Map merges params into a CommandDefinition and returns a Command Definition.

Types

type BasicRequestResolver

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

BasicRequestResolver is a basic resolver that assumes that the given request name *is* the route name.

func (*BasicRequestResolver) Init

func (r *BasicRequestResolver) Init(registry *Registry)

Init initializes the BasicRequestResolver.

func (*BasicRequestResolver) Resolve

func (r *BasicRequestResolver) Resolve(path string, cxt Context) (string, error)

Resolve returns the given path. This is a non-transforming resolver.

type Cmd added in v1.2.0

type Cmd struct {
	Name  string
	Fn    Command
	Using Parameters
}

Cmd associates a cookoo.Command to a Route.

The Name is the direct reference to a command. When a Command returns output, that output is inserted into the Context with the key Name.

Fn specifies which cookoo.Command should be executed during this step.

Using contains a list of Parameters that Cookoo can pass into the Command at execution time.

type CmdDef added in v1.2.0

type CmdDef struct {
	Name  string
	Def   CommandDefinition
	Using Parameters
}

type Command

type Command func(cxt Context, params *Params) (interface{}, Interrupt)

Command executes a command and returns a result. A Cookoo app has a registry, which has zero or more routes. Each route executes a sequence of zero or more commands. A command is of this type.

type CommandDefinition added in v1.2.0

type CommandDefinition interface {
	// Run provides the same functionality as a Command function, but with
	// the added benefit of having all of the fields present on the struct. For that
	// reason, there is no Params attached.
	Run(c Context) (interface{}, Interrupt)
}

CommandDefinition describes the fields that should be attached to a Command.

CommandDefinitions should be composed of public fields and a Run method.

type Person struct {
	Name string
	Age int
	IgnoreMe string `coo:"-"`
}

type Context

type Context interface {
	// Add puts a name/value pair to the context.
	// DEPRECATED. This will be removed in Cookoo 2.0. Use
	// Put instead.
	Add(string, ContextValue)

	// Put inserts a name/value pair into the context.
	//
	// This is used to add data to a context. The context does nothing
	// to manage manipulation of context values. Values are placed in
	// as-is, and are retrieved as-is. Unless an implementor has
	// made a value immutable, context values are mutable.
	Put(string, ContextValue)

	// Given a name, get a value from the context.
	//
	// Get requires a default value (which may be nil).
	//
	// Example:
	// 	ip := cxt.Get("ip", "127.0.0.1").(string)
	//
	// Contrast this usage with that of cxt.Has(), which may be used for more
	// traditional field checking:
	//
	// Example:
	// 	ip, ok := cxt.Has("ip")
	// 	if !ok {
	// 		// do something error-ish
	// 	}
	// 	ipStr := ip.(string)
	//
	// The cxt.Get() call avoids the cumbersome check/type-assertion combo
	// that occurs with cxt.Has().
	Get(string, interface{}) ContextValue
	// Given a name, check if the key exists, and if it does return the value.
	Has(string) (ContextValue, bool)
	// Get a datasource by name.
	Datasource(string) Datasource
	// Get a map of all datasources.
	Datasources() map[string]Datasource
	// Check if a datasource exists, and return it if it does.
	HasDatasource(string) (Datasource, bool)
	// Add a datasource.
	AddDatasource(string, Datasource)
	// Remove a datasource from the context.
	RemoveDatasource(string)
	// Get the length of the context. This is the number of context values.
	// Datsources are not counted.
	Len() int
	// Make a shallow copy of the context.
	Copy() Context
	// Get the content (no datasources) as a map.
	AsMap() map[string]ContextValue
	// Get a logger.
	Logger(name string) (io.Writer, bool)
	// Add a logger.
	AddLogger(name string, logger io.Writer)
	// Remove a logger.
	RemoveLogger(name string)
	// Send a log with a prefix.
	Log(prefix string, v ...interface{})
	// Send a log and formatting string with a prefix.
	Logf(prefix string, format string, v ...interface{})
}

A Context is a collection of data that is associated with the current request.

Contexts are used to exchange information from command to command inside of a particular chain of commands (a route). Commands may access the data inside of a context, and may also modify a context.

A context maintains two different types of data: *context variables* and *datasources*.

Context variables are data that can be passed, in current form, from command to command -- analogous to passing variables via parameters in function calls.

Datasources are (as the name implies) sources of data. For example, a database, a file, a cache, and a key-value store are all datasources.

For long-running apps, it is generally assumed (though by no means required) that datasources are "long lived" and context variables are "short lived." While modifying a data source may impact other requests, generally it is safe to assume that modifying a variable is localized to the particular request.

Correct Usage

A word of warning.

The Cookoo system was designed around the theory that commands should generally work with datasources *directly* and context variables *indirectly*. Context variables should generally be passed into a command via a cookoo.Param. And a command generally should return a value that can then be placed into the context on its behalf.

The reason for this design is that it then makes it much easier for higher- level programming, such as changing input or modifying output at the registry level, not within the commands themselves.

Datasources, on the other hand, are designed to be leveraged primarily by commands. This involves a layer of conventionality, but it also pushes data access logic into the commands where it belongs.

So, for example, a SQL-based datasource should be *declared* at the top level of a program (where it will be added to the context), but the actual interaction with that datasource should happen inside of commands themselves, not at the registry level.

func NewContext

func NewContext() Context

NewContext creates a new empty cookoo.ExecutionContext and calls its Init() method.

func SyncContext added in v1.1.0

func SyncContext(cxt Context) Context

SyncContext wraps a context, syncronizing access to it.

This uses a read/write mutex which allows multiple reads at a time, but locks both reading and writing for writes.

To avoid really nefarious bugs, the same mutex locks context values and datasource values (since there is no guarantee that one is not backed by the other).

type ContextValue

type ContextValue interface{}

ContextValue is an empty interface defining a context value. Semantically, this is the same as interface{}

type Datasource

type Datasource interface{}

Datasource is an empty interface defining a Datasource. Semantically, this is the same as interface{}

type DefaultGetter added in v1.2.0

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

DefaultGetter represents a Getter instance for a default value.

A default getter always returns the given default value.

func (*DefaultGetter) Get added in v1.2.0

func (e *DefaultGetter) Get(name string, value interface{}) interface{}

func (*DefaultGetter) Has added in v1.2.0

func (e *DefaultGetter) Has(name string) (interface{}, bool)

type ExecutionContext

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

ExecutionContext is the core implementation of a Context.

An ExecutionContext is an unordered map-based context.

func (*ExecutionContext) Add

func (cxt *ExecutionContext) Add(name string, value ContextValue)

Add a name/value pair to the context. DEPRECATED: Use Put instead.

func (*ExecutionContext) AddDatasource

func (cxt *ExecutionContext) AddDatasource(name string, ds Datasource)

AddDatasource adds a datasource to the map of datasources. A datasource is typically something like a connection to a database that you want to keep open persistently and share between requests. To add a datasource to the map just add it with a name. e.g. cxt.AddDatasource("mysql", foo) where foo is the struct for the datasource.

func (*ExecutionContext) AddLogger

func (cxt *ExecutionContext) AddLogger(name string, logger io.Writer)

AddLogger adds a logger. The logging system can have one of more loggers keyed by name.

func (*ExecutionContext) AsMap

func (cxt *ExecutionContext) AsMap() map[string]ContextValue

AsMap returns the values of the context as a map keyed by a string.

func (*ExecutionContext) Copy

func (cxt *ExecutionContext) Copy() Context

Copy the context into a new context.

func (*ExecutionContext) Datasource

func (cxt *ExecutionContext) Datasource(name string) Datasource

Datasource get a datasource from the map of datasources. A datasource (e.g., a connection to a database) is retrieved as an interface so its type will need to be specified before it can be used. Take an example of the variable foo that is a struct of type Foo. foo = cxt.Datasource("foo").(*Foo)

func (*ExecutionContext) Datasources

func (cxt *ExecutionContext) Datasources() map[string]Datasource

Datasources gets the map of datasources.

func (*ExecutionContext) Get

func (cxt *ExecutionContext) Get(name string, defaultValue interface{}) ContextValue

Get retrieves a value from the context given a name. If a value does not exist on the context the default is returned.

func (*ExecutionContext) GetAll

func (cxt *ExecutionContext) GetAll() map[string]ContextValue

GetAll gets a map of all name/value pairs in the present context.

func (*ExecutionContext) Has

func (cxt *ExecutionContext) Has(name string) (value ContextValue, found bool)

Has is a special form of Get that also returns a flag indicating if the value is found. This fetches the value and also returns a flag indicating if the value was found. This is useful in cases where the value may legitimately be 0.

func (*ExecutionContext) HasDatasource

func (cxt *ExecutionContext) HasDatasource(name string) (Datasource, bool)

HasDatasource checks whether the named datasource exists, and return it if it does.

func (*ExecutionContext) Init

func (cxt *ExecutionContext) Init() *ExecutionContext

Init initializes a context.

If an existing context is re-initialized, all of its associated values, datasources, and loggers will be unset.

func (*ExecutionContext) Len

func (cxt *ExecutionContext) Len() int

Len returns the length of the context as in the length of the values stores.

func (*ExecutionContext) Log

func (cxt *ExecutionContext) Log(prefix string, v ...interface{})

Log logs a message to one of more loggers.

func (*ExecutionContext) Logf

func (cxt *ExecutionContext) Logf(prefix string, format string, v ...interface{})

Logf logs a message to one or more loggers and uses a format string.

func (*ExecutionContext) Logger

func (cxt *ExecutionContext) Logger(name string) (io.Writer, bool)

Logger gets a logger. The logging system can have one or more loggers that are stored keyed by name.

func (*ExecutionContext) Put

func (cxt *ExecutionContext) Put(name string, value ContextValue)

Put inserts a value into the context.

func (*ExecutionContext) RemoveDatasource

func (cxt *ExecutionContext) RemoveDatasource(name string)

RemoveDatasource removes a datasouce from the map of datasources.

func (*ExecutionContext) RemoveLogger

func (cxt *ExecutionContext) RemoveLogger(name string)

RemoveLogger removes a logger. The logging system can have one of more loggers keyed by name.

func (*ExecutionContext) SkipLogPrefix

func (cxt *ExecutionContext) SkipLogPrefix(prefixes ...string)

SkipLogPrefix ignores logging messages to any of the given prefixes.

While this is not a part of the Context interface, the ExecutionContext allows you to ignore certain logging prefixes. For example, to ignore the `debug` and `info` messages, you might want to do something like this:

cxt.(*ExecutionContext).SkipLogPrefix("debug", "info")
cxt.Logf("debug", "This message will be ignored.")

In the above case, the subsequent call to `Logf()` is ignored.

type FatalError

type FatalError struct {
	Message string
}

FatalError is a fatal error, which will stop the router from continuing a route.

When Cookoo encounters a `FatalError`, it will log the error and immediately stop processing the route.

Note that by default Cookoo treats and unhandled `error` as if it were a `FatalError`.

func (*FatalError) Error

func (err *FatalError) Error() string

Error returns the error message.

type Getter added in v1.2.0

type Getter interface {
	Get(string, interface{}) interface{}
	Has(string) (interface{}, bool)
}

Getter can get values in two ways.

A Get() can be given a default value, in which case it will return either the value associated with the key or, if that's not found, the default value.

A Has() doesn't take a default value, but instead returns both the value (if found) and a boolean flag indicating whether it is found.

In Cookoo 1.x, Context's Get() function returns a ContextValue instead of an interface. For that reason, you may need to wrap Cxt in GettableCxt to make it a true Getter.

In Cookoo 1.x, KeyValueDatasource uses Value() instead of Get()/Has(). For that reason, you can wrap a KeyValueDatasource in a GettableDS() to make it behave like a Getter.

func GetFromFirst added in v1.2.0

func GetFromFirst(key string, defaultVal interface{}, sources ...Getter) (interface{}, Getter)

GetFromFirst gets the value from the first Getter that has the key.

This provides a method for scanning, for example, Params, Context, and KeyValueDatasource and returning the first one that matches.

If no Getter has the key, the default value is returned, and the returned Getter is an instance of DefaultGetter.

func GettableCxt added in v1.2.0

func GettableCxt(cxt Context) Getter

GettableCxt makes a Context into a Getter.

This is forward-compatibility code, and will be rendered unnecessary in Cookoo 2.x.

func GettableDS added in v1.2.0

func GettableDS(ds KeyValueDatasource) Getter

GettableDS makes a KeyValueDatasource into a Getter.

This is forward-compatibility code, and will be rendered unnecessary in Cookoo 2.x.

type Include added in v1.2.0

type Include struct {
	Path string
}

Include imports all of the Tasks on another route into the present Route.

type Interrupt

type Interrupt interface{}

Interrupt is a generic return for a command. Generally, a command should return one of the following in the interrupt slot: - A FatalError, which will stop processing. - A RecoverableError, which will continue the chain. - A Reroute, which will cause a different route to be run.

func AddToContext

func AddToContext(cxt Context, params *Params) (interface{}, Interrupt)

AddToContext adds all of the param name/value pairs into the context.

Params

  • Any params will be added into the context.

func ForwardTo

func ForwardTo(cxt Context, params *Params) (interface{}, Interrupt)

ForwardTo forwards to the given route name.

To prevent possible loops or problematic re-routes, use ignoreRoutes.

Params

  • route: The route to forward to. This is required.
  • ignoreRoutes: Route names that should be ignored (generate recoverable errors).

func LogMessage

func LogMessage(cxt Context, params *Params) (interface{}, Interrupt)

LogMessage prints a message to the log.

Params

  • msg: The message to print
  • level: The log level (default: "info")

type KeyValueDatasource

type KeyValueDatasource interface {
	Value(key string) interface{}
}

KeyValueDatasource is a datasource that can retrieve values by (string) keys. Datsources can be just about anything. But a key/value datasource can be used for a special purpose. They can be accessed in From() clauses in a registry configuration.

type Param added in v1.2.0

type Param struct {
	Name         string
	DefaultValue interface{}
	From         string
}

Param describes an individual parameter which will be passed to a Command.

The Name is the name of the parameter. The Command itself dictates which Names it uses.

The DefaultValue is the value of the Parameter if nothing else is specified.

From indicates where the Param value may come from. Examples: `From("cxt:foo")` gets the value from the value of the key 'foo' in the Context.

type Parameters added in v1.2.0

type Parameters []Param

type Params

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

func NewParams

func NewParams(size int) *Params

NewParams creates a Params object of a given size.

func NewParamsWithValues

func NewParamsWithValues(initialVals map[string]interface{}) *Params

NewParamsWithValues initializes a Params object with the given values.

Create a new Params instance, initialized with the given map. Note that the given map is actually used (not copied).

func (*Params) AsMap

func (p *Params) AsMap() map[string]interface{}

AsMap returns all parameters as a map[string]interface{}.

This does no checking of the parameters.

func (*Params) Get

func (p *Params) Get(name string, defaultValue interface{}) interface{}

Get gets a parameter value, or returns the default value.

func (*Params) Has

func (p *Params) Has(name string) (value interface{}, ok bool)

Has checks if a parameter exists, and return it if found.

func (*Params) Init

func (p *Params) Init(initialValues map[string]interface{})

Init initializes a Params object with an initial map of values.

func (*Params) Len

func (p *Params) Len() int

Len returns the number of params.

func (*Params) Requires

func (p *Params) Requires(paramNames ...string) (ok bool, missing []string)

Requires verifies that the given keys exist in the Params.

Require that a given list of parameters are present. If they are all present, ok = true. Otherwise, ok = false and the `missing` array contains a list of missing params.

func (*Params) RequiresValue

func (p *Params) RequiresValue(paramNames ...string) (ok bool, missing []string)

RequiresValue verifies that the given keys exist and that their values are non-empty.

Requires that given parameters are present and non-empty. This is more powerful than Requires(), which simply checks to see if the the Using() clause declared the value.

func (*Params) Validate

func (p *Params) Validate(name string, validator func(interface{}) bool) (value interface{}, ok bool)

Validate provides a validator callback for params. Given a name and a validation function, return a valid value. If the value is not valid, ok = false.

type RecoverableError

type RecoverableError struct {
	Message string
}

RecoverableError is an error that should not cause the router to stop processing.

When Cookoo encounters a `RecoverableError`, it will log the error as a warning, but will then continue to execute the next command in the route.

func (*RecoverableError) Error

func (err *RecoverableError) Error() string

Error returns the error message.

type Registry

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

A Registry contains the the callback routes and the commands each route executes.

func NewRegistry

func NewRegistry() *Registry

NewRegistry returns a new initialized registry.

func (*Registry) AddRoute added in v1.2.0

func (r *Registry) AddRoute(route Route) error

AddRoute adds a single route to the registry.

func (*Registry) AddRoutes added in v1.2.0

func (r *Registry) AddRoutes(routes ...Route) error

AddRoutes adds one or more routes to the registry.

func (*Registry) Does

func (r *Registry) Does(cmd Command, commandName string) *Registry

Does adds a command to the end of the chain of commands for the current (most recently specified) route.

func (*Registry) DoesCmdDef added in v1.2.0

func (r *Registry) DoesCmdDef(cd CommandDefinition, name string) *Registry

func (*Registry) From

func (r *Registry) From(fromVal ...string) *Registry

From sepcifies where to get the value from for the most recently specified paramater as set by Using.

func (*Registry) Includes

func (r *Registry) Includes(route string) *Registry

Includes makes the commands from another route avaiable on this route.

func (*Registry) Init

func (r *Registry) Init() *Registry

Init initializes a registry. If a Registry is created through a means other than NewRegistry Init should be called on it.

func (*Registry) Route

func (r *Registry) Route(name, description string) *Registry

Route specifies a new route to add to the registry.

func (*Registry) RouteNames

func (r *Registry) RouteNames() []string

RouteNames gets a slice containing the names of every registered route.

The route names are returned in the order they were added to the registry. This is useful to some resolvers, which apply rules in order.

func (*Registry) RouteSpec

func (r *Registry) RouteSpec(routeName string) (spec *routeSpec, ok bool)

RouteSpec gets a ruote cased on its name.

func (*Registry) Routes

func (r *Registry) Routes() map[string]*routeSpec

Routes gets an unordered map of routes names to route specs.

If order is important, use RouteNames to get the names (in order).

func (*Registry) Using

func (r *Registry) Using(name string) *Registry

Using specifies a paramater to use for the most recently specified command as set by Does.

func (*Registry) WithDefault

func (r *Registry) WithDefault(value interface{}) *Registry

WithDefault specifies the default value for the most recently specified parameter as set by Using.

type RequestResolver

type RequestResolver interface {
	Init(registry *Registry)
	Resolve(path string, cxt Context) (string, error)
}

RequestResolver is the interface for the request resolver. A request resolver is responsible for transforming a request name to a route name. For example, a web-specific resolver may take a URI and return a route name. Or it make take an HTTP verb and return a route name.

type Reroute

type Reroute struct {
	Route string
}

Reroute is a command can return a Reroute to tell the router to execute a different route.

A `Command` may return a `Reroute` to cause Cookoo to stop executing the current route and jump to another.

func Forward(c Context, p *Params) (interface{}, Interrupt) {
	return nil, &Reroute{"anotherRoute"}
}

func NewReroute added in v1.2.0

func NewReroute(route string) *Reroute

Creates a new Reroute.

func (*Reroute) RouteTo

func (rr *Reroute) RouteTo() string

RouteTo returns the route to reroute to.

type Route added in v1.2.0

type Route struct {
	Name, Help string
	Does       Tasks
}

Route declares a new Cookoo route.

A Route has a name, which is used to identify and call it, and Help. The Help can be used by other tools to generate help text or information about an application's structure.

Routes are composed of a series of Tasks, each of which is executed in order.

type RouteDetails added in v1.2.0

type RouteDetails interface {
	Name() string
	Description() string
}

type RouteError

type RouteError struct {
	Message string
}

RouteError indicates that a route cannot be executed successfully.

func (*RouteError) Error

func (e *RouteError) Error() string

Error returns the error.

type Router

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

Router is the Cookoo router. A Cookoo app works by passing a request into a router, and relying on the router to execute the appropriate chain of commands.

func NewRouter

func NewRouter(reg *Registry) *Router

NewRouter creates a new Router.

func (*Router) HandleRequest

func (r *Router) HandleRequest(name string, cxt Context, taint bool) error

HandleRequest does a request. This executes a request "named" name (this string is passed through the request resolver.) The context is cloned (shallow copy) and passed in as the base context.

If taint is `true`, then no routes that begin with `@` can be executed. Taint should be set to true on anything that relies on a name supplied by an external client.

This will do the following:

  • resolve the request name into a route name (using a RequestResolver)
  • look up the route
  • execute each command on the route in order

The following context variables are placed into the context during a run:

route.Name - Processed name of the current route
route.Description - Description of the current route
route.RequestName - raw route name as passed by the client
command.Name - current command name (changed with each command)

If an error occurred during processing, an error type is returned.

func (*Router) HasRoute

func (r *Router) HasRoute(name string) bool

HasRoute checks whether or not the route exists. Note that this does NOT resolve a request name into a route name. This expects a route name.

func (*Router) Init

func (r *Router) Init(registry *Registry) *Router

Init initializes the Router.

func (*Router) RequestResolver

func (r *Router) RequestResolver() RequestResolver

RequestResolver gets the request resolver.

func (*Router) ResolveRequest

func (r *Router) ResolveRequest(name string, cxt Context) (string, error)

ResolveRequest resolver a given string into a route name.

func (*Router) SetRegistry

func (r *Router) SetRegistry(reg *Registry)

SetRegistry sets the registry.

func (*Router) SetRequestResolver

func (r *Router) SetRequestResolver(resolver RequestResolver)

SetRequestResolver sets the request resolver. The resolver is responsible for taking an arbitrary string and resolving it to a registry route.

Example: Take a URI and translate it to a route.

type Stop

type Stop struct{}

Stop a route, but not as an error condition.

When Cookoo encounters a `Stop`, it will not execute any more commands on a given route. However, it will not emit an error, either.

type Task added in v1.2.0

type Task interface {
	// contains filtered or unexported methods
}

type Tasks added in v1.2.0

type Tasks []Task

Tasks represents a list of discrete tasks that are run on a Route.

There are two kinds of Tasks: Cmd (a command) and Include, which imports a Tasks list from another route.

Directories

Path Synopsis
database
active
active package contains basic Active Record support.
active package contains basic Active Record support.
sql
SQL datasource and commands for Cookoo.
SQL datasource and commands for Cookoo.
Examples and documentation for Cookoo.
Examples and documentation for Cookoo.
The Cookoo `fmt` package provides utility wrappers for formatting text.
The Cookoo `fmt` package provides utility wrappers for formatting text.
Package log contains logging helpers.
Package log contains logging helpers.
Safely is a package for providing safety wrappers around commonly used features.
Safely is a package for providing safety wrappers around commonly used features.
web
Extra datasources for Web servers.
Extra datasources for Web servers.

Jump to

Keyboard shortcuts

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