Skip to content

Commit fb7c318

Browse files
authored
Relax Transformer name rules (#109)
Relax the Transformer name to be any Go identifier or qualified identifier. Clarify in the documentation how this is used (e.g., in Diff) and what names are valid. Fixes #102
1 parent 19e9c26 commit fb7c318

File tree

3 files changed

+13
-17
lines changed

3 files changed

+13
-17
lines changed

cmp/options.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package cmp
77
import (
88
"fmt"
99
"reflect"
10+
"regexp"
1011
"strings"
1112

1213
"github.com/google/go-cmp/cmp/internal/function"
@@ -205,6 +206,11 @@ func (invalid) apply(s *state, _, _ reflect.Value) {
205206
panic(fmt.Sprintf("cannot handle unexported field: %#v\n%s", s.curPath, help))
206207
}
207208

209+
// identRx represents a valid identifier according to the Go specification.
210+
const identRx = `[_\p{L}][_\p{L}\p{N}]*`
211+
212+
var identsRx = regexp.MustCompile(`^` + identRx + `(\.` + identRx + `)*$`)
213+
208214
// Transformer returns an Option that applies a transformation function that
209215
// converts values of a certain type into that of another.
210216
//
@@ -222,7 +228,9 @@ func (invalid) apply(s *state, _, _ reflect.Value) {
222228
// to prevent the transformer from being recursively applied upon itself.
223229
//
224230
// The name is a user provided label that is used as the Transform.Name in the
225-
// transformation PathStep. If empty, an arbitrary name is used.
231+
// transformation PathStep (and eventually shown in the Diff output).
232+
// The name must be a valid identifier or qualified identifier in Go syntax.
233+
// If empty, an arbitrary name is used.
226234
func Transformer(name string, f interface{}) Option {
227235
v := reflect.ValueOf(f)
228236
if !function.IsType(v.Type(), function.Transformer) || v.IsNil() {
@@ -231,7 +239,7 @@ func Transformer(name string, f interface{}) Option {
231239
if name == "" {
232240
name = "λ" // Lambda-symbol as place-holder for anonymous transformer
233241
}
234-
if !isValid(name) {
242+
if !identsRx.MatchString(name) {
235243
panic(fmt.Sprintf("invalid name: %q", name))
236244
}
237245
tr := &transformer{name: name, fnc: reflect.ValueOf(f)}

cmp/options_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,9 @@ func TestOptionPanic(t *testing.T) {
113113
args: []interface{}{"/*", func(int) bool { return true }},
114114
wantPanic: "invalid name",
115115
}, {
116-
label: "Transformer",
117-
fnc: Transformer,
118-
args: []interface{}{"_", func(int) bool { return true }},
119-
wantPanic: "invalid name",
116+
label: "Transformer",
117+
fnc: Transformer,
118+
args: []interface{}{"_", func(int) bool { return true }},
120119
}, {
121120
label: "FilterPath",
122121
fnc: FilterPath,

cmp/path.go

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -296,14 +296,3 @@ func isExported(id string) bool {
296296
r, _ := utf8.DecodeRuneInString(id)
297297
return unicode.IsUpper(r)
298298
}
299-
300-
// isValid reports whether the identifier is valid.
301-
// Empty and underscore-only strings are not valid.
302-
func isValid(id string) bool {
303-
ok := id != "" && id != "_"
304-
for j, c := range id {
305-
ok = ok && (j > 0 || !unicode.IsDigit(c))
306-
ok = ok && (c == '_' || unicode.IsLetter(c) || unicode.IsDigit(c))
307-
}
308-
return ok
309-
}

0 commit comments

Comments
 (0)