🔀 Merge branch 'release/0.2.0' into stable
This commit is contained in:
		
				commit
				
					
						a82c8f2324
					
				
			
		
					 11 changed files with 348 additions and 32 deletions
				
			
		|  | @ -1,5 +1,14 @@ | ||||||
| # Changelog | # Changelog | ||||||
| 
 | 
 | ||||||
|  | ### [0.2.0] - 2025-03-14 | ||||||
|  | 
 | ||||||
|  | - Add `IncrementalFormat`* Generators | ||||||
|  | - Add `Slug`* Generators | ||||||
|  | - Add `WithOriginalSlug`* Options | ||||||
|  | - Change signature of `Generator` function | ||||||
|  | 
 | ||||||
|  | Note that this last change **is** a breaking change from 0.0.3, but only for custom Generators. | ||||||
|  | 
 | ||||||
| ## [0.0.3] - 2025-03-11 | ## [0.0.3] - 2025-03-11 | ||||||
| 
 | 
 | ||||||
| ### Features | ### Features | ||||||
|  |  | ||||||
|  | @ -10,7 +10,7 @@ import ( | ||||||
| func TestNewConf(t *testing.T) { | func TestNewConf(t *testing.T) { | ||||||
| 	c := NewConfig() | 	c := NewConfig() | ||||||
| 	assert.Equal(t, ".txt", c.extension) | 	assert.Equal(t, ".txt", c.extension) | ||||||
| 	st, _ := c.generator() | 	st, _ := c.generator(&c) | ||||||
| 	_, parseErr := uuid.Parse(st) | 	_, parseErr := uuid.Parse(st) | ||||||
| 	assert.NoError(t, parseErr) | 	assert.NoError(t, parseErr) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										102
									
								
								generators.go
									
										
									
									
									
								
							
							
						
						
									
										102
									
								
								generators.go
									
										
									
									
									
								
							|  | @ -2,15 +2,18 @@ package nomino | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
| 	"errors" | 	"errors" | ||||||
|  | 	"fmt" | ||||||
|  | 	"strconv" | ||||||
| 	"time" | 	"time" | ||||||
| 
 | 
 | ||||||
| 	"github.com/google/uuid" | 	"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. | ||||||
| // Technically, it doesn't necessarily need to be random, and could be based on time, or a counter, | // Technically, it doesn't necessarily need to be random, and could be based on time, or a counter, | ||||||
| // for example. | // for example. | ||||||
| type Generator func() (string, error) | type Generator func(conf *Config) (string, error) | ||||||
| 
 | 
 | ||||||
| // WithGenerator sets the specified generator | // WithGenerator sets the specified generator | ||||||
| func WithGenerator(g Generator) Option { | func WithGenerator(g Generator) Option { | ||||||
|  | @ -22,7 +25,7 @@ func WithGenerator(g Generator) Option { | ||||||
| // ErrMissingGenerators is returned by a multi-generator if no generators are 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() (string, error) { | func missingGen(*Config) (string, error) { | ||||||
| 	return "", ErrMissingGenerators | 	return "", ErrMissingGenerators | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -38,14 +41,14 @@ func MultiGeneratorInOrder(gens ...Generator) Generator { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	var idx int | 	var idx int | ||||||
| 	return func() (string, error) { | 	return func(c *Config) (string, error) { | ||||||
| 		st, err := gens[idx]() | 		st, err := gens[idx](c) | ||||||
| 		idx = (idx + 1) % len(gens) | 		idx = (idx + 1) % len(gens) | ||||||
| 		return st, err | 		return st, err | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func uuidGen() (string, error) { | func uuidGen(*Config) (string, error) { | ||||||
| 	u, err := uuid.NewRandom() | 	u, err := uuid.NewRandom() | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
|  | @ -80,12 +83,12 @@ func Time(t time.Time) Generator { | ||||||
| 
 | 
 | ||||||
| // FormattedTime generates a date and time for the supplied time with the supplied format. | // FormattedTime generates a date and time for the supplied time with the supplied format. | ||||||
| func FormattedTime(t time.Time, f string) Generator { | func FormattedTime(t time.Time, f string) Generator { | ||||||
| 	return func() (string, error) { | 	return func(*Config) (string, error) { | ||||||
| 		return t.Format(f), nil | 		return t.Format(f), nil | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // FileTimestamp is the default format for WithTimestampUTC and WithTimeUTC | // FileTimestampNoTZ is the default format for WithTimestampUTC and WithTimeUTC | ||||||
| const FileTimestampNoTZ string = "2006-01-02_03-05-06" | 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. | // TimestampUTC generates a date and time for the current time in UTC without a timezone in the format. | ||||||
|  | @ -97,3 +100,88 @@ func TimestampUTC() Generator { | ||||||
| func TimeUTC(t time.Time) Generator { | func TimeUTC(t time.Time) Generator { | ||||||
| 	return FormattedTime(t.UTC(), FileTimestampNoTZ) | 	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) { | ||||||
|  | 		name, err := getOriginal(c) | ||||||
|  | 		return slug.Make(name), err | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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 | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,7 @@ package nomino | ||||||
| import "fmt" | import "fmt" | ||||||
| 
 | 
 | ||||||
| func ExampleWithGenerator_custom_generator() { | func ExampleWithGenerator_custom_generator() { | ||||||
| 	gen := func() (string, error) { | 	gen := func(*Config) (string, error) { | ||||||
| 		return "hello", nil | 		return "hello", nil | ||||||
| 	} | 	} | ||||||
| 	option := WithGenerator(gen) | 	option := WithGenerator(gen) | ||||||
|  | @ -18,3 +18,146 @@ func ExampleWithGenerator_custom_generator() { | ||||||
| 	// hello.txt | 	// hello.txt | ||||||
| 	// hello | 	// hello | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncremental() { | ||||||
|  | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(Incremental())) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_0.txt | ||||||
|  | 	// foo_1.txt | ||||||
|  | 	// foo_2.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalWithStart() { | ||||||
|  | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(IncrementalWithStart(42))) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	// Output: | ||||||
|  | 	// foo_42.txt | ||||||
|  | 	// foo_43.txt | ||||||
|  | 	// foo_44.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleIncrementalWithStep() { | ||||||
|  | 	conf := NewConfig(WithPrefix("foo"), WithGenerator(IncrementalWithStep(2))) | ||||||
|  | 
 | ||||||
|  | 	str, _ := Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	fmt.Println(str) | ||||||
|  | 
 | ||||||
|  | 	str, _ = Make(conf) | ||||||
|  | 	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 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -10,10 +10,10 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestWithGenerator(t *testing.T) { | func TestWithGenerator(t *testing.T) { | ||||||
| 	g := func() (string, error) { return "abc", 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() | 	st, err := c.generator(&c) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, "abc", st) | 	assert.Equal(t, "abc", st) | ||||||
| } | } | ||||||
|  | @ -22,49 +22,49 @@ func TestMultiGeneratorInOrder(t *testing.T) { | ||||||
| 	st1 := "abc" | 	st1 := "abc" | ||||||
| 	st2 := "def" | 	st2 := "def" | ||||||
| 	er1 := errors.New("oops") | 	er1 := errors.New("oops") | ||||||
| 	g1 := func() (string, error) { return st1, nil } | 	g1 := func(*Config) (string, error) { return st1, nil } | ||||||
| 	g2 := func() (string, error) { return st2, nil } | 	g2 := func(*Config) (string, error) { return st2, nil } | ||||||
| 	g3 := func() (string, error) { return "", er1 } | 	g3 := func(*Config) (string, error) { return "", er1 } | ||||||
| 	g := MultiGeneratorInOrder(g1, g2, g3) | 	g := MultiGeneratorInOrder(g1, g2, g3) | ||||||
| 	st, err := g() | 	st, err := g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st1, st) | 	assert.Equal(t, st1, st) | ||||||
| 	st, err = g() | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st2, st) | 	assert.Equal(t, st2, st) | ||||||
| 	st, err = g() | 	st, err = g(nil) | ||||||
| 	assert.Zero(t, st) | 	assert.Zero(t, st) | ||||||
| 	assert.ErrorIs(t, err, er1) | 	assert.ErrorIs(t, err, er1) | ||||||
| 	st, err = g() | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st1, st) | 	assert.Equal(t, st1, st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorInOrderOne(t *testing.T) { | func TestMultiGeneratorInOrderOne(t *testing.T) { | ||||||
| 	st1 := "abc" | 	st1 := "abc" | ||||||
| 	g1 := func() (string, error) { return st1, nil } | 	g1 := func(*Config) (string, error) { return st1, nil } | ||||||
| 	g := MultiGeneratorInOrder(g1) | 	g := MultiGeneratorInOrder(g1) | ||||||
| 
 | 
 | ||||||
| 	st, err := g() | 	st, err := g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st1, st) | 	assert.Equal(t, st1, st) | ||||||
| 	st, err = g() | 	st, err = g(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, st1, st) | 	assert.Equal(t, st1, st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestMultiGeneratorInOrderMissing(t *testing.T) { | func TestMultiGeneratorInOrderMissing(t *testing.T) { | ||||||
| 	g := MultiGeneratorInOrder() | 	g := MultiGeneratorInOrder() | ||||||
| 	st, err := g() | 	st, err := g(nil) | ||||||
| 	assert.Zero(t, st) | 	assert.Zero(t, st) | ||||||
| 	assert.ErrorIs(t, err, ErrMissingGenerators) | 	assert.ErrorIs(t, err, ErrMissingGenerators) | ||||||
| 	st, err = g() | 	st, err = g(nil) | ||||||
| 	assert.Zero(t, st) | 	assert.Zero(t, st) | ||||||
| 	assert.ErrorIs(t, err, ErrMissingGenerators) | 	assert.ErrorIs(t, err, ErrMissingGenerators) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestUUID(t *testing.T) { | func TestUUID(t *testing.T) { | ||||||
| 	st, err := UUID()() | 	st, err := UUID()(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	_, parseErr := uuid.Parse(st) | 	_, parseErr := uuid.Parse(st) | ||||||
| 	assert.NoError(t, parseErr) | 	assert.NoError(t, parseErr) | ||||||
|  | @ -80,13 +80,13 @@ func TestUUIDFail(t *testing.T) { | ||||||
| 	uuid.SetRand(badRead{}) | 	uuid.SetRand(badRead{}) | ||||||
| 	defer uuid.SetRand(nil) | 	defer uuid.SetRand(nil) | ||||||
| 
 | 
 | ||||||
| 	_, err := UUID()() | 	_, err := UUID()(nil) | ||||||
| 	assert.Equal(t, errors.New("sorry"), err) | 	assert.Equal(t, errors.New("sorry"), err) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestTimestamp(t *testing.T) { | func TestTimestamp(t *testing.T) { | ||||||
| 	n := time.Now() | 	n := time.Now() | ||||||
| 	st, err := Timestamp()() | 	st, err := Timestamp()(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, n.Format(FileTimestamp), st) | 	assert.Equal(t, n.Format(FileTimestamp), st) | ||||||
| } | } | ||||||
|  | @ -94,14 +94,29 @@ func TestTimestamp(t *testing.T) { | ||||||
| func TestTime(t *testing.T) { | func TestTime(t *testing.T) { | ||||||
| 	d := time.Date(1986, time.March, 28, 12, 0, 0, 0, time.UTC) | 	d := time.Date(1986, time.March, 28, 12, 0, 0, 0, time.UTC) | ||||||
| 
 | 
 | ||||||
| 	st, err := Time(d)() | 	st, err := Time(d)(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, d.Format(FileTimestamp), st) | 	assert.Equal(t, d.Format(FileTimestamp), st) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestTimestampUTC(t *testing.T) { | func TestTimestampUTC(t *testing.T) { | ||||||
| 	n := time.Now() | 	n := time.Now() | ||||||
| 	st, err := TimestampUTC()() | 	st, err := TimestampUTC()(nil) | ||||||
| 	assert.NoError(t, err) | 	assert.NoError(t, err) | ||||||
| 	assert.Equal(t, n.UTC().Format(FileTimestampNoTZ), st) | 	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) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -4,11 +4,13 @@ go 1.23.6 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/google/uuid v1.6.0 | 	github.com/google/uuid v1.6.0 | ||||||
|  | 	github.com/gosimple/slug v1.15.0 | ||||||
| 	github.com/stretchr/testify v1.10.0 | 	github.com/stretchr/testify v1.10.0 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||||
|  | 	github.com/gosimple/unidecode v1.0.1 // indirect | ||||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||||
| 	gopkg.in/yaml.v3 v3.0.1 // indirect | 	gopkg.in/yaml.v3 v3.0.1 // indirect | ||||||
| ) | ) | ||||||
|  |  | ||||||
							
								
								
									
										4
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -2,6 +2,10 @@ 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/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/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ= | ||||||
|  | github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o= | ||||||
|  | github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc= | ||||||
| github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||||||
| github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||||||
| github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								make.go
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								make.go
									
										
									
									
									
								
							|  | @ -6,7 +6,7 @@ import "fmt" | ||||||
| // 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 will be returned instead. | // If the name generator returns an error (generally, it shouldn't), that will be returned instead. | ||||||
| func Make(conf Config) (string, error) { | func Make(conf Config) (string, error) { | ||||||
| 	name, err := conf.generator() | 	name, err := conf.generator(&conf) | ||||||
| 	if err != nil { | 	if err != nil { | ||||||
| 		return "", err | 		return "", err | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								make_test.go
									
										
									
									
									
								
							
							
						
						
									
										16
									
								
								make_test.go
									
										
									
									
									
								
							|  | @ -8,7 +8,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestMake(t *testing.T) { | func TestMake(t *testing.T) { | ||||||
| 	genOpt := WithGenerator(func() (string, error) { return "abc", nil }) | 	genOpt := WithGenerator(func(*Config) (string, error) { return "abc", nil }) | ||||||
| 	testcases := []struct { | 	testcases := []struct { | ||||||
| 		name string | 		name string | ||||||
| 		opts []Option | 		opts []Option | ||||||
|  | @ -47,8 +47,20 @@ func TestMake(t *testing.T) { | ||||||
| 
 | 
 | ||||||
| func TestMakeErr(t *testing.T) { | func TestMakeErr(t *testing.T) { | ||||||
| 	retErr := errors.New("oops") | 	retErr := errors.New("oops") | ||||||
| 	conf := NewConfig(WithGenerator(func() (string, error) { return "foobar", retErr })) | 	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, retErr) | 	assert.ErrorIs(t, err, retErr) | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | func TestMakeDoesntChangeConf(t *testing.T) { | ||||||
|  | 	gen := func(c *Config) (string, error) { | ||||||
|  | 		c.original = "" | ||||||
|  | 		return "foo", nil | ||||||
|  | 	} | ||||||
|  | 	conf := NewConfig(WithGenerator(gen), WithOriginal("foobar")) | ||||||
|  | 	st, err := Make(conf) | ||||||
|  | 	assert.Equal(t, "foobar", conf.original) | ||||||
|  | 	assert.Equal(t, "foo.txt", st) | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | } | ||||||
|  |  | ||||||
							
								
								
									
										22
									
								
								options.go
									
										
									
									
									
								
							
							
						
						
									
										22
									
								
								options.go
									
										
									
									
									
								
							|  | @ -1,6 +1,10 @@ | ||||||
| package nomino | package nomino | ||||||
| 
 | 
 | ||||||
| import "strings" | import ( | ||||||
|  | 	"strings" | ||||||
|  | 
 | ||||||
|  | 	"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) | ||||||
|  | @ -13,6 +17,22 @@ 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) | ||||||
|  | func WithOriginalSlug(o string) Option { | ||||||
|  | 	return func(c *Config) { | ||||||
|  | 		c.original = slug.Make(o) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // 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) | ||||||
|  | func WithOriginalSlugLang(o, lang string) Option { | ||||||
|  | 	return func(c *Config) { | ||||||
|  | 		c.original = slug.MakeLang(o, lang) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // WithPrefix sets a prefix for the generated name. | // WithPrefix sets a prefix for the generated name. | ||||||
| func WithPrefix(p string) Option { | func WithPrefix(p string) Option { | ||||||
| 	return func(c *Config) { | 	return func(c *Config) { | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								options_examples_test.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								options_examples_test.go
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,23 @@ | ||||||
|  | package nomino | ||||||
|  | 
 | ||||||
|  | import "fmt" | ||||||
|  | 
 | ||||||
|  | func ExampleWithOriginalSlug() { | ||||||
|  | 	st, _ := Make(NewConfig( | ||||||
|  | 		WithOriginalSlug("Hello, World"), | ||||||
|  | 		WithGenerator(Incremental()), | ||||||
|  | 	)) | ||||||
|  | 
 | ||||||
|  | 	fmt.Println(st) | ||||||
|  | 	// Output: 0_hello-world.txt | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func ExampleWithOriginalSlugLang() { | ||||||
|  | 	st, _ := Make(NewConfig( | ||||||
|  | 		WithOriginalSlugLang("Diese & Dass", "de"), | ||||||
|  | 		WithGenerator(Incremental()), | ||||||
|  | 	)) | ||||||
|  | 
 | ||||||
|  | 	fmt.Println(st) | ||||||
|  | 	// Output: 0_diese-und-dass.txt | ||||||
|  | } | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue