Compare commits
	
		
			No commits in common. "stable" and "v0.2.1" have entirely different histories.
		
	
	
		
	
		
					 31 changed files with 612 additions and 1189 deletions
				
			
		|  | @ -1,39 +0,0 @@ | ||||||
| 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 |  | ||||||
							
								
								
									
										95
									
								
								CHANGELOG.md
									
										
									
									
									
								
							
							
						
						
									
										95
									
								
								CHANGELOG.md
									
										
									
									
									
								
							|  | @ -1,111 +1,54 @@ | ||||||
| # Changelog | # Changelog | ||||||
| 
 | 
 | ||||||
| ### [1.0.0] - 2025-03-31 - 🚀 Stable release! | ### [0.2.1] - 2025-03-14 | ||||||
| 
 |  | ||||||
| #### Support |  | ||||||
| 
 |  | ||||||
| - 📝 Vastly improved [go docs](https://pkg.go.dev/codeberg.org/danjones000/nomino). |  | ||||||
| - 📝 Fill out README with examples and links. |  | ||||||
| 
 |  | ||||||
| #### Tools |  | ||||||
| 
 |  | ||||||
| - 🛠 Replace all linting with golangci-lint |  | ||||||
| 
 |  | ||||||
| #### Code quality |  | ||||||
| 
 |  | ||||||
| - 🚨 A bunch of small improvements from new linter |  | ||||||
| 
 |  | ||||||
| ### [0.5.0] - 2025-03-19 - ✨ Different types of UUIDs |  | ||||||
| 
 | 
 | ||||||
| #### Features | #### Features | ||||||
| 
 | 
 | ||||||
| - ✨ Allow for different types of UUIDs in the UUID `Generator` | - Add Hash Generator | ||||||
| - ✨ `Config.AddOptions` method |  | ||||||
| - ✨ `Generator.MakeWithConfig` method |  | ||||||
| 
 |  | ||||||
| #### Support |  | ||||||
| 
 |  | ||||||
| - 📝 Some better examples |  | ||||||
| 
 |  | ||||||
| ### [0.4.0] - 2025-03-15 - ✨ More Generators, and `Generator.Make` method |  | ||||||
| 
 |  | ||||||
| #### Features |  | ||||||
| 
 |  | ||||||
| - ✨ Add Random Generator |  | ||||||
| - ✨ Add Make method to Generator |  | ||||||
| - ✨ Add MultiGeneratorRandomOrder |  | ||||||
| 
 |  | ||||||
| #### Changes |  | ||||||
| 
 |  | ||||||
| - 💔 Breaking changes: Replace HashType with Hasher: This supports all crypto.Hash |  | ||||||
| 
 |  | ||||||
| #### Support |  | ||||||
| 
 |  | ||||||
| - 📝 Add some missing doc comments |  | ||||||
| 
 |  | ||||||
| ### [0.3.0] - 2025-03-14 - ♻️ Refactor multiple Generators into one |  | ||||||
| 
 |  | ||||||
| #### Features |  | ||||||
| 
 |  | ||||||
| - ♻️ Simplified multiple `Generator` functions to single function with options |  | ||||||
| - 📝 Added a lot of examples for docs |  | ||||||
| - ✨ Can add extra `Option`s to `Make` |  | ||||||
| 
 |  | ||||||
| Multiple breaking changes around Generators. |  | ||||||
| 
 |  | ||||||
| #### Bugs |  | ||||||
| 
 |  | ||||||
| - 🐛 Fixed date formats |  | ||||||
| 
 |  | ||||||
| ### [0.2.1] - 2025-03-14 - ✨ New Hash Generator |  | ||||||
| 
 |  | ||||||
| #### Features |  | ||||||
| 
 |  | ||||||
| - ✨ Add Hash Generator |  | ||||||
| 
 | 
 | ||||||
| #### Dev Tooling | #### Dev Tooling | ||||||
| 
 | 
 | ||||||
| - 🛠 Added a task to serve docs | - Added a task to serve docs | ||||||
| - 🛠 Added tasts to check code complexity | - Added tasts to check code complexity | ||||||
| 
 | 
 | ||||||
| #### Miscellaneous | #### Miscellaneous | ||||||
| 
 | 
 | ||||||
| - 💚 Fixed some `go vet` complaints | - Fixed some `go vet` complaints | ||||||
| 
 | 
 | ||||||
| ### [0.2.0] - 2025-03-14 - ✨ New `Generator`s | ### [0.2.0] - 2025-03-14 | ||||||
| 
 | 
 | ||||||
| #### Features | #### Features | ||||||
| 
 | 
 | ||||||
| - ✨ Add `IncrementalFormat`* Generators | - Add `IncrementalFormat`* Generators | ||||||
| - ✨ Add `Slug`* Generators | - Add `Slug`* Generators | ||||||
| - ✨ Add `WithOriginalSlug`* Options | - Add `WithOriginalSlug`* Options | ||||||
| - 💔 Change signature of `Generator` function | - Change signature of `Generator` function | ||||||
| 
 | 
 | ||||||
| Note that this last change **is** a breaking change from 0.0.3, but only for custom Generators. | Note that this last change **is** a breaking change from 0.0.3, but only for custom Generators. | ||||||
| 
 | 
 | ||||||
| ## [0.0.3] - 2025-03-11 - ✨ `WithSeparator` | ## [0.0.3] - 2025-03-11 | ||||||
| 
 | 
 | ||||||
| ### Features | ### Features | ||||||
| 
 | 
 | ||||||
| - ✨ Added `WithSeparator` to allow for different separators between the parts of the generated filename. | - Added `WithSeparator` to allow for different separators between the parts of the generated filename. | ||||||
| 
 | 
 | ||||||
| ## [0.0.2] - 2025-03-11 - 🐛 Bugfix | ## [0.0.2] - 2025-03-11 | ||||||
| 
 | 
 | ||||||
| Bugfix release | Bugfix release | ||||||
| 
 | 
 | ||||||
| ### Fixes | ### Fixes | ||||||
| 
 | 
 | ||||||
| - 🐛 Extension being ignored. Original included twice. | - Extension being ignored. Original included twice. | ||||||
| 
 | 
 | ||||||
| ## [0.0.1] - 2025-03-10 - 🚀 Initial Release | ## [0.0.1] - 2025-03-10 | ||||||
| 
 | 
 | ||||||
| Initial Release! Hope you like it! | Initial Release! Hope you like it! | ||||||
| 
 | 
 | ||||||
| ### Added | ### Added | ||||||
| 
 | 
 | ||||||
| - ✨ `nomino.Make`` | - nomino.Make | ||||||
| - ✨ `nomino.Config` | - nomino.Config | ||||||
| - ✨ `nomino.Generator` | - nomino.Generator | ||||||
|     + We needs more of these until I'm ready |     + We needs more of these until I'm ready | ||||||
| - ✅ Lots of tests! | - Lots of tests! | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										78
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										78
									
								
								README.md
									
										
									
									
									
								
							|  | @ -4,80 +4,8 @@ The purpose of nomino is to generate (probably random) filenames, for example, i | ||||||
| 
 | 
 | ||||||
| It takes a lot of inspiration (although no actual code) from [Onym](https://github.com/Blaspsoft/onym). | It takes a lot of inspiration (although no actual code) from [Onym](https://github.com/Blaspsoft/onym). | ||||||
| 
 | 
 | ||||||
| Make sure to check out the [official documentation][docs]. | ## TODO | ||||||
| 
 | 
 | ||||||
| ## Installation | I'll fill this out more in depth later. | ||||||
| 
 | 
 | ||||||
| Add `codeberg.org/danjones000/nomino` to your project. You can do `go get codeberg.org/danjones000/nomino`, or simply add it to an import and run `go mod tidy`. | For now, check [official documentation](https://pkg.go.dev/codeberg.org/danjones000/nomino). | ||||||
| 
 |  | ||||||
| But, you probably already know this. |  | ||||||
| 
 |  | ||||||
| ## Usage |  | ||||||
| 
 |  | ||||||
| There are **a lot** of examples in the [official documentation][examples]. Take a look through these to get an idea. |  | ||||||
| 
 |  | ||||||
| The main concept in `nomino` is the [Generator][]. The simplest way to generate a random filename, is to use the [Generator][] directly, in this way: |  | ||||||
| 
 |  | ||||||
| ```go |  | ||||||
| import ( |  | ||||||
|     "fmt" |  | ||||||
|     "codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
|     name, _ := nomino.Random().Make() |  | ||||||
|     fmt.Println(name) // Du3Sfh8p.txt |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| The second argument is an error. Most of the generators are always successful, and that error will be `nil`, but you should check the errors if you're not sure. |  | ||||||
| 
 |  | ||||||
| The second way to generate a new filename is using the [Make][] function. |  | ||||||
| 
 |  | ||||||
| ```go |  | ||||||
| import ( |  | ||||||
|     "fmt" |  | ||||||
|     "codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func main() { |  | ||||||
|     config := nomino.NewConfig(nomino.WithGenerator(nomino.Random())) |  | ||||||
|     name, _ := nomino.Make(config) |  | ||||||
|     fmt.Println(name) // Du3Sfh8p.txt |  | ||||||
| } |  | ||||||
| ``` |  | ||||||
| 
 |  | ||||||
| Although in these examples, `nomino.Make` is more verbose, it can be beneficial to using that function if you have some customizations to how you generate the filenames. |  | ||||||
| 
 |  | ||||||
| ### Configuration |  | ||||||
| 
 |  | ||||||
| The [Config][] allows you to customize how the generated filename works with various [Options][Option]. The [options][Option] allows you to customize things like [adding a prefix](https://pkg.go.dev/codeberg.org/danjones000/nomino#WithPrefix), or changing the [extension](https://pkg.go.dev/codeberg.org/danjones000/nomino#WithExtension) of the generated filename (by default, it uses `.txt`). |  | ||||||
| 
 |  | ||||||
| Have a look at [all the Options][Option]. |  | ||||||
| 
 |  | ||||||
| ### Generator |  | ||||||
| 
 |  | ||||||
| The [Generator][] is the piece that returns the "random" portion of the generated filename, although, it doesn't actually have to be random. |  | ||||||
| 
 |  | ||||||
| Here are the built-in [Generators][Generator]: |  | ||||||
| 
 |  | ||||||
| - [UUID](https://pkg.go.dev/codeberg.org/danjones000/nomino#UUID) generates a UUID. This is the default if none is specified. |  | ||||||
| - [Random](https://pkg.go.dev/codeberg.org/danjones000/nomino#Random) generates a random string. By default, it's 8 characters long, but can be whatever length you provide. |  | ||||||
| - [Incremental](https://pkg.go.dev/codeberg.org/danjones000/nomino#Incremental) will generate just a series of integers, starting at 0. |  | ||||||
| - [Timestamp](https://pkg.go.dev/codeberg.org/danjones000/nomino#Timestamp) generates a string from the current time. It will look like "2009-11-10T23-00-00+0000.txt", although this can be customized. |  | ||||||
| - Both [Slug](https://pkg.go.dev/codeberg.org/danjones000/nomino#Slug) and [Hash](https://pkg.go.dev/codeberg.org/danjones000/nomino#Hash) work on the original name provided by [WithOriginal](https://pkg.go.dev/codeberg.org/danjones000/nomino#WithOriginal). Slug generats a slug from the name, while Hash hashes it. By default, it uses MD5. |  | ||||||
| 
 |  | ||||||
| You can also use multiple generators, either [in order](https://pkg.go.dev/codeberg.org/danjones000/nomino#MultiGeneratorInOrder), or [in a random order](https://pkg.go.dev/codeberg.org/danjones000/nomino#MultiGeneratorRandomOrder). |  | ||||||
| 
 |  | ||||||
| Finally, you can create a [custom generator](https://pkg.go.dev/codeberg.org/danjones000/nomino#example-WithGenerator-CustomGenerator) as well. |  | ||||||
| 
 |  | ||||||
| ## RTFM (Read the fabulous manual) |  | ||||||
| 
 |  | ||||||
| [Official docs][docs], especially the [examples][]. Especially check out the [full example](https://pkg.go.dev/codeberg.org/danjones000/nomino#example-package), which includes how to use a global configuration. |  | ||||||
| 
 |  | ||||||
| [docs]: https://pkg.go.dev/codeberg.org/danjones000/nomino |  | ||||||
| [examples]: https://pkg.go.dev/codeberg.org/danjones000/nomino#pkg-examples |  | ||||||
| [Generator]: https://pkg.go.dev/codeberg.org/danjones000/nomino#Generator |  | ||||||
| [Config]: https://pkg.go.dev/codeberg.org/danjones000/nomino#Config |  | ||||||
| [Option]: https://pkg.go.dev/codeberg.org/danjones000/nomino#Option |  | ||||||
| [Make]: https://pkg.go.dev/codeberg.org/danjones000/nomino#Make |  | ||||||
|  |  | ||||||
							
								
								
									
										61
									
								
								Taskfile.yml
									
										
									
									
									
								
							
							
						
						
									
										61
									
								
								Taskfile.yml
									
										
									
									
									
								
							|  | @ -5,7 +5,7 @@ tasks: | ||||||
|     cmds: |     cmds: | ||||||
|       - task: fmt |       - task: fmt | ||||||
|       - task: test |       - task: test | ||||||
|       - task: lint |       - task: build | ||||||
| 
 | 
 | ||||||
|   fmt: |   fmt: | ||||||
|     desc: Format go code |     desc: Format go code | ||||||
|  | @ -22,16 +22,67 @@ tasks: | ||||||
|     cmds: |     cmds: | ||||||
|       - go generate ./... |       - go generate ./... | ||||||
| 
 | 
 | ||||||
|   lint: |   vet: | ||||||
|     desc: Do static analysis |     desc: Vet go code | ||||||
|  |     sources: | ||||||
|  |       - '**/*.go' | ||||||
|  |     deps: [gen] | ||||||
|  |     cmds: | ||||||
|  |       - go vet ./... | ||||||
|  | 
 | ||||||
|  |   critic: | ||||||
|  |     desc: Critique go code | ||||||
|     sources: |     sources: | ||||||
|       - '**/*.go' |       - '**/*.go' | ||||||
|     cmds: |     cmds: | ||||||
|       - golangci-lint run |       - 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 | ||||||
| 
 | 
 | ||||||
|   test: |   test: | ||||||
|     desc: Run unit tests |     desc: Run unit tests | ||||||
|     deps: [fmt] |     deps: [fmt, vet, gen] | ||||||
|     sources: |     sources: | ||||||
|       - '**/*.go' |       - '**/*.go' | ||||||
|     generates: |     generates: | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								config.go
									
										
									
									
									
								
							
							
						
						
									
										14
									
								
								config.go
									
										
									
									
									
								
							|  | @ -1,6 +1,5 @@ | ||||||
| package nomino | package nomino | ||||||
| 
 | 
 | ||||||
| // Config controls how the generatred filename is created. |  | ||||||
| type Config struct { | type Config struct { | ||||||
| 	original  string | 	original  string | ||||||
| 	prefix    string | 	prefix    string | ||||||
|  | @ -10,25 +9,14 @@ type Config struct { | ||||||
| 	generator Generator | 	generator Generator | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // NewConfig returns a new [Config] with each [Option] specified. |  | ||||||
| // With no Options, the Config uses an extension of .txt, a separator |  | ||||||
| // of _, and the [UUID] [Generator]. |  | ||||||
| func NewConfig(options ...Option) Config { | func NewConfig(options ...Option) Config { | ||||||
| 	conf := Config{ | 	conf := Config{ | ||||||
| 		extension: ".txt", | 		extension: ".txt", | ||||||
| 		separator: "_", | 		separator: "_", | ||||||
| 		generator: UUID(nil), | 		generator: uuidGen, | ||||||
| 	} | 	} | ||||||
| 	for _, opt := range options { | 	for _, opt := range options { | ||||||
| 		opt(&conf) | 		opt(&conf) | ||||||
| 	} | 	} | ||||||
| 	return conf | 	return conf | ||||||
| } | } | ||||||
| 
 |  | ||||||
| // AddOptions creates a new [Config] with each [Option] added. |  | ||||||
| func (c Config) AddOptions(options ...Option) Config { |  | ||||||
| 	for _, opt := range options { |  | ||||||
| 		opt(&c) |  | ||||||
| 	} |  | ||||||
| 	return c |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -20,12 +20,3 @@ func TestNewConfWithOpts(t *testing.T) { | ||||||
| 	assert.Equal(t, "", c.extension) | 	assert.Equal(t, "", c.extension) | ||||||
| 	assert.Equal(t, "foobar", c.prefix) | 	assert.Equal(t, "foobar", c.prefix) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func TestConfAddOpts(t *testing.T) { |  | ||||||
| 	c := Config{original: "hi"} |  | ||||||
| 	c2 := c.AddOptions(WithOriginalSlug("Hello, my dear"), WithPrefix("yo")) |  | ||||||
| 	assert.Equal(t, "", c.prefix) |  | ||||||
| 	assert.Equal(t, "hi", c.original) |  | ||||||
| 	assert.Equal(t, "hello-my-dear", c2.original) |  | ||||||
| 	assert.Equal(t, "yo", c2.prefix) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -1,60 +0,0 @@ | ||||||
| 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 { |  | ||||||
| 	// Here, we use nomino.Make function to generate the filename. |  | ||||||
| 	// We use our global config, and add in a few extra Options specific to this. |  | ||||||
| 	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 { |  | ||||||
| 	// Because we're using a different Generator, we chose to use the Make method on the Generator. |  | ||||||
| 	// We add in additional Options with the `AddOptions` method on the `Config` |  | ||||||
| 	newName, _ := nomino.Timestamp(nomino.TimestampUTC()). |  | ||||||
| 		MakeWithConfig(NominoConfig().AddOptions( |  | ||||||
| 			nomino.WithExtension("webm"), |  | ||||||
| 		)) |  | ||||||
| 	return newName |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // This 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) |  | ||||||
| } |  | ||||||
							
								
								
									
										75
									
								
								gen_file.go
									
										
									
									
									
								
							
							
						
						
									
										75
									
								
								gen_file.go
									
										
									
									
									
								
							|  | @ -1,75 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto" |  | ||||||
| 	"encoding/hex" |  | ||||||
| 	"errors" |  | ||||||
| 	"hash" |  | ||||||
| 
 |  | ||||||
| 	"github.com/gosimple/slug" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // 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) { |  | ||||||
| 	if c.original == "" { |  | ||||||
| 		return "", ErrMissingOriginal |  | ||||||
| 	} |  | ||||||
| 	name := c.original |  | ||||||
| 	c.original = "" |  | ||||||
| 	return name, nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Slug generates a name from the original filename. |  | ||||||
| // When this is used, the original filename will be removed from the final filename. |  | ||||||
| // If a language is specified, that may affect the resulting slug. |  | ||||||
| func Slug(lang ...string) Generator { |  | ||||||
| 	ret := slug.Make |  | ||||||
| 	if len(lang) > 0 { |  | ||||||
| 		ret = func(in string) string { |  | ||||||
| 			return slug.MakeLang(in, lang[0]) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 	return func(c *Config) (string, error) { |  | ||||||
| 		name, err := getOriginal(c) |  | ||||||
| 		return ret(name), err |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // HashingFunc is a function that generates a [hash.Hash]. |  | ||||||
| type HashingFunc func() hash.Hash |  | ||||||
| 
 |  | ||||||
| // New allows [HashingFunc] to be used as a [Hasher]. |  | ||||||
| func (hf HashingFunc) New() hash.Hash { |  | ||||||
| 	return hf() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // Hasher is a type returns a [hash.Hash]. |  | ||||||
| // All [crypto.Hash] may be used. |  | ||||||
| type Hasher interface { |  | ||||||
| 	New() hash.Hash |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // ErrInvalidHash is returned by the [Hash] [Generator] when an invalid [Hasher] is passed. |  | ||||||
| var ErrInvalidHash = errors.New("invalid hash type") |  | ||||||
| 
 |  | ||||||
| // Hash generates a name from a hash of the filename. |  | ||||||
| // When this is used, the original filename will be removed from the final filename. |  | ||||||
| func Hash(h Hasher) Generator { |  | ||||||
| 	if h == nil { |  | ||||||
| 		h = crypto.MD5 |  | ||||||
| 	} |  | ||||||
| 	return func(c *Config) (string, error) { |  | ||||||
| 		if h == crypto.MD5SHA1 { |  | ||||||
| 			return "", ErrInvalidHash |  | ||||||
| 		} |  | ||||||
| 		name, err := getOriginal(c) |  | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		hs := h.New() |  | ||||||
| 		hs.Write([]byte(name)) |  | ||||||
| 		return hex.EncodeToString(hs.Sum(nil)), nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,56 +0,0 @@ | ||||||
| package nomino_test |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto" |  | ||||||
| 	"crypto/hmac" |  | ||||||
| 	"fmt" |  | ||||||
| 	"hash" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ExampleSlug() { |  | ||||||
| 	str, _ := nomino.Slug().Make(nomino.WithOriginal("My name is Jimmy")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: my-name-is-jimmy.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleSlug_withLang() { |  | ||||||
| 	str, _ := nomino.Slug("de"). |  | ||||||
| 		Make(nomino.WithOriginal("Diese & Dass")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: diese-und-dass.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleHash_mD5() { |  | ||||||
| 	str, _ := nomino.Hash(crypto.MD5). |  | ||||||
| 		Make(nomino.WithOriginal("foobar")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 	// Output: 3858f62230ac3c915f300c664312c63f.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleHash_sHA1() { |  | ||||||
| 	str, _ := nomino.Hash(crypto.SHA1). |  | ||||||
| 		Make(nomino.WithOriginal("foobar")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 	// Output: 8843d7f92416211de9ebb963ff4ce28125932878.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleHash_sHA256() { |  | ||||||
| 	str, _ := nomino.Hash(crypto.SHA256). |  | ||||||
| 		Make(nomino.WithOriginal("foobar")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 	// Output: c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleHashingFunc_hMAC() { |  | ||||||
| 	var hasher nomino.HashingFunc = func() hash.Hash { |  | ||||||
| 		return hmac.New(crypto.SHA1.New, []byte("hello")) |  | ||||||
| 	} |  | ||||||
| 	g := nomino.Hash(hasher) |  | ||||||
| 	str, _ := g.Make(nomino.WithOriginal("foobar")) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 	// Output: 85f767c284c80a3a59a9635194321d20dd90f31b.txt |  | ||||||
| } |  | ||||||
|  | @ -1,37 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto" |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestSlugMissingFilename(t *testing.T) { |  | ||||||
| 	conf := NewConfig(WithGenerator(Slug())) |  | ||||||
| 	st, err := conf.generator(&conf) |  | ||||||
| 	assert.Zero(t, st) |  | ||||||
| 	assert.ErrorIs(t, err, ErrMissingOriginal) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestSlugRemovesOriginal(t *testing.T) { |  | ||||||
| 	conf := NewConfig(WithGenerator(Slug()), WithOriginal("Hello, World")) |  | ||||||
| 	st, err := conf.generator(&conf) |  | ||||||
| 	assert.Zero(t, conf.original) |  | ||||||
| 	assert.Equal(t, "hello-world", st) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestHashBadHash(t *testing.T) { |  | ||||||
| 	conf := NewConfig(WithOriginal("foobar"), WithGenerator(Hash(crypto.MD5SHA1))) |  | ||||||
| 	st, err := conf.generator(&conf) |  | ||||||
| 	assert.Equal(t, "", st) |  | ||||||
| 	assert.ErrorIs(t, err, ErrInvalidHash) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestHashMissingOriginal(t *testing.T) { |  | ||||||
| 	conf := NewConfig(WithGenerator(Hash(nil))) |  | ||||||
| 	st, err := conf.generator(&conf) |  | ||||||
| 	assert.Equal(t, "", st) |  | ||||||
| 	assert.ErrorIs(t, err, ErrMissingOriginal) |  | ||||||
| } |  | ||||||
							
								
								
									
										55
									
								
								gen_int.go
									
										
									
									
									
								
							
							
						
						
									
										55
									
								
								gen_int.go
									
										
									
									
									
								
							|  | @ -1,55 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"strconv" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| type incConf struct { |  | ||||||
| 	start int |  | ||||||
| 	step  int |  | ||||||
| 	cb    func(int) string |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // IncrementalOption sets an option for the [Incremental] [Generator]. |  | ||||||
| type IncrementalOption func(c *incConf) |  | ||||||
| 
 |  | ||||||
| // Incremental generates a name that is a series of integers. |  | ||||||
| // By default it begins at 0 and increments by 1 each time. |  | ||||||
| func Incremental(opts ...IncrementalOption) Generator { |  | ||||||
| 	c := incConf{step: 1, cb: strconv.Itoa} |  | ||||||
| 	for _, opt := range opts { |  | ||||||
| 		opt(&c) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	next := c.start |  | ||||||
| 	return func(*Config) (string, error) { |  | ||||||
| 		out := c.cb(next) |  | ||||||
| 		next += c.step |  | ||||||
| 		return out, nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // IncrementalStart sets the starting integer for [Incremental]. |  | ||||||
| func IncrementalStart(start int) IncrementalOption { |  | ||||||
| 	return func(c *incConf) { |  | ||||||
| 		c.start = start |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // IncrementalStepsets the step by which [Incremental] increases with each invocation. |  | ||||||
| func IncrementalStep(step int) IncrementalOption { |  | ||||||
| 	return func(c *incConf) { |  | ||||||
| 		c.step = step |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 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". |  | ||||||
| func IncrementalFormat(format string) IncrementalOption { |  | ||||||
| 	return func(c *incConf) { |  | ||||||
| 		c.cb = func(i int) string { |  | ||||||
| 			return fmt.Sprintf(format, i) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,121 +0,0 @@ | ||||||
| package nomino_test |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ExampleIncremental() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("foo"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	str, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// foo_0.txt |  | ||||||
| 	// foo_1.txt |  | ||||||
| 	// foo_2.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleIncrementalStart() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("foo"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental( |  | ||||||
| 			nomino.IncrementalStart(42), |  | ||||||
| 		)), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	str, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// foo_42.txt |  | ||||||
| 	// foo_43.txt |  | ||||||
| 	// foo_44.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleIncrementalStep() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("foo"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental( |  | ||||||
| 			nomino.IncrementalStep(2), |  | ||||||
| 		)), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	str, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// foo_0.txt |  | ||||||
| 	// foo_2.txt |  | ||||||
| 	// foo_4.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleIncremental_withStartAndStep() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("foo"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental( |  | ||||||
| 			nomino.IncrementalStart(42), |  | ||||||
| 			nomino.IncrementalStep(2), |  | ||||||
| 		)), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	str, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// foo_42.txt |  | ||||||
| 	// foo_44.txt |  | ||||||
| 	// foo_46.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleIncrementalFormat() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("foo"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental( |  | ||||||
| 			nomino.IncrementalFormat("%03d"), |  | ||||||
| 		)), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	str, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// foo_000.txt |  | ||||||
| 	// foo_001.txt |  | ||||||
| 	// foo_002.txt |  | ||||||
| } |  | ||||||
							
								
								
									
										91
									
								
								gen_rand.go
									
										
									
									
									
								
							
							
						
						
									
										91
									
								
								gen_rand.go
									
										
									
									
									
								
							|  | @ -1,91 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"crypto/rand" |  | ||||||
| 	"strings" |  | ||||||
| 
 |  | ||||||
| 	"github.com/deatil/go-encoding/base62" |  | ||||||
| 	"github.com/google/uuid" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // UUIDer is an interface for generating UUIDs, by the [UUID] [Generator]. |  | ||||||
| // It is recommended that you use either the [UUIDv4] or [UUIDv7] variables. |  | ||||||
| type UUIDer interface { |  | ||||||
| 	UUID() (uuid.UUID, error) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // UUIDFunc is a function that generates a UUID. |  | ||||||
| type UUIDFunc func() (uuid.UUID, error) |  | ||||||
| 
 |  | ||||||
| // UUID allows [UUIDFunc] to be used as a [UUIDer]. |  | ||||||
| func (u UUIDFunc) UUID() (uuid.UUID, error) { |  | ||||||
| 	return u() |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| var ( |  | ||||||
| 	// UUIDv1. You probably don't want to use this. It is included for completeness sake. |  | ||||||
| 	UUIDv1 = UUIDFunc(uuid.NewUUID) |  | ||||||
| 	// UUIDv4 is the default. |  | ||||||
| 	UUIDv4 = UUIDFunc(uuid.NewRandom) |  | ||||||
| 	// UUIDv6 is primarily a replacement for UUIDv1. You probably should use 4 or 7. |  | ||||||
| 	UUIDv6 = UUIDFunc(uuid.NewV6) |  | ||||||
| 	// UUIDv7 should be used if you want it sortable by time. |  | ||||||
| 	UUIDv7 = UUIDFunc(uuid.NewV7) |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| // UUID generates a UUID. If nil is passed as an argument, |  | ||||||
| // a UUIDv4 is generated. |  | ||||||
| func UUID(u UUIDer) Generator { |  | ||||||
| 	if u == nil { |  | ||||||
| 		u = UUIDv4 |  | ||||||
| 	} |  | ||||||
| 	return func(*Config) (string, error) { |  | ||||||
| 		uu, err := u.UUID() |  | ||||||
| 		if err != nil { |  | ||||||
| 			return "", err |  | ||||||
| 		} |  | ||||||
| 		return uu.String(), nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type randConf struct { |  | ||||||
| 	length int |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // RandomOption is an option for the [Random] [Generator]. |  | ||||||
| type RandomOption func(*randConf) |  | ||||||
| 
 |  | ||||||
| // RandomLength controls the length of the string generated by [Random]. |  | ||||||
| func RandomLength(length int) RandomOption { |  | ||||||
| 	return func(c *randConf) { |  | ||||||
| 		c.length = length |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func getRandomBytes(l int) []byte { |  | ||||||
| 	key := make([]byte, l) |  | ||||||
| 	_, _ = 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 { |  | ||||||
| 	c := randConf{8} |  | ||||||
| 	for _, opt := range opts { |  | ||||||
| 		opt(&c) |  | ||||||
| 	} |  | ||||||
| 	return func(*Config) (string, error) { |  | ||||||
| 		var buff strings.Builder |  | ||||||
| 		buff.Grow(c.length) |  | ||||||
| 		fillBuffer(&buff, c.length) |  | ||||||
| 		return buff.String(), nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,40 +0,0 @@ | ||||||
| package nomino_test |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ExampleUUID() { |  | ||||||
| 	gen := nomino.UUID(nil) |  | ||||||
| 
 |  | ||||||
| 	str, _ := gen.Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = gen.Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleUUID_v7() { |  | ||||||
| 	gen := nomino.UUID(nomino.UUIDv7) |  | ||||||
| 
 |  | ||||||
| 	str, _ := gen.Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = gen.Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| 
 |  | ||||||
| 	str, _ = gen.Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleRandom() { |  | ||||||
| 	str, _ := nomino.Random().Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleRandomLength() { |  | ||||||
| 	str, _ := nomino.Random(nomino.RandomLength(32)).Make() |  | ||||||
| 	fmt.Println(str) |  | ||||||
| } |  | ||||||
|  | @ -1,41 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| 
 |  | ||||||
| 	"github.com/google/uuid" |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestUUID(t *testing.T) { |  | ||||||
| 	st, err := UUID(nil)(nil) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	_, parseErr := uuid.Parse(st) |  | ||||||
| 	assert.NoError(t, parseErr) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type badRead struct{} |  | ||||||
| 
 |  | ||||||
| func (badRead) Read([]byte) (int, error) { |  | ||||||
| 	return 0, errTest |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestUUIDFail(t *testing.T) { |  | ||||||
| 	uuid.SetRand(badRead{}) |  | ||||||
| 	defer uuid.SetRand(nil) |  | ||||||
| 
 |  | ||||||
| 	_, err := UUID(nil)(nil) |  | ||||||
| 	assert.ErrorIs(t, err, errTest) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestRand(t *testing.T) { |  | ||||||
| 	st, err := Random()(nil) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	assert.Len(t, st, 8) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestRandLen(t *testing.T) { |  | ||||||
| 	st, err := Random(RandomLength(32))(nil) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	assert.Len(t, st, 32) |  | ||||||
| } |  | ||||||
							
								
								
									
										59
									
								
								gen_ts.go
									
										
									
									
									
								
							
							
						
						
									
										59
									
								
								gen_ts.go
									
										
									
									
									
								
							|  | @ -1,59 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import "time" |  | ||||||
| 
 |  | ||||||
| // FileTimestamp is the default format for [Timestamp]. |  | ||||||
| const FileTimestamp string = "2006-01-02T15-04-05-0700" |  | ||||||
| 
 |  | ||||||
| // FileTimestampNoTZ is the default format when using the [TimestampUTC] [TimestampOption]. |  | ||||||
| const FileTimestampNoTZ string = "2006-01-02T15-04-05" |  | ||||||
| 
 |  | ||||||
| type timestampConf struct { |  | ||||||
| 	format string |  | ||||||
| 	ts     time.Time |  | ||||||
| 	utc    bool |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 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. |  | ||||||
| func Timestamp(opts ...TimestampOption) Generator { |  | ||||||
| 	c := timestampConf{format: FileTimestamp, ts: time.Now()} |  | ||||||
| 	for _, opt := range opts { |  | ||||||
| 		opt(&c) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if c.utc { |  | ||||||
| 		c.ts = c.ts.UTC() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return func(*Config) (string, error) { |  | ||||||
| 		return c.ts.Format(c.format), nil |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TimestampFormat sets the format for the generated name. |  | ||||||
| // Consult [time.Time.Format] for details on the format. |  | ||||||
| func TimestampFormat(format string) TimestampOption { |  | ||||||
| 	return func(c *timestampConf) { |  | ||||||
| 		c.format = format |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TimestampTime sets the time for the generated name. |  | ||||||
| // By default, [Timestamp] uses the current time. |  | ||||||
| func TimestampTime(t time.Time) TimestampOption { |  | ||||||
| 	return func(c *timestampConf) { |  | ||||||
| 		c.ts = t |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // TimestampUTC uses the time in UTC, while also stripping the timezone from the format. |  | ||||||
| func TimestampUTC() TimestampOption { |  | ||||||
| 	return func(c *timestampConf) { |  | ||||||
| 		c.utc = true |  | ||||||
| 		c.format = FileTimestampNoTZ |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
|  | @ -1,41 +0,0 @@ | ||||||
| package nomino_test |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"fmt" |  | ||||||
| 	"time" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ExampleTimestamp() { |  | ||||||
| 	gen := nomino.Timestamp() |  | ||||||
| 	s, _ := gen.Make() |  | ||||||
| 	fmt.Println(s) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleTimestampTime() { |  | ||||||
| 	tz, _ := time.LoadLocation("America/New_York") |  | ||||||
| 	ts := time.Date(2009, time.January, 20, 12, 5, 0, 0, tz) |  | ||||||
| 	gen := nomino.Timestamp(nomino.TimestampTime(ts)) |  | ||||||
| 	s, _ := gen.Make() |  | ||||||
| 	fmt.Println(s) |  | ||||||
| 	// Output: 2009-01-20T12-05-00-0500.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleTimestampFormat() { |  | ||||||
| 	tz, _ := time.LoadLocation("America/New_York") |  | ||||||
| 	ts := time.Date(2009, time.January, 20, 12, 5, 0, 0, tz) |  | ||||||
| 	gen := nomino.Timestamp(nomino.TimestampTime(ts), nomino.TimestampFormat("2006#01#02<>15|04|05-0700")) |  | ||||||
| 	s, _ := gen.Make() |  | ||||||
| 	fmt.Println(s) |  | ||||||
| 	// Output: 2009#01#20<>12|05|00-0500.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleTimestampUTC() { |  | ||||||
| 	tz, _ := time.LoadLocation("America/New_York") |  | ||||||
| 	ts := time.Date(2009, time.January, 20, 12, 5, 0, 0, tz) |  | ||||||
| 	gen := nomino.Timestamp(nomino.TimestampTime(ts), nomino.TimestampUTC()) |  | ||||||
| 	s, _ := gen.Make() |  | ||||||
| 	fmt.Println(s) |  | ||||||
| 	// Output: 2009-01-20T17-05-00.txt |  | ||||||
| } |  | ||||||
|  | @ -1,15 +0,0 @@ | ||||||
| package nomino |  | ||||||
| 
 |  | ||||||
| import ( |  | ||||||
| 	"testing" |  | ||||||
| 	"time" |  | ||||||
| 
 |  | ||||||
| 	"github.com/stretchr/testify/assert" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestTimestamp(t *testing.T) { |  | ||||||
| 	n := time.Now() |  | ||||||
| 	st, err := Timestamp()(nil) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	assert.Equal(t, n.Format(FileTimestamp), st) |  | ||||||
| } |  | ||||||
							
								
								
									
										209
									
								
								generators.go
									
										
									
									
									
								
							
							
						
						
									
										209
									
								
								generators.go
									
										
									
									
									
								
							|  | @ -1,8 +1,17 @@ | ||||||
| package nomino | package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"crypto/md5" | ||||||
|  | 	"crypto/sha1" | ||||||
|  | 	"crypto/sha256" | ||||||
| 	"errors" | 	"errors" | ||||||
| 	"math/rand" | 	"fmt" | ||||||
|  | 	"hash" | ||||||
|  | 	"strconv" | ||||||
|  | 	"time" | ||||||
|  | 
 | ||||||
|  | 	"github.com/google/uuid" | ||||||
|  | 	"github.com/gosimple/slug" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Generator is a function that returns the "random" portion of the returned filename. | // Generator is a function that returns the "random" portion of the returned filename. | ||||||
|  | @ -10,25 +19,14 @@ import ( | ||||||
| // for example. | // for example. | ||||||
| type Generator func(conf *Config) (string, error) | type Generator func(conf *Config) (string, error) | ||||||
| 
 | 
 | ||||||
| // Make allows you to generate a new string directly from a [Generator]. | // WithGenerator sets the specified generator | ||||||
| func (g Generator) Make(opts ...Option) (string, error) { |  | ||||||
| 	return g.MakeWithConfig(NewConfig(opts...)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // MakeWithConfig allows you to generate a new string directly from a [Generator] |  | ||||||
| // with a pre-existing Config. |  | ||||||
| func (g Generator) MakeWithConfig(c Config) (string, error) { |  | ||||||
| 	return Make(c.AddOptions(WithGenerator(g))) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // WithGenerator sets the specified [Generator]. |  | ||||||
| func WithGenerator(g Generator) Option { | func WithGenerator(g Generator) Option { | ||||||
| 	return func(c *Config) { | 	return func(c *Config) { | ||||||
| 		c.generator = g | 		c.generator = g | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ErrMissingGenerators is returned by a multi-generator if a [Generator] isn't supplied. | // ErrMissingGenerators is returned by a multi-generator if no generators are supplied. | ||||||
| var ErrMissingGenerators = errors.New("no generators supplied") | var ErrMissingGenerators = errors.New("no generators supplied") | ||||||
| 
 | 
 | ||||||
| func missingGen(*Config) (string, error) { | func missingGen(*Config) (string, error) { | ||||||
|  | @ -36,7 +34,7 @@ func missingGen(*Config) (string, error) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MultiGeneratorInOrder allows the use of multiple generators. Each new invokation will use the next generator in turn. | // MultiGeneratorInOrder allows the use of multiple generators. Each new invokation will use the next generator in turn. | ||||||
| // If none are passed, the generator will always return [ErrMissingGenerators]. | // If none are passed, the generator will always return ErrMissingGenerators. | ||||||
| func MultiGeneratorInOrder(gens ...Generator) Generator { | func MultiGeneratorInOrder(gens ...Generator) Generator { | ||||||
| 	if len(gens) == 0 { | 	if len(gens) == 0 { | ||||||
| 		return missingGen | 		return missingGen | ||||||
|  | @ -54,20 +52,181 @@ func MultiGeneratorInOrder(gens ...Generator) Generator { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // MultiGeneratorRandomOrder allows the use of multiple generators. Each new invokation will use one of the generators randomly. | func uuidGen(*Config) (string, error) { | ||||||
| // If none are passed, the generator will always return [ErrMissingGenerators]. | 	u, err := uuid.NewRandom() | ||||||
| func MultiGeneratorRandomOrder(gens ...Generator) Generator { | 	if err != nil { | ||||||
| 	if len(gens) == 0 { | 		return "", err | ||||||
| 		return missingGen | 	} | ||||||
|  | 	return u.String(), nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 	if len(gens) == 1 { | // UUID generates a UUIDv4. | ||||||
| 		return gens[0] | func UUID() Generator { | ||||||
|  | 	return uuidGen | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // FileTimestamp is the default format for WithTimestamp and WithTime | ||||||
|  | const FileTimestamp string = "2006-01-02_03-05-06-0700" | ||||||
|  | 
 | ||||||
|  | // Timestamp generates a a date and time for the current time. | ||||||
|  | // It is formatted accourding to FileTimestamp | ||||||
|  | func Timestamp() Generator { | ||||||
|  | 	return TimestampWithFormat(FileTimestamp) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TimestampWithFormat generates a date and time for the current time with the supplied format. | ||||||
|  | func TimestampWithFormat(f string) Generator { | ||||||
|  | 	return FormattedTime(time.Now(), FileTimestamp) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Time generates a date and time for the supplied time. | ||||||
|  | // It is formatted accourding to FileTimestamp | ||||||
|  | func Time(t time.Time) Generator { | ||||||
|  | 	return FormattedTime(t, FileTimestamp) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FormattedTime generates a date and time for the supplied time with the supplied format. | ||||||
|  | func FormattedTime(t time.Time, f string) Generator { | ||||||
|  | 	return func(*Config) (string, error) { | ||||||
|  | 		return t.Format(f), nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // FileTimestampNoTZ is the default format for WithTimestampUTC and WithTimeUTC | ||||||
|  | const FileTimestampNoTZ string = "2006-01-02_03-05-06" | ||||||
|  | 
 | ||||||
|  | // TimestampUTC generates a date and time for the current time in UTC without a timezone in the format. | ||||||
|  | func TimestampUTC() Generator { | ||||||
|  | 	return TimeUTC(time.Now()) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // TimeUTC generates a date and time for the supplied time in UTC without a timezone in the format. | ||||||
|  | func TimeUTC(t time.Time) Generator { | ||||||
|  | 	return FormattedTime(t.UTC(), FileTimestampNoTZ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Incremental generates a name that is a series of integers starting at 0 | ||||||
|  | func Incremental() Generator { | ||||||
|  | 	return IncrementalWithStartAndStep(0, 1) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalFormat generates a name that is a series of integers starting at 0, formatted with Printf | ||||||
|  | // This is mostly likely useful with a format like "%02d" | ||||||
|  | func IncrementalFormat(format string) Generator { | ||||||
|  | 	return IncrementalFormatWithStartAndStep(0, 1, format) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalWithStart generates a name that is a series of integers starting at the specified number | ||||||
|  | func IncrementalWithStart(start int) Generator { | ||||||
|  | 	return IncrementalWithStartAndStep(start, 1) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalFormatWithStart generates a name that is a series of integers starting at the specified number, formatted with Printf | ||||||
|  | func IncrementalFormatWithStart(start int, format string) Generator { | ||||||
|  | 	return IncrementalFormatWithStartAndStep(start, 1, format) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalWithStep generates a name that is a series of integers, starting at 0, and increasing the specified number each time | ||||||
|  | func IncrementalWithStep(step int) Generator { | ||||||
|  | 	return IncrementalWithStartAndStep(0, step) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalFormatWithStep generates a name that is a series of integers, starting at 0, and increasing the specified number each time, | ||||||
|  | // formatted with Printf | ||||||
|  | func IncrementalFormatWithStep(step int, format string) Generator { | ||||||
|  | 	return IncrementalFormatWithStartAndStep(0, step, format) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func incrementalHelper(start, step int, cb func(int) string) Generator { | ||||||
|  | 	next := start | ||||||
|  | 	return func(*Config) (string, error) { | ||||||
|  | 		out := cb(next) | ||||||
|  | 		next += step | ||||||
|  | 		return out, nil | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // InrementalWithStartAndStep generates a name that is a series of integers, starting at the specified number, | ||||||
|  | // and increasing the specified step each time | ||||||
|  | func IncrementalWithStartAndStep(start, step int) Generator { | ||||||
|  | 	return incrementalHelper(start, step, strconv.Itoa) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // IncrementalFormatWithStartAndStep generates a name that is a series of integers, starting at the specified number, | ||||||
|  | // and increasing the specified step each time, formatted with Printf | ||||||
|  | func IncrementalFormatWithStartAndStep(start, step int, format string) Generator { | ||||||
|  | 	return incrementalHelper(start, step, func(i int) string { | ||||||
|  | 		return fmt.Sprintf(format, i) | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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) { | ||||||
|  | 	if c.original == "" { | ||||||
|  | 		return "", ErrMissingOriginal | ||||||
|  | 	} | ||||||
|  | 	name := c.original | ||||||
|  | 	c.original = "" | ||||||
|  | 	return name, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Slug generates a name from the original filename. | ||||||
|  | // When this is used, the original filename will be removed from the final filename. | ||||||
|  | func Slug() Generator { | ||||||
| 	return func(c *Config) (string, error) { | 	return func(c *Config) (string, error) { | ||||||
| 		//nolint:gosec // This is not security sensitive, so a weak number generator is fine. | 		name, err := getOriginal(c) | ||||||
| 		idx := rand.Int() % len(gens) | 		return slug.Make(name), err | ||||||
| 		return gens[idx](c) | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // SlugWithLang generates a name from the original filename, accounting for the given language. | ||||||
|  | // When this is used, the original filename will be removed from the final filename. | ||||||
|  | func SlugWithLang(lang string) Generator { | ||||||
|  | 	return func(c *Config) (string, error) { | ||||||
|  | 		name, err := getOriginal(c) | ||||||
|  | 		return slug.MakeLang(name, lang), err | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // HashingFunc is a function that generates a hash.Hash | ||||||
|  | type HashingFunc func() hash.Hash | ||||||
|  | 
 | ||||||
|  | //go:generate stringer -type=HashType | ||||||
|  | 
 | ||||||
|  | // HashType represents a particular hashing algorithm | ||||||
|  | type HashType uint8 | ||||||
|  | 
 | ||||||
|  | const ( | ||||||
|  | 	MD5 HashType = iota + 1 | ||||||
|  | 	SHA1 | ||||||
|  | 	SHA256 | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | // ErrInvalidHashType is returned by the Hash generator when an invalid HashType is passed | ||||||
|  | var ErrInvalidHashType = errors.New("invalid hash type") | ||||||
|  | 
 | ||||||
|  | var hashMap = map[HashType]HashingFunc{ | ||||||
|  | 	MD5:    md5.New, | ||||||
|  | 	SHA1:   sha1.New, | ||||||
|  | 	SHA256: sha256.New, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Hash generates a name from a hash of the filename. | ||||||
|  | // When this is used, the original filename will be removed from the final filename. | ||||||
|  | func Hash(t HashType) Generator { | ||||||
|  | 	f, ok := hashMap[t] | ||||||
|  | 	return func(c *Config) (string, error) { | ||||||
|  | 		if !ok { | ||||||
|  | 			return "", fmt.Errorf("%w: %s", ErrInvalidHashType, t) | ||||||
|  | 		} | ||||||
|  | 		name, err := getOriginal(c) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return "", err | ||||||
|  | 		} | ||||||
|  | 		hs := f() | ||||||
|  | 		hs.Write([]byte(name)) | ||||||
|  | 		return fmt.Sprintf("%x", hs.Sum(nil)), nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,20 +1,17 @@ | ||||||
| package nomino_test | package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import "fmt" | ||||||
| 	"fmt" |  | ||||||
| 
 | 
 | ||||||
| 	"codeberg.org/danjones000/nomino" | func ExampleWithGenerator_custom_generator() { | ||||||
| ) | 	gen := func(*Config) (string, error) { | ||||||
| 
 |  | ||||||
| func ExampleWithGenerator_customGenerator() { |  | ||||||
| 	var gen nomino.Generator = func(*nomino.Config) (string, error) { |  | ||||||
| 		return "hello", nil | 		return "hello", nil | ||||||
| 	} | 	} | ||||||
|  | 	option := WithGenerator(gen) | ||||||
| 
 | 
 | ||||||
| 	str, _ := gen.Make() | 	str, _ := Make(NewConfig(option)) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	str, _ = gen.Make(nomino.WithoutExtension()) | 	str, _ = Make(NewConfig(option, WithoutExtension())) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	// Output: | 	// Output: | ||||||
|  | @ -22,58 +19,175 @@ func ExampleWithGenerator_customGenerator() { | ||||||
| 	// hello | 	// hello | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ExampleGenerator_Make() { | func ExampleIncremental() { | ||||||
| 	g := nomino.Incremental() | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(Incremental())) | ||||||
| 	st, _ := g.Make() |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 
 | 
 | ||||||
| 	st, _ = g.Make(nomino.WithPrefix("foo")) | 	str, _ := Make(conf) | ||||||
| 	fmt.Println(st) | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	// Output: | 	// Output: | ||||||
| 	// 0.txt | 	// foo_0.txt | ||||||
| 	// foo_1.txt | 	// foo_1.txt | ||||||
|  | 	// foo_2.txt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ExampleMultiGeneratorInOrder() { | func ExampleIncrementalWithStart() { | ||||||
| 	gen1 := func(*nomino.Config) (string, error) { | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(IncrementalWithStart(42))) | ||||||
| 		return "bonjour", nil |  | ||||||
| 	} |  | ||||||
| 	gen2 := func(*nomino.Config) (string, error) { |  | ||||||
| 		return "goodbye", nil |  | ||||||
| 	} |  | ||||||
| 	gen := nomino.MultiGeneratorInOrder(gen1, gen2) |  | ||||||
| 
 | 
 | ||||||
| 	str, _ := gen.Make() | 	str, _ := Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	str, _ = gen.Make() | 	str, _ = Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	str, _ = gen.Make() | 	str, _ = Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	// Output: | 	// Output: | ||||||
| 	// bonjour.txt | 	// foo_42.txt | ||||||
| 	// goodbye.txt | 	// foo_43.txt | ||||||
| 	// bonjour.txt | 	// foo_44.txt | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ExampleMultiGeneratorRandomOrder() { | func ExampleIncrementalWithStep() { | ||||||
| 	gen1 := func(*nomino.Config) (string, error) { | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(IncrementalWithStep(2))) | ||||||
| 		return "guten-tag", nil |  | ||||||
| 	} |  | ||||||
| 	gen2 := func(*nomino.Config) (string, error) { |  | ||||||
| 		return "wiedersehen", nil |  | ||||||
| 	} |  | ||||||
| 	gen := nomino.MultiGeneratorRandomOrder(gen1, gen2) |  | ||||||
| 
 | 
 | ||||||
| 	str, _ := gen.Make() | 	str, _ := Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	str, _ = gen.Make() | 	str, _ = Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
| 
 | 
 | ||||||
| 	str, _ = gen.Make() | 	str, _ = Make(conf) | ||||||
| 	fmt.Println(str) | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_0.txt | ||||||
|  | 	// foo_2.txt | ||||||
|  | 	// foo_4.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalWithStartAndStep() { | ||||||
|  | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(IncrementalWithStartAndStep(42, 2))) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_42.txt | ||||||
|  | 	// foo_44.txt | ||||||
|  | 	// foo_46.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalFormat() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithPrefix("foo"), | ||||||
|  | 		WithGenerator(IncrementalFormat("%03d")), | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_000.txt | ||||||
|  | 	// foo_001.txt | ||||||
|  | 	// foo_002.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalFormatWithStart() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithPrefix("foo"), | ||||||
|  | 		WithGenerator(IncrementalFormatWithStart(9, "%02d")), | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_09.txt | ||||||
|  | 	// foo_10.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalFormatWithStep() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithPrefix("foo"), | ||||||
|  | 		WithGenerator(IncrementalFormatWithStep(10, "%02d")), | ||||||
|  | 	) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_00.txt | ||||||
|  | 	// foo_10.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleSlug() { | ||||||
|  | 	conf := NewConfig(WithGenerator(Slug()), WithOriginal("My name is Jimmy")) | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: my-name-is-jimmy.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleSlugWithLang() { | ||||||
|  | 	conf := NewConfig(WithGenerator(SlugWithLang("de")), WithOriginal("Diese & Dass")) | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: diese-und-dass.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleHash_mD5() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithOriginal("foobar"), | ||||||
|  | 		WithGenerator(Hash(MD5)), | ||||||
|  | 	) | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 	// Output: 3858f62230ac3c915f300c664312c63f.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleHash_sHA1() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithOriginal("foobar"), | ||||||
|  | 		WithGenerator(Hash(SHA1)), | ||||||
|  | 	) | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 	// Output: 8843d7f92416211de9ebb963ff4ce28125932878.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleHash_sHA256() { | ||||||
|  | 	conf := NewConfig( | ||||||
|  | 		WithOriginal("foobar"), | ||||||
|  | 		WithGenerator(Hash(SHA256)), | ||||||
|  | 	) | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 	// Output: c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2.txt | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,60 +2,56 @@ package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
| 	"testing" | 	"testing" | ||||||
|  | 	"time" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/google/uuid" | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| const ( |  | ||||||
| 	out1 string = "abc" |  | ||||||
| 	out2 string = "def" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| var ( |  | ||||||
| 	outs           = []string{out1, out2} |  | ||||||
| 	err1           = errors.New("oops") |  | ||||||
| 	gen1 Generator = func(*Config) (string, error) { return out1, nil } |  | ||||||
| 	gen2 Generator = func(*Config) (string, error) { return out2, nil } |  | ||||||
| 	gen3 Generator = func(*Config) (string, error) { return "", err1 } |  | ||||||
| 	gens           = []Generator{gen1, gen2, gen3} |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func TestWithGenerator(t *testing.T) { | func TestWithGenerator(t *testing.T) { | ||||||
| 	g := func(*Config) (string, error) { return out1, nil } | 	g := func(*Config) (string, error) { return "abc", nil } | ||||||
| 	var c Config | 	var c Config | ||||||
| 	WithGenerator(g)(&c) | 	WithGenerator(g)(&c) | ||||||
| 	st, err := c.generator(&c) | 	st, err := c.generator(&c) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out1, st) | 	assert.Equal(t, "abc", st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorInOrder(t *testing.T) { | func TestMultiGeneratorInOrder(t *testing.T) { | ||||||
| 	g := MultiGeneratorInOrder(gens...) | 	st1 := "abc" | ||||||
|  | 	st2 := "def" | ||||||
|  | 	er1 := errors.New("oops") | ||||||
|  | 	g1 := func(*Config) (string, error) { return st1, nil } | ||||||
|  | 	g2 := func(*Config) (string, error) { return st2, nil } | ||||||
|  | 	g3 := func(*Config) (string, error) { return "", er1 } | ||||||
|  | 	g := MultiGeneratorInOrder(g1, g2, g3) | ||||||
| 	st, err := g(nil) | 	st, err := g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out1, st) | 	assert.Equal(t, st1, st) | ||||||
| 	st, err = g(nil) | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out2, st) | 	assert.Equal(t, st2, st) | ||||||
| 	st, err = g(nil) | 	st, err = g(nil) | ||||||
| 	assert.Zero(t, st) | 	assert.Zero(t, st) | ||||||
| 	assert.ErrorIs(t, err, err1) | 	assert.ErrorIs(t, err, er1) | ||||||
| 	st, err = g(nil) | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out1, st) | 	assert.Equal(t, st1, st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorInOrderOne(t *testing.T) { | func TestMultiGeneratorInOrderOne(t *testing.T) { | ||||||
| 	g1 := func(*Config) (string, error) { return out1, nil } | 	st1 := "abc" | ||||||
|  | 	g1 := func(*Config) (string, error) { return st1, nil } | ||||||
| 	g := MultiGeneratorInOrder(g1) | 	g := MultiGeneratorInOrder(g1) | ||||||
| 
 | 
 | ||||||
| 	st, err := g(nil) | 	st, err := g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out1, st) | 	assert.Equal(t, st1, st) | ||||||
| 	st, err = g(nil) | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, out1, st) | 	assert.Equal(t, st1, st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorInOrderMissing(t *testing.T) { | func TestMultiGeneratorInOrderMissing(t *testing.T) { | ||||||
|  | @ -68,38 +64,80 @@ func TestMultiGeneratorInOrderMissing(t *testing.T) { | ||||||
| 	assert.ErrorIs(t, err, ErrMissingGenerators) | 	assert.ErrorIs(t, err, ErrMissingGenerators) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorRandomOrder(t *testing.T) { | func TestUUID(t *testing.T) { | ||||||
| 	g := MultiGeneratorRandomOrder(gens...) | 	st, err := UUID()(nil) | ||||||
| 	for i := 0; i < 4; i++ { |  | ||||||
| 		st, err := g(nil) |  | ||||||
| 		if err != nil { |  | ||||||
| 			assert.Zero(t, st) |  | ||||||
| 			assert.ErrorIs(t, err, err1) |  | ||||||
| 		} else { |  | ||||||
| 			assert.Contains(t, outs, st) |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func TestMultiGeneratorRandomOrderOne(t *testing.T) { |  | ||||||
| 	st1 := "abc" |  | ||||||
| 	g1 := func(*Config) (string, error) { return st1, nil } |  | ||||||
| 	g := MultiGeneratorRandomOrder(g1) |  | ||||||
| 
 |  | ||||||
| 	st, err := g(nil) |  | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st1, st) | 	_, parseErr := uuid.Parse(st) | ||||||
| 	st, err = g(nil) | 	assert.NoError(t, parseErr) | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 	assert.Equal(t, st1, st) |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorRandomOrderMissing(t *testing.T) { | type badRead struct{} | ||||||
| 	g := MultiGeneratorRandomOrder() | 
 | ||||||
| 	st, err := g(nil) | func (badRead) Read([]byte) (int, error) { | ||||||
| 	assert.Zero(t, st) | 	return 0, errors.New("sorry") | ||||||
| 	assert.ErrorIs(t, err, ErrMissingGenerators) | } | ||||||
| 	st, err = g(nil) | 
 | ||||||
| 	assert.Zero(t, st) | func TestUUIDFail(t *testing.T) { | ||||||
| 	assert.ErrorIs(t, err, ErrMissingGenerators) | 	uuid.SetRand(badRead{}) | ||||||
|  | 	defer uuid.SetRand(nil) | ||||||
|  | 
 | ||||||
|  | 	_, err := UUID()(nil) | ||||||
|  | 	assert.Equal(t, errors.New("sorry"), err) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTimestamp(t *testing.T) { | ||||||
|  | 	n := time.Now() | ||||||
|  | 	st, err := Timestamp()(nil) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Equal(t, n.Format(FileTimestamp), st) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTime(t *testing.T) { | ||||||
|  | 	d := time.Date(1986, time.March, 28, 12, 0, 0, 0, time.UTC) | ||||||
|  | 
 | ||||||
|  | 	st, err := Time(d)(nil) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Equal(t, d.Format(FileTimestamp), st) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestTimestampUTC(t *testing.T) { | ||||||
|  | 	n := time.Now() | ||||||
|  | 	st, err := TimestampUTC()(nil) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 	assert.Equal(t, n.UTC().Format(FileTimestampNoTZ), st) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestSlugMissingFilename(t *testing.T) { | ||||||
|  | 	conf := NewConfig(WithGenerator(Slug())) | ||||||
|  | 	st, err := conf.generator(&conf) | ||||||
|  | 	assert.Zero(t, st) | ||||||
|  | 	assert.ErrorIs(t, err, ErrMissingOriginal) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestSlugRemovesOriginal(t *testing.T) { | ||||||
|  | 	conf := NewConfig(WithGenerator(Slug()), WithOriginal("Hello, World")) | ||||||
|  | 	st, err := conf.generator(&conf) | ||||||
|  | 	assert.Zero(t, conf.original) | ||||||
|  | 	assert.Equal(t, "hello-world", st) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestHashBadHash(t *testing.T) { | ||||||
|  | 	conf := NewConfig(WithOriginal("foobar"), WithGenerator(Hash(0))) | ||||||
|  | 	st, err := conf.generator(&conf) | ||||||
|  | 	assert.Equal(t, "", st) | ||||||
|  | 	assert.ErrorIs(t, err, ErrInvalidHashType) | ||||||
|  | 	assert.ErrorContains(t, err, "invalid hash type: HashType(0)") | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestHashMissingOriginal(t *testing.T) { | ||||||
|  | 	conf := NewConfig(WithGenerator(Hash(MD5))) | ||||||
|  | 	st, err := conf.generator(&conf) | ||||||
|  | 	assert.Equal(t, "", st) | ||||||
|  | 	assert.ErrorIs(t, err, ErrMissingOriginal) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestHashTypeStringer(t *testing.T) { | ||||||
|  | 	s := fmt.Sprintf("%s", MD5) | ||||||
|  | 	assert.Equal(t, "MD5", s) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										1
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -3,7 +3,6 @@ module codeberg.org/danjones000/nomino | ||||||
| go 1.23.6 | go 1.23.6 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/deatil/go-encoding v1.0.3003 |  | ||||||
| 	github.com/google/uuid v1.6.0 | 	github.com/google/uuid v1.6.0 | ||||||
| 	github.com/gosimple/slug v1.15.0 | 	github.com/gosimple/slug v1.15.0 | ||||||
| 	github.com/stretchr/testify v1.10.0 | 	github.com/stretchr/testify v1.10.0 | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -1,7 +1,5 @@ | ||||||
| github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||||||
| github.com/deatil/go-encoding v1.0.3003 h1:2b05UO+5JfVcXcOa8n/X3pm8aC6L6ET0mBZCb1kj3ck= |  | ||||||
| github.com/deatil/go-encoding v1.0.3003/go.mod h1:lTMMKsG0RRPGZzdW2EPVJCA7HQy4o1ZQKPf5CmVDy2k= |  | ||||||
| github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= | ||||||
| github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= | ||||||
| github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= | github.com/gosimple/slug v1.15.0 h1:wRZHsRrRcs6b0XnxMUBM6WK1U1Vg5B0R7VkIf1Xzobo= | ||||||
|  |  | ||||||
							
								
								
									
										26
									
								
								hashtype_string.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								hashtype_string.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,26 @@ | ||||||
|  | // Code generated by "stringer -type=HashType"; DO NOT EDIT. | ||||||
|  | 
 | ||||||
|  | package nomino | ||||||
|  | 
 | ||||||
|  | import "strconv" | ||||||
|  | 
 | ||||||
|  | func _() { | ||||||
|  | 	// An "invalid array index" compiler error signifies that the constant values have changed. | ||||||
|  | 	// Re-run the stringer command to generate them again. | ||||||
|  | 	var x [1]struct{} | ||||||
|  | 	_ = x[MD5-1] | ||||||
|  | 	_ = x[SHA1-2] | ||||||
|  | 	_ = x[SHA256-3] | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const _HashType_name = "MD5SHA1SHA256" | ||||||
|  | 
 | ||||||
|  | var _HashType_index = [...]uint8{0, 3, 7, 13} | ||||||
|  | 
 | ||||||
|  | func (i HashType) String() string { | ||||||
|  | 	i -= 1 | ||||||
|  | 	if i >= HashType(len(_HashType_index)-1) { | ||||||
|  | 		return "HashType(" + strconv.FormatInt(int64(i+1), 10) + ")" | ||||||
|  | 	} | ||||||
|  | 	return _HashType_name[_HashType_index[i]:_HashType_index[i+1]] | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								make.go
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								make.go
									
										
									
									
									
								
							|  | @ -2,24 +2,15 @@ package nomino | ||||||
| 
 | 
 | ||||||
| import "fmt" | import "fmt" | ||||||
| 
 | 
 | ||||||
| // Make generates a random filename. The behavior can be controlled by specifying Options. | // Make generates a random filename. The behavior can be controlled by specifying Options | ||||||
| // In general, the final filename will be [prefix]_[generated_string]_[original_filename]_[suffix].[extension]. | // In general, the final filename will be [prefix]_[generated_string]_[original_filename]_[suffix].[extension]. | ||||||
| // If the name generator returns an error (generally, it shouldn't), that error will be returned instead. | // If the name generator returns an error (generally, it shouldn't), that will be returned instead. | ||||||
| func Make(conf Config, opts ...Option) (string, error) { | func Make(conf Config) (string, error) { | ||||||
| 	for _, opt := range opts { |  | ||||||
| 		opt(&conf) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	name, err := conf.generator(&conf) | 	name, err := conf.generator(&conf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
| 	seperateConf(&conf) |  | ||||||
| 
 | 
 | ||||||
| 	return fmt.Sprintf("%s%s%s%s%s", conf.prefix, name, conf.original, conf.suffix, conf.extension), nil |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func seperateConf(conf *Config) { |  | ||||||
| 	if conf.prefix != "" { | 	if conf.prefix != "" { | ||||||
| 		conf.prefix += conf.separator | 		conf.prefix += conf.separator | ||||||
| 	} | 	} | ||||||
|  | @ -28,5 +19,8 @@ func seperateConf(conf *Config) { | ||||||
| 	} | 	} | ||||||
| 	if conf.suffix != "" { | 	if conf.suffix != "" { | ||||||
| 		conf.suffix = conf.separator + conf.suffix | 		conf.suffix = conf.separator + conf.suffix | ||||||
|  | 
 | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	return fmt.Sprintf("%s%s%s%s%s", conf.prefix, name, conf.original, conf.suffix, conf.extension), nil | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,30 +1,9 @@ | ||||||
| package nomino_test | package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import "fmt" | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 | 
 | ||||||
| func ExampleMake_basic() { | func ExampleMake_basic() { | ||||||
| 	// Use default config | 	// Use default config | ||||||
| 	out, _ := nomino.Make(nomino.NewConfig()) | 	out, _ := Make(NewConfig()) | ||||||
| 	fmt.Println(out) | 	fmt.Println(out) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func ExampleMake_withExtraOptions() { |  | ||||||
| 	gen := nomino.Incremental() |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithGenerator(gen), |  | ||||||
| 		nomino.WithPrefix("pre"), |  | ||||||
| 	) |  | ||||||
| 
 |  | ||||||
| 	st, _ := nomino.Make(conf, nomino.WithOriginal("foobar")) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	st, _ = nomino.Make(conf, nomino.WithOriginal("baz")) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 
 |  | ||||||
| 	// Output: |  | ||||||
| 	// pre_0_foobar.txt |  | ||||||
| 	// pre_1_baz.txt |  | ||||||
| } |  | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								make_test.go
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								make_test.go
									
										
									
									
									
								
							|  | @ -7,8 +7,6 @@ import ( | ||||||
| 	"github.com/stretchr/testify/assert" | 	"github.com/stretchr/testify/assert" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| var errTest = errors.New("sorry") |  | ||||||
| 
 |  | ||||||
| func TestMake(t *testing.T) { | func TestMake(t *testing.T) { | ||||||
| 	genOpt := WithGenerator(func(*Config) (string, error) { return "abc", nil }) | 	genOpt := WithGenerator(func(*Config) (string, error) { return "abc", nil }) | ||||||
| 	testcases := []struct { | 	testcases := []struct { | ||||||
|  | @ -50,10 +48,11 @@ func TestMake(t *testing.T) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMakeErr(t *testing.T) { | func TestMakeErr(t *testing.T) { | ||||||
| 	conf := NewConfig(WithGenerator(func(*Config) (string, error) { return "foobar", errTest })) | 	retErr := errors.New("oops") | ||||||
|  | 	conf := NewConfig(WithGenerator(func(*Config) (string, error) { return "foobar", retErr })) | ||||||
| 	st, err := Make(conf) | 	st, err := Make(conf) | ||||||
| 	assert.Zero(t, st) | 	assert.Zero(t, st) | ||||||
| 	assert.ErrorIs(t, err, errTest) | 	assert.ErrorIs(t, err, retErr) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMakeDoesntChangeConf(t *testing.T) { | func TestMakeDoesntChangeConf(t *testing.T) { | ||||||
|  | @ -67,18 +66,3 @@ func TestMakeDoesntChangeConf(t *testing.T) { | ||||||
| 	assert.Equal(t, "foo.txt", st) | 	assert.Equal(t, "foo.txt", st) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| } | } | ||||||
| 
 |  | ||||||
| func TestMakeOptsDoesntChangeConf(t *testing.T) { |  | ||||||
| 	gen := Incremental() |  | ||||||
| 	conf := NewConfig(WithGenerator(gen), WithPrefix("pre")) |  | ||||||
| 
 |  | ||||||
| 	st, err := Make(conf, WithOriginal("foobar")) |  | ||||||
| 	assert.Equal(t, "", conf.original) |  | ||||||
| 	assert.Equal(t, "pre_0_foobar.txt", st) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| 
 |  | ||||||
| 	st, err = Make(conf, WithOriginal("baz")) |  | ||||||
| 	assert.Equal(t, "", conf.original) |  | ||||||
| 	assert.Equal(t, "pre_1_baz.txt", st) |  | ||||||
| 	assert.NoError(t, err) |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  | @ -1,7 +0,0 @@ | ||||||
| // Package nomino is a utility that allows us to generate random filenames. |  | ||||||
| // |  | ||||||
| // There are two main methods of using nomino. |  | ||||||
| // |  | ||||||
| //  1. Using the [Make] function. |  | ||||||
| //  2. Creating a generator, and using its [Generator.Make] method. |  | ||||||
| package nomino |  | ||||||
|  | @ -6,7 +6,7 @@ import ( | ||||||
| 	"github.com/gosimple/slug" | 	"github.com/gosimple/slug" | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| // Option sets configuration parameters for [Config]. | // Option sets configuration parameters for Config. | ||||||
| type Option func(c *Config) | type Option func(c *Config) | ||||||
| 
 | 
 | ||||||
| // WithOriginal sets the original filename. | // WithOriginal sets the original filename. | ||||||
|  | @ -18,7 +18,7 @@ func WithOriginal(o string) Option { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // WithOriginal sets the original filename as a slug. | // 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 { | func WithOriginalSlug(o string) Option { | ||||||
| 	return func(c *Config) { | 	return func(c *Config) { | ||||||
| 		c.original = slug.Make(o) | 		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. | // 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 { | func WithOriginalSlugLang(o, lang string) Option { | ||||||
| 	return func(c *Config) { | 	return func(c *Config) { | ||||||
| 		c.original = slug.MakeLang(o, lang) | 		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 { | func WithoutExtension() Option { | ||||||
| 	return func(c *Config) { | 	return func(c *Config) { | ||||||
| 		c.extension = "" | 		c.extension = "" | ||||||
|  |  | ||||||
|  | @ -1,91 +1,11 @@ | ||||||
| package nomino_test | package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import "fmt" | ||||||
| 	"fmt" |  | ||||||
| 
 |  | ||||||
| 	"codeberg.org/danjones000/nomino" |  | ||||||
| ) |  | ||||||
| 
 |  | ||||||
| func ExampleWithExtension() { |  | ||||||
| 	st, _ := nomino.Make(nomino.NewConfig( |  | ||||||
| 		nomino.WithExtension("xml"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	)) |  | ||||||
| 
 |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: 0.xml |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleWithoutExtension() { |  | ||||||
| 	st, _ := nomino.Make(nomino.NewConfig( |  | ||||||
| 		nomino.WithoutExtension(), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	)) |  | ||||||
| 
 |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: 0 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleWithPrefix() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("pref"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	) |  | ||||||
| 	st, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 
 |  | ||||||
| 	st, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: |  | ||||||
| 	// pref_0.txt |  | ||||||
| 	// pref_1.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleWithSeparator() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithPrefix("pref"), |  | ||||||
| 		nomino.WithSeparator("---"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	) |  | ||||||
| 	st, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 
 |  | ||||||
| 	st, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: |  | ||||||
| 	// pref---0.txt |  | ||||||
| 	// pref---1.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleWithSuffix() { |  | ||||||
| 	conf := nomino.NewConfig( |  | ||||||
| 		nomino.WithSuffix("suff"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	) |  | ||||||
| 	st, _ := nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 
 |  | ||||||
| 	st, _ = nomino.Make(conf) |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: |  | ||||||
| 	// 0_suff.txt |  | ||||||
| 	// 1_suff.txt |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func ExampleWithOriginal() { |  | ||||||
| 	st, _ := nomino.Make(nomino.NewConfig( |  | ||||||
| 		nomino.WithOriginal("Hello, World"), |  | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), |  | ||||||
| 	)) |  | ||||||
| 
 |  | ||||||
| 	fmt.Println(st) |  | ||||||
| 	// Output: 0_Hello, World.txt |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| func ExampleWithOriginalSlug() { | func ExampleWithOriginalSlug() { | ||||||
| 	st, _ := nomino.Make(nomino.NewConfig( | 	st, _ := Make(NewConfig( | ||||||
| 		nomino.WithOriginalSlug("Hello, World"), | 		WithOriginalSlug("Hello, World"), | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), | 		WithGenerator(Incremental()), | ||||||
| 	)) | 	)) | ||||||
| 
 | 
 | ||||||
| 	fmt.Println(st) | 	fmt.Println(st) | ||||||
|  | @ -93,9 +13,9 @@ func ExampleWithOriginalSlug() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func ExampleWithOriginalSlugLang() { | func ExampleWithOriginalSlugLang() { | ||||||
| 	st, _ := nomino.Make(nomino.NewConfig( | 	st, _ := Make(NewConfig( | ||||||
| 		nomino.WithOriginalSlugLang("Diese & Dass", "de"), | 		WithOriginalSlugLang("Diese & Dass", "de"), | ||||||
| 		nomino.WithGenerator(nomino.Incremental()), | 		WithGenerator(Incremental()), | ||||||
| 	)) | 	)) | ||||||
| 
 | 
 | ||||||
| 	fmt.Println(st) | 	fmt.Println(st) | ||||||
|  |  | ||||||
							
								
								
									
										48
									
								
								options_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								options_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | ||||||
|  | package nomino | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"testing" | ||||||
|  | 
 | ||||||
|  | 	"github.com/stretchr/testify/assert" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func TestWithOriginal(t *testing.T) { | ||||||
|  | 	var c Config | ||||||
|  | 	name := "foobar" | ||||||
|  | 	WithOriginal(name)(&c) | ||||||
|  | 	assert.Equal(t, name, c.original) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWithPrefix(t *testing.T) { | ||||||
|  | 	var c Config | ||||||
|  | 	pref := "draft" | ||||||
|  | 	WithPrefix(pref)(&c) | ||||||
|  | 	assert.Equal(t, pref, c.prefix) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWithSuffix(t *testing.T) { | ||||||
|  | 	var c Config | ||||||
|  | 	suff := "out" | ||||||
|  | 	WithSuffix(suff)(&c) | ||||||
|  | 	assert.Equal(t, suff, c.suffix) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWithoutExtension(t *testing.T) { | ||||||
|  | 	c := Config{extension: ".foobar"} | ||||||
|  | 	WithoutExtension()(&c) | ||||||
|  | 	assert.Equal(t, "", c.extension) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWithExtension(t *testing.T) { | ||||||
|  | 	var c Config | ||||||
|  | 	ext := "yaml" | ||||||
|  | 	WithExtension(ext)(&c) | ||||||
|  | 	assert.Equal(t, "."+ext, c.extension) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func TestWithSeparator(t *testing.T) { | ||||||
|  | 	var c Config | ||||||
|  | 	sep := "---" | ||||||
|  | 	WithSeparator(sep)(&c) | ||||||
|  | 	assert.Equal(t, sep, c.separator) | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue