Package generator defines an interface for code generators to implement.

    To use this package, you'll implement the "Package" and "Generator" interfaces; you'll call NewContext to load up the types you want to work with, and then you'll call one or more of the Execute methods. See the interface definitions for explanations. All output will have gofmt called on it automatically, so you do not need to worry about generating correct indentation.

    This package also exposes SnippetWriter. SnippetWriter reduces to a minimum the boilerplate involved in setting up a template from go's text/template package. Additionally, all naming systems in the Context will be added as functions to the parsed template, so that they can be called directly from your templates!



    View Source
    const (
    	GolangFileType = "golang"


    This section is empty.


    func NewImportTracker

    func NewImportTracker(typesToAdd ...*types.Type) namer.ImportTracker


    type Args

    type Args map[interface{}]interface{}

      Args exists to make it convenient to construct arguments for SnippetWriter.Do.

      func (Args) With

      func (a Args) With(key, value interface{}) Args

        With makes a copy of a and adds the given key, value pair.

        func (Args) WithArgs

        func (a Args) WithArgs(rhs Args) Args

          WithArgs makes a copy of a and adds the given arguments.

          type Context

          type Context struct {
          	// A map from the naming system to the names for that system. E.g., you
          	// might have public names and several private naming systems.
          	Namers namer.NameSystems
          	// All the types, in case you want to look up something.
          	Universe types.Universe
          	// All the user-specified packages.  This is after recursive expansion.
          	Inputs []string
          	// The canonical ordering of the types (will be filtered by both the
          	// Package's and Generator's Filter methods).
          	Order []*types.Type
          	// A set of types this context can process. If this is empty or nil,
          	// the default "golang" filetype will be provided.
          	FileTypes map[string]FileType
          	// If true, Execute* calls will just verify that the existing output is
          	// correct. (You may set this after calling NewContext.)
          	Verify bool
          	// contains filtered or unexported fields

            Context is global context for individual generators to consume.

            func NewContext

            func NewContext(b *parser.Builder, nameSystems namer.NameSystems, canonicalOrderName string) (*Context, error)

              NewContext generates a context from the given builder, naming systems, and the naming system you wish to construct the canonical ordering from.

              func (*Context) AddDir

              func (ctxt *Context) AddDir(path string) error

                AddDir adds a Go package to the context. The specified path must be a single go package import path. GOPATH, GOROOT, and the location of your go binary (`which go`) will all be searched, in the normal Go fashion. Deprecated. Please use AddDirectory.

                func (*Context) AddDirectory

                func (ctxt *Context) AddDirectory(path string) (*types.Package, error)

                  AddDirectory adds a Go package to the context. The specified path must be a single go package import path. GOPATH, GOROOT, and the location of your go binary (`which go`) will all be searched, in the normal Go fashion.

                  func (*Context) ExecutePackage

                  func (c *Context) ExecutePackage(outDir string, p Package) error

                    ExecutePackage executes a single package. 'outDir' is the base directory in which to place the package; it should be a physical path on disk, not an import path. e.g.: '/path/to/home/path/to/gopath/src/' The package knows its import path already, this will be appended to 'outDir'.

                    func (*Context) ExecutePackages

                    func (c *Context) ExecutePackages(outDir string, packages Packages) error

                      ExecutePackages runs the generators for every package in 'packages'. 'outDir' is the base directory in which to place all the generated packages; it should be a physical path on disk, not an import path. e.g.: /path/to/home/path/to/gopath/src/ Each package has its import path already, this will be appended to 'outDir'.

                      func (*Context) IncomingImports

                      func (ctxt *Context) IncomingImports() map[string][]string

                        IncomingImports returns the incoming imports for each package. The map is lazily computed.

                        func (*Context) TransitiveIncomingImports

                        func (ctxt *Context) TransitiveIncomingImports() map[string][]string

                          TransitiveIncomingImports returns the transitive closure of the incoming imports for each package. The map is lazily computed.

                          type DefaultFileType

                          type DefaultFileType struct {
                          	Format   func([]byte) ([]byte, error)
                          	Assemble func(io.Writer, *File)

                          func NewGolangFile

                          func NewGolangFile() *DefaultFileType

                          func (DefaultFileType) AssembleFile

                          func (ft DefaultFileType) AssembleFile(f *File, pathname string) error

                          func (DefaultFileType) VerifyFile

                          func (ft DefaultFileType) VerifyFile(f *File, pathname string) error

                          type DefaultGen

                          type DefaultGen struct {
                          	// OptionalName, if present, will be used for the generator's name, and
                          	// the filename (with ".go" appended).
                          	OptionalName string
                          	// OptionalBody, if present, will be used as the return from the "Init"
                          	// method. This causes it to be static content for the entire file if
                          	// no other generator touches the file.
                          	OptionalBody []byte

                            DefaultGen implements a do-nothing Generator.

                            It can be used to implement static content files.

                            func (DefaultGen) FileType

                            func (d DefaultGen) FileType() string

                            func (DefaultGen) Filename

                            func (d DefaultGen) Filename() string

                            func (DefaultGen) Filter

                            func (d DefaultGen) Filter(*Context, *types.Type) bool

                            func (DefaultGen) Finalize

                            func (d DefaultGen) Finalize(*Context, io.Writer) error

                            func (DefaultGen) GenerateType

                            func (d DefaultGen) GenerateType(*Context, *types.Type, io.Writer) error

                            func (DefaultGen) Imports

                            func (d DefaultGen) Imports(*Context) []string

                            func (DefaultGen) Init

                            func (d DefaultGen) Init(c *Context, w io.Writer) error

                            func (DefaultGen) Name

                            func (d DefaultGen) Name() string

                            func (DefaultGen) Namers

                            func (d DefaultGen) Namers(*Context) namer.NameSystems

                            func (DefaultGen) PackageConsts

                            func (d DefaultGen) PackageConsts(*Context) []string

                            func (DefaultGen) PackageVars

                            func (d DefaultGen) PackageVars(*Context) []string

                            type DefaultPackage

                            type DefaultPackage struct {
                            	// Short name of package, used in the "package xxxx" line.
                            	PackageName string
                            	// Import path of the package, and the location on disk of the package.
                            	PackagePath string
                            	// The location of the package on disk.
                            	Source string
                            	// Emitted at the top of every file.
                            	HeaderText []byte
                            	// Emitted only for a "doc.go" file; appended to the HeaderText for
                            	// that file.
                            	PackageDocumentation []byte
                            	// If non-nil, will be called on "Generators"; otherwise, the static
                            	// list will be used. So you should set only one of these two fields.
                            	GeneratorFunc func(*Context) []Generator
                            	GeneratorList []Generator
                            	// Optional; filters the types exposed to the generators.
                            	FilterFunc func(*Context, *types.Type) bool

                              DefaultPackage contains a default implementation of Package.

                              func (*DefaultPackage) Filter

                              func (d *DefaultPackage) Filter(c *Context, t *types.Type) bool

                              func (*DefaultPackage) Generators

                              func (d *DefaultPackage) Generators(c *Context) []Generator

                              func (*DefaultPackage) Header

                              func (d *DefaultPackage) Header(filename string) []byte

                              func (*DefaultPackage) Name

                              func (d *DefaultPackage) Name() string

                              func (*DefaultPackage) Path

                              func (d *DefaultPackage) Path() string

                              func (*DefaultPackage) SourcePath

                              func (d *DefaultPackage) SourcePath() string

                              type ErrorTracker

                              type ErrorTracker struct {
                              	// contains filtered or unexported fields

                                ErrorTracker tracks errors to the underlying writer, so that you can ignore them until you're ready to return.

                                func NewErrorTracker

                                func NewErrorTracker(w io.Writer) *ErrorTracker

                                  NewErrorTracker makes a new error tracker; note that it implements io.Writer.

                                  func (*ErrorTracker) Error

                                  func (et *ErrorTracker) Error() error

                                    Error returns nil if no error has occurred, otherwise it returns the error.

                                    func (*ErrorTracker) Write

                                    func (et *ErrorTracker) Write(p []byte) (n int, err error)

                                      Write intercepts calls to Write.

                                      type File

                                      type File struct {
                                      	Name              string
                                      	FileType          string
                                      	PackageName       string
                                      	Header            []byte
                                      	PackagePath       string
                                      	PackageSourcePath string
                                      	Imports           map[string]struct{}
                                      	Vars              bytes.Buffer
                                      	Consts            bytes.Buffer
                                      	Body              bytes.Buffer

                                      type FileType

                                      type FileType interface {
                                      	AssembleFile(f *File, path string) error
                                      	VerifyFile(f *File, path string) error

                                      type Generator

                                      type Generator interface {
                                      	// The name of this generator. Will be included in generated comments.
                                      	Name() string
                                      	// Filter should return true if this generator cares about this type.
                                      	// (otherwise, GenerateType will not be called.)
                                      	// Filter is called before any of the generator's other functions;
                                      	// subsequent calls will get a context with only the types that passed
                                      	// this filter.
                                      	Filter(*Context, *types.Type) bool
                                      	// If this generator needs special namers, return them here. These will
                                      	// override the original namers in the context if there is a collision.
                                      	// You may return nil if you don't need special names. These names will
                                      	// be available in the context passed to the rest of the generator's
                                      	// functions.
                                      	// A use case for this is to return a namer that tracks imports.
                                      	Namers(*Context) namer.NameSystems
                                      	// Init should write an init function, and any other content that's not
                                      	// generated per-type. (It's not intended for generator specific
                                      	// initialization! Do that when your Package constructs the
                                      	// Generators.)
                                      	Init(*Context, io.Writer) error
                                      	// Finalize should write finish up functions, and any other content that's not
                                      	// generated per-type.
                                      	Finalize(*Context, io.Writer) error
                                      	// PackageVars should emit an array of variable lines. They will be
                                      	// placed in a var ( ... ) block. There's no need to include a leading
                                      	// \t or trailing \n.
                                      	PackageVars(*Context) []string
                                      	// PackageConsts should emit an array of constant lines. They will be
                                      	// placed in a const ( ... ) block. There's no need to include a leading
                                      	// \t or trailing \n.
                                      	PackageConsts(*Context) []string
                                      	// GenerateType should emit the code for a particular type.
                                      	GenerateType(*Context, *types.Type, io.Writer) error
                                      	// Imports should return a list of necessary imports. They will be
                                      	// formatted correctly. You do not need to include quotation marks,
                                      	// return only the package name; alternatively, you can also return
                                      	// imports in the format `name "path/to/pkg"`. Imports will be called
                                      	// after Init, PackageVars, PackageConsts, and GenerateType, to allow
                                      	// you to keep track of what imports you actually need.
                                      	Imports(*Context) []string
                                      	// Preferred file name of this generator, not including a path. It is
                                      	// allowed for multiple generators to use the same filename, but it's
                                      	// up to you to make sure they don't have colliding import names.
                                      	// TODO: provide per-file import tracking, removing the requirement
                                      	// that generators coordinate..
                                      	Filename() string
                                      	// A registered file type in the context to generate this file with. If
                                      	// the FileType is not found in the context, execution will stop.
                                      	FileType() string

                                        Generator is the contract for anything that wants to do auto-generation. It's expected that the io.Writers passed to the below functions will be ErrorTrackers; this allows implementations to not check for io errors, making more readable code.

                                        The call order for the functions that take a Context is: 1. Filter() // Subsequent calls see only types that pass this. 2. Namers() // Subsequent calls see the namers provided by this. 3. PackageVars() 4. PackageConsts() 5. Init() 6. GenerateType() // Called N times, once per type in the context's Order. 7. Imports()

                                        You may have multiple generators for the same file.

                                        type Package

                                        type Package interface {
                                        	// Name returns the package short name.
                                        	Name() string
                                        	// Path returns the package import path.
                                        	Path() string
                                        	// SourcePath returns the location of the package on disk.
                                        	SourcePath() string
                                        	// Filter should return true if this package cares about this type.
                                        	// Otherwise, this type will be omitted from the type ordering for
                                        	// this package.
                                        	Filter(*Context, *types.Type) bool
                                        	// Header should return a header for the file, including comment markers.
                                        	// Useful for copyright notices and doc strings. Include an
                                        	// autogeneration notice! Do not include the "package x" line.
                                        	Header(filename string) []byte
                                        	// Generators returns the list of generators for this package. It is
                                        	// allowed for more than one generator to write to the same file.
                                        	// A Context is passed in case the list of generators depends on the
                                        	// input types.
                                        	Generators(*Context) []Generator

                                          Package contains the contract for generating a package.

                                          type Packages

                                          type Packages []Package

                                            Packages is a list of packages to generate.

                                            type SnippetWriter

                                            type SnippetWriter struct {
                                            	// contains filtered or unexported fields

                                              SnippetWriter is an attempt to make the template library usable. Methods are chainable, and you don't have to check Error() until you're all done.

                                              func NewSnippetWriter

                                              func NewSnippetWriter(w io.Writer, c *Context, left, right string) *SnippetWriter

                                                w is the destination; left and right are the delimiters; @ and $ are both reasonable choices.

                                                c is used to make a function for every naming system, to which you can pass a type and get the corresponding name.

                                                func (*SnippetWriter) Do

                                                func (s *SnippetWriter) Do(format string, args interface{}) *SnippetWriter

                                                  Do parses format and runs args through it. You can have arbitrary logic in the format (see the text/template documentation), but consider running many short templates with ordinary go logic in between--this may be more readable. Do is chainable. Any error causes every other call to do to be ignored, and the error will be returned by Error(). So you can check it just once, at the end of your function.

                                                  'args' can be quite literally anything; read the text/template documentation for details. Maps and structs work particularly nicely. Conveniently, the types package is designed to have structs that are easily referencable from the template language.


                                                  sw := generator.NewSnippetWriter(outBuffer, context, "$", "$") sw.Do(`The public type name is: $.type|public$`, map[string]interface{}{"type": t}) return sw.Error()

                                                  Where: * "$" starts a template directive * "." references the entire thing passed as args * "type" therefore sees a map and looks up the key "type" * "|" means "pass the thing on the left to the thing on the right" * "public" is the name of a naming system, so the SnippetWriter has given

                                                  the template a function called "public" that takes a *types.Type and
                                                  returns the naming system's name. E.g., if the type is "string" this might
                                                  return "String".

                                                  * the second "$" ends the template directive.

                                                  The map is actually not necessary. The below does the same thing:

                                                  sw.Do(`The public type name is: $.|public$`, t)

                                                  You may or may not find it more readable to use the map with a descriptive key, but if you want to pass more than one arg, the map or a custom struct becomes a requirement. You can do arbitrary logic inside these templates, but you should consider doing the logic in go and stitching them together for the sake of your readers.

                                                  TODO: Change Do() to optionally take a list of pairs of parameters (key, value) and have it construct a combined map with that and args.

                                                  func (*SnippetWriter) Error

                                                  func (s *SnippetWriter) Error() error

                                                    Error returns any encountered error.

                                                    func (*SnippetWriter) Out

                                                    func (s *SnippetWriter) Out() io.Writer