mirror of
https://github.com/tmrts/go-patterns.git
synced 2024-11-21 20:46:08 +03:00
Add functional options idiom
This commit is contained in:
parent
abcdf32672
commit
c0937dd592
@ -104,7 +104,7 @@ __Idioms__:
|
|||||||
|
|
||||||
| Pattern | Description |
|
| Pattern | Description |
|
||||||
|:-------:| ----------- |
|
|:-------:| ----------- |
|
||||||
| [Functional Options](functional_options.go) | Allows creating clean APIs with sane defaults and idiomatic overrides |
|
| [Functional Options](idiom/functional_options.md) | Allows creating clean APIs with sane defaults and idiomatic overrides |
|
||||||
|
|
||||||
__Anti-Patterns__:
|
__Anti-Patterns__:
|
||||||
|
|
||||||
|
@ -1,65 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import "os"
|
|
||||||
|
|
||||||
type Arguments struct {
|
|
||||||
UID int
|
|
||||||
GID int
|
|
||||||
Flags int
|
|
||||||
Contents string
|
|
||||||
Permissions os.FileMode
|
|
||||||
}
|
|
||||||
|
|
||||||
type Argument func(*Arguments)
|
|
||||||
|
|
||||||
func UID(userID int) Argument {
|
|
||||||
return func(args *Arguments) {
|
|
||||||
args.UID = userID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GID(groupID int) Argument {
|
|
||||||
return func(args *Arguments) {
|
|
||||||
args.GID = groupID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Contents(c string) Argument {
|
|
||||||
return func(args *Arguments) {
|
|
||||||
args.Contents = c
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func Permissions(perms os.FileMode) Argument {
|
|
||||||
return func(args *Arguments) {
|
|
||||||
args.Permissions = perms
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(filepath string, setters ...Argument) error {
|
|
||||||
// Default Arguments
|
|
||||||
args := &Arguments{
|
|
||||||
UID: os.Getuid(),
|
|
||||||
GID: os.Getgid(),
|
|
||||||
Contents: "",
|
|
||||||
Permissions: 0666,
|
|
||||||
Flags: os.O_CREATE | os.O_EXCL | os.O_WRONLY,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, setter := range setters {
|
|
||||||
setter(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
f, err := os.OpenFile(filepath, args.Flags, args.Permissions)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
defer f.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := f.WriteString(args.Contents); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return f.Chown(args.UID, args.GID)
|
|
||||||
}
|
|
90
idiom/functional_options.md
Normal file
90
idiom/functional_options.md
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
# Functional Options
|
||||||
|
Functional options are a method of implementing clean/eloquent APIs in Go.
|
||||||
|
Options implemented as a function set the state of that option.
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### Options
|
||||||
|
```go
|
||||||
|
package file
|
||||||
|
|
||||||
|
type Options struct {
|
||||||
|
UID int
|
||||||
|
GID int
|
||||||
|
Flags int
|
||||||
|
Contents string
|
||||||
|
Permissions os.FileMode
|
||||||
|
}
|
||||||
|
|
||||||
|
type Option func(*Options)
|
||||||
|
|
||||||
|
func UID(userID int) Option {
|
||||||
|
return func(args *Options) {
|
||||||
|
args.UID = userID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GID(groupID int) Option {
|
||||||
|
return func(args *Options) {
|
||||||
|
args.GID = groupID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Contents(c string) Option {
|
||||||
|
return func(args *Options) {
|
||||||
|
args.Contents = c
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Permissions(perms os.FileMode) Option {
|
||||||
|
return func(args *Options) {
|
||||||
|
args.Permissions = perms
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Constructor
|
||||||
|
```go
|
||||||
|
package file
|
||||||
|
|
||||||
|
func New(filepath string, setters ...Option) error {
|
||||||
|
// Default Options
|
||||||
|
args := &Options{
|
||||||
|
UID: os.Getuid(),
|
||||||
|
GID: os.Getgid(),
|
||||||
|
Contents: "",
|
||||||
|
Permissions: 0666,
|
||||||
|
Flags: os.O_CREATE | os.O_EXCL | os.O_WRONLY,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, setter := range setters {
|
||||||
|
setter(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
f, err := os.OpenFile(filepath, args.Flags, args.Permissions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
defer f.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := f.WriteString(args.Contents); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return f.Chown(args.UID, args.GID)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
```go
|
||||||
|
emptyFile, err := file.New("/tmp/empty.txt")
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fillerFile, err := file.New("/tmp/file.txt", file.UID(1000), file.Contents("Lorem Ipsum Dolor Amet"))
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user