genie

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Sep 2, 2020 License: MIT Imports: 7 Imported by: 3

README

Genie

Genie is a tool for generating Go code, inspired by kubebuilder.

At a high-level, Genie uses Generators which act upon annotated Go types, using markers (see components below)

Components

Marker

A marker consists of a prefix (genie), name (somemarker) and optional arguments (someargs=abcdef)

Example:

// +genie:somemarker:someargs=abcdef
type SomeStruct struct {
	SomeProperty string
}

Generator

Generators define a marker name upon which they act, and are registered in Genie. Generators utilise jennifer to generate code

Example:

type SomeGenerator struct {
	*genie.BaseGenerator
}

func NewSomeMarkerGenerator() *SomeGenerator {
	return &SomeGenerator{
		BaseGenerator: genie.NewBaseGenerator("somemarker"),
	}
}

func (g *SomeGenerator) Generate(marker genie.Marker, typeName string, j *jen.File) error {
	j.Type().Id("Generated" + typeName).Struct(
		jen.Id("GeneratedProperty1").Float32(),
	)
	return nil
}

Input

Inputs implement the Input interface, which are responsible for parsing Go code and returning a slice of ast.File. Genie provides two basic implementations:

  • FileInput: Reads and parses code from a file
  • DirectoryInput: Reads and parses code from a directory

Output

Outputs implement the Output interface, which are responsible for outputting jen.File, typically to files. Genie provides one basic implementation:

  • FileOutput: Outputs generated code to a file

Example

Using the components above, we'll create a package to be invoked by go:generate to generate code from struct markers. In this example, we're going to generate an API response struct for an annotated model

model.go

This file will contain our annotated model struct and go:generate comment:

//go:generate go run generate/model_apiresponse.go
package main

// +genie:apiresponse
type Person struct {
	Name string
}

generate/model_apiresponse.go

This file will contain a single generator to act upon the apiresponse marker, and a main func to invoke Genie with this generator (note, Genie can act upon multiple generators at a time)

package main

import (
	"log"

	"github.com/0x4c6565/genie"
	"github.com/dave/jennifer/jen"
)

type APIResponseGenerator struct {
	*genie.BaseGenerator
}

func NewAPIResponseGenerator() *APIResponseGenerator {
	return &APIResponseGenerator{
		BaseGenerator: genie.NewBaseGenerator("apiresponse"),
	}
}

func (g *APIResponseGenerator) Generate(marker genie.Marker, typeName string, j *jen.File) error {
	j.Type().Id(typeName + "APIResponse").Struct(
		jen.Id("Data").Id(typeName),
	)
	return nil
}

func main() {
	err := genie.NewGenie(
		genie.NewFileInput("model.go"),
		genie.NewFileOutput("model_apiresponse_generated.go"),
		"main",
		NewAPIResponseGenerator(),
	).Generate()

	if err != nil {
		log.Fatal(err)
	}

	log.Print("Finished")
}

We can then proceed to run the generator:

go generate ./...

This will render the following into model_apiresponse_generated.go:

package main

type PersonAPIResponse struct {
	Data Person
}

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BaseGenerator

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

func NewBaseGenerator

func NewBaseGenerator(markerName string) *BaseGenerator

func (*BaseGenerator) MarkerName

func (g *BaseGenerator) MarkerName() string

type DirectoryInput

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

func NewDirectoryInput

func NewDirectoryInput(path string) *DirectoryInput

func (*DirectoryInput) Read

func (f *DirectoryInput) Read() ([]*ast.File, error)

type FileInput

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

func NewFileInput

func NewFileInput(path string) *FileInput

func (*FileInput) Read

func (f *FileInput) Read() ([]*ast.File, error)

type FileOutput

type FileOutput struct {
	DestinationPath string
}

func NewFileOutput

func NewFileOutput(destinationPath string) *FileOutput

func (*FileOutput) Write

func (f *FileOutput) Write(j *jen.File) error

type Generator

type Generator interface {
	MarkerName() string
	Generate(marker Marker, typeName string, j *jen.File) error
}

type Genie

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

func NewGenie

func NewGenie(input Input, output Output, pkg string, generators ...Generator) *Genie

func (*Genie) Generate

func (g *Genie) Generate() error

func (*Genie) WithGenerator

func (g *Genie) WithGenerator(generators ...Generator) *Genie

func (*Genie) WithPrefix

func (g *Genie) WithPrefix(p string) *Genie

type Input

type Input interface {
	Read() ([]*ast.File, error)
}

type Marker

type Marker struct {
	Name string
	Args string
}

type Output

type Output interface {
	Write(j *jen.File) error
}

Jump to

Keyboard shortcuts

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