tfortools

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 7, 2021 License: Apache-2.0 Imports: 15 Imported by: 8

README

Templates for Tools

Go Report Card GoDoc

Package tfortools provides a set of functions that are designed to make it easier for developers to add template based scripting to their command line tools.

Command line tools written in Go often allow users to specify a template script to tailor the output of the tool to their specific needs. This can be useful both when visually inspecting the data and also when invoking command line tools in scripts. The best example of this is go list which allows users to pass a template script to extract interesting information about Go packages. For example,

go list -f '{{range .Imports}}{{println .}}{{end}}'

prints all the imports of the current package.

The aim of this package is to make it easier for developers to add template scripting support to their tools and easier for users of these tools to extract the information they need. It does this by augmenting the templating language provided by the standard library package text/template in two ways:

  1. It auto generates descriptions of the data structures passed as input to a template script for use in help messages. This ensures that help usage information is always up to date with the source code.

  2. It provides a suite of convenience functions to make it easy for script writers to extract the data they need. There are functions for sorting, selecting rows and columns and generating nicely formatted tables.

For example, if a program passed a slice of structs containing stock data to a template script, we could use the following script to extract the names of the 3 stocks with the highest trade volume.

{{table (cols (head (sort . "Volume" "dsc") 3) "Name" "Volume")}}

The output might look something like this:

Name              Volume
Happy Enterprises 6395624278
Big Company       7500000
Medium Company    300122

The functions head, sort, tables and col are provided by this package.

Documentation

Overview

Package tfortools provides a set of functions that are designed to make it easier for developers to add template based scripting to their command line tools.

Command line tools written in Go often allow users to specify a template script to tailor the output of the tool to their specific needs. This can be useful both when visually inspecting the data and also when invoking command line tools in scripts. The best example of this is go list which allows users to pass a template script to extract interesting information about Go packages. For example,

go list -f '{{range .Imports}}{{println .}}{{end}}'

prints all the imports of the current package.

The aim of this package is to make it easier for developers to add template scripting support to their tools and easier for users of these tools to extract the information they need. It does this by augmenting the templating language provided by the standard library package text/template in two ways:

1. It auto generates descriptions of the data structures passed as input to a template script for use in help messages. This ensures that help usage information is always up to date with the source code.

2. It provides a suite of convenience functions to make it easy for script writers to extract the data they need. There are functions for sorting, selecting rows and columns and generating nicely formatted tables.

For example, if a program passed a slice of structs containing stock data to a template script, we could use the following script to extract the names of the 3 stocks with the highest trade volume.

{{table (cols (head (sort . "Volume" "dsc") 3) "Name" "Volume")}}

The output might look something like this:

Name              Volume
Happy Enterprises 6395624278
Big Company       7500000
Medium Company    300122

The functions head, sort, tables and col are provided by this package.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CreateTemplate

func CreateTemplate(name, tmplSrc string, cfg *Config) (*template.Template, error)

CreateTemplate creates a new template, whose source is contained within the tmplSrc parameter and whose name is given by the name parameter. The functions enabled in the cfg parameter will be made available to the template source code specified in tmplSrc. If cfg is nil, all the additional functions provided by tfortools will be enabled.

func GenerateUsageDecorated

func GenerateUsageDecorated(flag string, i interface{}, cfg *Config) string

GenerateUsageDecorated is similar to GenerateUsageUndecorated with the exception that it outputs the usage information for all the new functions enabled in the Config object cfg. If cfg is nil, help information is printed for all new template functions defined by this package.

Example
cfg := NewConfig(OptCols)
help := GenerateUsageDecorated("-f", []struct{ X, Y int }{}, cfg)
fmt.Println(help)
Output:

The template passed to the --f option operates on a

[]struct {
	X int
	Y int
}

Some new functions have been added to Go's template language

- 'cols' can be used to extract certain columns from a table consisting of a
  slice or array of structs.  It returns a new slice of structs which contain
  only the fields requested by the caller.   For example, given a slice of structs

  {{cols . "Name" "Address"}}

  returns a new slice of structs, each element of which is a structure with only
  two fields, 'Name' and 'Address'.

func GenerateUsageUndecorated

func GenerateUsageUndecorated(i interface{}) string

GenerateUsageUndecorated returns a formatted string identifying the elements of the type of object i that can be accessed from inside a template. Unexported struct values and channels are not output as they cannot be usefully accessed inside a template.

The output produced by GenerateUsageUndecorated preserves structure tags. There is one special case however. Tags with a key of "tfortools" are output as comments at the end of the line containing the field, rather than as tags. This tag can be used to document your structures.

Example
i := struct {
	X       int    `tfortools:"This is an int"`
	Y       string `json:"omitempty" tfortools:"This is a string"`
	hidden  float64
	Invalid chan int
}{}
help := GenerateUsageUndecorated(i)
fmt.Println(help)
Output:

struct {
	X int    // This is an int
	Y string `json:"omitempty"` // This is a string
}

func OptAllFilters

func OptAllFilters(c *Config)

OptAllFilters is a convenience function that enables the following functions; 'filter', 'filterContains', 'filterHasPrefix', 'filterHasSuffix', 'filterFolded', and 'filterRegexp'

func OptAllFns

func OptAllFns(c *Config)

OptAllFns enables all template extension functions provided by this package

func OptCols

func OptCols(c *Config)

OptCols indicates that the 'cols' function should be enabled. 'cols' can be used to extract certain columns from a table consisting of a slice or array of structs. It returns a new slice of structs which contain only the fields requested by the caller. For example, given a slice of structs

{{cols . "Name" "Address"}}

returns a new slice of structs, each element of which is a structure with only two fields, 'Name' and 'Address'.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the first and last names of people in a nicely formatted table
script := `{{tablex (cols . "FirstName" "Surname") 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

// Normally you would pass os.Stdout directly into OutputToTemplate.  Here
// we're outputting the result of the running the script to a buffer.  We need
// to do this so we can remove the whitespace at the end of each line of the
// table.  The test fails with the newline present as go tests implementation
// of output: for examples, trims spaces.

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName   Surname
Marcus      Cicero
Gaius       Caesar
Marcus      Crassus

func OptDescribe

func OptDescribe(c *Config)

OptDescribe indicates that the 'describe' function should be enabled. 'describe' takes a single argument and outputs a description of the type of that argument. It can be useful if the type of the object operated on by a template program is not described in the help of the tool that executes the template.

{{describe . }}

outputs a description of the type of '.'.

Example
data := []struct{ FirstName, MiddleName, Surname string }{}

// Describe the type of data
script := `{{describe .}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

[]struct {
	FirstName  string
	MiddleName string
	Surname    string
}

func OptFilter

func OptFilter(c *Config)

OptFilter indicates that the filter function should be enabled. 'filter' operates on an slice or array of structures. It allows the caller to filter the input array based on the value of a single field. The function returns a slice containing only the objects that satisfy the filter, e.g.

{{len (filter . "Protected" "true")}}

outputs the number of elements whose "Protected" field is equal to "true".

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print the surname of all people whose first name is Marcus
script := `{{range (filter . "FirstName" "Marcus")}}{{println .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Cicero
Crassus

func OptFilterContains

func OptFilterContains(c *Config)

OptFilterContains indicates that the filterContains function should be enabled. 'filterContains' operates along the same lines as filter, but returns substring matches

{{len(filterContains . "Name" "Cloud"}})

outputs the number of elements whose "Name" field contains the word "Cloud".

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Count the number of people whose middle name contains a 'ul'
script := `{{len (filterContains . "MiddleName" "ul")}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

2

func OptFilterFolded

func OptFilterFolded(c *Config)

OptFilterFolded indicates that the filterFolded function should be enabled. 'filterFolded' is similar to filter, but returns matches based on equality under Unicode case-folding.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the first and surnames of all people whose first name is marcus
script := `{{range (filterFolded . "FirstName" "marcus")}}{{println .FirstName .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Marcus Cicero
Marcus Crassus

func OptFilterHasPrefix

func OptFilterHasPrefix(c *Config)

OptFilterHasPrefix indicates that the filterHasPrefix function should be enabled. 'filterHasPrefix' is similar to filter, but returns prefix matches.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print all the surnames that start with 'Ci'
script := `{{select (filterHasPrefix . "Surname" "Ci") "Surname"}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Cicero

func OptFilterHasSuffix

func OptFilterHasSuffix(c *Config)

OptFilterHasSuffix indicates that the filterHasSuffix function should be enabled. 'filterHasSuffix' is similar to filter, but returns suffix matches.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print all the surnames that end with 'us'
script := `{{select (filterHasSuffix . "Surname" "us") "Surname"}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Crassus

func OptFilterRegexp

func OptFilterRegexp(c *Config)

OptFilterRegexp indicates that the filterRegexp function should be enabled. 'filterRegexp' is similar to filter, but returns matches based on regular expression matching

{{len (filterRegexp . "Name" "^Docker[ a-zA-z]*latest$"}})

outputs the number of elements whose "Name" field have 'Docker' as a prefix and 'latest' as a suffix in their name.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the first and last names of all people whose middle name ends in 'ius' and whose
// second letter is 'u'
script := `{{range (filterRegexp . "MiddleName" "^.u.*ius$")}}{{println .FirstName .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Marcus Cicero
Gaius Caesar

func OptHTable added in v0.2.0

func OptHTable(c *Config)

OptHTable indicates that the 'htable' function should be enabled. 'htable' outputs each element of an array or a slice of structs in its own two column table. The values for the first column are taken from the names of the structs' fields. The second column contains the field values. Hidden fields and fields of type channel are ignored. The tabwidth and minimum column width are hardcoded to 8. An example of htable's usage is

{{htable .}}

func OptHTableAlt added in v0.2.0

func OptHTableAlt(c *Config)

OptHTableAlt indicates that the 'htablealt' function should be enabled. 'htablealt' Similar to table except that objects are formatted using %#v

func OptHTableX added in v0.2.0

func OptHTableX(c *Config)

OptHTableX indicates that the 'htablex' function should be enabled. 'htablex' is similar to htable but it allows the caller more control over the tables' appearances. Users can control the names displayed in the first column and also set the tab and column width. 'htablex' takes 4 or more parameters. The first parameter is the slice of structs to output, the second is the minimum column width, the third the tab width and the fourth is the padding. The fifth and subsequent parameters are the values displayed in the first column of each table. These first column values are optional and the field names of the structures will be used if they are absent. Example of its usage are:

{{htablex . 12 8 1 "Field 1" "Field 2"}}
{{htablex . 8 8 1}}
Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the names of people in a series of nicely formatted tables
script := `{{htablex . 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName:  Marcus
MiddleName: Tullius
Surname:    Cicero

FirstName:  Gaius
MiddleName: Julius
Surname:    Caesar

FirstName:  Marcus
MiddleName: Licinius
Surname:    Crassus

func OptHTableXAlt added in v0.2.0

func OptHTableXAlt(c *Config)

OptHTableXAlt indicates that the 'htablexalt' function should be enabled. 'htablexalt' Similar to htablex except that objects are formatted using %#v

Example
data := []struct {
	FirstName string
	Mask      uint32
}{
	{"Marcus", 255},
	{"Gaius", 10},
	{"Marcus", 6},
}

script := `{{htablexalt . 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName:  "Marcus"
Mask:       0xff

FirstName:  "Gaius"
Mask:       0xa

FirstName:  "Marcus"
Mask:       0x6

func OptHead

func OptHead(c *Config)

OptHead indicates that the 'head' function should be enabled. 'head' operates on a slice or an array, returning the first n elements of that array as a new slice. If n is not provided, a slice containing the first element of the input slice is returned. For example,

{{ head .}}

returns a single element slice containing the first element of '.' and

{{ head . 3}}

returns a slice containing the first three elements of '.'. If '.' contains only 2 elements the slice returned by

{{ head . 3}}

would be identical to the input slice.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print the surname of the first person in the database
script := `{{range (head .)}}{{println .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Cicero

func OptPromote

func OptPromote(c *Config)

OptPromote indicates that the 'promote' function should be enabled. 'promote' takes two arguments, a slice or an array of structures and a field path. It returns a new slice containing only the objects identified by the field path. The field path is a period separated list of structure field names. Promote can be useful to extract a set of objects deep within a data structure into a new slice that can be passed to other functions, e.g., table. For example, given the following type

[]struct {
    uninteresting int
    user struct {
        credentials struct {
            name string
            password string
        }
    }
}

{{promote . "user.credentials"}}

returns a slice of credentials one for each element of the original top level slice.

Example
type cred struct {
	Name     string
	Password string
}

type u struct {
	Credentials cred
}

data := []struct {
	Uninteresting int
	User          u
}{
	{0, u{cred{"Marcus", "1234"}}},
	{0, u{cred{"Gaius", "0000"}}},
}

// Create a new []cred containing the credentials embedded within data,
// iterate through this new slice printing out the names and passwords.
// The cred instances rooted at "User.Credentials" in the data object
// are promoted to the top level in the new slice.
script := `{{range (promote . "User.Credentials")}}{{printf "%s %s\n" .Name .Password}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Marcus 1234
Gaius 0000

func OptRows

func OptRows(c *Config)

OptRows indicates that the 'rows' function should be enabled. 'rows' is used to extract a set of given rows from a slice or an array. It takes at least two parameters. The first is the slice on which to operate. All subsequent parameters must be integers that correspond to a row in the input slice. Indicies that refer to non-existent rows are ignored. For example:

{{rows . 1 2}}

extracts the 2nd and 3rd rows from the slice represented by '.'.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print the surname of the first and third people in the database
script := `{{range (rows . 0 2)}}{{println .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Cicero
Crassus

func OptSelect

func OptSelect(c *Config)

OptSelect indicates that the 'select' function should be enabled. 'select' operates on a slice of structs. It outputs the value of a specified field for each struct on a new line , e.g.,

{{select . "Name"}}

prints the 'Name' field of each structure in the slice.

func OptSelectAlt

func OptSelectAlt(c *Config)

OptSelectAlt indicates that the 'selectalt' function should be enabled. 'selectalt' Similar to select except that objects are formatted using %#v

Example
data := []struct{ Integer uint32 }{{255}}
script := `{{selectalt . "Integer"}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

0xff

func OptSliceof

func OptSliceof(c *Config)

OptSliceof indicates that the 'sliceof' function should be enabled. 'sliceof' takes one argument and returns a new slice containing only that argument.

Example
script := `{{index (sliceof .) 0}}`
if err := OutputToTemplate(os.Stdout, "names", script, 1, nil); err != nil {
	panic(err)
}
Output:

1

func OptSort

func OptSort(c *Config)

OptSort indicates that the 'sort' function should be enabled. 'sort' sorts a slice or an array of structs. It takes three parameters. The first is the slice; the second is the name of the structure field by which to 'sort'; the third provides the direction of the 'sort'. The third parameter is optional. If provided, it must be either "asc" or "dsc". If omitted the elements of the slice are sorted in ascending order. The type of the second field can be a number or a string. When presented with another type, 'sort' will try to sort the elements by the string representation of the chosen field. The following example sorts a slice in ascending order by the Name field.

{{sort . "Name"}}
Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the names of people sorted by their Surnames
script := `{{tablex (sort . "Surname") 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

// Normally you would pass os.Stdout directly into OutputToTemplate.  Here
// we're outputting the result of the running the script to a buffer.  We need
// to do this so we can remove the whitespace at the end of each line of the
// table.  The test fails with the newline present as go tests implementation
// of output: for examples, trims spaces.

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName   MiddleName  Surname
Gaius       Julius      Caesar
Marcus      Tullius     Cicero
Marcus      Licinius    Crassus

func OptTable

func OptTable(c *Config)

OptTable indicates that the 'table' function should be enabled. 'table' outputs a table given an array or a slice of structs. The table headings are taken from the names of the structs fields. Hidden fields and fields of type channel are ignored. The tabwidth and minimum column width are hardcoded to 8. An example of table's usage is

{{table .}}

func OptTableAlt

func OptTableAlt(c *Config)

OptTableAlt indicates that the 'tablealt' function should be enabled. 'tablealt' Similar to table except that objects are formatted using %#v

func OptTableX

func OptTableX(c *Config)

OptTableX indicates that the 'tablex' function should be enabled. 'tablex' is similar to table but it allows the caller more control over the table's appearance. Users can control the names of the headings and also set the tab and column width. 'tablex' takes 4 or more parameters. The first parameter is the slice of structs to output, the second is the minimum column width, the third the tab width and the fourth is the padding. The fifth and subsequent parameters are the names of the column headings. The column headings are optional and the field names of the structure will be used if they are absent. Example of its usage are:

{{tablex . 12 8 1 "Column 1" "Column 2"}}
{{tablex . 8 8 1}}
Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Output the names of people in a nicely formatted table
script := `{{tablex . 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

// Normally you would pass os.Stdout directly into OutputToTemplate.  Here
// we're outputting the result of the running the script to a buffer.  We need
// to do this so we can remove the whitespace at the end of each line of the
// table.  The test fails with the newline present as go tests implementation
// of output: for examples, trims spaces.

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName   MiddleName  Surname
Marcus      Tullius     Cicero
Gaius       Julius      Caesar
Marcus      Licinius    Crassus

func OptTableXAlt

func OptTableXAlt(c *Config)

OptTableXAlt indicates that the 'tablexalt' function should be enabled. 'tablexalt' Similar to tablex except that objects are formatted using %#v

Example
data := []struct {
	FirstName string
	Mask      uint32
}{
	{"Marcus", 255},
	{"Gaius", 10},
	{"Marcus", 6},
}

script := `{{tablexalt . 12 8 0}}`
var b bytes.Buffer
if err := OutputToTemplate(&b, "names", script, data, nil); err != nil {
	panic(err)
}

scanner := bufio.NewScanner(&b)
for scanner.Scan() {
	fmt.Println(strings.TrimSpace(scanner.Text()))
}
Output:

FirstName   Mask
"Marcus"    0xff
"Gaius"     0xa
"Marcus"    0x6

func OptTail

func OptTail(c *Config)

OptTail indicates that the 'tail' function should be enabled. 'tail' is similar to head except that it returns a slice containing the last n elements of the input slice. For example,

{{tail . 2}}

returns a new slice containing the last two elements of '.'.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// Print the surname of the first person in the database
script := `{{range (tail .)}}{{println .Surname}}{{end}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Crassus

func OptToCSV added in v0.2.0

func OptToCSV(c *Config)

OptToCSV indicates that the 'tocsv' function should be enabled. 'tocsv' converts a [][]string or a slice of structs to csv format, e.g., {{tocsv .}}

'tocsv' takes an optional boolean parameter, which if true, omits the first row containing the structure field name derived column headings. This boolean parameter defaults to false and is ignored when operating on a [][]string.

func OptToJSON

func OptToJSON(c *Config)

OptToJSON indicates that the 'tosjon' function should be enabled. 'tojson' outputs the target object in json format, e.g., {{tojson .}}

Example
data := []struct {
	Name       string
	AgeAtDeath int
	Battles    []string
}{
	{"Caesar", 55, []string{"Battle of Alesia", "Battle of Dyrrhachium", "Battle of the Nile"}},
	{"Alexander", 32, []string{"Battle of Issus", "Battle of Gaugamela", "Battle of the Hydaspes"}},
}

script := `{{tojson .}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

[
	{
		"Name": "Caesar",
		"AgeAtDeath": 55,
		"Battles": [
			"Battle of Alesia",
			"Battle of Dyrrhachium",
			"Battle of the Nile"
		]
	},
	{
		"Name": "Alexander",
		"AgeAtDeath": 32,
		"Battles": [
			"Battle of Issus",
			"Battle of Gaugamela",
			"Battle of the Hydaspes"
		]
	}
]

func OptToTable added in v0.2.0

func OptToTable(c *Config)

OptToTable indicates that the 'totable' function should be enabled. 'totable' takes a slice of a slice of strings as an argument and returns a slice of structures. The field names of the structures are taken from the values of the first row in the slice. The types of the fields are derived from the values specified in the second row. The input slice should be of length 2 or greater. Data in columns in the second and subsequent rows should be homogenous. The elements of the first row should be unique and ideally be valid exported variable names. 'totable' will try to sanitize the field names, if they are not valid go identifiers.

Example
data := [][]string{
	{"Message", "Code", "Occurrence"},
	{"Too many GOSUBs", "37", "0.1"},
	{"Too many REPEATs", "44", "0.15"},
}
script := `{{with (totable .)}}{{select . "Message"}}{{select . "Code"}}{{select . "Occurrence"}}{{end}}`
if err := OutputToTemplate(os.Stdout, "errors", script, data, nil); err != nil {
	panic(err)
}
Output:

Too many GOSUBs
Too many REPEATs
37
44
0.1
0.15

func OutputToTemplate

func OutputToTemplate(w io.Writer, name, tmplSrc string, obj interface{}, cfg *Config) (err error)

OutputToTemplate executes the template, whose source is contained within the tmplSrc parameter, on the object obj. The name of the template is given by the name parameter. The results of the execution are output to w. The functions enabled in the cfg parameter will be made available to the template source code specified in tmplSrc. If cfg is nil, all the additional functions provided by tfortools will be enabled.

Example
data := []struct{ FirstName, MiddleName, Surname string }{
	{"Marcus", "Tullius", "Cicero"},
	{"Gaius", "Julius", "Caesar"},
	{"Marcus", "Licinius", "Crassus"},
}

// print the surname of the person whose middlename is lexographically smallest.
script := `{{select (head (sort . "MiddleName")) "Surname"}}`
if err := OutputToTemplate(os.Stdout, "names", script, data, nil); err != nil {
	panic(err)
}
Output:

Caesar

func TemplateFunctionHelp

func TemplateFunctionHelp(c *Config) string

TemplateFunctionHelp generates formatted documentation that describes the additional functions that the Config object c adds to Go's templating language. If c is nil, documentation is generated for all functions provided by tfortools.

func TemplateFunctionHelpSingle

func TemplateFunctionHelpSingle(name string, c *Config) (string, error)

TemplateFunctionHelpSingle returns help for a single function specified by name. An error is returned if the function cannot be found.

Example
cfg := NewConfig(OptCols, OptRows)
err := cfg.AddCustomFn(strings.TrimSpace, "trim",
	"- trim trims leading and trailing whitespace from string")
if err != nil {
	panic(err)
}
help, err := TemplateFunctionHelpSingle("cols", cfg)
if err != nil {
	panic(err)
}
fmt.Println(help)

help, err = TemplateFunctionHelpSingle("trim", cfg)
if err != nil {
	panic(err)
}
fmt.Println(help)
Output:

- 'cols' can be used to extract certain columns from a table consisting of a
  slice or array of structs.  It returns a new slice of structs which contain
  only the fields requested by the caller.   For example, given a slice of structs

  {{cols . "Name" "Address"}}

  returns a new slice of structs, each element of which is a structure with only
  two fields, 'Name' and 'Address'.

- trim trims leading and trailing whitespace from string

func TemplateFunctionNames

func TemplateFunctionNames(c *Config) []string

TemplateFunctionNames returns a slice of all the functions enabled in the supplied Config object.

Example
cfg := NewConfig(OptCols, OptRows)
err := cfg.AddCustomFn(strings.TrimSpace, "trim",
	"- trim trims leading and trailing whitespace from string")
if err != nil {
	panic(err)
}
for _, fn := range TemplateFunctionNames(cfg) {
	fmt.Println(fn)
}
Output:

cols
rows
trim

Types

type Config

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

Config is used to specify which functions should be added Go's template language. It's not necessary to create a Config option. Nil can be passed to all tfortools functions that take a Context object indicating the default behaviour is desired. However, if you wish to restrict the number of functions added to Go's template language or you want to add your own functions, you'll need to create a Config object. This can be done using the NewConfig function.

All members of Config are private.

func NewConfig

func NewConfig(options ...func(*Config)) *Config

NewConfig creates a new Config object that can be passed to other functions in this package. The Config option keeps track of which new functions are added to Go's template libray. If this function is called without arguments, none of the functions defined in this package are enabled in the resulting Config object. To control which functions get added specify some options, e.g.,

ctx := tfortools.NewConfig(tfortools.OptHead, tfortools.OptTail)

creates a new Config object that enables the 'head' and 'tail' functions only.

To add all the functions, use the OptAllFNs options, e.g.,

ctx := tfortools.NewConfig(tfortools.OptAllFNs)

func (*Config) AddCustomFn

func (c *Config) AddCustomFn(fn interface{}, name, helpText string) error

AddCustomFn adds a custom function to the template language understood by tfortools.CreateTemplate and tfortools.OutputToTemplate. The function implementation is provided by fn, its name, i.e., the name used to invoke the function in a program, is provided by name and the help for the function is provided by helpText. An error will be returned if a function with the same name is already associated with this Config object.

Example
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
cfg := NewConfig(OptAllFns)
err := cfg.AddCustomFn(func(n []int) int {
	sum := 0
	for _, num := range n {
		sum += num
	}
	return sum
}, "sum", "- sum \"Returns\" the sum of a slice of integers")
if err != nil {
	panic(err)
}

// Print the sum of a slice of numbers
script := `{{println (sum .)}}`
if err = OutputToTemplate(os.Stdout, "sums", script, nums, cfg); err != nil {
	panic(err)
}
Output:

55

func (*Config) Len

func (c *Config) Len() int

func (*Config) Less

func (c *Config) Less(i, j int) bool

func (*Config) Swap

func (c *Config) Swap(i, j int)

Notes

Bugs

  • Map to slice

Directories

Path Synopsis
_talks
examples
csv

Jump to

Keyboard shortcuts

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