Documentation
¶
Overview ¶
Package ganno implements java-style annotations in Go. This library includes a lexer (based on https://github.com/brainicorn/goblex) and a pluggable annotation parser.
Annotations can be written in the following formats:
@simpleAnnotation() @simplewithParam(mykey=myval) @quotedVal(somekey="my value") @multipleParams(magic="wizards", awesome="unicorns") @multipleVals(mypets=["dog", "kitty cat"])
Annotations may also be split across multiple lines:
@stuffILike( instrument="drums" ,mypets=[ "dog" ,"kitty cat" ] ,food="nutritional units" )
Although this library can be used out of the box as-is, consumer can also "plug-in" custom annotation types that can validate discovered annotations and provide strongly-type attribute accessors.
Custom Annotations and their factories can be re-used/distributed as libraries and registered with parsers at runtime.
see example below
Example ¶
package main import ( "fmt" "strconv" ) // PetAnno is a custom Annotation type for @pet() annotations type PetAnno struct { Attrs map[string][]string } func (a *PetAnno) AnnotationName() string { return "pet" } func (a *PetAnno) Attributes() map[string][]string { return a.Attrs } // HasFur is a strongly-typed accessor for the "hasfur" attribute func (a *PetAnno) Hasfur() bool { b, _ := strconv.ParseBool(a.Attrs["hasfur"][0]) return b } // Name is an accessor for the "name" attribute func (a *PetAnno) Name() string { return a.Attrs["name"][0] } // PetAnnoFactory is our custom factory that can validate @pet attributes and return new PetAnnos type PetAnnoFactory struct{} func (f *PetAnnoFactory) ValidateAndCreate(name string, attrs map[string][]string) (Annotation, error) { furs, furOk := attrs["hasfur"] _, nameOk := attrs["name"] // require the hasfur attr if !furOk { return nil, fmt.Errorf("pet annotation requires the attribute %q", "hasfur") } // require the name attr if !nameOk { return nil, fmt.Errorf("pet annotation requires the attribute %q", "name") } // make sure hasfur is a parsable boolean if _, err := strconv.ParseBool(furs[0]); err != nil { return nil, fmt.Errorf("pet annotation attribute %q must have a boolean value", "hasfur") } return &PetAnno{ Attrs: attrs, }, nil } func main() { parser := NewAnnotationParser() //register our factory parser.RegisterFactory("pet", &PetAnnoFactory{}) input := `my @pet(name="fluffy buns", hasFur=true) is soooo cute!` annos, errs := parser.Parse(input) if len(errs) > 0 { panic(errs[0]) } // get our one pet annotation and cast it to a PetAnno mypet := annos.ByName("pet")[0].(*PetAnno) fmt.Printf("%s is fluffy? %t\n", mypet.Name(), mypet.Hasfur()) }
Output: fluffy buns is fluffy? true
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Annotation ¶
type Annotation interface { // AnnotationName is the name of the annotation between the @ symbol and the (. // The value needs to be a valid ident and comparisons are case-insensitive AnnotationName() string // Attributes holds any key/value pairs inside of the (). // The map key is the (loer-cased) key found in the key/val pair. The value is a slice of strings. // The value is a slice even if the annotation has a single value to support multi-value k/v pairs. Attributes() map[string][]string }
Annotation is the interface for a single annotation instance. This is what is returned by an AnnotationFactory. Consumers can implement their own custom annotations using this interface.
Custom implementations can/should provide strongly typed accessors for their specific attributes.
type AnnotationFactory ¶
type AnnotationFactory interface { // ValidateAndCreate is caled by parsers when they find an annotation whose (lower-case) name // matches the name of the registered factory. This is the same value passed in as name to this // method which allows registering the same factory multiple times under different names. // // attrs is the map of k/v pairs found when parsing the annotation. This method should use the attrs // to validate that the annotation has all expected/required parameters. // // Any validation error should be returned as error. ValidateAndCreate(name string, attrs map[string][]string) (Annotation, error) }
AnnotationFactory is the interface consumers can implement to provide custom Annotation creation.
AnnotationFactories can be registered with the parser by name.
type AnnotationParser ¶
type AnnotationParser interface { // RegisterFactory registers an AnnotationFactory with the supplied name. The name will be // lower-case compared with the names of discovered annotations to choose the proper factory for // creation. // // If name is blank or a factory with the same name has already been registered an error will be // retured. RegisterFactory(name string, factory AnnotationFactory) error // Parse lexes all of the tokens in the input string and returns an Annotations object which holds // all of the valid discovered annotations. The annotations may be of various types/implementations // based on the registered factories and can be cast to those specific types. // // If a validation error is returned by the factory during creation, the annotation will not be // added to the Annotations and the error will be put into the returned errors slice. Parse(input string) (Annotations, []error) }
AnnotationParser is the interface for parsing a string and returning Annotations. The returned Annnotations object should be populated with Annotation objects created using the registered AnnotationFactory objects.
Consumers of this library shouldn't need to implement this interface unless they have very specific custom parsing needs.
func NewAnnotationParser ¶
func NewAnnotationParser() AnnotationParser
NewAnnotationParser creates an AnnotationParser that can be used to discover annotations.
type Annotations ¶
type Annotations interface { // All returns a slice of all found Annotation objects All() []Annotation // ByName retrieves a slice of Annotation objects whose name matches name. The name comparison // should use strings.ToLower before comparing. ByName(name string) []Annotation }
Annotations is the interface for holding the collection of annotations found during parsing. This interface provides helper methods for retrieving all annotations or annotations by name.
For the most part consumers do not need to implement this unless they implement a custom AnnotationParser and have a specific need to augment annotation retrieval.