mirror of
https://codeberg.org/scip/gfn.git
synced 2025-12-16 18:30:57 +01:00
moved to codeberg
This commit is contained in:
@@ -1,69 +0,0 @@
|
||||
# vim: set ts=2 sw=2 tw=0 fo=cnqoj
|
||||
|
||||
version: 2
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod tidy
|
||||
|
||||
gitea_urls:
|
||||
api: https://codeberg.org/api/v1
|
||||
download: https://codeberg.org
|
||||
|
||||
builds:
|
||||
- env:
|
||||
- CGO_ENABLED=0
|
||||
goos:
|
||||
- linux
|
||||
- windows
|
||||
- darwin
|
||||
- freebsd
|
||||
|
||||
archives:
|
||||
- formats: [tar.gz]
|
||||
# this name template makes the OS and Arch compatible with the results of `uname`.
|
||||
name_template: >-
|
||||
{{ .ProjectName }}_
|
||||
{{- title .Os }}_
|
||||
{{- if eq .Arch "amd64" }}x86_64
|
||||
{{- else if eq .Arch "386" }}i386
|
||||
{{- else }}{{ .Arch }}{{ end }}
|
||||
{{- if .Arm }}v{{ .Arm }}{{ end }}_{{ .Tag }}
|
||||
# use zip for windows archives
|
||||
format_overrides:
|
||||
- goos: windows
|
||||
formats: [zip]
|
||||
- goos: linux
|
||||
formats: [tar.gz,binary]
|
||||
files:
|
||||
- src: "*.md"
|
||||
strip_parent: true
|
||||
- src: "docs/*"
|
||||
strip_parent: true
|
||||
- src: Makefile.dist
|
||||
dst: Makefile
|
||||
wrap_in_directory: true
|
||||
|
||||
changelog:
|
||||
sort: asc
|
||||
filters:
|
||||
exclude:
|
||||
- "^docs:"
|
||||
- "^test:"
|
||||
groups:
|
||||
- title: Improved
|
||||
regexp: '^.*?(feat|add|new)(\([[:word:]]+\))??!?:.+$'
|
||||
order: 0
|
||||
- title: Fixed
|
||||
regexp: '^.*?(bug|fix)(\([[:word:]]+\))??!?:.+$'
|
||||
order: 1
|
||||
- title: Changed
|
||||
order: 999
|
||||
|
||||
release:
|
||||
header: "# Release Notes"
|
||||
footer: >-
|
||||
|
||||
---
|
||||
|
||||
Full Changelog: [{{ .PreviousTag }}...{{ .Tag }}](https://codeberg.org/scip/epuppy/compare/{{ .PreviousTag }}...{{ .Tag }})
|
||||
@@ -1,36 +0,0 @@
|
||||
matrix:
|
||||
platform:
|
||||
- linux/amd64
|
||||
goversion:
|
||||
- 1.24
|
||||
|
||||
labels:
|
||||
platform: ${platform}
|
||||
|
||||
steps:
|
||||
build:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- go get
|
||||
- go build
|
||||
|
||||
linter:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b $(go env GOPATH)/bin v2.5.0
|
||||
- golangci-lint --version
|
||||
- golangci-lint run ./...
|
||||
depends_on: [build]
|
||||
|
||||
test:
|
||||
when:
|
||||
event: [push]
|
||||
image: golang:${goversion}
|
||||
commands:
|
||||
- go get
|
||||
- go test -v -cover
|
||||
depends_on: [build,linter]
|
||||
@@ -1,15 +0,0 @@
|
||||
# build release
|
||||
|
||||
labels:
|
||||
platform: linux/amd64
|
||||
|
||||
steps:
|
||||
goreleaser:
|
||||
image: goreleaser/goreleaser
|
||||
when:
|
||||
event: [tag]
|
||||
environment:
|
||||
GITEA_TOKEN:
|
||||
from_secret: DEPLOY_TOKEN
|
||||
commands:
|
||||
- goreleaser release --clean --verbose
|
||||
142
Instructions.md
142
Instructions.md
@@ -1,142 +0,0 @@
|
||||
# Introduction
|
||||
|
||||
Fantasy Name Generator has two interfaces that each strike its own
|
||||
balance between ease of use and functionality. The Simple Interface is
|
||||
extremely easy but only offers you a limited form of control over the
|
||||
names that get generated. The Advanced Interface is not quite as easy
|
||||
to learn -- see instructions for using it below -- but allows you
|
||||
practically limitless control over the type of names that get
|
||||
generated. Among other things, it allows you to generate names that
|
||||
are variations on a name you already have in mind.
|
||||
|
||||
# Simple Interface
|
||||
|
||||
The Simple Interface provides a drop-down box to allow you to set what
|
||||
kind of names you want to generate. The "Default Names" choice in this
|
||||
list contains a diverse mix of generic name types, while the other
|
||||
choices are more specialized.
|
||||
|
||||
To use the Simple Interface, simply select a name type from the
|
||||
drop-down list and hit the Generate Names button next to it.
|
||||
|
||||
# Advanced Interface
|
||||
|
||||
The Advanced Interface offers a maximum of control over the names that
|
||||
get generated. You can use it to generate names or words with
|
||||
unfamiliar linguistic roots or to generate variations on a specific
|
||||
name.
|
||||
|
||||
The Advanced Interface has a "Collapse Triples" checkbox, which is
|
||||
checked by default. When on, names with three or more of the same
|
||||
letter in a row will be reduced reduced to just two prior to being
|
||||
printed out. So if the name "Purghinnn" was generated and the
|
||||
"Collapse Triples" checkbox was checked, it would appear as just
|
||||
"Purghinn." In addition, if the letter in question does not make sense
|
||||
to have even doubled, it will be reduced to just one. So the name
|
||||
"Leguiin" would be reduced to just "Leguin." If the "Collapse Triples"
|
||||
checkbox is left unchecked, this reduction step will not take
|
||||
place. It doesn't mean you will get unnatural double and triple letter
|
||||
sequences; it just means no efforts will be made to prevent them. We
|
||||
recommend you leave this option turned on unless you have a special
|
||||
need for it to be off.
|
||||
|
||||
The heart of the Advanced Interface is the "Name Generation Template"
|
||||
field. The name generation template describes how names should be
|
||||
constructed. For instance, a template could dictate that all names be
|
||||
a consonant followed by a vowel or vowel combination followed by a
|
||||
consonant or consonant combination. This template would generate short
|
||||
names. The template could also employ the use of random predefined
|
||||
syllables (such as 'tor', 'ash', 'ald', and 'dar'); a very effective
|
||||
template, one used frequently when default names are generated using
|
||||
the Simple Interface, is one that dictates names should consist simply
|
||||
of two predefined syllables.
|
||||
|
||||
Templates get more complicated than that, but they don't have
|
||||
to. Simple and effective templates may do nothing but list how many
|
||||
consonant combinations, vowel combinations, and syllables should
|
||||
comprise a word, and in what order. At generation time, random
|
||||
consonant combinations, random vowel combinations, and random
|
||||
syllables will be placed together according to the template to form
|
||||
each name. The randomizer used will be weighted so that more
|
||||
frequently seen letters, such as 't' and 's', will appear more often
|
||||
than less frequently seen letters, such as 'j' and 'z'. This goes a
|
||||
long way toward generating good, pronouncable names.
|
||||
|
||||
A consonant combination is two or three consonants that tend to go
|
||||
well together, such as 'ch', 'ck', 'tt', and 'str'. Examples of vowel
|
||||
combinations are 'ou', 'ai', and 'ee'. In your template, you will be
|
||||
able to specify whether you want only single consonants and single
|
||||
vowels or whether you want to allow the possibility of combinations.
|
||||
|
||||
Each name type in the Simple Interface uses its own set of predefined
|
||||
templates, hence the diversity of names you can get from it,
|
||||
especially when using the "Default Names" choice. In the Advanced
|
||||
Interface, you can define your own by entering it into the "Name
|
||||
Generation Field."
|
||||
|
||||
In a template, a single case-sensitive character is used to represent
|
||||
each component of the name. 's' means syllable; 'v' means single
|
||||
vowel; 'V' means vowel or vowel combination. The consonants are a
|
||||
little more complicated, because the template distinguishes between
|
||||
consonant combinations that are appropriate for the beginning of
|
||||
names, like 'wh' and 'chr', and consonant combinations that are
|
||||
appropriate for the middle or ending of names, like 'nd' and 'ck'. To
|
||||
avoid generating names that, for example, start with 'nd' or 'ck',
|
||||
this distinction is necessary, although most consonant combinations
|
||||
are members of both groups, as they can appear anywhere. In templates,
|
||||
the character 'c' represents a single consonant and is appropriate
|
||||
anywhere in a name. The character 'B' (note that it is capital)
|
||||
represents a consonant or consonant combination appropriate for the
|
||||
beginning of a name; the character 'C' represents a consonant or
|
||||
consonant combination appropriate anywhere else. The apostrophe
|
||||
character can be used to insert an apostrophe into the name; the
|
||||
hyphen character can be used to insert a hyphen into the name. These
|
||||
symbols and other, special-purpose symbols, are all documented in the
|
||||
quick reference guide. Some example templates:
|
||||
|
||||
* `ss`
|
||||
* `BVC`
|
||||
* `s'vCv`
|
||||
* `Bv-s`
|
||||
|
||||
Templates can be more complicated when you add parentheses into them. Any character in parentheses appears in the generated names literally. The template (str)VC, for example, will generate short names starting with 'str', like "Stript", "Stroagh", and "Strun". If you include an or bar, the '|' character, then either what's on the left or what's on the right will be chosen to be included in the name. The template (st|tr)VC will generate short names that start with either 'st' or 'tr'. Parentheses are useful when you already have an idea of what you want a name to look like but want to see variations on it. Here are some more sample templates:
|
||||
|
||||
* `ss(ien|ian)`
|
||||
* `(d|t|p|w)(r)VCv`
|
||||
* `ss(ly|ily|ish|ing)`
|
||||
|
||||
Angle brackets are another valid construct in templates. Angle
|
||||
brackets can be used with `|` characters in the same way as
|
||||
parentheses can, but what goes inside angle brackets isn't literal
|
||||
text but template codes for syllables, consonants, vowels, and so
|
||||
on. The template `<s|ss>v` generates names that consist either of one
|
||||
or two syllables, followed by a vowel. Here are some examples:
|
||||
|
||||
* `<c|cvc>s`
|
||||
* `(ma)<VC|s|Vs>`
|
||||
* `<Bv|V>(ck|kk|k)v`
|
||||
|
||||
If there is nothing on one side of an or bar, it allows the
|
||||
possibility of nothing. For example, the template `(s|)(mor)ss`
|
||||
generates names that start with `mor` and names that start with
|
||||
`smor`. The template ss<|v> generates two syllable names that may or
|
||||
may not have an extra vowel appended. Also, parentheses and angle
|
||||
brackets can be nested; the template `(ghoa|<s>)VC` generates names
|
||||
that start with either `ghoa` or a predefined syllable. Here are more
|
||||
examples:
|
||||
|
||||
* `(s||t)VC`
|
||||
* `<|s|ss|sss>s`
|
||||
* `<V|VCV|((a|e)i)>`
|
||||
|
||||
Nesting can influence the frequency certain choices are made. For
|
||||
example, a template starting with (r|s|t) will generate names that
|
||||
start with either 'r', 's', or 't', where each of the three letters
|
||||
appear with approximately equal frequency. But if you use a template
|
||||
starting with (r|(s|t)), roughly half the generated names will start
|
||||
with 'r', and only a quarter will start with 's', and a quarter will
|
||||
start with 't'.
|
||||
|
||||
Although the vast majority of the time, you won't need to use very
|
||||
complex constructions with nested parentheses and angle brackets, once
|
||||
in a while this functionality can be very helpful.
|
||||
87
Makefile
87
Makefile
@@ -1,87 +0,0 @@
|
||||
# Copyright © 2024 Thomas von Dein
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
#
|
||||
# no need to modify anything below
|
||||
tool = gfn
|
||||
VERSION = $(shell grep VERSION config.go | head -1 | cut -d '"' -f2)
|
||||
archs = darwin freebsd linux windows
|
||||
PREFIX = /usr/local
|
||||
UID = root
|
||||
GID = 0
|
||||
HAVE_POD := $(shell pod2text -h 2>/dev/null)
|
||||
|
||||
all: buildlocal
|
||||
|
||||
|
||||
buildlocal:
|
||||
CGO_LDFLAGS='-static' go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o $(tool)
|
||||
|
||||
install: buildlocal
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
|
||||
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
|
||||
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/
|
||||
|
||||
clean:
|
||||
rm -rf $(tool) coverage.out testdata t/out
|
||||
|
||||
test: clean
|
||||
mkdir -p t/out
|
||||
go test ./... $(ARGS)
|
||||
|
||||
testlint: test lint
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
lint-full:
|
||||
golangci-lint run --enable-all --exclude-use-default --disable exhaustivestruct,exhaustruct,depguard,interfacer,deadcode,golint,structcheck,scopelint,varcheck,ifshort,maligned,nosnakecase,godot,funlen,gofumpt,cyclop,noctx,gochecknoglobals,paralleltest
|
||||
|
||||
testfuzzy: clean
|
||||
go test -fuzz ./... $(ARGS)
|
||||
|
||||
singletest:
|
||||
@echo "Call like this: make singletest TEST=TestPrepareColumns ARGS=-v"
|
||||
go test -run $(TEST) $(ARGS)
|
||||
|
||||
cover-report:
|
||||
go test ./... -cover -coverprofile=coverage.out
|
||||
go tool cover -html=coverage.out
|
||||
|
||||
goupdate:
|
||||
go get -t -u=patch ./...
|
||||
|
||||
buildall:
|
||||
./mkrel.sh $(tool) $(VERSION)
|
||||
|
||||
release:
|
||||
gh release create v$(VERSION) --generate-notes
|
||||
|
||||
show-versions: buildlocal
|
||||
@echo "### gfn version:"
|
||||
@./gfn -V
|
||||
|
||||
@echo
|
||||
@echo "### go module versions:"
|
||||
@go list -m all
|
||||
|
||||
@echo
|
||||
@echo "### go version used for building:"
|
||||
@grep -m 1 go go.mod
|
||||
|
||||
# lint:
|
||||
# golangci-lint run -p bugs -p unused
|
||||
@@ -1,18 +0,0 @@
|
||||
# -*-make-*-
|
||||
|
||||
.PHONY: install all
|
||||
|
||||
tool = rpn
|
||||
PREFIX = /usr/local
|
||||
UID = root
|
||||
GID = 0
|
||||
|
||||
all:
|
||||
@echo "Type 'sudo make install' to install the tool."
|
||||
@echo "To change prefix, type 'sudo make install PREFIX=/opt'"
|
||||
|
||||
install:
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/share/doc
|
||||
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
|
||||
install -o $(UID) -g $(GID) -m 444 *.md $(PREFIX)/share/doc/
|
||||
@@ -6,6 +6,9 @@
|
||||
[](https://codeberg.org/scip/gfn/blob/master/LICENSE)
|
||||
[](https://goreportcard.com/report/codeberg.org/scip/gfn)
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This software is now being maintained on [Codeberg](https://codeberg.org/scip/gfn/).
|
||||
|
||||
Generate fantasy names for games and stories. It uses the fine
|
||||
[fantasyname module](https://github.com/s0rg/fantasyname) by
|
||||
[s0rg](https://github.com/s0rg/), which implements the code created by
|
||||
|
||||
21
Reference.md
21
Reference.md
@@ -1,21 +0,0 @@
|
||||
This is a quick reference guide to the syntax used in the "Name
|
||||
Generation Template" of the Advanced Interface. If you don't know how
|
||||
to use the information below, see the instructions first.
|
||||
|
||||
| Character | Meaning |
|
||||
|-----------|-------------------------------------------------------------------------|
|
||||
| s | generic syllable |
|
||||
| v | single vowel |
|
||||
| V | single vowel or vowel combination |
|
||||
| c | single consonant |
|
||||
| B | single consonant or consonant combination suitable for beginning a word |
|
||||
| C | single consonant or consonant combination suitable anywhere in a word |
|
||||
| i | unit for an insult |
|
||||
| m | unit for a mushy name |
|
||||
| M | unit for a mushy name ending |
|
||||
| D | consonant or consonant suited for a stupid person's name |
|
||||
| d | syllable suited for a stupid person's name (always begins with a vowel) |
|
||||
| ' | literal apostrophe |
|
||||
| ( ) | denotes that anything inside is literal |
|
||||
| < > | denotes that anything inside is a special symbol |
|
||||
| \| | logical OR operator for use in ( ) and < > |
|
||||
275
config.go
275
config.go
@@ -1,275 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/knadh/koanf/parsers/toml"
|
||||
"github.com/knadh/koanf/providers/confmap"
|
||||
"github.com/knadh/koanf/providers/file"
|
||||
"github.com/knadh/koanf/providers/posflag"
|
||||
"github.com/knadh/koanf/v2"
|
||||
flag "github.com/spf13/pflag"
|
||||
)
|
||||
|
||||
const (
|
||||
MIDDLE_EARTH = "(bil|bal|ban|hil|ham|hal|hol|hob|wil|me|or|ol|od|gor|for|fos|tol|ar|fin|ere|leo|vi|bi|bren|thor)" +
|
||||
"(|go|orbis|apol|adur|mos|ri|i|na|ole|n)" +
|
||||
"(|tur|axia|and|bo|gil|bin|bras|las|mac|grim|wise|l|lo|fo|co|ra|via|" +
|
||||
"da|ne|ta|y|wen|thiel|phin|dir|dor|tor|rod|on|rdo|dis)"
|
||||
JAPANESE_NAMES_CONSTRAINED = "(aka|aki|bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|hon|hoshi|" +
|
||||
"ichi|iwa|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|ta|o|oo|oka|" +
|
||||
"saka|saki|sawa|shita|shima|i|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|zawa|zen|sen|" +
|
||||
"ao|gin|kin|ken|shiro|zaki|yuki|asa)(||||||||||bashi|gawa|kawa|furu|fuku|fuji|hana|hara|haru|hashi|hira|" +
|
||||
"hon|hoshi|chi|wa|ka|kami|kawa|ki|kita|kuchi|kuro|marui|matsu|miya|mori|moto|mura|nabe|naka|nishi|no|da|" +
|
||||
"ta|o|oo|oka|saka|saki|sawa|shita|shima|suzu|taka|take|to|toku|toyo|ue|wa|wara|wata|yama|yoshi|kei|ko|" +
|
||||
"zawa|zen|sen|ao|gin|kin|ken|shiro|zaki|yuki|sa)"
|
||||
JAPANESE_NAMES_DIVERSE = "(a|i|u|e|o|||||)" +
|
||||
"(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|" +
|
||||
"no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|" +
|
||||
"re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|" +
|
||||
"chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|" +
|
||||
"yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)" +
|
||||
"(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|" +
|
||||
"no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|" +
|
||||
"ro|ro|ro|wa|wa|wa|wa|wo|wo)|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|shi|su|su|se|so|ta|ta|chi|chi|" +
|
||||
"tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|mu|mu|mu|me|mo|mo|mo|ya|yu|yu|" +
|
||||
"yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)(|(ka|ki|ki|ku|ku|ke|ke|ko|ko|sa|sa|sa|shi|shi|" +
|
||||
"shi|su|su|se|so|ta|ta|chi|chi|tsu|te|to|na|ni|ni|nu|nu|ne|no|no|ha|hi|fu|fu|he|ho|ma|ma|ma|mi|mi|mi|mu|" +
|
||||
"mu|mu|mu|me|mo|mo|mo|ya|yu|yu|yu|yo|ra|ra|ra|ri|ru|ru|ru|re|ro|ro|ro|wa|wa|wa|wa|wo|wo)))(|||n)"
|
||||
CHINESE_NAMES = "(zh|x|q|sh|h)(ao|ian|uo|ou|ia)(|(l|w|c|p|b|m)(ao|ian|uo|ou|ia)" +
|
||||
"(|n)|-(l|w|c|p|b|m)(ao|ian|uo|ou|ia)(|(d|j|q|l)(a|ai|iu|ao|i)))"
|
||||
GREEK_NAMES = "<s<v|V>(tia)|s<v|V>(os)|B<v|V>c(ios)|B<v|V><c|C>v(ios|os)>"
|
||||
HAWAIIAN_NAMES_1 = "((h|k|l|m|n|p|w)|)(a|e|i|o|u)((h|k|l|m|n|p|w)|)(a|e|i|o|u)(((h|k|l|m|n|p|w)|)" +
|
||||
"(a|e|i|o|u)|)(((h|k|l|m|n|p|w)|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w)|)(a|e|i|o|u)|)(((h|k|l|m|n|p|w)|)" +
|
||||
"(a|e|i|o|u)|)"
|
||||
HAWAIIAN_NAMES_2 = "((h|k|l|m|n|p|w|)(a|e|i|o|u|a|e|i|o|u|ae|ai|ao|au|oi|ou|eu|ei)" +
|
||||
"(k|l|m|n|p|)|)(h|k|l|m|n|p|w|)(a|e|i|o|u|a|e|i|o|u|ae|ai|ao|au|oi|ou|eu|ei)(k|l|m|n|p|)"
|
||||
OLD_LATIN_PLACE_NAMES = "sv(nia|lia|cia|sia)"
|
||||
DRAGONS_PERN = "<<s|ss>|<VC|vC|B|BVs|Vs>><v|V|v|<v(l|n|r)|vc>>(th)"
|
||||
DRAGON_RIDERS = "c<s|cvc>"
|
||||
POKEMON = "<i|s>v(mon|chu|zard|rtle)"
|
||||
FANTASY_VOWELS_R = "(|(<B>|s|h|ty|ph|r))(i|ae|ya|ae|eu|ia|i|eo|ai|a)" +
|
||||
"(lo|la|sri|da|dai|the|sty|lae|due|li|lly|ri|na|ral|sur|rith)(|(su|nu|sti|llo|ria|))" +
|
||||
"(|(n|ra|p|m|lis|cal|deu|dil|suir|phos|ru|dru|rin|raap|rgue))"
|
||||
FANTASY_S_A = "(cham|chan|jisk|lis|frich|isk|lass|mind|sond|sund|ass|chad|lirt|und|mar|lis|il|<BVC>)" +
|
||||
"(jask|ast|ista|adar|irra|im|ossa|assa|osia|ilsa|<vCv>)(|(an|ya|la|sta|sda|sya|st|nya))"
|
||||
FANTASY_H_L = "(ch|cht|sh|cal|val|ell|har|shar|shal|rel|laen|ral|jht|alr|ch|cht|av)" +
|
||||
"(|(is|al|ow|ish|ul|el|ar|iel))" +
|
||||
"(aren|aeish|aith|even|adur|ulash|alith|atar|aia|erin|aera|ael|ira|iel|ahur|ishul)"
|
||||
FANTASY_N_L = "(ethr|qil|mal|er|eal|far|fil|fir|ing|ind|il|lam|quel|quar|quan|qar|pal|mal|yar|um|ard|enn|ey)" +
|
||||
"(|(<vc>|on|us|un|ar|as|en|ir|ur|at|ol|al|an))" +
|
||||
"(uard|wen|arn|on|il|ie|on|iel|rion|rian|an|ista|rion|rian|cil|mol|yon)"
|
||||
FANTASY_K_N = "(taith|kach|chak|kank|kjar|rak|kan|kaj|tach|rskal|kjol|jok|jor|jad|kot|kon|" +
|
||||
"knir|kror|kol|tul|rhaok|rhak|krol|jan|kag|ryr)(<vc>|in|or|an|ar|och|un|mar|yk|ja|arn|ir|ros|ror)" +
|
||||
"(|(mund|ard|arn|karr|chim|kos|rir|arl|kni|var|an|in|ir|a|i|as))"
|
||||
FANTASY_J_G_Z = "(aj|ch|etz|etzl|tz|kal|gahn|kab|aj|izl|ts|jaj|lan|kach|chaj|qaq|jol|ix|az|biq|nam)" +
|
||||
"(|(<vc>|aw|al|yes|il|ay|en|tom||oj|im|ol|aj|an|as))" +
|
||||
"(aj|am|al|aqa|ende|elja|ich|ak|ix|in|ak|al|il|ek|ij|os|al|im)"
|
||||
FANTASY_K_J_Y = "(yi|shu|a|be|na|chi|cha|cho|ksa|yi|shu)" +
|
||||
"(th|dd|jj|sh|rr|mk|n|rk|y|jj|th)" +
|
||||
"(us|ash|eni|akra|nai|ral|ect|are|el|urru|aja|al|uz|ict|arja|ichi|ural|iru|aki|esh)"
|
||||
FANTASY_S_E = "(syth|sith|srr|sen|yth|ssen|then|fen|ssth|kel|syn|est|bess|inth|nen|tin|cor|" +
|
||||
"sv|iss|ith|sen|slar|ssil|sthen|svis|s|ss|s|ss)" +
|
||||
"(|(tys|eus|yn|of|es|en|ath|elth|al|ell|ka|ith|yrrl|is|isl|yr|ast|iy))" +
|
||||
"(us|yn|en|ens|ra|rg|le|en|ith|ast|zon|in|yn|ys)"
|
||||
)
|
||||
|
||||
type Template struct {
|
||||
Name string
|
||||
Tmpl string
|
||||
}
|
||||
|
||||
var Templates = map[string]string{
|
||||
"MiddleEarth": MIDDLE_EARTH,
|
||||
"JapaneseNamesConstrained": JAPANESE_NAMES_CONSTRAINED,
|
||||
"JapaneseNamesDiverse": JAPANESE_NAMES_DIVERSE,
|
||||
"ChineseNames": CHINESE_NAMES,
|
||||
"GreekNames": GREEK_NAMES,
|
||||
"HawaiianNames1": HAWAIIAN_NAMES_1,
|
||||
"HawaiianNames2": HAWAIIAN_NAMES_2,
|
||||
"OldLatinPlaceNames": OLD_LATIN_PLACE_NAMES,
|
||||
"DragonsPern": DRAGONS_PERN,
|
||||
"DragonRiders": DRAGON_RIDERS,
|
||||
"Pokemon": POKEMON,
|
||||
"FantasyR": FANTASY_VOWELS_R,
|
||||
"FantasySA": FANTASY_S_A,
|
||||
"FantasyHL": FANTASY_H_L,
|
||||
"FantasyNL": FANTASY_N_L,
|
||||
"FantasyKN": FANTASY_K_N,
|
||||
"FantasyJGZ": FANTASY_J_G_Z,
|
||||
"FantasyKJY": FANTASY_K_J_Y,
|
||||
"FantasySE": FANTASY_S_E,
|
||||
"Funny": "sdD",
|
||||
"Idiots": "ii",
|
||||
}
|
||||
|
||||
const (
|
||||
VERSION string = "0.0.9"
|
||||
DefaultCount int = 160 // number of words to generate if -c is omitted
|
||||
DefaultColumns int = 10 // number of columns to print
|
||||
MaxWidth int = 72 // max width of output, adjusts columns
|
||||
Usage string = `This is gfn, a fantasy name generator cli.
|
||||
|
||||
Usage: gfn [-vld] [-c <config file>] [-n <number of names>] <name|code>
|
||||
|
||||
Options:
|
||||
-c --config Config file to use (optional)
|
||||
-n --number Number of names to generate
|
||||
-l --list List pre-compiled shortcuts
|
||||
-d --debug Show debugging output
|
||||
-v --version Show program version
|
||||
|
||||
pattern syntax The letters s, v, V, c, B, C, i, m, M, D, and d
|
||||
represent different types of random replacements:
|
||||
|
||||
s - generic syllable
|
||||
v - vowel
|
||||
V - vowel or vowel combination
|
||||
c - consonant
|
||||
B - consonant or consonant combination suitable for beginning a word
|
||||
C - consonant or consonant combination suitable anywhere in a word
|
||||
i - insult
|
||||
m - mushy name
|
||||
M - mushy name ending
|
||||
D - consonant suited for a stupid person's name
|
||||
d - syllable suited for a stupid person's name (begins with a vowel)
|
||||
Everything else is emitted literally.
|
||||
|
||||
All characters between parenthesis () are emitted literally. For
|
||||
example, the pattern s(dim), emits a random generic syllable followed
|
||||
by dim.
|
||||
|
||||
Characters between angle brackets <> emit patterns from the table
|
||||
above. Imagine the entire pattern is wrapped in one of these.
|
||||
|
||||
In both types of groupings, a vertical bar | denotes a random
|
||||
choice. Empty groups are allowed. For example, (foo|bar) emits either
|
||||
foo or bar. The pattern <c|v|> emits a constant, vowel, or nothing at
|
||||
all.
|
||||
|
||||
An exclamation point ! means to capitalize the component that follows
|
||||
it. For example, !(foo) will emit Foo and v!s will emit a lowercase
|
||||
vowel followed by a capitalized syllable, like eRod.`
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Showversion bool `koanf:"version"` // -v
|
||||
Debug bool `koanf:"debug"` // -d
|
||||
Listshortcuts bool `koanf:"list"` // -l
|
||||
Number int `koanf:"number"` // -c
|
||||
Templates map[string]string `koanf:"templates"`
|
||||
Config string `koanf:"config"`
|
||||
Columns int `koanf:"columns"` // number of columns to use
|
||||
Code string // arg
|
||||
WordWidth int // max width of generated words
|
||||
}
|
||||
|
||||
func InitConfig(output io.Writer) (*Config, error) {
|
||||
var kloader = koanf.New(".")
|
||||
|
||||
// Load default values using the confmap provider.
|
||||
if err := kloader.Load(confmap.Provider(map[string]interface{}{
|
||||
"number": DefaultCount,
|
||||
"columns": DefaultColumns,
|
||||
}, "."), nil); err != nil {
|
||||
return nil, fmt.Errorf("failed to load default values into koanf: %w", err)
|
||||
}
|
||||
|
||||
// setup custom usage
|
||||
flagset := flag.NewFlagSet("config", flag.ContinueOnError)
|
||||
flagset.Usage = func() {
|
||||
_, err := fmt.Fprintln(output, Usage)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// parse commandline flags
|
||||
flagset.BoolP("list", "l", false, "show list of precompiled codes")
|
||||
flagset.BoolP("version", "v", false, "show program version")
|
||||
flagset.BoolP("debug", "d", false, "enable debug output")
|
||||
flagset.IntP("number", "n", 1, "number of names to generate")
|
||||
flagset.StringP("config", "c", "", "config file")
|
||||
|
||||
if err := flagset.Parse(os.Args[1:]); err != nil {
|
||||
return nil, fmt.Errorf("failed to parse program arguments: %w", err)
|
||||
}
|
||||
|
||||
// generate a list of config files to try to load, including the
|
||||
// one provided via -c, if any
|
||||
var configfiles []string
|
||||
|
||||
configfile, _ := flagset.GetString("config")
|
||||
home, _ := os.UserHomeDir()
|
||||
|
||||
if configfile != "" {
|
||||
configfiles = []string{configfile}
|
||||
} else {
|
||||
configfiles = []string{
|
||||
"/etc/gfn.conf", "/usr/local/etc/gfn.conf", // unix variants
|
||||
filepath.Join(home, ".config", "gfn", "config"),
|
||||
filepath.Join(home, ".gfn"),
|
||||
"gfn.conf",
|
||||
}
|
||||
}
|
||||
|
||||
// Load the config file[s]
|
||||
for _, cfgfile := range configfiles {
|
||||
if path, err := os.Stat(cfgfile); !os.IsNotExist(err) {
|
||||
if !path.IsDir() {
|
||||
if err := kloader.Load(file.Provider(cfgfile), toml.Parser()); err != nil {
|
||||
return nil, fmt.Errorf("error loading config file: %w", err)
|
||||
}
|
||||
}
|
||||
} // else: we ignore the file if it doesn't exists
|
||||
}
|
||||
|
||||
// command line setup
|
||||
if err := kloader.Load(posflag.Provider(flagset, ".", kloader), nil); err != nil {
|
||||
return nil, fmt.Errorf("error loading flags: %w", err)
|
||||
}
|
||||
|
||||
// fetch values
|
||||
conf := &Config{}
|
||||
if err := kloader.Unmarshal("", &conf); err != nil {
|
||||
return nil, fmt.Errorf("error unmarshalling: %w", err)
|
||||
}
|
||||
|
||||
// arg is the code
|
||||
if len(flagset.Args()) > 0 {
|
||||
conf.Code = flagset.Args()[0]
|
||||
}
|
||||
|
||||
// merge configured and hardcoded templates
|
||||
if conf.Templates == nil {
|
||||
conf.Templates = Templates
|
||||
} else {
|
||||
for name, code := range Templates {
|
||||
conf.Templates[name] = code
|
||||
}
|
||||
}
|
||||
|
||||
return conf, nil
|
||||
}
|
||||
76
generate.go
76
generate.go
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
fn "github.com/s0rg/fantasyname"
|
||||
)
|
||||
|
||||
// Actual fantasy name generation
|
||||
func Generate(conf *Config) ([]string, error) {
|
||||
// we register each generated word to avoid duplicates, which
|
||||
// naturally happens every while
|
||||
reg := map[string]int{}
|
||||
|
||||
// library call
|
||||
gen, err := fn.Compile(conf.Code, fn.Collapse(true))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not compile FN code: %w", err)
|
||||
}
|
||||
|
||||
// fetch requested number of names
|
||||
for i := 0; len(reg) < conf.Number; i++ {
|
||||
name := gen.String()
|
||||
|
||||
if !Exists(reg, name) {
|
||||
reg[name] = 1
|
||||
|
||||
if conf.WordWidth < len(name) {
|
||||
conf.WordWidth = len(name)
|
||||
}
|
||||
}
|
||||
|
||||
// static codes (like 'akx', which is no FN code, just a
|
||||
// literal) generates just 1 item
|
||||
if i > conf.Number*2 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
slog.Debug("Generated fantasy names from code",
|
||||
"code", conf.Code, "count-names", len(reg))
|
||||
|
||||
// adjust columns, if needed
|
||||
if conf.WordWidth*conf.Columns > MaxWidth {
|
||||
conf.Columns = MaxWidth / conf.WordWidth
|
||||
}
|
||||
|
||||
// we just return a slice of names
|
||||
names := make([]string, len(reg))
|
||||
|
||||
i := 0
|
||||
for k := range reg {
|
||||
names[i] = k
|
||||
i++
|
||||
}
|
||||
|
||||
return names, nil
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var tests = []struct {
|
||||
name string
|
||||
want bool
|
||||
code string
|
||||
}{
|
||||
{
|
||||
name: "code-ok",
|
||||
want: true,
|
||||
code: "!s(na|ha|ma|va)v",
|
||||
},
|
||||
{
|
||||
name: "code-fail",
|
||||
want: false,
|
||||
code: "!s(na|ha|ma|vav",
|
||||
},
|
||||
}
|
||||
|
||||
var conf = &Config{
|
||||
Number: 3,
|
||||
}
|
||||
|
||||
func TestGenerate(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
testname := fmt.Sprintf("generate-%s", tt.name)
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
conf.Code = tt.code
|
||||
|
||||
names, err := Generate(conf)
|
||||
|
||||
if err != nil {
|
||||
if tt.want {
|
||||
t.Errorf("Generate() returned an unexpected error: %s", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if len(names) != 3 {
|
||||
t.Errorf("Generate() returned wrong number of results\nExp: %+v\nGot: %+v\n",
|
||||
conf.Number, len(names))
|
||||
return
|
||||
}
|
||||
|
||||
for idx, name := range names {
|
||||
if len(name) == 0 {
|
||||
t.Errorf("Generate() returned empty results\nIndex: %d\nGot: <%s>\n",
|
||||
idx, name)
|
||||
return
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
5
gfn.conf
5
gfn.conf
@@ -1,5 +0,0 @@
|
||||
# example config file
|
||||
[[Templates]]
|
||||
morph = "!s(na|ha|ma|va)v"
|
||||
morphium = "!s(na|ha|ma|va)v(ius|ium|aum|oum|eum)"
|
||||
|
||||
33
go.mod
33
go.mod
@@ -1,33 +0,0 @@
|
||||
module codeberg.org/scip/gfn
|
||||
|
||||
go 1.24.0
|
||||
|
||||
toolchain go1.24.5
|
||||
|
||||
require (
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0
|
||||
github.com/knadh/koanf/providers/confmap v1.0.0
|
||||
github.com/knadh/koanf/providers/file v1.2.0
|
||||
github.com/knadh/koanf/providers/posflag v1.0.1
|
||||
github.com/knadh/koanf/v2 v2.3.0
|
||||
github.com/rogpeppe/go-internal v1.14.1
|
||||
github.com/s0rg/fantasyname v1.3.6
|
||||
github.com/spf13/pflag v1.0.10
|
||||
github.com/tlinden/yadu v0.1.3
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/fatih/color v1.16.0 // indirect
|
||||
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 // indirect
|
||||
github.com/knadh/koanf/maps v0.1.2 // indirect
|
||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml v1.9.5 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/tools v0.26.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
53
go.sum
53
go.sum
@@ -1,53 +0,0 @@
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9LvH92wZUgs=
|
||||
github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/knadh/koanf/maps v0.1.2 h1:RBfmAW5CnZT+PJ1CVc1QSJKf4Xu9kxfQgYVQSu8hpbo=
|
||||
github.com/knadh/koanf/maps v0.1.2/go.mod h1:npD/QZY3V6ghQDdcQzl1W4ICNVTkohC8E73eI2xW4yI=
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0 h1:S2hLqS4TgWZYj4/7mI5m1CQQcWurxUz6ODgOub/6LCI=
|
||||
github.com/knadh/koanf/parsers/toml v0.1.0/go.mod h1:yUprhq6eo3GbyVXFFMdbfZSo928ksS+uo0FFqNMnO18=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.0 h1:mHKLJTE7iXEys6deO5p6olAiZdG5zwp8Aebir+/EaRE=
|
||||
github.com/knadh/koanf/providers/confmap v1.0.0/go.mod h1:txHYHiI2hAtF0/0sCmcuol4IDcuQbKTybiB1nOcUo1A=
|
||||
github.com/knadh/koanf/providers/file v1.2.0 h1:hrUJ6Y9YOA49aNu/RSYzOTFlqzXSCpmYIDXI7OJU6+U=
|
||||
github.com/knadh/koanf/providers/file v1.2.0/go.mod h1:bp1PM5f83Q+TOUu10J/0ApLBd9uIzg+n9UgthfY+nRA=
|
||||
github.com/knadh/koanf/providers/posflag v1.0.1 h1:EnMxHSrPkYCFnKgBUl5KBgrjed8gVFrcXDzaW4l/C6Y=
|
||||
github.com/knadh/koanf/providers/posflag v1.0.1/go.mod h1:3Wn3+YG3f4ljzRyCUgIwH7G0sZ1pMjCOsNBovrbKmAk=
|
||||
github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM=
|
||||
github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
|
||||
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
|
||||
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
|
||||
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
|
||||
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
|
||||
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
|
||||
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
|
||||
github.com/s0rg/fantasyname v1.3.6 h1:KOezDl0ijuuIDre06tqMz8idCEIdaM7KMkSnU/8bCxc=
|
||||
github.com/s0rg/fantasyname v1.3.6/go.mod h1:9cZ037rckuT6N7DijPi2xpuuYFgJpLlcbpXMptYuEdY=
|
||||
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/tlinden/yadu v0.1.3 h1:5cRCUmj+l5yvlM2irtpFBIJwVV2DPEgYSaWvF19FtcY=
|
||||
github.com/tlinden/yadu v0.1.3/go.mod h1:l3bRmHKL9zGAR6pnBHY2HRPxBecf7L74BoBgOOpTcUA=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
|
||||
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
115
main.go
115
main.go
@@ -1,115 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
|
||||
"log/slog"
|
||||
|
||||
"github.com/tlinden/yadu"
|
||||
)
|
||||
|
||||
func main() {
|
||||
os.Exit(Main(os.Stdout))
|
||||
}
|
||||
|
||||
func TMain() int {
|
||||
return Main(os.Stdout)
|
||||
}
|
||||
|
||||
func Main(output io.Writer) int {
|
||||
// parse config file and command line parameters, if any
|
||||
conf, err := InitConfig(output)
|
||||
if err != nil {
|
||||
return Die(err)
|
||||
}
|
||||
|
||||
if conf.Showversion {
|
||||
_, err := fmt.Fprintf(output, "This is gfn version %s\n", VERSION)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// enable debugging, if needed. We only use log/slog for
|
||||
// debugging, so there's no need to configure it outside debugging
|
||||
if conf.Debug {
|
||||
logLevel := &slog.LevelVar{}
|
||||
// we're using a more verbose logger in debug mode
|
||||
buildInfo, _ := debug.ReadBuildInfo()
|
||||
opts := &yadu.Options{
|
||||
Level: logLevel,
|
||||
AddSource: true,
|
||||
}
|
||||
|
||||
logLevel.Set(slog.LevelDebug)
|
||||
|
||||
handler := yadu.NewHandler(output, opts)
|
||||
debuglogger := slog.New(handler).With(
|
||||
slog.Group("program_info",
|
||||
slog.Int("pid", os.Getpid()),
|
||||
slog.String("go_version", buildInfo.GoVersion),
|
||||
),
|
||||
)
|
||||
slog.SetDefault(debuglogger)
|
||||
}
|
||||
|
||||
// just show what we have
|
||||
if conf.Listshortcuts {
|
||||
ListTemplates(conf, output)
|
||||
return 0
|
||||
}
|
||||
|
||||
// code argument is mandatory
|
||||
if len(conf.Code) == 0 {
|
||||
_, err := fmt.Fprintln(output, Usage)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// check if we can use a template, otherwise consider the argument
|
||||
// to be FN code
|
||||
if Exists(conf.Templates, conf.Code) {
|
||||
slog.Debug("Argument resolves to template code",
|
||||
"name", conf.Code, "code", conf.Templates[conf.Code])
|
||||
|
||||
conf.Code = conf.Templates[conf.Code]
|
||||
}
|
||||
|
||||
// all prepared, run baby run
|
||||
names, err := Generate(conf)
|
||||
if err != nil {
|
||||
return Die(err)
|
||||
}
|
||||
|
||||
if err = PrintColumns(conf, names, output); err != nil {
|
||||
return Die(err)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
38
main_test.go
38
main_test.go
@@ -1,38 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/rogpeppe/go-internal/testscript"
|
||||
)
|
||||
|
||||
// see https://bitfieldconsulting.com/golang/test-scripts
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testscript.Main(m, map[string]func(){
|
||||
"gfn": main,
|
||||
})
|
||||
}
|
||||
|
||||
func TestGfn(t *testing.T) {
|
||||
testscript.Run(t, testscript.Params{
|
||||
Dir: "t",
|
||||
})
|
||||
}
|
||||
75
mkrel.sh
75
mkrel.sh
@@ -1,75 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright © 2024 Thomas von Dein
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
# get list with: go tool dist list
|
||||
DIST="darwin/amd64
|
||||
freebsd/amd64
|
||||
linux/amd64
|
||||
netbsd/amd64
|
||||
openbsd/amd64
|
||||
windows/amd64
|
||||
freebsd/arm64
|
||||
linux/arm64
|
||||
netbsd/arm64
|
||||
openbsd/arm64
|
||||
windows/arm64"
|
||||
|
||||
tool="$1"
|
||||
version="$2"
|
||||
|
||||
if test -z "$version"; then
|
||||
echo "Usage: $0 <tool name> <release version>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -rf releases
|
||||
mkdir -p releases
|
||||
|
||||
|
||||
for D in $DIST; do
|
||||
os=${D/\/*/}
|
||||
arch=${D/*\//}
|
||||
binfile="releases/${tool}-${os}-${arch}-${version}"
|
||||
|
||||
if test "$os" = "windows"; then
|
||||
binfile="${binfile}.exe"
|
||||
fi
|
||||
|
||||
tardir="${tool}-${os}-${arch}-${version}"
|
||||
tarfile="releases/${tool}-${os}-${arch}-${version}.tar.gz"
|
||||
set -x
|
||||
GOOS=${os} GOARCH=${arch} go build -tags osusergo,netgo -ldflags "-extldflags=-static" -o ${binfile}
|
||||
mkdir -p ${tardir}
|
||||
cp ${binfile} README.md LICENSE ${tardir}/
|
||||
echo 'tool = gfn
|
||||
PREFIX = /usr/local
|
||||
UID = root
|
||||
GID = 0
|
||||
|
||||
install:
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/bin
|
||||
install -d -o $(UID) -g $(GID) $(PREFIX)/man/man1
|
||||
install -o $(UID) -g $(GID) -m 555 $(tool) $(PREFIX)/sbin/
|
||||
install -o $(UID) -g $(GID) -m 444 $(tool).1 $(PREFIX)/man/man1/' > ${tardir}/Makefile
|
||||
tar cpzf ${tarfile} ${tardir}
|
||||
sha256sum ${binfile} | cut -d' ' -f1 > ${binfile}.sha256
|
||||
sha256sum ${tarfile} | cut -d' ' -f1 > ${tarfile}.sha256
|
||||
rm -rf ${tardir}
|
||||
set +x
|
||||
done
|
||||
|
||||
118
printer.go
118
printer.go
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"log/slog"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// Output a list of hardcoded FN code templates
|
||||
func ListTemplates(conf *Config, output io.Writer) {
|
||||
slog.Debug("Listing configured templates", "templates", conf.Templates)
|
||||
|
||||
names := []string{}
|
||||
|
||||
for name := range conf.Templates {
|
||||
names = append(names, name)
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
|
||||
for _, name := range names {
|
||||
_, err := fmt.Fprintln(output, name)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Columnar output
|
||||
func PrintColumns(conf *Config, names []string, output io.Writer) error {
|
||||
count := len(names)
|
||||
|
||||
// no need for the hassle to calculate columns
|
||||
if count <= conf.Columns {
|
||||
for _, name := range names {
|
||||
_, err := fmt.Fprintln(output, name)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// get a transposed list of columns
|
||||
padlist, max := Getcolumns(names, conf.Columns)
|
||||
|
||||
// make sure there's enough spacing between the columns
|
||||
format := fmt.Sprintf("%%-%ds", max+1)
|
||||
|
||||
for _, row := range padlist {
|
||||
for _, word := range row {
|
||||
_, err := fmt.Fprintf(output, format, word)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
}
|
||||
_, err := fmt.Fprintln(output)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to print to output: %s", err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Getcolumns(names []string, columns int) ([][]string, int) {
|
||||
words := len(names)
|
||||
max := 0
|
||||
|
||||
// we'll have a list of $columns columns
|
||||
padlist := make([][]string, columns)
|
||||
|
||||
// initialize'em
|
||||
for col := 0; col < columns; col++ {
|
||||
padlist[col] = []string{}
|
||||
}
|
||||
|
||||
// fill from input
|
||||
for idx := 0; idx < words; idx += columns {
|
||||
for col := 0; col < columns; col++ {
|
||||
if idx+col >= words {
|
||||
padlist[col] = append(padlist[col], "")
|
||||
} else {
|
||||
padlist[col] = append(padlist[col], names[idx+col])
|
||||
length := len(names[idx+col])
|
||||
if length > max {
|
||||
max = length
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// turn columns to rows
|
||||
return Transpose(padlist), max
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn -d Vs
|
||||
stdout 'gfn/generate.go:'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn -h
|
||||
stdout 'This is gfn'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn -l
|
||||
stdout 'JapaneseNamesDiverse'
|
||||
@@ -1 +0,0 @@
|
||||
! exec gfn
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn akx
|
||||
stdout 'akx'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn akx
|
||||
! stdout 'akx akx'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn Idiots
|
||||
stdout 'face'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn sVdmi(usus|hehe)
|
||||
stdout 'usus'
|
||||
@@ -1,2 +0,0 @@
|
||||
exec gfn -v
|
||||
stdout 'This is gfn version'
|
||||
65
util.go
65
util.go
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import "log"
|
||||
|
||||
func Exists[K comparable, V any](m map[K]V, v K) bool {
|
||||
if _, ok := m[v]; ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func Die(err error) int {
|
||||
log.Fatal("Error: ", err.Error())
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
// find an item in a list, generic variant
|
||||
func Contains[E comparable](s []E, v E) bool {
|
||||
for _, vs := range s {
|
||||
if v == vs {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Transpose a matrix, x=>y, y=>x
|
||||
// via https://gist.github.com/tanaikech/5cb41424ff8be0fdf19e78d375b6adb8
|
||||
func Transpose(slice [][]string) [][]string {
|
||||
xl := len(slice[0])
|
||||
yl := len(slice)
|
||||
|
||||
result := make([][]string, xl)
|
||||
|
||||
for i := range result {
|
||||
result[i] = make([]string, yl)
|
||||
}
|
||||
|
||||
for i := 0; i < xl; i++ {
|
||||
for j := 0; j < yl; j++ {
|
||||
result[i][j] = slice[j][i]
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
139
util_test.go
139
util_test.go
@@ -1,139 +0,0 @@
|
||||
/*
|
||||
Copyright © 2024 Thomas von Dein
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testexists = []struct {
|
||||
name string
|
||||
want bool
|
||||
key int
|
||||
hash map[int]int
|
||||
}{
|
||||
{
|
||||
name: "have-key",
|
||||
want: true,
|
||||
key: 1,
|
||||
hash: map[int]int{1: 4, 2: 5},
|
||||
},
|
||||
{
|
||||
name: "miss-key",
|
||||
want: false,
|
||||
key: 3,
|
||||
hash: map[int]int{1: 4, 2: 5},
|
||||
},
|
||||
}
|
||||
|
||||
func TestExists(t *testing.T) {
|
||||
for _, tt := range testexists {
|
||||
testname := fmt.Sprintf("exists-%s", tt.name)
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
got := Exists(tt.hash, tt.key)
|
||||
|
||||
if got != tt.want {
|
||||
t.Errorf("Exists() returned wrong result\nExp: %+v\nGot: %+v\n",
|
||||
tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var testcontains = []struct {
|
||||
name string
|
||||
want bool
|
||||
key int
|
||||
list []int
|
||||
}{
|
||||
{
|
||||
name: "have-item",
|
||||
want: true,
|
||||
key: 1,
|
||||
list: []int{1, 2},
|
||||
},
|
||||
{
|
||||
name: "miss-item",
|
||||
want: false,
|
||||
key: 3,
|
||||
list: []int{1, 2},
|
||||
},
|
||||
}
|
||||
|
||||
func TestContains(t *testing.T) {
|
||||
for _, tt := range testcontains {
|
||||
testname := fmt.Sprintf("contains-%s", tt.name)
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
got := Contains(tt.list, tt.key)
|
||||
|
||||
if got != tt.want {
|
||||
t.Errorf("Contains() returned wrong result\nExp: %+v\nGot: %+v\n",
|
||||
tt.want, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var testtranspose = []struct {
|
||||
name string
|
||||
slice [][]string
|
||||
expect [][]string
|
||||
}{
|
||||
{
|
||||
name: "2x2-matrix",
|
||||
slice: [][]string{
|
||||
{"a1", "a2"},
|
||||
{"b1", "b2"},
|
||||
},
|
||||
expect: [][]string{
|
||||
{"a1", "b1"},
|
||||
{"a2", "b2"},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "2x3-matrix",
|
||||
slice: [][]string{
|
||||
{"a1", "a2", "a3"},
|
||||
{"b1", "b2", "b3"},
|
||||
},
|
||||
expect: [][]string{
|
||||
{"a1", "b1"},
|
||||
{"a2", "b2"},
|
||||
{"a3", "b3"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestTranspose(t *testing.T) {
|
||||
for _, tt := range testtranspose {
|
||||
testname := fmt.Sprintf("transpose-%s", tt.name)
|
||||
t.Run(testname, func(t *testing.T) {
|
||||
got := Transpose(tt.slice)
|
||||
|
||||
if !reflect.DeepEqual(tt.expect, got) {
|
||||
t.Errorf("Transpose() returned wrong result\nExp: %+v\nGot: %+v\n",
|
||||
tt.expect, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user