Skip to content

Commit 4eeaec5

Browse files
committed
add more tests for app run
1 parent 5aaed4b commit 4eeaec5

File tree

11 files changed

+223
-98
lines changed

11 files changed

+223
-98
lines changed

_examples/cliapp/main.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,10 @@ func main() {
2020
app := gcli.NewApp(func(app *gcli.App) {
2121
app.Version = "3.0.0"
2222
app.Desc = "this is my cli application"
23-
app.On(gcli.EvtAppInit, func(data ...interface{}) {
23+
app.On(gcli.EvtAppInit, func(data ...interface{}) bool {
2424
// do something...
2525
// fmt.Println("init app")
26+
return true
2627
})
2728

2829
// app.SetVerbose(gcli.VerbDebug)

app.go

+33-28
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,8 @@ import (
1616
* CLI application
1717
*************************************************************/
1818

19-
// HookFunc definition.
20-
// func arguments:
21-
// in app, like: func(app *App, data interface{})
22-
// in cmd, like: func(cmd *Command, data interface{})
23-
// type HookFunc func(obj interface{}, data interface{})
24-
type HookFunc func(obj ...interface{})
25-
26-
// Commander interface definition
27-
type Commander interface {
19+
// Handler interface definition
20+
type Handler interface {
2821
// Creator for create new command
2922
Creator() *Command
3023
// Config bind Flags or Arguments for the command
@@ -42,10 +35,11 @@ type Logo struct {
4235
// App the cli app definition
4336
type App struct {
4437
// internal use
38+
// - *cmdLine
39+
// - HelpVars
40+
// - Hooks // allow hooks: "init", "before", "after", "error"
4541
core
46-
// *cmdLine
47-
// HelpVars
48-
// Hooks // allow hooks: "init", "before", "after", "error"
42+
// for manager commands
4943
commandBase
5044

5145
// Name app name
@@ -62,7 +56,7 @@ type App struct {
6256
// args on after parse global options and command name.
6357
args []string
6458
// all commands by module TODO remove
65-
moduleCommands map[string]map[string]*Command
59+
// moduleCommands map[string]map[string]*Command
6660

6761
// rawFlagArgs []string
6862
// clean os.args, not contains bin-name and command-name
@@ -218,13 +212,15 @@ func (app *App) AddCommand(c *Command) {
218212
app.commandBase.addCommand(app.Name, c)
219213
}
220214

221-
// AddCommander to the application
222-
func (app *App) AddCommander(cmder Commander) {
223-
c := cmder.Creator()
224-
c.Func = cmder.Execute
215+
// AddHandler to the application
216+
func (app *App) AddHandler(h Handler) {
217+
c := h.Creator()
218+
c.Func = h.Execute
225219

226220
// binding flags
227-
cmder.Config(c)
221+
h.Config(c)
222+
223+
// add
228224
app.AddCommand(c)
229225
}
230226

@@ -329,8 +325,11 @@ func (app *App) prepareRun() (code int, name string) {
329325
// name is not empty, but is not command.
330326
if app.inputName == "" {
331327
Logf(VerbDebug, "input the command is not an registered: %s", name)
332-
// display unknown input command and similar commands tips
333-
app.showCommandTips(name)
328+
329+
if ok := app.fireEvent(EvtCmdNotFound, name); ok {
330+
// display unknown input command and similar commands tips
331+
app.showCommandTips(name)
332+
}
334333
return
335334
}
336335

@@ -359,7 +358,7 @@ func (app *App) findCommandName() (name string) {
359358
name = args[0]
360359
// is empty string or is an option
361360
if name == "" || name[0] == '-' {
362-
return ""
361+
return ""
363362
}
364363

365364
Debugf("the raw input command name(args[0]) is '%s'", name)
@@ -389,7 +388,7 @@ func (app *App) findCommandName() (name string) {
389388

390389
bakName := realName
391390
realName = nodes[0]
392-
app.args = append(nodes[1:], args[1:]...) // update app.args
391+
app.args = append(nodes[1:], args[1:]...) // update app.args
393392
Debugf("the '%s' is an command ID, expand it, command '%s', args: %v",
394393
bakName,
395394
realName,
@@ -503,10 +502,10 @@ func (app *App) exitOnEnd(code int) int {
503502
// if IsGteVerbose(VerbDebug) {
504503
// app.Infoln("[DEBUG] The Runtime Call Stacks:")
505504

506-
// bts := goutil.GetCallStacks(true)
507-
// app.Println(string(bts), len(bts))
508-
// cs := goutil.GetCallersInfo(2, 10)
509-
// app.Println(strings.Join(cs, "\n"), len(cs))
505+
// bts := goutil.GetCallStacks(true)
506+
// app.Println(string(bts), len(bts))
507+
// cs := goutil.GetCallersInfo(2, 10)
508+
// app.Println(strings.Join(cs, "\n"), len(cs))
510509
// }
511510

512511
if app.ExitOnEnd {
@@ -519,6 +518,12 @@ func (app *App) exitOnEnd(code int) int {
519518
// name can be:
520519
// - top command name in the app. 'top'
521520
// - command path in the app. 'top sub'
521+
//
522+
// Usage:
523+
// app.Exec("top")
524+
// app.Exec("top:sub")
525+
// app.Exec("top sub")
526+
// app.Exec("top sub", []string{"-a", "val0", "arg0"})
522527
func (app *App) Exec(path string, args []string) error {
523528
cmd := app.MatchByPath(path)
524529
if cmd == nil {
@@ -562,10 +567,10 @@ func (app *App) On(name string, handler HookFunc) {
562567
app.core.On(name, handler)
563568
}
564569

565-
func (app *App) fireEvent(event string, data interface{}) {
570+
func (app *App) fireEvent(event string, data interface{}) bool {
566571
Debugf("trigger the application event: <green>%s</>", event)
567572

568-
app.core.Fire(event, app, data)
573+
return app.core.Fire(event, app, data)
569574
}
570575

571576
/*************************************************************

app_test.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
"github.com/gookit/color"
1010
"github.com/gookit/gcli/v3"
11+
"github.com/gookit/goutil/dump"
1112
"github.com/stretchr/testify/assert"
1213
)
1314

@@ -20,7 +21,8 @@ var (
2021
Name: "simple",
2122
Desc: "an simple command",
2223
Func: func(c *gcli.Command, args []string) error {
23-
fmt.Println(c.Path(), args)
24+
dump.Println(c.Path(), args)
25+
c.SetValue("simple", "simple command")
2426
return nil
2527
},
2628
}
@@ -432,7 +434,7 @@ func TestApp_showCommandTips(t *testing.T) {
432434
func TestApp_AddCommander(t *testing.T) {
433435
app := gcli.NewApp()
434436

435-
app.AddCommander(&UserCommand{})
437+
app.AddHandler(&UserCommand{})
436438

437439
assert.True(t, app.HasCommand("test"))
438440
}

base.go

+75-27
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ import (
1010
"strings"
1111

1212
"github.com/gookit/color"
13+
"github.com/gookit/goutil/mathutil"
1314
"github.com/gookit/goutil/structs"
15+
"github.com/gookit/goutil/strutil"
1416
)
1517

1618
// core definition TODO rename to context ??
@@ -108,10 +110,78 @@ func (s SimplePrinter) Errorln(a ...interface{}) {
108110
color.Error.Println(a...)
109111
}
110112

113+
// simple map[string]interface{} struct
114+
type mapData struct {
115+
data map[string]interface{}
116+
}
117+
118+
// Data get all
119+
func (md *mapData) Data() map[string]interface{} {
120+
return md.data
121+
}
122+
123+
// SetData set all data
124+
func (md *mapData) SetData(data map[string]interface{}) {
125+
md.data = data
126+
}
127+
128+
// Value get from data
129+
func (md *mapData) Value(key string) interface{} {
130+
return md.data[key]
131+
}
132+
133+
// StrValue get from data
134+
func (md *mapData) StrValue(key string) string {
135+
return strutil.MustString(md.data[key])
136+
}
137+
138+
// IntValue get from data
139+
func (md *mapData) IntValue(key string) int {
140+
return mathutil.MustInt(md.data[key])
141+
}
142+
143+
// SetValue to data
144+
func (md *mapData) SetValue(key string, val interface{}) {
145+
if md.data == nil {
146+
md.data = make(map[string]interface{})
147+
}
148+
md.data[key] = val
149+
}
150+
151+
// ClearData all data
152+
func (md *mapData) ClearData() {
153+
md.data = nil
154+
}
155+
111156
/*************************************************************
112157
* simple events manage
113158
*************************************************************/
114159

160+
// HookFunc definition.
161+
// func arguments:
162+
// in app, like: func(app *App, data ...interface{})
163+
// in cmd, like: func(cmd *Command, data ...interface{})
164+
// type HookFunc func(obj interface{}, data interface{})
165+
// return:
166+
// - True go on handle. default is True
167+
// - False stop goon handle.
168+
type HookFunc func(data ...interface{}) bool
169+
170+
// HookCtx struct
171+
type HookCtx struct {
172+
mapData
173+
App *App
174+
Cmd *Command
175+
176+
name string
177+
data map[string]interface{}
178+
}
179+
180+
// Name of event
181+
func (hc *HookCtx) Name() string {
182+
return hc.name
183+
}
184+
115185
// Hooks struct
116186
type Hooks struct {
117187
// Hooks can setting some hooks func on running.
@@ -137,10 +207,12 @@ func (h *Hooks) AddOn(name string, handler HookFunc) {
137207
}
138208

139209
// Fire event by name, allow with event data
140-
func (h *Hooks) Fire(event string, data ...interface{}) {
210+
func (h *Hooks) Fire(event string, data ...interface{}) bool {
141211
if handler, ok := h.hooks[event]; ok {
142-
handler(data...)
212+
return handler(data...)
143213
}
214+
215+
return true
144216
}
145217

146218
// HasHook register
@@ -314,6 +386,7 @@ func (hv *HelpVars) ReplaceVars(input string) string {
314386

315387
// will inject to every Command
316388
type commandBase struct {
389+
mapData
317390
// Logo ASCII logo setting
318391
Logo *Logo
319392
// Version app version. like "1.0.1"
@@ -349,8 +422,6 @@ type commandBase struct {
349422

350423
// store some runtime errors
351424
errors []error
352-
// TODO simple context data map
353-
data map[string]interface{}
354425
}
355426

356427
func newCommandBase() commandBase {
@@ -530,26 +601,3 @@ func (b *commandBase) CmdAliases() *structs.Aliases {
530601
func (b *commandBase) AliasesMapping() map[string]string {
531602
return b.cmdAliases.Mapping()
532603
}
533-
534-
// Data get
535-
func (b *commandBase) Data() map[string]interface{} {
536-
return b.data
537-
}
538-
539-
// SetData to cmd
540-
func (b *commandBase) SetData(data map[string]interface{}) {
541-
b.data = data
542-
}
543-
544-
// Value get from b.data
545-
func (b *commandBase) Value(key string) interface{} {
546-
return b.data[key]
547-
}
548-
549-
// SetValue to b.data
550-
func (b *commandBase) SetValue(key string, val interface{}) {
551-
if b.data == nil {
552-
b.data = make(map[string]interface{})
553-
}
554-
b.data[key] = val
555-
}

0 commit comments

Comments
 (0)