Skip to content

Ignoring fields with struct tag expr:"-" and make "in" return false for unexported fields #806

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions builtin/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,11 @@ func get(params ...any) (out any, err error) {
fieldName := i.(string)
value := v.FieldByNameFunc(func(name string) bool {
field, _ := v.Type().FieldByName(name)
if field.Tag.Get("expr") == fieldName {
tagName := field.Tag.Get("expr")
if tagName == fieldName {
return true
}
return name == fieldName
return tagName != "-" && name == fieldName
})
if value.IsValid() {
return value.Interface(), nil
Expand Down
16 changes: 12 additions & 4 deletions checker/nature/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ import (
)

func fieldName(field reflect.StructField) string {
if taggedName := field.Tag.Get("expr"); taggedName != "" {
switch taggedName := field.Tag.Get("expr"); taggedName {
case "-":
return ""
case "":
return field.Name
default:
return taggedName
}
return field.Name
}

func fetchField(t reflect.Type, name string) (reflect.StructField, bool) {
Expand All @@ -23,7 +27,7 @@ func fetchField(t reflect.Type, name string) (reflect.StructField, bool) {
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
// Search all fields, even embedded structs.
if fieldName(field) == name {
if n := fieldName(field); n != "" && n == name {
return field, true
}
}
Expand Down Expand Up @@ -69,7 +73,11 @@ func StructFields(t reflect.Type) map[string]Nature {
}
}

table[fieldName(f)] = Nature{
name := fieldName(f)
if name == "" {
continue
}
table[name] = Nature{
Type: f.Type,
FieldIndex: f.Index,
}
Expand Down
69 changes: 67 additions & 2 deletions expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"reflect"
"strings"
"sync"
"testing"
"time"
Expand Down Expand Up @@ -139,7 +140,71 @@ func ExampleEnv_tagged_field_names() {

fmt.Printf("%v", output)

// Output : Hello World
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is unrelated but I realized that this example test was not being run because there is a space between Output and :, so I removed the space and the example test is now running and is successful.

// Output: Hello World
}

func ExampleEnv_hidden_tagged_field_names() {
type Internal struct {
Visible string
Hidden string `expr:"-"`
}
type environment struct {
Visible string
Hidden string `expr:"-"`
HiddenInternal Internal `expr:"-"`
VisibleInternal Internal
}

env := environment{
Hidden: "First level secret",
HiddenInternal: Internal{
Visible: "Second level secret",
Hidden: "Also hidden",
},
VisibleInternal: Internal{
Visible: "Not a secret",
Hidden: "Hidden too",
},
}

hiddenValues := []string{
`Hidden`,
`HiddenInternal`,
`HiddenInternal.Visible`,
`HiddenInternal.Hidden`,
`VisibleInternal.Hidden`,
}
for _, expression := range hiddenValues {
output, err := expr.Eval(expression, env)
if err == nil || !strings.Contains(err.Error(), "cannot fetch") {
fmt.Printf("unexpected output: %v; err: %v\n", output, err)
return
}
fmt.Printf("%q is hidden as expected\n", expression)
}

visibleValues := []string{
`Visible`,
`VisibleInternal`,
`VisibleInternal.Visible`,
}
for _, expression := range visibleValues {
_, err := expr.Eval(expression, env)
if err != nil {
fmt.Printf("unexpected error: %v\n", err)
return
}
fmt.Printf("%q is visible as expected\n", expression)
}

// Output: "Hidden" is hidden as expected
// "HiddenInternal" is hidden as expected
// "HiddenInternal.Visible" is hidden as expected
// "HiddenInternal.Hidden" is hidden as expected
// "VisibleInternal.Hidden" is hidden as expected
// "Visible" is visible as expected
// "VisibleInternal" is visible as expected
// "VisibleInternal.Visible" is visible as expected
}

func ExampleAsKind() {
Expand Down Expand Up @@ -529,7 +594,7 @@ func ExamplePatch() {
}
fmt.Printf("%v", output)

// Output : Hello, you, world!
// Output: Hello, you, world!
Comment on lines -532 to +612
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above: this is unrelated but I realized that this example test was not being run because there is a space between Output and :, so I removed the space and the example test is now running and is successful.

}

func ExampleWithContext() {
Expand Down
5 changes: 3 additions & 2 deletions vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,11 @@ func Fetch(from, i any) any {
fieldName := i.(string)
value := v.FieldByNameFunc(func(name string) bool {
field, _ := v.Type().FieldByName(name)
if field.Tag.Get("expr") == fieldName {
tagName := field.Tag.Get("expr")
if tagName == fieldName {
return true
}
return name == fieldName
return tagName != "-" && name == fieldName
})
if value.IsValid() {
return value.Interface()
Expand Down