Examples
Small, complete patterns that show how directives, metadata, and templates fit together. Copy one, rename its template, and adapt the generated API to your project.
Enum stringer
Use the embedded template when you need the conventional implementation:
package status
//mgo:gen std.stringer trimprefix=Status
type Status int
const (
StatusPending Status = iota
StatusRunning
StatusDone
)
Running metago . generates String() string. For unknown values it returns Status(value).
A custom template gives you complete control:
{{ define "short-status" }}
func (v {{ name . }}) String() string {
switch v {
{{- range .Values }}
case {{ .Name }}:
return {{ quote (trimPrefix .Name "Status") }}
{{- end }}
default:
return "unknown"
}
}
{{ end }}
//mgo:gen short-status
type Status int
Interface mock
package users
//mgo:gen std.mock
type Store interface {
Find(id string) (User, error)
Save(user User) error
}
Metago generates a MockStore with one function field per method:
func TestService(t *testing.T) {
store := MockStore{
FindFunc: func(id string) (User, error) {
return User{ID: id}, nil
},
SaveFunc: func(user User) error {
return nil
},
}
service := NewService(store)
// ...
}
Use named, non-variadic interface parameters. Embedded interface methods are not expanded by the standard mock template.
Reflection-free JSON
Generate the project-owned runtime once:
// Package jsonruntime contains generated JSON support.
//
//mgo:gen std.serde.jsonruntime
package jsonruntime
Set the runtime import for every codec in metago.toml:
[templates."std.serde".args]
runtime = "example.com/project/internal/jsonruntime"
strict = "true"
maxinput = "1048576"
Derive codecs on models:
package users
//mgo:gen std.serde
type User struct {
ID int64 `json:"id"`
Name string `json:"name"`
Tags []string `json:"tags,omitempty"`
Address Address `json:"address"`
}
//mgo:gen std.serde
type Address struct {
City string `json:"city"`
}
The generated types implement json.Marshaler and json.Unmarshaler. Nested generated types call each other directly. Unsupported field shapes fall back to encoding/json for that field.
Struct map codec
package config
//mgo:gen std.mapstruct allowmissing
type Server struct {
Host string `mapstructure:"host,required"`
Port int `mapstructure:"port"`
TLS TLS `mapstructure:"tls"`
}
type TLS struct {
Enabled bool `mapstructure:"enabled"`
CertFile string `mapstructure:"cert_file"`
}
Generated code decodes exact Go values transactionally:
var server Server
err := server.Decode(map[string]any{
"host": "127.0.0.1",
"port": 8080,
"tls": map[string]any{
"enabled": true,
},
})
encoded := server.Encode()
allowmissing makes untagged fields optional; the required tag option keeps host mandatory.
Validation properties
Properties let one declaration feed multiple generators without coupling it to a fixed schema:
//mgo:gen validate
type Signup struct {
Email string `json:"email"` //mgo:validate required format=email
Name string `json:"name"` //mgo:validate required max=80
Age int `json:"age"` //mgo:validate min=18
}
{{ define "validate" }}
func (v {{ name . }}) Validate() error {
{{- range .Fields }}
{{- if propHas . "validate" "required" }}
if v.{{ .Name }} == {{ zero . }} {
return fmt.Errorf({{ quote (printf "%s is required" (tagName . "json")) }})
}
{{- end }}
{{- end }}
return nil
}
{{ imports "fmt" }}
{{ end }}
The imports call can appear after the generated code; it records the import and emits no text.
Package registry
One aggregate invocation can inspect marker directives across a package:
//mgo:gen route-table
package api
//mgo:gen route GET /users
func ListUsers() {}
//mgo:gen route POST /users
func CreateUser() {}
{{ define "route" }}{{ end }}
{{ define "route-table" }}
type Route struct {
Method string
Path string
}
var Routes = []Route{
{{- range .Package.Metas }}
{{- if eq .Template "route" }}
{Method: {{ quote (index .Argv 0) }}, Path: {{ quote (index .Argv 1) }}},
{{- end }}
{{- end }}
}
{{ end }}
The empty route template acts as a marker. .Package.Metas remains stable in file and line order.
Inline generated code
Inline output is useful when generated declarations are easier to understand beside their source:
//mgo:inline constructor
type Client struct {
BaseURL string
Token string
}
{{ define "constructor" }}
func New{{ name . }}(
{{- range .Fields }}
{{ unexported .Name }} {{ typeof . }},
{{- end }}
) *{{ name . }} {
return &{{ name . }}{
{{- range .Fields }}
{{ .Name }}: {{ unexported .Name }},
{{- end }}
}
}
{{ end }}
Metago inserts the constructor after Client and closes the managed region with //mgo:end. Later runs replace only that region.
Test-only generation
Directives in test files stay in test builds:
package service_test
//mgo:gen std.mock
// Define a test-only interface with named parameters.
type Clock interface {
Now() time.Time
}
For an external service_test package, Metago writes meta_service_test.go. Internal test directives write meta_test.go. Production meta.go remains unaffected.
For exact supported targets, helper signatures, and standard-template options, use the reference.