Skip to content

Commit 70d848d

Browse files
author
dapeng
committed
feat: v2 version, refactoring
1 parent 671e8ef commit 70d848d

File tree

226 files changed

+5805
-17377
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

226 files changed

+5805
-17377
lines changed

cemetery.go

Lines changed: 0 additions & 552 deletions
This file was deleted.

cemetery_test.go

Lines changed: 0 additions & 765 deletions
This file was deleted.

coffin.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package gone
2+
3+
import (
4+
"reflect"
5+
"sort"
6+
)
7+
8+
// coffin represents a component container in the gone framework
9+
type coffin struct {
10+
name string
11+
goner any
12+
13+
order int
14+
onlyForName bool
15+
forceReplace bool
16+
17+
defaultTypeMap map[reflect.Type]bool
18+
lazyFill bool
19+
needInitBeforeUse bool
20+
isFill bool
21+
isInit bool
22+
}
23+
24+
func newCoffin(goner any) *coffin {
25+
_, needInitBeforeUse := goner.(Initiator)
26+
if !needInitBeforeUse {
27+
_, needInitBeforeUse = goner.(InitiatorNoError)
28+
}
29+
if !needInitBeforeUse {
30+
_, needInitBeforeUse = goner.(NamedProvider)
31+
}
32+
33+
return &coffin{
34+
goner: goner,
35+
defaultTypeMap: make(map[reflect.Type]bool),
36+
needInitBeforeUse: needInitBeforeUse,
37+
}
38+
}
39+
40+
func (c *coffin) isDefault(t reflect.Type) bool {
41+
return c.defaultTypeMap[t]
42+
}
43+
44+
// coffinList is a slice of coffin pointers that implements sort.Interface
45+
type coffinList []*coffin
46+
47+
func (c coffinList) Len() int {
48+
return len(c)
49+
}
50+
51+
func (c coffinList) Less(i, j int) bool {
52+
return c[i].order < c[j].order
53+
}
54+
55+
func (c coffinList) Swap(i, j int) {
56+
c[i], c[j] = c[j], c[i]
57+
}
58+
59+
// SortCoffins sorts a slice of coffins by their order
60+
func SortCoffins(coffins []*coffin) {
61+
sort.Sort(coffinList(coffins))
62+
}
63+
64+
func isInitiator(co *coffin) bool {
65+
if _, ok := co.goner.(Initiator); ok {
66+
return true
67+
}
68+
if _, ok := co.goner.(InitiatorNoError); ok {
69+
return true
70+
}
71+
return false
72+
}

coffin_test.go

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
package gone
2+
3+
import (
4+
"reflect"
5+
"testing"
6+
)
7+
8+
func TestCoffinListSort(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
coffins []*coffin
12+
expected []*coffin
13+
}{
14+
{
15+
name: "Sort by order - ascending",
16+
coffins: []*coffin{
17+
{name: "C", order: 3},
18+
{name: "A", order: 1},
19+
{name: "B", order: 2},
20+
},
21+
expected: []*coffin{
22+
{name: "A", order: 1},
23+
{name: "B", order: 2},
24+
{name: "C", order: 3},
25+
},
26+
},
27+
{
28+
name: "Sort with same orders",
29+
coffins: []*coffin{
30+
{name: "A", order: 1},
31+
{name: "B", order: 1},
32+
{name: "C", order: 1},
33+
},
34+
expected: []*coffin{
35+
{name: "A", order: 1},
36+
{name: "B", order: 1},
37+
{name: "C", order: 1},
38+
},
39+
},
40+
{
41+
name: "Sort with negative orders",
42+
coffins: []*coffin{
43+
{name: "C", order: 1},
44+
{name: "A", order: -2},
45+
{name: "B", order: -1},
46+
},
47+
expected: []*coffin{
48+
{name: "A", order: -2},
49+
{name: "B", order: -1},
50+
{name: "C", order: 1},
51+
},
52+
},
53+
{
54+
name: "Empty slice",
55+
coffins: []*coffin{},
56+
expected: []*coffin{},
57+
},
58+
{
59+
name: "Single element",
60+
coffins: []*coffin{
61+
{name: "A", order: 1},
62+
},
63+
expected: []*coffin{
64+
{name: "A", order: 1},
65+
},
66+
},
67+
}
68+
69+
for _, tt := range tests {
70+
t.Run(tt.name, func(t *testing.T) {
71+
// Test Sort method
72+
SortCoffins(tt.coffins)
73+
74+
// Check if the result matches expected
75+
if !reflect.DeepEqual(tt.coffins, tt.expected) {
76+
t.Errorf("SortCoffins() got = %v, want %v", formatCoffins(tt.coffins), formatCoffins(tt.expected))
77+
}
78+
79+
// Verify that the result is actually sorted
80+
for i := 1; i < len(tt.coffins); i++ {
81+
if tt.coffins[i-1].order > tt.coffins[i].order {
82+
t.Errorf("SortCoffins() result is not sorted at index %d: %v", i, formatCoffins(tt.coffins))
83+
}
84+
}
85+
})
86+
}
87+
}
88+
89+
func TestCoffinListInterface(t *testing.T) {
90+
list := coffinList{
91+
{name: "B", order: 2},
92+
{name: "A", order: 1},
93+
{name: "C", order: 3},
94+
}
95+
96+
// Test Len()
97+
if got := list.Len(); got != 3 {
98+
t.Errorf("coffinList.Len() = %v, want %v", got, 3)
99+
}
100+
101+
// Test Less()
102+
tests := []struct {
103+
i, j int
104+
expected bool
105+
}{
106+
{0, 1, false}, // 2 > 1, should be false
107+
{1, 2, true}, // 1 < 3, should be true
108+
{0, 2, true}, // 2 < 3, should be true
109+
}
110+
111+
for _, tt := range tests {
112+
t.Run(formatLessTest(list[tt.i], list[tt.j]), func(t *testing.T) {
113+
if got := list.Less(tt.i, tt.j); got != tt.expected {
114+
t.Errorf("coffinList.Less(%v, %v) = %v, want %v",
115+
tt.i, tt.j, got, tt.expected)
116+
}
117+
})
118+
}
119+
120+
// Test Swap()
121+
original := make([]*coffin, len(list))
122+
copy(original, list)
123+
124+
list.Swap(0, 2)
125+
if list[0].order != original[2].order || list[2].order != original[0].order {
126+
t.Errorf("coffinList.Swap(0, 2) failed, got %v, want swapped %v",
127+
formatCoffins(list), formatCoffins(original))
128+
}
129+
}
130+
131+
// Helper function to format coffins for error messages
132+
func formatCoffins(coffins []*coffin) string {
133+
result := "["
134+
for i, c := range coffins {
135+
if i > 0 {
136+
result += ", "
137+
}
138+
result += "{" + c.name + ":" + string(rune('0'+c.order)) + "}"
139+
}
140+
result += "]"
141+
return result
142+
}
143+
144+
// Helper function to format Less test description
145+
func formatLessTest(a, b *coffin) string {
146+
return "Less " + a.name + "(" + string(rune('0'+a.order)) + ") " +
147+
b.name + "(" + string(rune('0'+b.order)) + ")"
148+
}

config.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package gone
2+
3+
import (
4+
"github.com/gone-io/gone/internal/json"
5+
"os"
6+
"reflect"
7+
"strconv"
8+
"time"
9+
)
10+
11+
const ConfigureName = "configure"
12+
13+
// Configure defines the interface for configuration providers
14+
// Get retrieves a configuration value by key, storing it in v, with a default value if not found
15+
type Configure interface {
16+
Get(key string, v any, defaultVal string) error
17+
}
18+
19+
// ConfigProvider implements a provider for injecting configuration values
20+
// It uses an underlying Configure implementation to retrieve values
21+
type ConfigProvider struct {
22+
Flag
23+
configure Configure `gone:"configure"` // The Configure implementation to use
24+
}
25+
26+
// Name returns the provider name "config" used for registration
27+
func (s *ConfigProvider) Name() string {
28+
return "config"
29+
}
30+
31+
func (s *ConfigProvider) Init() {}
32+
33+
// Provide implements the provider interface to inject configuration values
34+
// Parameters:
35+
// - tagConf: The tag configuration string containing key and default value
36+
// - t: The reflect.Type of the value to provide
37+
//
38+
// Returns:
39+
// - The configured value of type t
40+
// - Error if configuration fails
41+
func (s *ConfigProvider) Provide(tagConf string, t reflect.Type) (any, error) {
42+
// Parse the tag string into a map and ordered keys
43+
m, keys := TagStringParse(tagConf)
44+
if len(keys) == 0 {
45+
return nil, NewInnerError("config-key is empty", ConfigError)
46+
}
47+
48+
// Get the first key and its default value
49+
key := keys[0]
50+
defaultValue := m[key]
51+
if defaultValue == "" {
52+
defaultValue = m["default"] // Fallback to "default" key if no value
53+
}
54+
55+
// Create new value of requested type and configure it
56+
value := reflect.New(t)
57+
err := s.configure.Get(key, value.Interface(), defaultValue)
58+
if err != nil {
59+
return nil, ToError(err)
60+
}
61+
return value.Elem().Interface(), nil
62+
}
63+
64+
type EnvConfigure struct {
65+
Flag
66+
}
67+
68+
// Get retrieves a configuration value from environment variables with fallback to default value.
69+
// Supports type conversion for various Go types including string, int, float, bool, and structs.
70+
//
71+
// Parameters:
72+
// - key: Environment variable name to look up
73+
// - v: Pointer to variable where the value will be stored
74+
// - defaultVal: Default value if environment variable is not set
75+
//
76+
// Returns error if:
77+
// - v is not a pointer
78+
// - Type conversion fails
79+
// - Unsupported type is provided
80+
func (s *EnvConfigure) Get(key string, v any, defaultVal string) error {
81+
// Get environment variable value, fallback to default if not set
82+
key = convertUppercaseCamel("GONE_" + key)
83+
env := os.Getenv(key)
84+
if env == "" {
85+
env = defaultVal
86+
}
87+
88+
// Verify v is a pointer
89+
rv := reflect.ValueOf(v)
90+
if rv.Kind() != reflect.Ptr {
91+
return NewInnerError("Value must be a pointer", ConfigError)
92+
}
93+
94+
// Type switch to handle different pointer types
95+
switch ptr := v.(type) {
96+
case *string:
97+
// String type needs no conversion
98+
*ptr = env
99+
case *int:
100+
// Convert string to int
101+
val, err := strconv.Atoi(env)
102+
if err != nil {
103+
return ToError(err)
104+
}
105+
*ptr = val
106+
case *int64:
107+
// Convert string to int64
108+
val, err := strconv.ParseInt(env, 10, 64)
109+
if err != nil {
110+
return ToError(err)
111+
}
112+
*ptr = val
113+
case *float64:
114+
// Convert string to float64
115+
val, err := strconv.ParseFloat(env, 64)
116+
if err != nil {
117+
return ToError(err)
118+
}
119+
*ptr = val
120+
case *bool:
121+
// Convert string to bool
122+
val, err := strconv.ParseBool(env)
123+
if err != nil {
124+
return ToError(err)
125+
}
126+
*ptr = val
127+
case *uint:
128+
// Convert string to uint
129+
val, err := strconv.ParseUint(env, 10, 64)
130+
if err != nil {
131+
return ToError(err)
132+
}
133+
*ptr = uint(val)
134+
case *uint64:
135+
// Convert string to uint64
136+
val, err := strconv.ParseUint(env, 10, 64)
137+
if err != nil {
138+
return ToError(err)
139+
}
140+
*ptr = val
141+
case *time.Duration:
142+
// Convert string to time.Duration
143+
val, err := time.ParseDuration(env)
144+
if err != nil {
145+
return ToError(err)
146+
}
147+
*ptr = val
148+
default:
149+
// Handle struct types by JSON unmarshal
150+
if rv.Elem().Kind() == reflect.Struct {
151+
err := json.Unmarshal([]byte(env), v)
152+
if err != nil {
153+
return ToError(err)
154+
}
155+
return nil
156+
}
157+
return NewInnerError("Unsupported type by EnvConfigure", ConfigError)
158+
}
159+
return nil
160+
}

0 commit comments

Comments
 (0)