foggo is generator of Functional Option Pattern And Applicable Functional Option Pattern from struct field in Golang code.
$ go install golang.org/x/tools/cmd/goimports@latest # foggo use 'goimports' command
$ go install github.com/rikeda71/foggo@latestfoggo provides fop and afop subcommand.
Usage:
foggo (fop|afop) [flags]
Flags:
-h, --help help for fop
Global Flags:
-p, --package string Package name having target struct (default ".")
-s, --struct string Target struct name (required)-
prepare a struct type.
// ./image/image.go package image type Image struct { Width int Height int // don't want to create option, specify `foggo:"-"` as the structure tag Src string `foggo:"-"` Alt string }
-
execute
foggo fopcommand.# struct must be set struct type name # package must be package path $ foggo fop --struct Image --package image
-
then
foggogenerates Functional Option Pattern code to./image/image_gen.go.// Code generated by foggo; DO NOT EDIT. package image type ImageOption func(*Image) func NewImage(options ...ImageOption) *Image { s := &Image{} for _, option := range options { option(s) } return s } func WithWidth(Width int) ImageOption { return func(args *Image) { args.Width = Width } } func WithHeight(Height int) ImageOption { return func(args *Image) { args.Height = Height } } func WithAlt(Alt string) ImageOption { return func(args *Image) { args.Alt = Alt } }
-
write Golang code using
functional option parameterpackage main import "github.com/user/project/image" func main() { image := NewImage( WithWidth(1280), WithHeight(720), WithAlt("alt title"), ) image.Src = "./image.png" ... }
-
prepare a struct type with
go:generate.// ./image/image.go package image //go:generate foggo fop --struct Image type Image struct { Width int Height int // don't want to create option, specify `foggo:"-"` as the structure tag Src string `foggo:"-"` Alt string }
-
execute
go generate ./...command.$ go generate ./...
-
the
foggogenerate Functional Option Pattern code to all files writtengo:generate.
afop is the method to generate Applicable Functional Option Pattern code.
-
prepare a struct type with
go:generate. (useafopsubcommand)// ./image/image.go package image //go:generate foggo afop --struct Image type Image struct { Width int Height int // don't want to create option, specify `foggo:"-"` as the structure tag Src string `foggo:"-"` Alt string }
-
execute
go generate ./...command.$ go generate ./...
-
the
foggogenerate Applicable Functional Option Pattern code to all files writtengo:generate.// Code generated by foggo; DO NOT EDIT. package image type ImageOption interface { apply(*Image) } type WidthOption struct { Width int } func (o WidthOption) apply(s *Image) { s.Width = o.Width } type HeightOption struct { Height int } func (o HeightOption) apply(s *Image) { s.Height = o.Height } type AltOption struct { Alt string } func (o AltOption) apply(s *Image) { s.Alt = o.Alt } func NewImage(options ...ImageOption) *Image { s := &Image{} for _, option := range options { option.apply(s) } return s }
-
write Golang code using
Applicable Functional Option Parameterpackage main import "github.com/user/project/image" func main() { image := NewImage( WidthOption(1280), HeightOption(720), AltOption("alt title"), ) image.Src = "./image.png" ... }
Functional Option Pattern(FOP) is one of the most common design patterns used in Golang code.
Golang cannot provide optional arguments such as keyword arguments (available in python, ruby, ...).
FOP is the technique for achieving optional arguments.
For more information, please refer to the following articles.
- https://commandcenter.blogspot.jp/2014/01/self-referential-functions-and-design.html
- https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis
Applicable Functional Option Pattern(AFOP) is testable FOP.
FOP express options to function.
For that reason, comparing to option function with same arguments fails (not testable).
AFOP express options to struct type and options have a parameter and apply method.
Struct type is comparable in Golang, options followed AFOP are testable.
AFOP proposed by following articles.