Documentation ¶
Overview ¶
Package vebben provides form-processing helpers for web development.
The package name should be pronounced in Hungarian.
WARNING ¶
This is pre-alpha software and may change at any time.
Example ¶
package main import ( "html/template" "os" "github.com/biztos/vebben" ) func main() { dot := map[string]interface{}{ "Title": "Hello World!", "Id": "examples", "Prices": []int{ 15, 11800002, 3582, 999231, 10012, }, } var tsrc = `<h1 id="{{ .Id | capfirst }}">{{ .Title }}</h1> <h2>Top Three Prices:</h2> <ol> {{- $p := sortintsdesc .Prices | truncintsto 3 }}{{ range $p }} <li>${{ intcomma . }}</li> {{- end }} </ol> ` tmpl, err := template.New("test").Funcs(vebben.NewFuncMap()).Parse(tsrc) if err != nil { panic(err) } if err := tmpl.Execute(os.Stdout, dot); err != nil { panic(err) } }
Output: <h1 id="Examples">Hello World!</h1> <h2>Top Three Prices:</h2> <ol> <li>$11,800,002</li> <li>$999,231</li> <li>$10,012</li> </ol>
Index ¶
- Variables
- func AddFormSpecType(t string, cf func(string) (interface{}, bool), ...)
- func DecodeForm(f FormValuer, specs []*FormSpec, target interface{}) error
- func GlyphLength(s string) int
- func Indent(depth int) string
- func IntRange(a, b int) []int
- func NewFuncMap() template.FuncMap
- func PathDepth(p string) int
- func ReverseInts(ii []int) []int
- func SortInts(ii []int) []int
- func SortIntsDesc(ii []int) []int
- func TruncInts(i []int) []int
- func TruncIntsTo(t int, i []int) []int
- type FormSpec
- type FormValuer
- type MultiError
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DateFormats = []string{
"2006. 01. 02.",
"2006. 01. 02",
"2006. 1. 2.",
"2006. 1. 2",
"2006.01.02.",
"2006.01.02",
"2006.1.2.",
"2006.1.2",
"2006-01-02",
"2006-1-2",
"2006 01 02",
"2006 1 2",
"20060102",
"02.01.2006",
"2.1.2006",
"01/02/2006",
"1/2/2006",
}
DateFormats holds the date formats we accept in forms (note: not times, just dates!)
var DateTimeFormats = []string{
"2006. 01. 02. 15:04",
"2006. 01. 02 15:04",
"2006. 1. 2. 15:04",
"2006. 1. 2 15:04",
"2006.01.02. 15:04",
"2006.01.02 15:04",
"2006.1.2. 15:04",
"2006.1.2 15:04",
"2006-01-02 15:04",
"2006-1-2 15:04",
"2006 01 02 15:04",
"2006 1 2 15:04",
"20060102150405",
"02.01.2006 15:04",
"2.1.2006 15:04",
"01/02/2006 15:04",
"1/2/2006 15:04",
}
DateTimeFormats holds the datetime formats we accept in forms (note: all require times, and only to minute precision; this might change in a general library).
var DecodeFormTrimSpace = true
By default, trim space from form values.
var FormValueTimeLocation, _ = time.LoadLocation("CET")
FormValueTimeLocation is the location (time zone) used for all form input.
Functions ¶
func AddFormSpecType ¶
func AddFormSpecType(t string, cf func(string) (interface{}, bool), vf func(*FormSpec, interface{}) error)
AddFormSpecType adds or replaces FormSpec type t with converter function cf and optional default validator vf. The converter must return a type that survives JSON marshaling and unmarshaling or runtime errors will occur in DecodeForm; its bool return value is the success or failure of the conversion. Note that in many cases this is unnecessary, as the struct's final type will unmarshal from a simple string.
func DecodeForm ¶
func DecodeForm(f FormValuer, specs []*FormSpec, target interface{}) error
DecodeForm populates the target structure from the values of a submitted form (or any other FormValuer). On failure, returns an error which may be cast as a MultiError for formatting.
Q: Why this and not one of the introspection-based libraries? A: None of those examined yet would work without major changes: * gorilla schema doesn't handle times * ajg/form is close but doesn't do times at locations, nor any validation * vala (with form) would almost work but is stubbornly non-idiomatic
Values are whitespace-trimmed before any processing occurs, unless DecodeFormTrimSpace is set to false.
Missing form fields are treated as the zero value unless they are required. Unhandled fields are ignored. Bad spec entries result in a panic.
Optional empty fields are converted to the zero value for the type.
Yes, this is messy, but whatchagonnado?
Example ¶
package main import ( "fmt" "net/http" "github.com/biztos/vebben" ) func main() { type ExampleFoo struct { Foo string `json:"foo"` Bar int `json:"bar"` } specs := []*vebben.FormSpec{ vebben.RequiredFormSpec("foo", "string", "6", "Foo"), vebben.RequiredFormSpec("bar", "int", "0-100", "Bar Percentage"), } target := &ExampleFoo{} // A validation failure: r, _ := http.NewRequest("GET", "/example?foo=bar", nil) err := vebben.DecodeForm(r, specs, target) if err != nil { fmt.Println(err.Error()) } // And a success: r2, _ := http.NewRequest("GET", "/example?foo=Bärfuß&bar=23", nil) err = vebben.DecodeForm(r2, specs, target) if err != nil { fmt.Println(err.Error()) } fmt.Println(target.Foo, target.Bar) }
Output: Foo has the wrong length Bar Percentage is required Bärfuß 23
func GlyphLength ¶
GlyphLength returns the number of NFKD-normalized Unicode glyphs in a utf-8 enconded string. For more information see here: http://unicode.org/reports/tr15/#Norm_Forms and here: http://stackoverflow.com/a/12668840
fmt.Println(GylphLength("műemlék")) // prints 7
This is used in DecodeForm but is also handy for length-checking any international input.
DEPRECATION WARNING ¶
It appears at first glance that one gets exactly the same result from this, which is presumably much faster:
len([]rune(s))
If that turns out to be the case, GlyphLength will be deprecated at some point. (Per the stackoverflow link above it's not, but the evidence given might no longer hold.)
func NewFuncMap ¶
NewFuncMap returns a function map containing all the available functions, mapped to names as shown below. This should be included in a template, usually the master template, as:
fm := vebben.NewFuncMap() tmpl, err := template.New("").Funcs(fm).Parse(MyTemplateData)
Functions Defined Here ¶
These correspond to the exported function names. By convention(?) the map keys, i.e. the function names called in the template, are lowercased.
truncints truncintsto sortints sortintsasc sortintsdesc reverseints intrange pathdepth indent
Functions From Kyoung-chan Lee's Gtf ¶
See https://github.com/leekchan/gtf for documentation.
replace default length lower upper truncatechars urlencode wordcount divisibleby lengthis trim capfirst pluralize yesno rjust ljust center filesizeformat apnumber intcomma ordinal first last join slice random striptags
func PathDepth ¶
PathDepth returns the depth of a cleaned URL path (or similar string), i.e. the number of slashes it contains.
func ReverseInts ¶
ReverseInts returns a copy of the input slice in reverse order, i.e. the opposite of the given order.
func SortIntsDesc ¶
SortIntsDesc returns a reverse-sorted (Descending) copy of a slice of integers.
func TruncIntsTo ¶
TruncIntsTo returns a slice of the input slice with a maximum of t elements. If t is negative, truncates to len(i) - t. Note the argument order: this is to facilitate piping in the template:
{{ $r := .SomeIntSlice | truncintsto 5 }}
Types ¶
type FormSpec ¶
type FormSpec struct { Key string Type string Required bool Limit string Name string Validator func(*FormSpec, interface{}) error // contains filtered or unexported fields }
FormSpec defines a single specification item for validating a form value corresponding to Key. It is used by DecodeForm.
Valid Type values include:
"string" // plain string "int" // int, max 32 bits large "int64" // int64 "float" // float64 "bool" // bool: input must be "true" or "false" if required "date" // date, without time part; see below. "datetime" // date, with time part; see below. "dateflex" // date, with or without time part; see below.
This list can be extended using the AddFormSpecType function.
The Limit describes a validation check, and may be left as an empty string. Limits include:
"123" // length (strings, int, int64) "1-10" // allowed range of value (numeric) or length (string) "a,b,c" // list of simple string values accepted "1,3,5" // list of simple numeric values accepted "re:^\w\d+$" // regular expression (strings only)
Note that the Limit is only processed during the Init phase. If Init is not called, the Validator should enforce any custom limits.
The optional Name is used in formatting error messages that may be shown to the user, e.g. "<Name> is out of range."
Dates are valid in any format listed under DateFormats; DateTimes use those in DateTimeFormat; DateFlex use both.
The Validator function is called with the FormSpec itself and the type-converted value (cf. Convert). Standard Validator functions are set by Init if no Validator exists when it is called.
func NewFormSpec ¶
NewFormSpec returns a pointer to an initialized FormSpec that is ready for use and whose Required property is set to r. The final two arguments, limit and name, may be omitted. If the spec is not understood, the function panics.
func OptionalFormSpec ¶
OptionalFormSpec returns a pointer to an initialized FormSpec that is ready for use, and whose Required property is false, with key k, type t and the provided limit and name. The latter two may be omitted.
func RequiredFormSpec ¶
RequiredFormSpec returns a pointer to a validated FormSpec that is ready for use, and whose Required property is true, with key k, type t and the provided limit and name. The latter two may be omitted. If the spec is not understood, the function panics.
func (*FormSpec) Convert ¶
Convert converts raw to the type indicated in the FormSpec's Type property, returning an error if it can not be converted. If there is no error then the returned value is safe to pass to a standard Validator function.
func (*FormSpec) Copy ¶
Copy returns a copy of the FormSpec with a new Key and Name. The Key must not be an empty or whitespace-only string (it is whitespace-trimmed); the Name defaults to the Key. Init is not called on the new object, as the source state is preserved.
Use this to more efficiently create many functionally identical spec items, e.g. required-string validators.
type FormValuer ¶
FormValuer is implemented by http.Request, and also in the unit tests for this package. It may also be useful for overriding the standard, permissive form parsing behavior in net/http.
type MultiError ¶
type MultiError struct {
Errors []error
}
MultiError is a type of error that contains a slice of errors. In the standard Error method they are joined with a newline, but if cast to type the errors may be examined (or formatted) individually.
func (*MultiError) Error ¶
func (e *MultiError) Error() string
Error implements the error interface for MultiError.