Skip to content

Add README.md for Bookman and Startup projects #19

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

Merged
merged 3 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
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
4 changes: 2 additions & 2 deletions conf/bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ func (param *BindParam) BindTag(tag string, validate reflect.StructTag) error {

// Filter defines an interface for filtering configuration fields during binding.
type Filter interface {
Do(i interface{}, param BindParam) (bool, error)
Do(i any, param BindParam) (bool, error)
}

// BindValue binds a value from properties `p` to the reflect.Value `v` of type `t`
Expand Down Expand Up @@ -366,7 +366,7 @@ func bindStruct(p Properties, v reflect.Value, t reflect.Type, param BindParam,
return fmt.Errorf("bind path=%s type=%s error: %w", param.Path, v.Type().String(), err)
}

for i := 0; i < t.NumField(); i++ {
for i := range t.NumField() {
ft := t.Field(i)
fv := v.Field(i)

Expand Down
34 changes: 17 additions & 17 deletions conf/bind_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@ func init() {
conf.RegisterSplitter("PointSplitter", PointSplitter)
}

type funcFilter func(i interface{}, param conf.BindParam) (bool, error)
type funcFilter func(i any, param conf.BindParam) (bool, error)

func (f funcFilter) Do(i interface{}, param conf.BindParam) (bool, error) {
func (f funcFilter) Do(i any, param conf.BindParam) (bool, error) {
return f(i, param)
}

Expand Down Expand Up @@ -77,7 +77,7 @@ func TestConverter(t *testing.T) {
})

t.Run("error", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"time": "2025-02-01M00:00:00",
})
err := p.Bind(&s)
Expand Down Expand Up @@ -304,7 +304,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value int `value:"${v}" expr:"$>9"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "1",
}).Bind(&s)
assert.ThatError(t, err).Matches("validate failed on .* for value 1")
Expand All @@ -321,7 +321,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value int `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "abc",
}).Bind(&s)
assert.ThatError(t, err).Matches("strconv.ParseInt: parsing .*: invalid syntax")
Expand All @@ -331,7 +331,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value uint `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "abc",
}).Bind(&s)
assert.ThatError(t, err).Matches("strconv.ParseUint: parsing .*: invalid syntax")
Expand All @@ -341,7 +341,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value float32 `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "abc",
}).Bind(&s)
assert.ThatError(t, err).Matches("strconv.ParseFloat: parsing .*: invalid syntax")
Expand All @@ -351,7 +351,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value bool `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "abc",
}).Bind(&s)
assert.ThatError(t, err).Matches("strconv.ParseBool: parsing .*: invalid syntax")
Expand All @@ -361,8 +361,8 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value []int `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
"v": []interface{}{
err := conf.Map(map[string]any{
"v": []any{
"1", "2", "a",
},
}).Bind(&s)
Expand Down Expand Up @@ -397,8 +397,8 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value map[string]int `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
"v": []interface{}{
err := conf.Map(map[string]any{
"v": []any{
"1", "2", "3",
},
}).Bind(&s)
Expand All @@ -409,7 +409,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
Value map[string]int `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "a:b,1:2",
}).Bind(&s)
assert.ThatError(t, err).Matches("property conflict at path v")
Expand Down Expand Up @@ -437,7 +437,7 @@ func TestProperties_Bind(t *testing.T) {
var s struct {
int `value:"${v}"`
}
err := conf.Map(map[string]interface{}{
err := conf.Map(map[string]any{
"v": "123",
}).Bind(&s)
assert.Nil(t, err)
Expand Down Expand Up @@ -574,7 +574,7 @@ func TestProperties_Bind(t *testing.T) {

v := reflect.ValueOf(&s).Elem()
err = conf.BindValue(conf.New(), v, v.Type(), param,
funcFilter(func(i interface{}, param conf.BindParam) (bool, error) {
funcFilter(func(i any, param conf.BindParam) (bool, error) {
return false, nil
}))
assert.Nil(t, err)
Expand All @@ -592,7 +592,7 @@ func TestProperties_Bind(t *testing.T) {

v := reflect.ValueOf(&s).Elem()
err = conf.BindValue(conf.New(), v, v.Type(), param,
funcFilter(func(i interface{}, param conf.BindParam) (bool, error) {
funcFilter(func(i any, param conf.BindParam) (bool, error) {
return true, nil
}))
assert.Nil(t, err)
Expand All @@ -610,7 +610,7 @@ func TestProperties_Bind(t *testing.T) {

v := reflect.ValueOf(&s).Elem()
err = conf.BindValue(conf.New(), v, v.Type(), param,
funcFilter(func(i interface{}, param conf.BindParam) (bool, error) {
funcFilter(func(i any, param conf.BindParam) (bool, error) {
return false, errors.New("filter error")
}))
assert.ThatError(t, err).Matches("filter error")
Expand Down
17 changes: 8 additions & 9 deletions conf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package conf
import (
"errors"
"fmt"
"maps"
"os"
"path/filepath"
"reflect"
Expand All @@ -37,7 +38,7 @@ import (
var (
readers = map[string]Reader{}
splitters = map[string]Splitter{}
converters = map[reflect.Type]interface{}{}
converters = map[reflect.Type]any{}
)

func init() {
Expand All @@ -56,8 +57,8 @@ func init() {
})
}

// Reader parses []byte into nested map[string]interface{}.
type Reader func(b []byte) (map[string]interface{}, error)
// Reader parses []byte into nested map[string]any.
type Reader func(b []byte) (map[string]any, error)

// RegisterReader registers its Reader for some kind of file extension.
func RegisterReader(r Reader, ext ...string) {
Expand Down Expand Up @@ -99,7 +100,7 @@ type Properties interface {
// Resolve resolves string that contains references.
Resolve(s string) (string, error)
// Bind binds properties into a value.
Bind(i interface{}, tag ...string) error
Bind(i any, tag ...string) error
// CopyTo copies properties into another by override.
CopyTo(out *MutableProperties) error
}
Expand Down Expand Up @@ -148,7 +149,7 @@ func Load(file string) (*MutableProperties, error) {
}

// Map creates *MutableProperties from map.
func Map(m map[string]interface{}) *MutableProperties {
func Map(m map[string]any) *MutableProperties {
p := New()
_ = p.merge(util.FlattenMap(m))
return p
Expand All @@ -167,9 +168,7 @@ func (p *MutableProperties) merge(m map[string]string) error {
// Data returns key-value pairs of the properties.
func (p *MutableProperties) Data() map[string]string {
m := make(map[string]string)
for k, v := range p.RawData() {
m[k] = v
}
maps.Copy(m, p.RawData())
return m
}

Expand Down Expand Up @@ -199,7 +198,7 @@ func (p *MutableProperties) Resolve(s string) (string, error) {
// value:"${a:=b}>>splitter", 'a' is the key, 'b' is the default value,
// 'splitter' is the Splitter's name when you want split string value
// into []string value.
func (p *MutableProperties) Bind(i interface{}, tag ...string) error {
func (p *MutableProperties) Bind(i any, tag ...string) error {

var v reflect.Value
{
Expand Down
24 changes: 12 additions & 12 deletions conf/conf_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ func TestProperties_Load(t *testing.T) {
func TestProperties_Resolve(t *testing.T) {

t.Run("success - 1", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
s, err := p.Resolve("${a.b.c[0]}")
Expand All @@ -68,7 +68,7 @@ func TestProperties_Resolve(t *testing.T) {
})

t.Run("success - 2", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
s, err := p.Resolve("${x:=${a.b.c[0]}}")
Expand All @@ -90,23 +90,23 @@ func TestProperties_Resolve(t *testing.T) {
})

t.Run("syntax error - 1", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
_, err := p.Resolve("${a.b.c}")
assert.ThatError(t, err).Matches("property a.b.c isn't simple value")
})

t.Run("syntax error - 2", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
_, err := p.Resolve("${a.b.c")
assert.ThatError(t, err).Matches("resolve string .* error: invalid syntax")
})

t.Run("syntax error - 3", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
_, err := p.Resolve("${a.b.c[0]}==${a.b.c}")
Expand All @@ -117,7 +117,7 @@ func TestProperties_Resolve(t *testing.T) {
func TestProperties_CopyTo(t *testing.T) {

t.Run("success", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
assert.That(t, p.Keys()).Equal([]string{
Expand All @@ -131,7 +131,7 @@ func TestProperties_CopyTo(t *testing.T) {
"a.b.c[0]": "3",
})

s := conf.Map(map[string]interface{}{
s := conf.Map(map[string]any{
"a.b.c": []string{"4", "5"},
})
assert.That(t, s.Keys()).Equal([]string{
Expand All @@ -156,14 +156,14 @@ func TestProperties_CopyTo(t *testing.T) {
})

t.Run("error", func(t *testing.T) {
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a.b.c": []string{"3"},
})
assert.That(t, p.Data()).Equal(map[string]string{
"a.b.c[0]": "3",
})

s := conf.Map(map[string]interface{}{
s := conf.Map(map[string]any{
"a.b.c": "3",
})
assert.That(t, s.Get("a.b.c")).Equal("3")
Expand All @@ -177,20 +177,20 @@ func BenchmarkResolve(b *testing.B) {
const src = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"

data := make([]byte, 2000)
for i := 0; i < len(data); i++ {
for i := range len(data) {
data[i] = src[rand.Intn(len(src))]
}
s := string(data)

b.Run("contains", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for b.Loop() {
_ = strings.Contains(s, "${")
}
})

p := conf.New()
b.Run("resolve", func(b *testing.B) {
for i := 0; i < b.N; i++ {
for b.Loop() {
_, _ = p.Resolve(s)
}
})
Expand Down
11 changes: 5 additions & 6 deletions conf/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package conf

import (
"fmt"
"maps"

"github.com/expr-lang/expr"
)
Expand All @@ -27,7 +28,7 @@ import (
type ValidateFunc[T any] func(T) bool

// validateFuncs holds a map of registered validation functions.
var validateFuncs = map[string]interface{}{}
var validateFuncs = map[string]any{}

// RegisterValidateFunc registers a validation function with a specific name.
// The function can then be used in validation expressions.
Expand All @@ -38,11 +39,9 @@ func RegisterValidateFunc[T any](name string, fn ValidateFunc[T]) {
// validateField validates a field using a validation expression (tag) and the field value (i).
// It evaluates the expression and checks if the result is true (i.e., the validation passes).
// If any error occurs during evaluation or if the validation fails, an error is returned.
func validateField(tag string, i interface{}) error {
env := map[string]interface{}{"$": i}
for k, v := range validateFuncs {
env[k] = v
}
func validateField(tag string, i any) error {
env := map[string]any{"$": i}
maps.Copy(env, validateFuncs)
r, err := expr.Eval(tag, env)
if err != nil {
return fmt.Errorf("eval %q returns error, %w", tag, err)
Expand Down
6 changes: 3 additions & 3 deletions conf/expr_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestExpr(t *testing.T) {
var v struct {
A int `value:"${a}" expr:"checkInt($)"`
}
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a": 4,
})
err := p.Bind(&v)
Expand All @@ -44,7 +44,7 @@ func TestExpr(t *testing.T) {
var v struct {
A int `value:"${a}" expr:"checkInt($)"`
}
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a": 14,
})
err := p.Bind(&v)
Expand All @@ -55,7 +55,7 @@ func TestExpr(t *testing.T) {
var v struct {
A int `value:"${a}" expr:"$+$"`
}
p := conf.Map(map[string]interface{}{
p := conf.Map(map[string]any{
"a": 4,
})
err := p.Bind(&v)
Expand Down
4 changes: 2 additions & 2 deletions conf/reader/json/json.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import (
)

// Read parses []byte in the json format into map.
func Read(b []byte) (map[string]interface{}, error) {
var ret map[string]interface{}
func Read(b []byte) (map[string]any, error) {
var ret map[string]any
err := json.Unmarshal(b, &ret)
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion conf/reader/json/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestRead(t *testing.T) {
"time": "2018-02-17T15:02:31+08:00"
}`))
assert.Nil(t, err)
assert.That(t, r).Equal(map[string]interface{}{
assert.That(t, r).Equal(map[string]any{
"empty": "",
"bool": false,
"int": float64(3),
Expand Down
Loading
Loading