diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1b2f5f5..c1d5c93 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,8 +4,6 @@ on: push: tags: - "v*" -permissions: - contents: write jobs: goreleaser: runs-on: ubuntu-latest @@ -18,14 +16,6 @@ jobs: uses: actions/setup-go@v2 with: go-version: 1.19 - - name: Create GitHub Release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: ${{ github.ref }} - body: ${{ env.CHANGELOG}} - name: Run GoReleaser uses: goreleaser/goreleaser-action@v2 with: diff --git a/.goreleaser.yaml b/.goreleaser.yaml index 7646ab7..f210077 100644 --- a/.goreleaser.yaml +++ b/.goreleaser.yaml @@ -10,6 +10,10 @@ builds: - linux - windows - darwin + goarch: + - amd64 + - arm64 + - "386" ignore: - goos: windows goarch: arm64 @@ -30,3 +34,6 @@ changelog: exclude: - '^docs:' - '^test:' +release: + draft: true + name_template: "v{{ .Version }}" diff --git a/Taskfile.yaml b/Taskfile.yaml index 1ad6fb1..9047dda 100644 --- a/Taskfile.yaml +++ b/Taskfile.yaml @@ -22,7 +22,7 @@ tasks: release:test: desc: Tests release process without publishing cmds: - - goreleaser --snapshot --rm-dist + - goreleaser --snapshot --clean data:dupe: desc: Checks dictionary data for duplicate entries cmds: diff --git a/cmd/fname/fname.go b/cmd/fname/fname.go index 4f32677..29898df 100644 --- a/cmd/fname/fname.go +++ b/cmd/fname/fname.go @@ -73,7 +73,7 @@ func main() { opts := []fname.GeneratorOption{} - c, err := fname.ParseCasing(casing) + c, err := fname.CasingFromString(casing) if err != nil { fmt.Fprintf(os.Stderr, "error: %s", err) os.Exit(1) diff --git a/generator.go b/generator.go index 5ee048a..7d51f26 100644 --- a/generator.go +++ b/generator.go @@ -10,15 +10,40 @@ import ( "golang.org/x/text/language" ) -type Casing string +type Casing int const ( - Lower Casing = "lower" - Upper Casing = "upper" - Title Casing = "title" + Lower Casing = iota + Upper + Title ) -// Generator is a random name generator. +func (c Casing) String() string { + switch c { + case Lower: + return "lower" + case Upper: + return "upper" + case Title: + return "title" + default: + return "unknown" + } +} + +func CasingFromString(casing string) (Casing, error) { + switch strings.ToLower(casing) { + case Lower.String(): + return Lower, nil + case Upper.String(): + return Upper, nil + case Title.String(): + return Title, nil + default: + return -1, fmt.Errorf("invalid casing: %s", casing) + } +} + type Generator struct { casing Casing dict *Dictionary @@ -47,7 +72,7 @@ func WithDelimiter(delimiter string) GeneratorOption { // WithSeed sets the seed used to generate random numbers. func WithSeed(seed int64) GeneratorOption { return func(g *Generator) { - g.rand.Seed(seed) + g.rand = rand.New(rand.NewSource(seed)) } } @@ -75,55 +100,31 @@ func NewGenerator(opts ...GeneratorOption) *Generator { // Generate generates a random name. func (g *Generator) Generate() (string, error) { - // Keep generating adjective and noun pairs until they are not the same. - var adjective, noun string - for adjective == noun { - adjective = g.dict.adjectives[g.rand.Intn(g.dict.LengthAdjective())] - noun = g.dict.nouns[g.rand.Intn(g.dict.LengthNoun())] + if g.size < 2 || g.size > 4 { + return "", fmt.Errorf("invalid size: %d", g.size) } - words := []string{adjective, noun} - - switch g.size { - case 2: - // do nothing - case 3: - verb := g.dict.verbs[g.rand.Intn(g.dict.LengthVerb())] - words = append(words, verb) - case 4: - verb := g.dict.verbs[g.rand.Intn(g.dict.LengthVerb())] - words = append(words, verb) - adverb := g.dict.adverbs[g.rand.Intn(g.dict.LengthAdverb())] - words = append(words, adverb) - default: - return "", fmt.Errorf("invalid size: %d", g.size) + words := make([]string, 0, g.size) + adjectiveIndex := g.rand.Intn(g.dict.LengthAdjective()) + nounIndex := g.rand.Intn(g.dict.LengthNoun()) + for adjectiveIndex == nounIndex { + nounIndex = g.rand.Intn(g.dict.LengthNoun()) } - return strings.Join(g.applyCasing(words...), g.delimiter), nil -} -// ParseCasing parses a string into a casing. -func ParseCasing(casing string) (Casing, error) { - switch casing { - case "lower": - return Lower, nil - case "upper": - return Upper, nil - case "title": - return Title, nil - default: - return "", fmt.Errorf("invalid casing: %s", casing) + words = append(words, g.dict.adjectives[adjectiveIndex], g.dict.nouns[nounIndex]) + + if g.size >= 3 { + words = append(words, g.dict.verbs[g.rand.Intn(g.dict.LengthVerb())]) } -} -var titleCaser = cases.Title(language.English) + if g.size == 4 { + words = append(words, g.dict.adverbs[g.rand.Intn(g.dict.LengthAdverb())]) + } -var casingMap = map[Casing]func(string) string{ - Lower: strings.ToLower, - Upper: strings.ToUpper, - Title: titleCaser.String, + return strings.Join(g.applyCasing(words), g.delimiter), nil } -func (g *Generator) applyCasing(words ...string) []string { +func (g *Generator) applyCasing(words []string) []string { if fn, ok := casingMap[g.casing]; ok { for i, word := range words { words[i] = fn(word) @@ -131,3 +132,11 @@ func (g *Generator) applyCasing(words ...string) []string { } return words } + +var titleCaser = cases.Title(language.English) + +var casingMap = map[Casing]func(string) string{ + Lower: strings.ToLower, + Upper: strings.ToUpper, + Title: titleCaser.String, +} diff --git a/generator_test.go b/generator_test.go index ecc9be2..406e9e1 100644 --- a/generator_test.go +++ b/generator_test.go @@ -185,7 +185,7 @@ func TestGenerate(t *testing.T) { } } -func TestParseCasing(t *testing.T) { +func TestCasingFromString(t *testing.T) { t.Log("Given the need to parse casing strings") { t.Log("\tWhen parsing a valid casing string") @@ -199,7 +199,7 @@ func TestParseCasing(t *testing.T) { {"title", Title}, } for _, tc := range testCases { - c, err := ParseCasing(tc.name) + c, err := CasingFromString(tc.name) if err != nil { t.Fatalf("\t\tShould be able to parse a valid casing string : %v", err) } @@ -214,7 +214,7 @@ func TestParseCasing(t *testing.T) { t.Log("\tWhen parsing an invalid casing string") { - _, err := ParseCasing("invalid") + _, err := CasingFromString("invalid") if err == nil { t.Fatal("\t\tShould not be able to parse an invalid casing string") }