cases: add HandleFinalSigma option Change-Id: Ifbeb19cdbd07552f92cc11824872bd71f6d46c37 Reviewed-on: https://go-review.googlesource.com/30105 Run-TryBot: Marcel van Lohuizen <mpvl@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/cases/cases.go b/cases/cases.go index bd7bc8c..6c3fa5f 100644 --- a/cases/cases.go +++ b/cases/cases.go
@@ -97,6 +97,12 @@ // An Option is used to modify the behavior of a Caser. type Option func(o *options) +// TODO: consider these options to take a boolean as well, like FinalSigma. +// The advantage of using this approach is that other providers of a lower-case +// algorithm could set different defaults by prefixing a user-provided slice +// of options with their own. This is handy, for instance, for the precis +// package which would override the default to not handle the Greek final sigma. + var ( // NoLower disables the lowercasing of non-leading letters for a title // caser. @@ -115,7 +121,7 @@ // TODO: segmenter, max ignorable, alternative versions, etc. - noFinalSigma bool // Only used for testing. + ignoreFinalSigma bool } func getOpts(o ...Option) (res options) { @@ -125,10 +131,12 @@ return } -func noLower(o *options) { - o.noLower = true -} +func noLower(o *options) { o.noLower = true } +func compact(o *options) { o.simple = true } -func compact(o *options) { - o.simple = true +// HandleFinalSigma specifies whether the special handling of Greek final sigma +// should be enabled. Unicode prescribes handling the Greek final sigma for all +// locales, but standards like IDNA and PRECIS override this default. +func HandleFinalSigma(enable bool) Option { + return func(o *options) { o.ignoreFinalSigma = !enable } }
diff --git a/cases/map.go b/cases/map.go index 68395fc..90c784b 100644 --- a/cases/map.go +++ b/cases/map.go
@@ -108,7 +108,7 @@ func makeLower(t language.Tag, o options) transform.SpanningTransformer { _, i, _ := matcher.Match(t) f := lowerFunc[i] - if o.noFinalSigma { + if o.ignoreFinalSigma { return &simpleCaser{f: f, span: isLower} } return &lowerCaser{ @@ -123,7 +123,7 @@ lower := x.lower if o.noLower { lower = (*context).copy - } else if !o.noFinalSigma { + } else if !o.ignoreFinalSigma { lower = finalSigma(lower) } return &titleCaser{
diff --git a/cases/map_test.go b/cases/map_test.go index 2f4f40e..7311131 100644 --- a/cases/map_test.go +++ b/cases/map_test.go
@@ -27,12 +27,6 @@ opts options } -// We don't support the NoFinalSigma option, but we use it to test the -// underlying lower casers and to be able to compare differences in performance. -func noFinalSigma(o *options) { - o.noFinalSigma = true -} - var testCases = []testCase{ 0: { lang: "und", @@ -40,7 +34,7 @@ title: "Abc Abc Abc Abc İsıi Εσάσ", lower: "abc abc abc abc i\u0307sıi εσάσ", upper: "ABC ABC ABC ABC İSII ΕΣΆΣ", - opts: getOpts(noFinalSigma), + opts: getOpts(HandleFinalSigma(false)), }, 1: { @@ -49,6 +43,7 @@ title: "Abc Abc Abc Abc İsıi Εσάς Σ _Σ -Σ", lower: "abc abc abc abc i\u0307sıi εσάς σ _σ -σ", upper: "ABC ABC ABC ABC İSII ΕΣΆΣ Σ _Σ -Σ", + opts: getOpts(HandleFinalSigma(true)), }, 2: { // Title cased runes. @@ -254,23 +249,23 @@ first, second string }{{ "title/nosigma/single midword", - Caser{makeTitle(language.Und, noSigma)}, + Title(language.Und, HandleFinalSigma(false)), "A.", "a", }, { "title/nosigma/single midword", - Caser{makeTitle(language.Und, noSigma)}, + Title(language.Und, HandleFinalSigma(false)), "A", ".a", }, { "title/nosigma/double midword", - Caser{makeTitle(language.Und, noSigma)}, + Title(language.Und, HandleFinalSigma(false)), "A..", "a", }, { "title/nosigma/double midword", - Caser{makeTitle(language.Und, noSigma)}, + Title(language.Und, HandleFinalSigma(false)), "A.", ".a", }, { "title/nosigma/double midword", - Caser{makeTitle(language.Und, noSigma)}, + Title(language.Und, HandleFinalSigma(false)), "A", "..a", }, { "title/sigma/single midword", @@ -384,14 +379,14 @@ want: "οσ οσσ", dstSize: minBufSize, srcSize: minBufSize, - t: makeLower(language.Und, noSigma), + t: Lower(language.Und, HandleFinalSigma(false)), }, { desc: "und/title/simple (no final sigma)", src: "ΟΣ ΟΣΣ", want: "Οσ Οσσ", dstSize: minBufSize, srcSize: minBufSize, - t: makeTitle(language.Und, noSigma), + t: Title(language.Und, HandleFinalSigma(false)), }, { desc: "und/title/final sigma: no error", src: "ΟΣ", @@ -686,13 +681,13 @@ src: "ος οσσ", want: "οσ οσσ", atEOF: true, - t: Caser{makeLower(language.Und, noSigma)}, + t: Lower(language.Und, HandleFinalSigma(false)), }, { desc: "und/title/simple (no final sigma)", src: "Οσ Οσσ", want: "Οσ Οσσ", atEOF: true, - t: Caser{makeTitle(language.Und, noSigma)}, + t: Title(language.Und, HandleFinalSigma(false)), }, { desc: "und/lower/final sigma: no error", src: "οΣ", // Oς @@ -740,7 +735,7 @@ src: "При", want: "При", atEOF: true, - t: Caser{makeTitle(language.Und, noSigma)}, + t: Title(language.Und, HandleFinalSigma(false)), }, { // Note: the choice to change the final sigma at the end in case of // too many case ignorables is arbitrary. The main reason for this @@ -884,10 +879,6 @@ // TODO: Improve ASCII performance. -var ( - noSigma = options{noFinalSigma: true} -) - func BenchmarkCasers(b *testing.B) { for _, s := range []struct{ name, text string }{ {"ascii", txtASCII}, @@ -917,10 +908,10 @@ }{ {"fold/default", Fold()}, {"upper/default", Upper(language.Und)}, - {"lower/sigma", makeLower(language.Und, options{})}, - {"lower/simple", makeLower(language.Und, noSigma)}, - {"title/sigma", makeTitle(language.Und, options{})}, - {"title/simple", makeTitle(language.Und, noSigma)}, + {"lower/sigma", Lower(language.Und)}, + {"lower/simple", Lower(language.Und, HandleFinalSigma(false))}, + {"title/sigma", Title(language.Und)}, + {"title/simple", Title(language.Und, HandleFinalSigma(false))}, } { c := Caser{t.caser} dst := make([]byte, len(src))