https://github.com/sirkon/opgen
Option builder generator.
https://github.com/sirkon/opgen
codegen codegeneration codegenerator go golang
Last synced: 7 months ago
JSON representation
Option builder generator.
- Host: GitHub
- URL: https://github.com/sirkon/opgen
- Owner: sirkon
- License: mit
- Created: 2022-09-30T08:39:01.000Z (about 3 years ago)
- Default Branch: master
- Last Pushed: 2022-10-01T07:57:18.000Z (about 3 years ago)
- Last Synced: 2024-06-20T02:10:32.370Z (over 1 year ago)
- Topics: codegen, codegeneration, codegenerator, go, golang
- Language: Go
- Homepage:
- Size: 19.5 KB
- Stars: 1
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# opgen
Option builder generator.
## Installation.
```shell
go get github.com/sirkon/main@latest
```## Rationale.
There are so-called functional options described nicely in this [article](https://golang.cafe/blog/golang-functional-options-pattern.html).
But imagine a situation where we have a custom buffered io package where both reader and writer need a way to set up
a buffer size and there will be also options that are reader and writer specific. Something like:```go
r, err := cio.NewBufferedReader(
r,
cio.WithBufferSize(size),
cio.WithStartPosition(pos),
cio.WithMaxReadPosition(readend), // This is reader specific options.
)...
w, err := cio.NewBufferedWriter(w, cio.WithBufferSize(size))
```This code will not compile because options for reader and writer will have different type in order to prevent
`cio.WithMaxReadPosition` usage for writer.There are ways to overcome this using generics: [article](https://golang.design/research/generic-option/)
But in the end the usage will be not exactly nice – shared options to have mandatory type parameter:
```go
r, err := cio.NewBufferedReader(r, cio.WithBufferSize[*BufferedReader](size))
```
.This utility provides a different way to functional options: we don't set options directly, we fulfill them with a
generated builder:```go
r, err := cio.NewBufferedReader(r, cio.BufferedReaderOptions().BufferSize(size))
```where builders for reader and writer will have different types and therefore no type clashes.
## How to use.
Option builder generation requires a package with Go code where you set up options for each type.
Imagine we have `github.com/company/cio` repository with `BufferedReader` type in it. Then we create a package
`github.com/company/cio/internal/options` with a set of files in it.```go
// github.com/company/cio/internal/options/buffered_reader_options.go
package optionsimport (
"log"
)// BufferedReaderBufferSize sets a buffer size, a default value is 4096.
const BufferedReaderBufferSize int = 4096// BufferedReaderLogger sets an error logger for a buffered reader.
func BufferedReaderLogger(err error) {
log.Println(err)
}
```Now, generate a builder:
```shell
opgen -s internal/options -d options_gen.go BufferedReader
```It will look for `BufferedReaderXXX` named constants (will provide a default value), variables (no default value) and
functions (will provide a default value – the function itself) where a type of each option will match a type of constant/variable/function.The builder will have methods in case of the file above:
```go
func (b BufferedReaderOptionsType) BufferSize(v int) BufferedReaderOptionsType { … }
func (b BufferedReaderOptionsType) Logger(v func(error)) BufferedReaderOptionsType { … }
```And the usage is supposed to be like this:
```go
v, err := cio.NewBufferedReader(
r,
cio.BufferedReaderOptions().
BufferSize(8192).
Logger(func (err error) {
fmt.Println(err)
}),
)
```
.