Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add enum.Builder #7

Merged
merged 1 commit into from
Sep 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
linters:
disable:
- dupword
- depguard
presets:
- bugs
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,20 @@ var (
fmt.Println(Red.Value.UI)
```

If the enum has lots of members and new ones may be added over time, it's easy to forget to register all members in the enum. To prevent this, use enum.Builder to define an enum:

```go
type Color enum.Member[string]

var (
b = enum.NewBuilder[string, Color]()
Red = b.Add(Color{"red"})
Green = b.Add(Color{"green"})
Blue = b.Add(Color{"blue"})
Colors = b.Enum()
)
```

## 🤔 QnA

1. **What happens when enums are added in Go itself?** I'll keep it alive until someone uses it but I expect the project popularity to quickly die out when there is native language support for enums. When you can mess with the compiler itself, you can do more. For example, this package can't provide an exhaustiveness check for switch statements using enums (maybe only by implementing a linter) but proper language-level enums would most likely have it.
Expand Down
32 changes: 32 additions & 0 deletions enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,35 @@ func (e Enum[M, V]) GoString() string {
joined := strings.Join(values, ", ")
return fmt.Sprintf("enum.New(%s)", joined)
}

// Builder is a constructor for an [Enum].
//
// Use [Builder.Add] to add new members to the future enum
// and then call [Builder.Enum] to create a new [Enum] with all added members.
//
// Builder is useful for when you have lots of enum members, and new ones
// are added over time, as the project grows. In such scenario, it's easy to forget
// to add in the [Enum] a newly created [Member].
// The builder is designed to prevent that.
type Builder[M iMember[V], V comparable] struct {
members []M
finished bool
}

// NewBuilder creates a new [Builder], a constructor for an [Enum].
func NewBuilder[V comparable, M iMember[V]]() Builder[M, V] {
return Builder[M, V]{make([]M, 0), false}
}

// Add registers a new [Member] in the builder.
func (b *Builder[M, V]) Add(m M) M {
b.members = append(b.members, m)
return m
}

// Enum creates a new [Enum] with all members registered using [Builder.Add].
func (b *Builder[M, V]) Enum() Enum[M, V] {
b.finished = true
e := New(b.members...)
return e
}
13 changes: 13 additions & 0 deletions enum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,16 @@ func TestEnum_Index_Panic(t *testing.T) {
}()
Colors.Index(Color{"purple"})
}

func TestBuilder(t *testing.T) {
is := is.New(t)
type Country enum.Member[string]
var (
b = enum.NewBuilder[string, Country]()
NL = b.Add(Country{"Netherlands"})
FR = b.Add(Country{"France"})
BE = b.Add(Country{"Belgium"})
Countries = b.Enum()
)
is.Equal(Countries.Members(), []Country{NL, FR, BE})
}
19 changes: 19 additions & 0 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,3 +182,22 @@ func ExampleEnum_TypeName() {
fmt.Println(tname)
// Output: string
}

func ExampleNewBuilder() {
type Color enum.Member[string]
var (
b = enum.NewBuilder[string, Color]()
Red = b.Add(Color{"red"})
Green = b.Add(Color{"green"})
Blue = b.Add(Color{"blue"})
Colors = b.Enum()
)

fmt.Println(
Colors.Contains(Red),
Colors.Contains(Green),
Colors.Contains(Blue),
)
// Output:
// true true true
}