Skip to content

Commit b7794a8

Browse files
authored
use method name as its command name if no name defined in Meta of input struct for package gcmd (#2019)
1 parent bb3c51c commit b7794a8

File tree

3 files changed

+104
-45
lines changed

3 files changed

+104
-45
lines changed

os/gcmd/gcmd_command_object.go

Lines changed: 42 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ import (
2828
)
2929

3030
const (
31-
tagNameDc = `dc`
32-
tagNameAd = `ad`
33-
tagNameEg = `eg`
31+
tagNameDc = `dc` // description.
32+
tagNameAd = `ad` // additional
33+
tagNameEg = `eg` // examples.
3434
tagNameArg = `arg`
3535
tagNameRoot = `root`
3636
)
@@ -61,7 +61,7 @@ func NewFromObject(object interface{}) (rootCmd *Command, err error) {
6161
}
6262

6363
// Root command creating.
64-
rootCmd, err = newCommandFromObjectMeta(object)
64+
rootCmd, err = newCommandFromObjectMeta(object, "")
6565
if err != nil {
6666
return
6767
}
@@ -76,17 +76,19 @@ func NewFromObject(object interface{}) (rootCmd *Command, err error) {
7676
}
7777
for i := 0; i < reflectValue.NumMethod(); i++ {
7878
var (
79-
method = reflectValue.Method(i)
80-
methodCmd *Command
79+
method = reflectValue.Type().Method(i)
80+
methodValue = reflectValue.Method(i)
81+
methodType = methodValue.Type()
82+
methodCmd *Command
8183
)
82-
methodCmd, err = newCommandFromMethod(object, method)
84+
methodCmd, err = newCommandFromMethod(object, method, methodValue, methodType)
8385
if err != nil {
8486
return
8587
}
8688
if nameSet.Contains(methodCmd.Name) {
8789
err = gerror.Newf(
8890
`command name should be unique, found duplicated command name in method "%s"`,
89-
method.Type().String(),
91+
methodType.String(),
9092
)
9193
return
9294
}
@@ -135,27 +137,23 @@ func methodToRootCmdWhenNameEqual(rootCmd *Command, methodCmd *Command) {
135137
}
136138
}
137139

138-
func newCommandFromObjectMeta(object interface{}) (command *Command, err error) {
139-
var (
140-
metaData = gmeta.Data(object)
141-
)
142-
if len(metaData) == 0 {
143-
err = gerror.Newf(
144-
`no meta data found in struct "%s"`,
145-
reflect.TypeOf(object).String(),
146-
)
147-
return
148-
}
140+
// The `object` is the Meta attribute from business object, and the `name` is the command name,
141+
// commonly from method name, which is used when no name tag is defined in Meta.
142+
func newCommandFromObjectMeta(object interface{}, name string) (command *Command, err error) {
143+
var metaData = gmeta.Data(object)
149144
if err = gconv.Scan(metaData, &command); err != nil {
150145
return
151146
}
152147
// Name filed is necessary.
153148
if command.Name == "" {
154-
err = gerror.Newf(
155-
`command name cannot be empty, "name" tag not found in meta of struct "%s"`,
156-
reflect.TypeOf(object).String(),
157-
)
158-
return
149+
if name == "" {
150+
err = gerror.Newf(
151+
`command name cannot be empty, "name" tag not found in meta of struct "%s"`,
152+
reflect.TypeOf(object).String(),
153+
)
154+
return
155+
}
156+
command.Name = name
159157
}
160158
if command.Description == "" {
161159
command.Description = metaData[tagNameDc]
@@ -169,71 +167,70 @@ func newCommandFromObjectMeta(object interface{}) (command *Command, err error)
169167
return
170168
}
171169

172-
func newCommandFromMethod(object interface{}, method reflect.Value) (command *Command, err error) {
173-
var (
174-
reflectType = method.Type()
175-
)
170+
func newCommandFromMethod(
171+
object interface{}, method reflect.Method, methodValue reflect.Value, methodType reflect.Type,
172+
) (command *Command, err error) {
176173
// Necessary validation for input/output parameters and naming.
177-
if reflectType.NumIn() != 2 || reflectType.NumOut() != 2 {
178-
if reflectType.PkgPath() != "" {
174+
if methodType.NumIn() != 2 || methodType.NumOut() != 2 {
175+
if methodType.PkgPath() != "" {
179176
err = gerror.NewCodef(
180177
gcode.CodeInvalidParameter,
181178
`invalid command: %s.%s.%s defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
182-
reflectType.PkgPath(), reflect.TypeOf(object).Name(), reflectType.Name(), reflectType.String(),
179+
methodType.PkgPath(), reflect.TypeOf(object).Name(), methodType.Name(), methodType.String(),
183180
)
184181
} else {
185182
err = gerror.NewCodef(
186183
gcode.CodeInvalidParameter,
187184
`invalid command: defined as "%s", but "func(context.Context, Input)(Output, error)" is required`,
188-
reflectType.String(),
185+
methodType.String(),
189186
)
190187
}
191188
return
192189
}
193-
if reflectType.In(0).String() != "context.Context" {
190+
if methodType.In(0).String() != "context.Context" {
194191
err = gerror.NewCodef(
195192
gcode.CodeInvalidParameter,
196193
`invalid command: defined as "%s", but the first input parameter should be type of "context.Context"`,
197-
reflectType.String(),
194+
methodType.String(),
198195
)
199196
return
200197
}
201-
if reflectType.Out(1).String() != "error" {
198+
if methodType.Out(1).String() != "error" {
202199
err = gerror.NewCodef(
203200
gcode.CodeInvalidParameter,
204201
`invalid command: defined as "%s", but the last output parameter should be type of "error"`,
205-
reflectType.String(),
202+
methodType.String(),
206203
)
207204
return
208205
}
209206
// The input struct should be named as `xxxInput`.
210-
if !gstr.HasSuffix(reflectType.In(1).String(), `Input`) {
207+
if !gstr.HasSuffix(methodType.In(1).String(), `Input`) {
211208
err = gerror.NewCodef(
212209
gcode.CodeInvalidParameter,
213210
`invalid struct naming for input: defined as "%s", but it should be named with "Input" suffix like "xxxInput"`,
214-
reflectType.In(1).String(),
211+
methodType.In(1).String(),
215212
)
216213
return
217214
}
218215
// The output struct should be named as `xxxOutput`.
219-
if !gstr.HasSuffix(reflectType.Out(0).String(), `Output`) {
216+
if !gstr.HasSuffix(methodType.Out(0).String(), `Output`) {
220217
err = gerror.NewCodef(
221218
gcode.CodeInvalidParameter,
222219
`invalid struct naming for output: defined as "%s", but it should be named with "Output" suffix like "xxxOutput"`,
223-
reflectType.Out(0).String(),
220+
methodType.Out(0).String(),
224221
)
225222
return
226223
}
227224

228225
var inputObject reflect.Value
229-
if method.Type().In(1).Kind() == reflect.Ptr {
230-
inputObject = reflect.New(method.Type().In(1).Elem()).Elem()
226+
if methodType.In(1).Kind() == reflect.Ptr {
227+
inputObject = reflect.New(methodType.In(1).Elem()).Elem()
231228
} else {
232-
inputObject = reflect.New(method.Type().In(1)).Elem()
229+
inputObject = reflect.New(methodType.In(1)).Elem()
233230
}
234231

235232
// Command creating.
236-
if command, err = newCommandFromObjectMeta(inputObject.Interface()); err != nil {
233+
if command, err = newCommandFromObjectMeta(inputObject.Interface(), method.Name); err != nil {
237234
return
238235
}
239236

@@ -312,7 +309,7 @@ func newCommandFromMethod(object interface{}, method reflect.Value) (command *Co
312309
inputValues = append(inputValues, inputObject)
313310

314311
// Call handler with dynamic created parameter values.
315-
results := method.Call(inputValues)
312+
results := methodValue.Call(inputValues)
316313
out = results[0].Interface()
317314
if !results[1].IsNil() {
318315
if v, ok := results[1].Interface().(error); ok {
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
2+
//
3+
// This Source Code Form is subject to the terms of the MIT License.
4+
// If a copy of the MIT was not distributed with this file,
5+
// You can obtain one at https://github.com/gogf/gf.
6+
7+
package gcmd_test
8+
9+
import (
10+
"context"
11+
"os"
12+
"testing"
13+
14+
"github.com/gogf/gf/v2/frame/g"
15+
"github.com/gogf/gf/v2/os/gcmd"
16+
"github.com/gogf/gf/v2/os/gctx"
17+
"github.com/gogf/gf/v2/test/gtest"
18+
)
19+
20+
type TestNoNameTagCase struct {
21+
g.Meta `name:"root"`
22+
}
23+
24+
type TestNoNameTagCaseRootInput struct {
25+
Name string
26+
}
27+
type TestNoNameTagCaseRootOutput struct {
28+
Content string
29+
}
30+
31+
func (c *TestNoNameTagCase) TEST(ctx context.Context, in TestNoNameTagCaseRootInput) (out *TestNoNameTagCaseRootOutput, err error) {
32+
out = &TestNoNameTagCaseRootOutput{
33+
Content: in.Name,
34+
}
35+
return
36+
}
37+
38+
func Test_Command_NoNameTagCase(t *testing.T) {
39+
gtest.C(t, func(t *gtest.T) {
40+
var ctx = gctx.New()
41+
cmd, err := gcmd.NewFromObject(TestNoNameTagCase{})
42+
t.AssertNil(err)
43+
44+
os.Args = []string{"root", "TEST", "-name=john"}
45+
value, err := cmd.RunWithValueError(ctx)
46+
t.AssertNil(err)
47+
t.Assert(value, `{"Content":"john"}`)
48+
})
49+
}

os/gcron/gcron_z_unit_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,17 @@ func TestCron_Remove(t *testing.T) {
8888
}
8989

9090
func TestCron_Add_FixedPattern(t *testing.T) {
91+
//debug := utils.IsDebugEnabled()
92+
//utils.SetDebugEnabled(true)
93+
//defer func() {
94+
// utils.SetDebugEnabled(debug)
95+
//}()
96+
for i := 0; i < 5; i++ {
97+
doTestCronAddFixedPattern(t)
98+
}
99+
}
100+
101+
func doTestCronAddFixedPattern(t *testing.T) {
91102
gtest.C(t, func(t *gtest.T) {
92103
var (
93104
now = time.Now()
@@ -96,6 +107,8 @@ func TestCron_Add_FixedPattern(t *testing.T) {
96107
minutes = now.Minute()
97108
seconds = now.Second() + 2
98109
)
110+
defer cron.Close()
111+
99112
if seconds >= 60 {
100113
seconds %= 60
101114
minutes++

0 commit comments

Comments
 (0)