🔀 Merge branch 'release/0.5.1' into stable
This commit is contained in:
		
				commit
				
					
						a5d78898c5
					
				
			
		
					 14 changed files with 153 additions and 104 deletions
				
			
		
							
								
								
									
										39
									
								
								.golangci.yaml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								.golangci.yaml
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,39 @@ | |||
| linters: | ||||
|   enable: | ||||
|     - errcheck | ||||
|     - gosimple | ||||
|     - govet | ||||
|     - ineffassign | ||||
|     - staticcheck | ||||
|     - unused | ||||
|     - copyloopvar | ||||
|     - dupl | ||||
|     - err113 | ||||
|     - errname | ||||
|     - exptostd | ||||
|     - fatcontext | ||||
|     - funlen | ||||
|     - gocognit | ||||
|     - goconst | ||||
|     - gocritic | ||||
|     - gocyclo | ||||
|     - godot | ||||
|     - godox | ||||
|     - gosec | ||||
|     - perfsprint | ||||
|     - testifylint | ||||
| 
 | ||||
| linters-settings: | ||||
|   testifylint: | ||||
|     enable-all: true | ||||
|     disable: | ||||
|       - require-error | ||||
|   gocognit: | ||||
|     min-complexity: 5 | ||||
|   gocyclo: | ||||
|     min-complexity: 5 | ||||
|   gocritic: | ||||
|     enable-all: true | ||||
|     settings: | ||||
|       hugeParam: | ||||
|         sizeThreshold: 255 | ||||
|  | @ -10,7 +10,7 @@ | |||
| 
 | ||||
| #### Support | ||||
| 
 | ||||
| - 📝 Some better examples` | ||||
| - 📝 Some better examples | ||||
| 
 | ||||
| ### [0.4.0] - 2025-03-15 - ✨ More Generators, and `Generator.Make` method | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										62
									
								
								Taskfile.yml
									
										
									
									
									
								
							
							
						
						
									
										62
									
								
								Taskfile.yml
									
										
									
									
									
								
							|  | @ -5,7 +5,7 @@ tasks: | |||
|     cmds: | ||||
|       - task: fmt | ||||
|       - task: test | ||||
|       - task: build | ||||
|       - task: lint | ||||
| 
 | ||||
|   fmt: | ||||
|     desc: Format go code | ||||
|  | @ -22,66 +22,16 @@ tasks: | |||
|     cmds: | ||||
|       - go generate ./... | ||||
| 
 | ||||
|   vet: | ||||
|     desc: Vet go code | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - go vet ./... | ||||
| 
 | ||||
|   critic: | ||||
|     desc: Critique go code | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - gocritic check ./... | ||||
| 
 | ||||
|   staticcheck: | ||||
|     desc: Static check go code | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - staticcheck ./... | ||||
| 
 | ||||
|   cog-complex: | ||||
|     desc: Calculate cognitive complexity | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - gocognit -over 5 . | ||||
| 
 | ||||
|   cyc-complex: | ||||
|     desc: Calculate cyclomatic complexity | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - gocyclo -over 5 . | ||||
| 
 | ||||
|   complex: | ||||
|     desc: Calculate complexities | ||||
|     deps: | ||||
|       - cog-complex | ||||
|       - cyc-complex | ||||
| 
 | ||||
|   vuln: | ||||
|     desc: Check for vulnerabilities | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - govulncheck ./... | ||||
| 
 | ||||
|   lint: | ||||
|     desc: Do static analysis | ||||
|     deps: | ||||
|       - vet | ||||
|       - critic | ||||
|       - staticcheck | ||||
|       - complex | ||||
|       - vuln | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     cmds: | ||||
|       - golangci-lint run | ||||
| 
 | ||||
|   test: | ||||
|     desc: Run unit tests | ||||
|     deps: [fmt, vet] | ||||
|     deps: [fmt] | ||||
|     sources: | ||||
|       - '**/*.go' | ||||
|     generates: | ||||
|  |  | |||
							
								
								
									
										56
									
								
								examples_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								examples_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,56 @@ | |||
| package nomino_test | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"codeberg.org/danjones000/nomino" | ||||
| ) | ||||
| 
 | ||||
| // Define a global Config. | ||||
| func NominoConfig() nomino.Config { | ||||
| 	return nomino.NewConfig( | ||||
| 		nomino.WithSeparator("-"), | ||||
| 		nomino.WithPrefix("upload"), | ||||
| 		nomino.WithGenerator(nomino.UUID( | ||||
| 			nomino.UUIDv7, | ||||
| 		)), | ||||
| 	) | ||||
| } | ||||
| 
 | ||||
| // / HandleImgUploads generates new filenames for images with a png extension. | ||||
| func HandleImgUploads(orig string) string { | ||||
| 	newName, _ := nomino.Make( | ||||
| 		NominoConfig(), | ||||
| 		nomino.WithExtension("png"), | ||||
| 		nomino.WithOriginalSlug(orig), | ||||
| 	) | ||||
| 
 | ||||
| 	return newName | ||||
| } | ||||
| 
 | ||||
| // HandleVidUploads generates a new filename for videos. | ||||
| // We ignore the original filename and use a timestamp for the generated part | ||||
| // with a webm extension. | ||||
| func HandleVidUploads() string { | ||||
| 	newName, _ := nomino.Timestamp(nomino.TimestampUTC()). | ||||
| 		MakeWithConfig(NominoConfig().AddOptions( | ||||
| 			nomino.WithExtension("webm"), | ||||
| 		)) | ||||
| 	return newName | ||||
| } | ||||
| 
 | ||||
| // Example shows how to use nomino. | ||||
| func Example() { | ||||
| 	// Pretend we have an image upload | ||||
| 	filename := "George" | ||||
| 	uploadImgName := HandleImgUploads(filename) | ||||
| 
 | ||||
| 	// Upload to storage | ||||
| 	fmt.Println(uploadImgName) | ||||
| 
 | ||||
| 	// New Video Upload | ||||
| 	uploadVidName := HandleVidUploads() | ||||
| 
 | ||||
| 	// Upload to storage | ||||
| 	fmt.Println(uploadVidName) | ||||
| } | ||||
							
								
								
									
										12
									
								
								gen_file.go
									
										
									
									
									
								
							
							
						
						
									
										12
									
								
								gen_file.go
									
										
									
									
									
								
							|  | @ -2,14 +2,14 @@ package nomino | |||
| 
 | ||||
| import ( | ||||
| 	"crypto" | ||||
| 	"encoding/hex" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"hash" | ||||
| 
 | ||||
| 	"github.com/gosimple/slug" | ||||
| ) | ||||
| 
 | ||||
| // ErrMissingOriginal is the error returned by Slug if there is no filename | ||||
| // ErrMissingOriginal is the error returned by Slug if there is no filename. | ||||
| var ErrMissingOriginal = errors.New("missing original filename") | ||||
| 
 | ||||
| func getOriginal(c *Config) (string, error) { | ||||
|  | @ -37,10 +37,10 @@ func Slug(lang ...string) Generator { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // HashingFunc is a function that generates a hash.Hash | ||||
| // HashingFunc is a function that generates a hash.Hash. | ||||
| type HashingFunc func() hash.Hash | ||||
| 
 | ||||
| // New allows HashingFunc to be used as a Hasher | ||||
| // New allows HashingFunc to be used as a Hasher. | ||||
| func (hf HashingFunc) New() hash.Hash { | ||||
| 	return hf() | ||||
| } | ||||
|  | @ -51,7 +51,7 @@ type Hasher interface { | |||
| 	New() hash.Hash | ||||
| } | ||||
| 
 | ||||
| // ErrInvalidHash is returned by the Hash generator when an invalid HashType is passed | ||||
| // ErrInvalidHash is returned by the Hash generator when an invalid HashType is passed. | ||||
| var ErrInvalidHash = errors.New("invalid hash type") | ||||
| 
 | ||||
| // Hash generates a name from a hash of the filename. | ||||
|  | @ -70,6 +70,6 @@ func Hash(h Hasher) Generator { | |||
| 		} | ||||
| 		hs := h.New() | ||||
| 		hs.Write([]byte(name)) | ||||
| 		return fmt.Sprintf("%x", hs.Sum(nil)), nil | ||||
| 		return hex.EncodeToString(hs.Sum(nil)), nil | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -11,7 +11,7 @@ type incConf struct { | |||
| 	cb    func(int) string | ||||
| } | ||||
| 
 | ||||
| // IncrementalOption sets an option for the Incremental Generator | ||||
| // IncrementalOption sets an option for the Incremental Generator. | ||||
| type IncrementalOption func(c *incConf) | ||||
| 
 | ||||
| // Incremental generates a name that is a series of integers. | ||||
|  | @ -30,7 +30,7 @@ func Incremental(opts ...IncrementalOption) Generator { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // IncrementalStart sets the starting integer for Incremental | ||||
| // IncrementalStart sets the starting integer for Incremental. | ||||
| func IncrementalStart(start int) IncrementalOption { | ||||
| 	return func(c *incConf) { | ||||
| 		c.start = start | ||||
|  | @ -45,7 +45,7 @@ func IncrementalStep(step int) IncrementalOption { | |||
| } | ||||
| 
 | ||||
| // IncrementalFormatsets the format for the number generated by Incremental. | ||||
| // It will be formatted with Printf. This is mostly likely useful with a format like "%02d" | ||||
| // It will be formatted with Printf. This is mostly likely useful with a format like "%02d". | ||||
| func IncrementalFormat(format string) IncrementalOption { | ||||
| 	return func(c *incConf) { | ||||
| 		c.cb = func(i int) string { | ||||
|  |  | |||
							
								
								
									
										16
									
								
								gen_rand.go
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								gen_rand.go
									
										
									
									
									
								
							|  | @ -52,10 +52,10 @@ type randConf struct { | |||
| 	length int | ||||
| } | ||||
| 
 | ||||
| // RandomOption is an option for the Random Generator | ||||
| // RandomOption is an option for the Random Generator. | ||||
| type RandomOption func(*randConf) | ||||
| 
 | ||||
| // RandomLength controls the length of the string generated by Random | ||||
| // RandomLength controls the length of the string generated by Random. | ||||
| func RandomLength(length int) RandomOption { | ||||
| 	return func(c *randConf) { | ||||
| 		c.length = length | ||||
|  | @ -64,11 +64,17 @@ func RandomLength(length int) RandomOption { | |||
| 
 | ||||
| func getRandomBytes(l int) []byte { | ||||
| 	key := make([]byte, l) | ||||
| 	rand.Read(key) | ||||
| 	_, _ = rand.Read(key) | ||||
| 	e := base62.StdEncoding.Encode(key) | ||||
| 	return e[:l] | ||||
| } | ||||
| 
 | ||||
| func fillBuffer(buff *strings.Builder, length int) { | ||||
| 	for buff.Len() < length { | ||||
| 		buff.Write(getRandomBytes(length - buff.Len())) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Random generates a random string containing the characters [A-Za-z0-9]. | ||||
| // By default, it will be eight characters long. | ||||
| func Random(opts ...RandomOption) Generator { | ||||
|  | @ -79,9 +85,7 @@ func Random(opts ...RandomOption) Generator { | |||
| 	return func(*Config) (string, error) { | ||||
| 		var buff strings.Builder | ||||
| 		buff.Grow(c.length) | ||||
| 		for buff.Len() < c.length { | ||||
| 			buff.Write(getRandomBytes(c.length - buff.Len())) | ||||
| 		} | ||||
| 		fillBuffer(&buff, c.length) | ||||
| 		return buff.String(), nil | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| package nomino | ||||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/google/uuid" | ||||
|  | @ -18,7 +17,7 @@ func TestUUID(t *testing.T) { | |||
| type badRead struct{} | ||||
| 
 | ||||
| func (badRead) Read([]byte) (int, error) { | ||||
| 	return 0, errors.New("sorry") | ||||
| 	return 0, errTest | ||||
| } | ||||
| 
 | ||||
| func TestUUIDFail(t *testing.T) { | ||||
|  | @ -26,7 +25,7 @@ func TestUUIDFail(t *testing.T) { | |||
| 	defer uuid.SetRand(nil) | ||||
| 
 | ||||
| 	_, err := UUID(nil)(nil) | ||||
| 	assert.Equal(t, errors.New("sorry"), err) | ||||
| 	assert.ErrorIs(t, err, errTest) | ||||
| } | ||||
| 
 | ||||
| func TestRand(t *testing.T) { | ||||
|  |  | |||
|  | @ -2,10 +2,10 @@ package nomino | |||
| 
 | ||||
| import "time" | ||||
| 
 | ||||
| // FileTimestamp is the default format for WithTimestamp and WithTime | ||||
| // FileTimestamp is the default format for WithTimestamp and WithTime. | ||||
| const FileTimestamp string = "2006-01-02T15-04-05-0700" | ||||
| 
 | ||||
| // FileTimestampNoTZ is the default format for WithTimestampUTC and WithTimeUTC | ||||
| // FileTimestampNoTZ is the default format for WithTimestampUTC and WithTimeUTC. | ||||
| const FileTimestampNoTZ string = "2006-01-02T15-04-05" | ||||
| 
 | ||||
| type timestampConf struct { | ||||
|  | @ -14,11 +14,11 @@ type timestampConf struct { | |||
| 	utc    bool | ||||
| } | ||||
| 
 | ||||
| // TimestampOption provides options for the Timestamp Generator | ||||
| // TimestampOption provides options for the Timestamp Generator. | ||||
| type TimestampOption func(c *timestampConf) | ||||
| 
 | ||||
| // Timestamp generates a a date and time. By default, it uses the current time, and will. | ||||
| // be formatted accourding to FileTimestamp | ||||
| // be formatted accourding to FileTimestamp. | ||||
| func Timestamp(opts ...TimestampOption) Generator { | ||||
| 	c := timestampConf{format: FileTimestamp, ts: time.Now()} | ||||
| 	for _, opt := range opts { | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ func (g Generator) MakeWithConfig(c Config) (string, error) { | |||
| 	return Make(c.AddOptions(WithGenerator(g))) | ||||
| } | ||||
| 
 | ||||
| // WithGenerator sets the specified generator | ||||
| // WithGenerator sets the specified generator. | ||||
| func WithGenerator(g Generator) Option { | ||||
| 	return func(c *Config) { | ||||
| 		c.generator = g | ||||
|  | @ -66,6 +66,7 @@ func MultiGeneratorRandomOrder(gens ...Generator) Generator { | |||
| 	} | ||||
| 
 | ||||
| 	return func(c *Config) (string, error) { | ||||
| 		//nolint:gosec // This is not security sensitive, so a weak number generator is fine. | ||||
| 		idx := rand.Int() % len(gens) | ||||
| 		return gens[idx](c) | ||||
| 	} | ||||
|  |  | |||
|  | @ -37,7 +37,7 @@ func ExampleGenerator_Make() { | |||
| 
 | ||||
| func ExampleMultiGeneratorInOrder() { | ||||
| 	gen1 := func(*nomino.Config) (string, error) { | ||||
| 		return "hello", nil | ||||
| 		return "bonjour", nil | ||||
| 	} | ||||
| 	gen2 := func(*nomino.Config) (string, error) { | ||||
| 		return "goodbye", nil | ||||
|  | @ -54,17 +54,17 @@ func ExampleMultiGeneratorInOrder() { | |||
| 	fmt.Println(str) | ||||
| 
 | ||||
| 	// Output: | ||||
| 	// hello.txt | ||||
| 	// bonjour.txt | ||||
| 	// goodbye.txt | ||||
| 	// hello.txt | ||||
| 	// bonjour.txt | ||||
| } | ||||
| 
 | ||||
| func ExampleMultiGeneratorRandomOrder() { | ||||
| 	gen1 := func(*nomino.Config) (string, error) { | ||||
| 		return "hello", nil | ||||
| 		return "guten-tag", nil | ||||
| 	} | ||||
| 	gen2 := func(*nomino.Config) (string, error) { | ||||
| 		return "goodbye", nil | ||||
| 		return "wiedersehen", nil | ||||
| 	} | ||||
| 	gen := nomino.MultiGeneratorRandomOrder(gen1, gen2) | ||||
| 
 | ||||
|  |  | |||
|  | @ -7,15 +7,6 @@ import ( | |||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| 
 | ||||
| func TestWithGenerator(t *testing.T) { | ||||
| 	g := func(*Config) (string, error) { return "abc", nil } | ||||
| 	var c Config | ||||
| 	WithGenerator(g)(&c) | ||||
| 	st, err := c.generator(&c) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, "abc", st) | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	out1 string = "abc" | ||||
| 	out2 string = "def" | ||||
|  | @ -30,6 +21,15 @@ var ( | |||
| 	gens           = []Generator{gen1, gen2, gen3} | ||||
| ) | ||||
| 
 | ||||
| func TestWithGenerator(t *testing.T) { | ||||
| 	g := func(*Config) (string, error) { return out1, nil } | ||||
| 	var c Config | ||||
| 	WithGenerator(g)(&c) | ||||
| 	st, err := c.generator(&c) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, out1, st) | ||||
| } | ||||
| 
 | ||||
| func TestMultiGeneratorInOrder(t *testing.T) { | ||||
| 	g := MultiGeneratorInOrder(gens...) | ||||
| 	st, err := g(nil) | ||||
|  | @ -47,16 +47,15 @@ func TestMultiGeneratorInOrder(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func TestMultiGeneratorInOrderOne(t *testing.T) { | ||||
| 	st1 := "abc" | ||||
| 	g1 := func(*Config) (string, error) { return st1, nil } | ||||
| 	g1 := func(*Config) (string, error) { return out1, nil } | ||||
| 	g := MultiGeneratorInOrder(g1) | ||||
| 
 | ||||
| 	st, err := g(nil) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, st1, st) | ||||
| 	assert.Equal(t, out1, st) | ||||
| 	st, err = g(nil) | ||||
| 	assert.NoError(t, err) | ||||
| 	assert.Equal(t, st1, st) | ||||
| 	assert.Equal(t, out1, st) | ||||
| } | ||||
| 
 | ||||
| func TestMultiGeneratorInOrderMissing(t *testing.T) { | ||||
|  |  | |||
|  | @ -7,6 +7,8 @@ import ( | |||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| 
 | ||||
| var errTest = errors.New("sorry") | ||||
| 
 | ||||
| func TestMake(t *testing.T) { | ||||
| 	genOpt := WithGenerator(func(*Config) (string, error) { return "abc", nil }) | ||||
| 	testcases := []struct { | ||||
|  | @ -48,11 +50,10 @@ func TestMake(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func TestMakeErr(t *testing.T) { | ||||
| 	retErr := errors.New("oops") | ||||
| 	conf := NewConfig(WithGenerator(func(*Config) (string, error) { return "foobar", retErr })) | ||||
| 	conf := NewConfig(WithGenerator(func(*Config) (string, error) { return "foobar", errTest })) | ||||
| 	st, err := Make(conf) | ||||
| 	assert.Zero(t, st) | ||||
| 	assert.ErrorIs(t, err, retErr) | ||||
| 	assert.ErrorIs(t, err, errTest) | ||||
| } | ||||
| 
 | ||||
| func TestMakeDoesntChangeConf(t *testing.T) { | ||||
|  |  | |||
|  | @ -18,7 +18,7 @@ func WithOriginal(o string) Option { | |||
| } | ||||
| 
 | ||||
| // WithOriginal sets the original filename as a slug. | ||||
| // This should not be used with the Slug Generator (as it would be redundant) | ||||
| // This should not be used with the Slug Generator (as it would be redundant). | ||||
| func WithOriginalSlug(o string) Option { | ||||
| 	return func(c *Config) { | ||||
| 		c.original = slug.Make(o) | ||||
|  | @ -26,7 +26,7 @@ func WithOriginalSlug(o string) Option { | |||
| } | ||||
| 
 | ||||
| // WithOriginal sets the original filename as a slug, taking the language into account. | ||||
| // This should not be used with the Slug Generator (as it would be redundant) | ||||
| // This should not be used with the Slug Generator (as it would be redundant). | ||||
| func WithOriginalSlugLang(o, lang string) Option { | ||||
| 	return func(c *Config) { | ||||
| 		c.original = slug.MakeLang(o, lang) | ||||
|  | @ -47,7 +47,7 @@ func WithSuffix(s string) Option { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| // WithoutExtension sets no extension for the generated filename. By default, it will be txt | ||||
| // WithoutExtension sets no extension for the generated filename. By default, it will be txt. | ||||
| func WithoutExtension() Option { | ||||
| 	return func(c *Config) { | ||||
| 		c.extension = "" | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue