-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #3 from dogmatiq/1-filters
Add support for filters.
- Loading branch information
Showing
18 changed files
with
521 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package dapper | ||
|
||
import ( | ||
"io" | ||
"reflect" | ||
|
||
"github.com/dogmatiq/iago" | ||
) | ||
|
||
// Filter is a function that provides custom formatting logic for specific | ||
// values. | ||
// | ||
// It writes a formatted representation of v to w, and returns the number of | ||
// bytes written. | ||
// | ||
// If the number of bytes written is non-zero, the default formatting logic is | ||
// skipped. | ||
// | ||
// Particular attention should be paid to the v.IsUnexported field. If this flag | ||
// is true, many operations on v.Value are unavailable. | ||
type Filter func(w io.Writer, v Value) (int, error) | ||
|
||
// reflectTypeType is the reflect.Type for reflect.Type itself. | ||
var reflectTypeType = reflect.TypeOf((*reflect.Type)(nil)).Elem() | ||
|
||
// ReflectTypeFilter is a filter that formats reflect.Type values. | ||
func ReflectTypeFilter(w io.Writer, v Value) (n int, err error) { | ||
defer iago.Recover(&err) | ||
|
||
if !v.DynamicType.Implements(reflectTypeType) { | ||
return 0, nil | ||
} | ||
|
||
if v.DynamicType.Kind() == reflect.Interface && v.Value.IsNil() { | ||
return 0, nil | ||
} | ||
|
||
ambiguous := false | ||
|
||
if v.IsAmbiguousStaticType { | ||
// always render the type if the static type is ambiguous | ||
ambiguous = true | ||
} else if v.IsAmbiguousDynamicType { | ||
// only consider the dynamic type to be ambiguous if the static type isn't reflect.Type | ||
// we're not really concerned with rendering the underlying implementation's type. | ||
ambiguous = v.StaticType != reflectTypeType | ||
} | ||
|
||
if ambiguous { | ||
n += iago.MustWriteString(w, "reflect.Type(") | ||
} | ||
|
||
if v.IsUnexported { | ||
n += iago.MustWriteString(w, "<unknown>") | ||
} else { | ||
t := v.Value.Interface().(reflect.Type) | ||
|
||
if s := t.PkgPath(); s != "" { | ||
n += iago.MustWriteString(w, s) | ||
n += iago.MustWriteString(w, ".") | ||
} | ||
|
||
if s := t.Name(); s != "" { | ||
n += iago.MustWriteString(w, s) | ||
} else { | ||
n += iago.MustWriteString(w, t.String()) | ||
} | ||
|
||
} | ||
|
||
// always render the pointer value for the type, this way when the field is | ||
// unexported we still get something we can compare to known types instead of a | ||
// rendering of the reflect.rtype struct. | ||
n += iago.MustWriteString(w, " ") | ||
n += iago.MustWriteString(w, formatPointerHex(v.Value.Pointer(), false)) | ||
|
||
if ambiguous { | ||
n += iago.MustWriteString(w, ")") | ||
} | ||
|
||
return | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
package dapper_test | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
type reflectType struct { | ||
Exported reflect.Type | ||
unexported reflect.Type | ||
} | ||
|
||
var ( | ||
intType = reflect.TypeOf(0) | ||
intTypePointer = formatReflectTypePointer(intType) | ||
mapType = reflect.TypeOf(map[string]string{}) | ||
mapTypePointer = formatReflectTypePointer(mapType) | ||
namedType = reflect.TypeOf(named{}) | ||
namedTypePointer = formatReflectTypePointer(namedType) | ||
) | ||
|
||
func formatReflectTypePointer(t reflect.Type) string { | ||
return fmt.Sprintf("0x%x", reflect.ValueOf(t).Pointer()) | ||
} | ||
|
||
func TestPrinter_ReflectTypeFilter(t *testing.T) { | ||
test( | ||
t, | ||
"built-in type", | ||
intType, | ||
"reflect.Type(int "+intTypePointer+")", | ||
) | ||
|
||
test( | ||
t, | ||
"built-in parameterized type", | ||
mapType, | ||
"reflect.Type(map[string]string "+mapTypePointer+")", | ||
) | ||
|
||
test( | ||
t, | ||
"named type", | ||
reflect.TypeOf(named{}), | ||
"reflect.Type(github.com/dogmatiq/dapper_test.named "+namedTypePointer+")", | ||
) | ||
|
||
typ := reflect.TypeOf(struct{ Int int }{}) | ||
test( | ||
t, | ||
"anonymous struct", | ||
typ, | ||
"reflect.Type(struct { Int int } "+formatReflectTypePointer(typ)+")", | ||
) | ||
|
||
typ = reflect.TypeOf((*interface{ Int() int })(nil)).Elem() | ||
test( | ||
t, | ||
"anonymous interface", | ||
typ, | ||
"reflect.Type(interface { Int() int } "+formatReflectTypePointer(typ)+")", | ||
) | ||
|
||
test( | ||
t, | ||
"includes type when in an anonymous struct", | ||
struct { | ||
Type reflect.Type | ||
}{ | ||
reflect.TypeOf(0), | ||
}, | ||
"{", | ||
" Type: reflect.Type(int "+intTypePointer+")", | ||
"}", | ||
) | ||
|
||
test( | ||
t, | ||
"does not include type if static type is also reflect.Type", | ||
reflectType{ | ||
Exported: reflect.TypeOf(0), | ||
}, | ||
"dapper_test.reflectType{", | ||
" Exported: int "+intTypePointer, | ||
" unexported: nil", | ||
"}", | ||
) | ||
|
||
test( | ||
t, | ||
"still renders the pointer address when the value is unexported", | ||
reflectType{ | ||
unexported: reflect.TypeOf(0), | ||
}, | ||
"dapper_test.reflectType{", | ||
" Exported: nil", | ||
" unexported: <unknown> "+intTypePointer, | ||
"}", | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.