Skip to content

Commit a59a1cb

Browse files
committed
chore(param): upgrade goNixArgParser
- refactor(Options): rename Command.OptionSet to Options - refactor(command): hide public member of `Command` - fix(command.ParseGroups): returns at lease one result - feat(flag): add `canFollowAssign`
1 parent 119229c commit a59a1cb

File tree

9 files changed

+225
-96
lines changed

9 files changed

+225
-96
lines changed

src/goNixArgParser/command.go

Lines changed: 47 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -7,54 +7,70 @@ import (
77
)
88

99
func NewCommand(
10-
name, summary, mergeOptionPrefix string,
10+
name, summary, mergeFlagPrefix string,
1111
restsSigns, groupSeps []string,
1212
) *Command {
1313
return &Command{
14-
Name: name,
15-
Summary: summary,
16-
OptionSet: NewOptionSet(mergeOptionPrefix, restsSigns, groupSeps),
17-
SubCommands: []*Command{},
14+
name: name,
15+
summary: summary,
16+
options: NewOptionSet(mergeFlagPrefix, restsSigns, groupSeps),
17+
subCommands: []*Command{},
1818
}
1919
}
2020

2121
func NewSimpleCommand(name, summary string) *Command {
2222
return &Command{
23-
Name: name,
24-
Summary: summary,
25-
OptionSet: NewSimpleOptionSet(),
26-
SubCommands: []*Command{},
23+
name: name,
24+
summary: summary,
25+
options: NewSimpleOptionSet(),
26+
subCommands: []*Command{},
2727
}
2828
}
2929

3030
func (c *Command) NewSubCommand(
31-
name, summary, mergeOptionPrefix string,
31+
name, summary, mergeFlagPrefix string,
3232
restsSigns, groupSeps []string,
3333
) *Command {
34-
subCommand := NewCommand(name, summary, mergeOptionPrefix, restsSigns, groupSeps)
35-
c.SubCommands = append(c.SubCommands, subCommand)
34+
subCommand := NewCommand(name, summary, mergeFlagPrefix, restsSigns, groupSeps)
35+
c.subCommands = append(c.subCommands, subCommand)
3636
return subCommand
3737
}
3838

3939
func (c *Command) NewSimpleSubCommand(name, summary string) *Command {
4040
subCommand := NewSimpleCommand(name, summary)
41-
c.SubCommands = append(c.SubCommands, subCommand)
41+
c.subCommands = append(c.subCommands, subCommand)
4242
return subCommand
4343
}
4444

4545
func (c *Command) GetSubCommand(name string) *Command {
46-
if c.SubCommands == nil {
46+
if c.subCommands == nil {
4747
return nil
4848
}
4949

50-
for _, cmd := range c.SubCommands {
51-
if cmd.Name == name {
50+
for _, cmd := range c.subCommands {
51+
if cmd.name == name {
5252
return cmd
5353
}
5454
}
5555
return nil
5656
}
5757

58+
func (c *Command) Name() string {
59+
return c.name
60+
}
61+
62+
func (c *Command) Summary() string {
63+
return c.summary
64+
}
65+
66+
func (c *Command) Options() *OptionSet {
67+
return c.options
68+
}
69+
70+
func (c *Command) SubCommands() []*Command {
71+
return c.subCommands
72+
}
73+
5874
func (c *Command) getNormalizedArgs(initArgs []string) (*Command, []*Arg) {
5975
cmd := c
6076

@@ -65,7 +81,7 @@ func (c *Command) getNormalizedArgs(initArgs []string) (*Command, []*Arg) {
6581
args := make([]*Arg, 0, len(initArgs))
6682

6783
for i, arg := range initArgs {
68-
if i == 0 && cmd.Name == arg {
84+
if i == 0 && cmd.name == arg {
6985
args = append(args, NewArg(arg, CommandArg))
7086
} else if subCmd := cmd.GetSubCommand(arg); subCmd != nil {
7187
args = append(args, NewArg(arg, CommandArg))
@@ -106,7 +122,7 @@ func (c *Command) splitCommandsArgs(initArgs, initConfigs []string) (
106122

107123
func (c *Command) Parse(initArgs, initConfigs []string) *ParseResult {
108124
leafCmd, commands, optionSetInitArgs, optionSetInitConfigs := c.splitCommandsArgs(initArgs, initConfigs)
109-
result := leafCmd.OptionSet.Parse(optionSetInitArgs, optionSetInitConfigs)
125+
result := leafCmd.options.Parse(optionSetInitArgs, optionSetInitConfigs)
110126
result.commands = commands
111127

112128
return result
@@ -116,10 +132,10 @@ func (c *Command) ParseGroups(initArgs, initConfigs []string) (results []*ParseR
116132
leafCmd, commands, optionSetInitArgs, optionSetInitConfigs := c.splitCommandsArgs(initArgs, initConfigs)
117133

118134
if len(optionSetInitArgs) == 0 && len(optionSetInitConfigs) == 0 {
119-
result := leafCmd.OptionSet.Parse(optionSetInitArgs, optionSetInitConfigs)
135+
result := leafCmd.options.Parse(optionSetInitArgs, optionSetInitConfigs)
120136
results = append(results, result)
121137
} else {
122-
results = leafCmd.OptionSet.ParseGroups(optionSetInitArgs, optionSetInitConfigs)
138+
results = leafCmd.options.ParseGroups(optionSetInitArgs, optionSetInitConfigs)
123139
}
124140

125141
for _, result := range results {
@@ -132,32 +148,32 @@ func (c *Command) ParseGroups(initArgs, initConfigs []string) (results []*ParseR
132148
func (c *Command) GetHelp() []byte {
133149
buffer := &bytes.Buffer{}
134150

135-
if len(c.Name) > 0 {
136-
buffer.WriteString(path.Base(c.Name))
151+
if len(c.name) > 0 {
152+
buffer.WriteString(path.Base(c.name))
137153
buffer.WriteString(": ")
138154
}
139-
if len(c.Summary) > 0 {
140-
buffer.WriteString(c.Summary)
155+
if len(c.summary) > 0 {
156+
buffer.WriteString(c.summary)
141157
}
142-
if len(c.Name) > 0 || len(c.Summary) > 0 {
158+
if len(c.name) > 0 || len(c.summary) > 0 {
143159
buffer.WriteByte('\n')
144160
} else {
145161
buffer.WriteString("Usage:\n")
146162
}
147163

148-
optionsHelp := c.OptionSet.GetHelp()
164+
optionsHelp := c.options.GetHelp()
149165
if len(optionsHelp) > 0 {
150166
buffer.WriteString("\nOptions:\n\n")
151167
buffer.Write(optionsHelp)
152168
}
153169

154-
if len(c.SubCommands) > 0 {
170+
if len(c.subCommands) > 0 {
155171
buffer.WriteString("\nSub commands:\n\n")
156-
for _, cmd := range c.SubCommands {
157-
buffer.WriteString(cmd.Name)
172+
for _, cmd := range c.subCommands {
173+
buffer.WriteString(cmd.name)
158174
buffer.WriteByte('\n')
159-
if len(cmd.Summary) > 0 {
160-
buffer.WriteString(cmd.Summary)
175+
if len(cmd.summary) > 0 {
176+
buffer.WriteString(cmd.summary)
161177
buffer.WriteByte('\n')
162178
}
163179
buffer.WriteByte('\n')

src/goNixArgParser/commandParse_test.go

Lines changed: 75 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@ import (
88
func getGitCommand() *Command {
99
cmdGit := NewSimpleCommand("git", "A version control tool")
1010

11-
cmdGit.OptionSet.AddFlag("version", "--version", "", "display version")
12-
cmdGit.OptionSet.AddFlag("help", "--help", "", "show git help")
11+
cmdGit.options.AddFlag("version", "--version", "", "display version")
12+
cmdGit.options.AddFlag("help", "--help", "", "show git help")
1313

1414
cmdSetUrl := cmdGit.NewSimpleSubCommand("remote", "manage remotes").NewSimpleSubCommand("set-url", "set remote url")
15-
cmdSetUrl.OptionSet.AddFlag("push", "--push", "", "")
15+
cmdSetUrl.options.AddFlag("push", "--push", "", "")
16+
cmdSetUrl.options.AddFlagValue("dummy", "--dummy", "", "", "dummy option")
1617

1718
cmdReset := cmdGit.NewSimpleSubCommand("reset", "reset command")
18-
cmdReset.OptionSet.AddFlag("hard", "--hard", "", "hard reset")
19-
cmdReset.OptionSet.AddFlag("mixed", "--mixed", "", "mixed reset")
20-
cmdReset.OptionSet.AddFlag("soft", "--soft", "", "soft reset")
19+
cmdReset.options.AddFlag("hard", "--hard", "", "hard reset")
20+
cmdReset.options.AddFlag("mixed", "--mixed", "", "mixed reset")
21+
cmdReset.options.AddFlag("soft", "--soft", "", "soft reset")
2122

2223
return cmdGit
2324
}
@@ -71,3 +72,71 @@ func TestParseCommand2(t *testing.T) {
7172
t.Error("rests", result.argRests)
7273
}
7374
}
75+
76+
func TestParseCommand3(t *testing.T) {
77+
cmd := getGitCommand()
78+
args := []string{"git", "remote", "set-url", "origin", "https://github.com/mjpclab/goNixArgParser.git"}
79+
configArgs := []string{"git", "remote", "set-url", "--dummy", "dummyconfigvalue"}
80+
result := cmd.Parse(args, configArgs)
81+
82+
dummy, _ := result.GetString("dummy")
83+
if dummy != "dummyconfigvalue" {
84+
fmt.Println("dummy:", dummy)
85+
t.Error("dummy config value error")
86+
}
87+
88+
configArgs = configArgs[1:]
89+
result = cmd.Parse(args, configArgs)
90+
91+
dummy, _ = result.GetString("dummy")
92+
if dummy != "dummyconfigvalue" {
93+
fmt.Println("dummy:", dummy)
94+
t.Error("dummy config value error")
95+
}
96+
}
97+
98+
func TestParseCommand4(t *testing.T) {
99+
cmd := getGitCommand()
100+
args := []string{"git", "remote", "set-url", "--dummy", "dummy0", "github", "https://github.com/mjpclab/goNixArgParser.git", ",,", "--dummy", "dummy1", "bitbucket", "https://bitbucket.com/mjpclab/goNixArgParser.git"}
101+
results := cmd.ParseGroups(args, nil)
102+
103+
dummy0, _ := results[0].GetString("dummy")
104+
if dummy0 != "dummy0" {
105+
t.Error(results[0].GetStrings("dummy"))
106+
}
107+
108+
dummy1, _ := results[1].GetString("dummy")
109+
if dummy1 != "dummy1" {
110+
t.Error(results[1].GetStrings("dummy"))
111+
}
112+
}
113+
114+
func TestParseCommand5(t *testing.T) {
115+
cmd := getGitCommand()
116+
args := []string{"git", "remote", "set-url", "github", "https://github.com/mjpclab/goNixArgParser.git", ",,", "bitbucket", "https://bitbucket.com/mjpclab/goNixArgParser.git"}
117+
configArgs := []string{"git", "remote", "set-url", "--dummy", "dummy0", ",,", "--dummy", "dummy1"}
118+
results := cmd.ParseGroups(args, configArgs)
119+
120+
dummy0, _ := results[0].GetString("dummy")
121+
if dummy0 != "dummy0" {
122+
t.Error(results[0].GetStrings("dummy"))
123+
}
124+
125+
dummy1, _ := results[1].GetString("dummy")
126+
if dummy1 != "dummy1" {
127+
t.Error(results[1].GetStrings("dummy"))
128+
}
129+
130+
configArgs = configArgs[1:]
131+
results = cmd.ParseGroups(args, configArgs)
132+
133+
dummy0, _ = results[0].GetString("dummy")
134+
if dummy0 != "dummy0" {
135+
t.Error(results[0].GetStrings("dummy"))
136+
}
137+
138+
dummy1, _ = results[1].GetString("dummy")
139+
if dummy1 != "dummy1" {
140+
t.Error(results[1].GetStrings("dummy"))
141+
}
142+
}

src/goNixArgParser/flag.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,18 @@
11
package goNixArgParser
22

3-
func NewFlag(name string, canMerge, canEqualAssign, canConcatAssign bool) *Flag {
3+
func NewFlag(name string, canMerge, canFollowAssign, canEqualAssign, canConcatAssign bool) *Flag {
44
return &Flag{
55
Name: name,
66
canMerge: canMerge,
7+
canFollowAssign: canFollowAssign,
78
canEqualAssign: canEqualAssign,
89
canConcatAssign: canConcatAssign,
910
}
1011
}
1112

1213
func NewSimpleFlag(name string) *Flag {
1314
isSingleChar := len(name) == 1 || (len(name) == 2 && name[0] == '-')
14-
return NewFlag(name, isSingleChar, !isSingleChar, false)
15+
return NewFlag(name, isSingleChar, true, !isSingleChar, false)
1516
}
1617

1718
func NewSimpleFlags(names []string) []*Flag {

src/goNixArgParser/optionSet.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,12 @@ func StringToSlice(input string) []string {
1717
}
1818

1919
func NewOptionSet(
20-
mergeOptionPrefix string,
20+
mergeFlagPrefix string,
2121
restsSigns []string,
2222
groupSeps []string,
2323
) *OptionSet {
2424
s := &OptionSet{
25-
mergeFlagPrefix: mergeOptionPrefix,
25+
mergeFlagPrefix: mergeFlagPrefix,
2626
restsSigns: restsSigns,
2727
groupSeps: groupSeps,
2828

@@ -37,7 +37,7 @@ func NewOptionSet(
3737
return s
3838
}
3939

40-
func (s *OptionSet) MergeOptionPrefix() string {
40+
func (s *OptionSet) MergeFlagPrefix() string {
4141
return s.mergeFlagPrefix
4242
}
4343

src/goNixArgParser/optionSetParse.go

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,24 @@ func (s *OptionSet) splitMergedArg(arg *Arg) (args []*Arg, success bool) {
1414
return
1515
}
1616

17+
if flagMap[argText] != nil {
18+
return
19+
}
20+
1721
mergedArgs := argText[len(s.mergeFlagPrefix):]
1822
splittedArgs := make([]*Arg, 0, len(mergedArgs))
19-
for _, mergedArg := range mergedArgs {
23+
for i, mergedArg := range mergedArgs {
2024
splittedArg := s.mergeFlagPrefix + string(mergedArg)
2125
flag := flagMap[splittedArg]
2226
if flag == nil || !flag.canMerge {
2327
return
2428
}
2529
splittedArgs = append(splittedArgs, NewArg(splittedArg, FlagArg))
30+
31+
if flag.canEqualAssign && i < len(mergedArgs)-1 && mergedArgs[i+1] == '=' {
32+
splittedArgs = append(splittedArgs, NewArg(mergedArgs[i+2:], ValueArg))
33+
break
34+
}
2635
}
2736

2837
return splittedArgs, true
@@ -118,10 +127,12 @@ func (s *OptionSet) splitConcatAssignArgs(initArgs []*Arg) []*Arg {
118127
return args
119128
}
120129

121-
func isValueArg(arg *Arg) bool {
130+
func isValueArg(flag *Flag, arg *Arg) bool {
122131
switch arg.Type {
123-
case ValueArg, UnknownArg:
132+
case ValueArg:
124133
return true
134+
case UnknownArg:
135+
return flag.canFollowAssign
125136
default:
126137
return false
127138
}
@@ -132,6 +143,7 @@ func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string,
132143
rests = []string{}
133144

134145
flagOptionMap := s.flagOptionMap
146+
flagMap := s.flagMap
135147

136148
if s.hasCanMerge {
137149
argObjs = s.splitMergedArgs(argObjs)
@@ -160,14 +172,15 @@ func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string,
160172
}
161173

162174
opt := flagOptionMap[arg.Text]
175+
flag := flagMap[arg.Text]
163176

164177
if !opt.AcceptValue { // option has no value
165178
args[opt.Key] = []string{}
166179
continue
167180
}
168181

169182
if !opt.MultiValues { // option has 1 value
170-
if i == argCount-1 || !isValueArg(argObjs[i+1]) { // no more value
183+
if i == argCount-1 || !isValueArg(flag, argObjs[i+1]) { // no more value
171184
if opt.OverridePrev || args[opt.Key] == nil {
172185
args[opt.Key] = []string{}
173186
}
@@ -189,7 +202,7 @@ func (s *OptionSet) parseArgsInGroup(argObjs []*Arg) (args map[string][]string,
189202
break
190203
}
191204

192-
if !isValueArg(argObjs[i+peeked+1]) { // no more value
205+
if !isValueArg(flag, argObjs[i+peeked+1]) { // no more value
193206
break
194207
}
195208

@@ -277,10 +290,8 @@ func splitArgsIntoGroups(argObjs []*Arg) [][]*Arg {
277290
continue
278291
}
279292

280-
if len(items) > 0 {
281-
groups = append(groups, items)
282-
items = []*Arg{}
283-
}
293+
groups = append(groups, items)
294+
items = []*Arg{}
284295
}
285296

286297
return groups

0 commit comments

Comments
 (0)