Skip to content

fix(dict): keys accepts maps of any value type, not just map[string]interface{} - #485

Open
bejaratommy wants to merge 1 commit into
Masterminds:masterfrom
bejaratommy:fix-keys-generic-maps
Open

bejaratommy wants to merge 1 commit into
Masterminds:masterfrom
bejaratommy:fix-keys-generic-maps

Conversation

@bejaratommy

Copy link
Copy Markdown

Problem

keys() is declared as func(dicts ...map[string]interface{}) []string. Go's text/template does static argument type-checking against the exact declared parameter type before calling a function, so passing any map whose value type isn't precisely interface{} (e.g. map[string]string, map[string]*MyStruct) panics before keys is ever invoked:

panic: template: example:4:28: executing "example" at <keys>: wrong type for value; expected map[string]interface {}; got map[string]string

This makes keys unusable on any dict-like data that doesn't happen to already be map[string]interface{}, e.g. maps produced by strongly-typed Go code passed into a template.

Reported in #455, hit independently by two people with different concrete map types (map[string]string and map[string]*T).

Fix

  • dict.go: change keys to func keys(dicts ...interface{}) ([]string, error). Internally use reflect to confirm each argument is a map (dereferencing one level of pointer) and that its keys are strings, then collect them. Returns an error for non-map arguments or maps with non-string keys instead of panicking.
  • dict_test.go: added TestKeysNonInterfaceMaps (covers map[string]string and map[string]int) and TestKeysNonMapErrors (non-map argument now returns an error rather than panicking). Existing TestKeys (covering the original map[string]interface{} behavior) still passes unmodified.

Testing

go build ./...
go vet ./...
go test ./... -run Keys -v   # PASS
go test ./...                # PASS (one unrelated pre-existing failure in
                              # TestRound reproduces identically on unmodified
                              # master — a floating point rounding edge case
                              # unrelated to this change)

Fixes #455

…nterface{}

keys() was declared as func(...map[string]interface{}) []string, so
text/template's static argument type-checking rejected any other map
type (map[string]string, map[string]*T, ...) before the function body
ever ran, panicking with "wrong type for value; expected
map[string]interface {}; got ...".

Change the signature to variadic interface{} and use reflection to
walk the map keys, returning an error for non-map arguments or maps
with non-string keys.

Fixes Masterminds#455

Signed-off-by: Tommy <tommy@bejara.net>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant