Skip to content

Commit a9e699c

Browse files
authored
Add AppendTimestamp option to make slug unique (#81)
1 parent 4a8e359 commit a9e699c

File tree

2 files changed

+100
-0
lines changed

2 files changed

+100
-0
lines changed

slug.go

+15
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"bytes"
1010
"regexp"
1111
"sort"
12+
"strconv"
1213
"strings"
14+
"time"
1315

1416
"github.com/gosimple/unidecode"
1517
)
@@ -36,6 +38,10 @@ var (
3638
// Default is true.
3739
Lowercase = true
3840

41+
// Append timestamp to the end in order to make slug unique
42+
// Default is false
43+
AppendTimestamp = false
44+
3945
regexpNonAuthorizedChars = regexp.MustCompile("[^a-zA-Z0-9-_]")
4046
regexpMultipleDashes = regexp.MustCompile("-+")
4147
)
@@ -127,6 +133,10 @@ func MakeLang(s string, lang string) (slug string) {
127133
slug = smartTruncate(slug)
128134
}
129135

136+
if AppendTimestamp {
137+
slug = slug + "-" + timestamp()
138+
}
139+
130140
return slug
131141
}
132142

@@ -177,6 +187,11 @@ func smartTruncate(text string) string {
177187
return text[:MaxLength]
178188
}
179189

190+
// timestamp returns current timestamp as string
191+
func timestamp() string {
192+
return strconv.FormatInt(time.Now().Unix(), 10)
193+
}
194+
180195
// IsSlug returns True if provided text does not contain white characters,
181196
// punctuation, all letters are lower case and only from ASCII range.
182197
// It could contain `-` and `_` but not at the beginning or end of the text.

slug_test.go

+85
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package slug
77

88
import (
9+
"regexp"
910
"testing"
1011
)
1112

@@ -344,6 +345,90 @@ func TestSlugMakeSmartTruncate(t *testing.T) {
344345
}
345346
}
346347

348+
func TestSlugMakeAppendTimestamp(t *testing.T) {
349+
testCases := []struct {
350+
in string
351+
want string
352+
appendTimestamp bool
353+
}{
354+
{"DOBROSLAWZYBORT", "dobroslawzybort", true},
355+
{"Dobroslaw Zybort", "dobroslaw-zybort", true},
356+
{" Dobroslaw Zybort ?", "dobroslaw-zybort", true},
357+
{"Dobrosław Żybort", "dobroslaw-zybort", true},
358+
{"Ala ma 6 kotów.", "ala-ma-6-kotow", true},
359+
360+
{"áÁàÀãÃâÂäÄąĄą̊Ą̊", "aaaaaaaaaaaaaa", true},
361+
{"ćĆĉĈçÇčČ", "cccccccc", true},
362+
{"éÉèÈẽẼêÊëËęĘěĚ", "eeeeeeeeeeeeee", true},
363+
{"íÍìÌĩĨîÎïÏįĮ", "iiiiiiiiiiii", true},
364+
{"łŁ", "ll", true},
365+
{"ńŃ", "nn", true},
366+
{"óÓòÒõÕôÔöÖǫǪǭǬø", "ooooooooooooooo", true},
367+
{"śŚšŠ", "ssss", true},
368+
{"řŘ", "rr", true},
369+
{"ťŤ", "tt", true},
370+
{"úÚùÙũŨûÛüÜųŲůŮ", "uuuuuuuuuuuuuu", true},
371+
{"y̨Y̨ýÝ", "yyyy", true},
372+
{"źŹżŹžŽ", "zzzzzz", true},
373+
{"·/,:;`˜'\"", "", true},
374+
{"2000–2013", "2000-2013", true},
375+
{"style—not", "style-not", true},
376+
{"test_slug", "test_slug", true},
377+
{"_test_slug_", "test_slug", true},
378+
{"-test-slug-", "test-slug", true},
379+
{"Æ", "ae", true},
380+
{"Ich heiße", "ich-heisse", true},
381+
{"𐀀", "", true}, // Bug #53
382+
{"% 5 @ 4 $ 3 / 2 & 1 & 2 # 3 @ 4 _ 5", "5-at-4-3-2-and-1-and-2-3-at-4-_-5", true},
383+
384+
{"This & that", "this-and-that", true},
385+
{"fácil €", "facil-eu", true},
386+
{"smile ☺", "smile", true},
387+
{"Hellö Wörld хелло ворлд", "hello-world-khello-vorld", true},
388+
{"\"C'est déjà l’été.\"", "cest-deja-lete", true},
389+
{"jaja---lol-méméméoo--a", "jaja-lol-mememeoo-a", true},
390+
{"影師", "ying-shi", true},
391+
{"Đanković & Kožušček", "dankovic-and-kozuscek", true},
392+
{"ĂăÂâÎîȘșȚț", "aaaaiisstt", true},
393+
394+
// No append timestamp
395+
{"DOBROSLAWZYBORT", "dobroslawzybort", false},
396+
{"Dobroslaw Zybort", "dobroslaw-zybort", false},
397+
{" Dobroslaw Zybort ?", "dobroslaw-zybort", false},
398+
{"Dobrosław Żybort", "dobroslaw-zybort", false},
399+
{"Ala ma 6 kotów.", "ala-ma-6-kotow", false},
400+
}
401+
402+
MaxLength = 0
403+
EnableSmartTruncate = true
404+
CustomRuneSub = nil
405+
CustomSub = nil
406+
Lowercase = true
407+
for index, st := range testCases {
408+
if st.appendTimestamp {
409+
AppendTimestamp = true
410+
} else {
411+
AppendTimestamp = false
412+
}
413+
got := Make(st.in)
414+
if st.appendTimestamp {
415+
want := regexp.MustCompile(`^` + st.want + `-\d{10}$`)
416+
if !want.MatchString(got) {
417+
t.Errorf(
418+
"%d. AppendTimestamp = %v; Make(%#v) = %#v; want %#v",
419+
index, st.appendTimestamp, st.in, got, want,
420+
)
421+
}
422+
continue
423+
}
424+
if got != st.want {
425+
t.Errorf(
426+
"%d. Make(%#v) = %#v; want %#v",
427+
index, st.in, got, st.want)
428+
}
429+
}
430+
}
431+
347432
func TestIsSlug(t *testing.T) {
348433
MaxLength = 0
349434
type args struct {

0 commit comments

Comments
 (0)