improve package gcmd, adding CaseSensitive option for options parsing, default is CaseInsensitive

This commit is contained in:
John Guo
2022-05-13 15:24:10 +08:00
parent b63e01adf6
commit a2905977ec
4 changed files with 82 additions and 12 deletions

View File

@ -28,6 +28,7 @@ type Command struct {
Examples string // Usage examples.
Additional string // Additional info about this command, which will be appended to the end of help info.
Strict bool // Strict parsing options, which means it returns error if invalid option given.
CaseSensitive bool // CaseSensitive parsing options, which means it parses input options in case-sensitive way.
Config string // Config node name, which also retrieves the values from config component along with command line.
parent *Command // Parent command for internal usage.
commands []*Command // Sub commands of this command.

View File

@ -146,7 +146,10 @@ func (c *Command) reParse(ctx context.Context, parser *Parser) (*Parser, error)
}
supportedOptions[optionKey] = !arg.Orphan
}
parser, err := Parse(supportedOptions, c.Strict)
parser, err := Parse(supportedOptions, ParserOption{
CaseSensitive: c.CaseSensitive,
Strict: c.Strict,
})
if err != nil {
return nil, err
}

View File

@ -21,9 +21,15 @@ import (
"github.com/gogf/gf/v2/text/gstr"
)
// ParserOption manages the parsing options.
type ParserOption struct {
CaseSensitive bool // Marks options parsing in case-sensitive way.
Strict bool // Whether stops parsing and returns error if invalid option passed.
}
// Parser for arguments.
type Parser struct {
strict bool // Whether stops parsing and returns error if invalid option passed.
option ParserOption // Parse option.
parsedArgs []string // As name described.
parsedOptions map[string]string // As name described.
passedOptions map[string]bool // User passed supported options, like: map[string]bool{"name,n":true}
@ -47,7 +53,7 @@ func ParserFromCtx(ctx context.Context) *Parser {
// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
//
// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
func Parse(supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {
if supportedOptions == nil {
command.Init(os.Args...)
return &Parser{
@ -55,7 +61,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
parsedOptions: GetOptAll(),
}, nil
}
return ParseArgs(os.Args, supportedOptions, strict...)
return ParseArgs(os.Args, supportedOptions, option...)
}
// ParseArgs creates and returns a new Parser with given arguments and supported options.
@ -64,7 +70,7 @@ func Parse(supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
// the value item of `supportedOptions` indicates whether corresponding option name needs argument or not.
//
// The optional parameter `strict` specifies whether stops parsing and returns error if invalid option passed.
func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool) (*Parser, error) {
func ParseArgs(args []string, supportedOptions map[string]bool, option ...ParserOption) (*Parser, error) {
if supportedOptions == nil {
command.Init(args...)
return &Parser{
@ -72,12 +78,12 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool)
parsedOptions: GetOptAll(),
}, nil
}
strictParsing := false
if len(strict) > 0 {
strictParsing = strict[0]
var parserOption ParserOption
if len(option) > 0 {
parserOption = option[0]
}
parser := &Parser{
strict: strictParsing,
option: parserOption,
parsedArgs: make([]string, 0),
parsedOptions: make(map[string]string),
passedOptions: supportedOptions,
@ -118,7 +124,7 @@ func ParseArgs(args []string, supportedOptions map[string]bool, strict ...bool)
}
i++
continue
} else if parser.strict {
} else if parser.option.Strict {
return nil, gerror.NewCodef(gcode.CodeInvalidParameter, `invalid option '%s'`, args[i])
}
}
@ -159,8 +165,18 @@ func (p *Parser) parseOption(argument string) string {
}
func (p *Parser) isOptionValid(name string) bool {
_, ok := p.supportedOptions[name]
return ok
// Case-Sensitive.
if p.option.CaseSensitive {
_, ok := p.supportedOptions[name]
return ok
}
// Case-InSensitive.
for optionName, _ := range p.supportedOptions {
if gstr.Equal(optionName, name) {
return true
}
}
return false
}
func (p *Parser) isOptionNeedArgument(name string) bool {

View File

@ -0,0 +1,50 @@
// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.
package gcmd_test
import (
"context"
"os"
"testing"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gcmd"
"github.com/gogf/gf/v2/os/gctx"
"github.com/gogf/gf/v2/test/gtest"
)
type TestParamsCase struct {
g.Meta `name:"root" root:"root"`
}
type TestParamsCaseRootInput struct {
g.Meta `name:"root"`
Name string
}
type TestParamsCaseRootOutput struct {
Content string
}
func (c *TestParamsCase) Root(ctx context.Context, in TestParamsCaseRootInput) (out *TestParamsCaseRootOutput, err error) {
out = &TestParamsCaseRootOutput{
Content: in.Name,
}
return
}
func Test_Command_ParamsCase(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
var ctx = gctx.New()
cmd, err := gcmd.NewFromObject(TestParamsCase{})
t.AssertNil(err)
os.Args = []string{"root", "-name=john"}
value, err := cmd.RunWithValueError(ctx)
t.AssertNil(err)
t.Assert(value, `{"Content":"john"}`)
})
}