Skip to content

Commit 0d46fd6

Browse files
goofinatorakamensky
authored andcommitted
decrease cyclomatic complexity: argument.go/parse (akamensky#53)
* decrease cyclomatic complexity: argument.go/parse * fmt
1 parent 543653f commit 0d46fd6

File tree

1 file changed

+196
-138
lines changed

1 file changed

+196
-138
lines changed

argument.go

Lines changed: 196 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -129,167 +129,225 @@ func (o *arg) reduce(position int, args *[]string) {
129129
}
130130
}
131131

132-
func (o *arg) parse(args []string, argCount int) error {
133-
// If unique do not allow more than one time
134-
if o.unique && (o.parsed || argCount > 1) {
135-
return fmt.Errorf("[%s] can only be present once", o.name())
132+
func (o *arg) parseInt(args []string, argCount int) error {
133+
//data of integer type is for
134+
switch {
135+
//FlagCounter argument
136+
case len(args) < 1:
137+
if o.size > 1 {
138+
return fmt.Errorf("[%s] must be followed by an integer", o.name())
139+
}
140+
*o.result.(*int) += argCount
141+
case len(args) > 1:
142+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
143+
//or Int argument with one integer parameter
144+
default:
145+
val, err := strconv.Atoi(args[0])
146+
if err != nil {
147+
return fmt.Errorf("[%s] bad interger value [%s]", o.name(), args[0])
148+
}
149+
*o.result.(*int) = val
136150
}
151+
o.parsed = true
152+
return nil
153+
}
137154

138-
// If validation function provided -- execute, on error return it immediately
139-
if o.opts != nil && o.opts.Validate != nil {
140-
err := o.opts.Validate(args)
141-
if err != nil {
142-
return err
155+
func (o *arg) parseBool(args []string) error {
156+
//data of bool type is for Flag argument
157+
*o.result.(*bool) = true
158+
o.parsed = true
159+
return nil
160+
}
161+
162+
func (o *arg) parseFloat(args []string) error {
163+
//data of float64 type is for Float argument with one float parameter
164+
if len(args) < 1 {
165+
return fmt.Errorf("[%s] must be followed by a floating point number", o.name())
166+
}
167+
if len(args) > 1 {
168+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
169+
}
170+
171+
val, err := strconv.ParseFloat(args[0], 64)
172+
if err != nil {
173+
return fmt.Errorf("[%s] bad floating point value [%s]", o.name(), args[0])
174+
}
175+
176+
*o.result.(*float64) = val
177+
o.parsed = true
178+
return nil
179+
}
180+
181+
func (o *arg) parseString(args []string) error {
182+
//data of string type is for String argument with one string parameter
183+
if len(args) < 1 {
184+
return fmt.Errorf("[%s] must be followed by a string", o.name())
185+
}
186+
if len(args) > 1 {
187+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
188+
}
189+
190+
// Selector case
191+
if o.selector != nil {
192+
match := false
193+
for _, v := range *o.selector {
194+
if args[0] == v {
195+
match = true
196+
}
197+
}
198+
if !match {
199+
return fmt.Errorf("bad value for [%s]. Allowed values are %v", o.name(), *o.selector)
200+
}
201+
}
202+
203+
*o.result.(*string) = args[0]
204+
o.parsed = true
205+
return nil
206+
}
207+
208+
func (o *arg) parseFile(args []string) error {
209+
//data of os.File type is for File argument with one file name parameter
210+
if len(args) < 1 {
211+
return fmt.Errorf("[%s] must be followed by a path to file", o.name())
212+
}
213+
if len(args) > 1 {
214+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
215+
}
216+
217+
f, err := os.OpenFile(args[0], o.fileFlag, o.filePerm)
218+
if err != nil {
219+
return err
220+
}
221+
222+
*o.result.(*os.File) = *f
223+
o.parsed = true
224+
return nil
225+
}
226+
227+
func (o *arg) parseStringList(args []string) error {
228+
//data of []string type is for List and StringList argument with set of string parameters
229+
if len(args) < 1 {
230+
return fmt.Errorf("[%s] must be followed by a string", o.name())
231+
}
232+
if len(args) > 1 {
233+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
234+
}
235+
236+
*o.result.(*[]string) = append(*o.result.(*[]string), args[0])
237+
o.parsed = true
238+
return nil
239+
}
240+
241+
func (o *arg) parseIntList(args []string) error {
242+
//data of []int type is for IntList argument with set of int parameters
243+
switch {
244+
case len(args) < 1:
245+
return fmt.Errorf("[%s] must be followed by a string representation of integer", o.name())
246+
case len(args) > 1:
247+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
248+
}
249+
250+
val, err := strconv.Atoi(args[0])
251+
if err != nil {
252+
return fmt.Errorf("[%s] bad interger value [%s]", o.name(), args[0])
253+
}
254+
*o.result.(*[]int) = append(*o.result.(*[]int), val)
255+
o.parsed = true
256+
return nil
257+
}
258+
259+
func (o *arg) parseFloatList(args []string) error {
260+
//data of []float64 type is for FloatList argument with set of int parameters
261+
switch {
262+
case len(args) < 1:
263+
return fmt.Errorf("[%s] must be followed by a string representation of integer", o.name())
264+
case len(args) > 1:
265+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
266+
}
267+
268+
val, err := strconv.ParseFloat(args[0], 64)
269+
if err != nil {
270+
return fmt.Errorf("[%s] bad floating point value [%s]", o.name(), args[0])
271+
}
272+
*o.result.(*[]float64) = append(*o.result.(*[]float64), val)
273+
o.parsed = true
274+
return nil
275+
}
276+
277+
func (o *arg) parseFileList(args []string) error {
278+
//data of []os.File type is for FileList argument with set of int parameters
279+
switch {
280+
case len(args) < 1:
281+
return fmt.Errorf("[%s] must be followed by a path to file", o.name())
282+
case len(args) > 1:
283+
return fmt.Errorf("[%s] followed by too many arguments", o.name())
284+
}
285+
f, err := os.OpenFile(args[0], o.fileFlag, o.filePerm)
286+
if err != nil {
287+
//if one of FileList's file opening have been failed, close all other in this list
288+
errs := make([]string, 0, len(*o.result.(*[]os.File)))
289+
for _, f := range *o.result.(*[]os.File) {
290+
if err := f.Close(); err != nil {
291+
//almost unreal, but what if another process closed this file
292+
errs = append(errs, err.Error())
293+
}
143294
}
295+
if len(errs) > 0 {
296+
err = fmt.Errorf("while handling error: %v, other errors occured: %#v", err.Error(), errs)
297+
}
298+
*o.result.(*[]os.File) = []os.File{}
299+
return err
144300
}
301+
*o.result.(*[]os.File) = append(*o.result.(*[]os.File), *f)
302+
o.parsed = true
303+
return nil
304+
}
145305

306+
func (o *arg) parseSomeType(args []string, argCount int) error {
307+
var err error
146308
switch o.result.(type) {
147309
case *help:
148310
helpText := o.parent.Help(nil)
149311
fmt.Print(helpText)
150312
os.Exit(0)
151-
//data of bool type is for Flag argument
152313
case *bool:
153-
*o.result.(*bool) = true
154-
o.parsed = true
155-
//data of integer type is for
314+
err = o.parseBool(args)
156315
case *int:
157-
switch {
158-
//FlagCounter argument
159-
case len(args) < 1:
160-
if o.size > 1 {
161-
return fmt.Errorf("[%s] must be followed by an integer", o.name())
162-
}
163-
*o.result.(*int) += argCount
164-
case len(args) > 1:
165-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
166-
//or Int argument with one integer parameter
167-
default:
168-
val, err := strconv.Atoi(args[0])
169-
if err != nil {
170-
return fmt.Errorf("[%s] bad interger value [%s]", o.name(), args[0])
171-
}
172-
*o.result.(*int) = val
173-
}
174-
o.parsed = true
175-
//data of float64 type is for Float argument with one float parameter
316+
err = o.parseInt(args, argCount)
176317
case *float64:
177-
if len(args) < 1 {
178-
return fmt.Errorf("[%s] must be followed by a floating point number", o.name())
179-
}
180-
if len(args) > 1 {
181-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
182-
}
183-
val, err := strconv.ParseFloat(args[0], 64)
184-
if err != nil {
185-
return fmt.Errorf("[%s] bad floating point value [%s]", o.name(), args[0])
186-
}
187-
*o.result.(*float64) = val
188-
o.parsed = true
189-
//data of string type is for String argument with one string parameter
318+
err = o.parseFloat(args)
190319
case *string:
191-
if len(args) < 1 {
192-
return fmt.Errorf("[%s] must be followed by a string", o.name())
193-
}
194-
if len(args) > 1 {
195-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
196-
}
197-
// Selector case
198-
if o.selector != nil {
199-
match := false
200-
for _, v := range *o.selector {
201-
if args[0] == v {
202-
match = true
203-
}
204-
}
205-
if !match {
206-
return fmt.Errorf("bad value for [%s]. Allowed values are %v", o.name(), *o.selector)
207-
}
208-
}
209-
*o.result.(*string) = args[0]
210-
o.parsed = true
211-
//data of os.File type is for File argument with one file name parameter
320+
err = o.parseString(args)
212321
case *os.File:
213-
if len(args) < 1 {
214-
return fmt.Errorf("[%s] must be followed by a path to file", o.name())
215-
}
216-
if len(args) > 1 {
217-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
218-
}
219-
f, err := os.OpenFile(args[0], o.fileFlag, o.filePerm)
220-
if err != nil {
221-
return err
222-
}
223-
*o.result.(*os.File) = *f
224-
o.parsed = true
225-
//data of []string type is for List and StringList argument with set of string parameters
322+
err = o.parseFile(args)
226323
case *[]string:
227-
if len(args) < 1 {
228-
return fmt.Errorf("[%s] must be followed by a string", o.name())
229-
}
230-
if len(args) > 1 {
231-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
232-
}
233-
*o.result.(*[]string) = append(*o.result.(*[]string), args[0])
234-
o.parsed = true
235-
//data of []int type is for IntList argument with set of int parameters
324+
err = o.parseStringList(args)
236325
case *[]int:
237-
switch {
238-
case len(args) < 1:
239-
return fmt.Errorf("[%s] must be followed by a string representation of integer", o.name())
240-
case len(args) > 1:
241-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
242-
}
243-
val, err := strconv.Atoi(args[0])
244-
if err != nil {
245-
return fmt.Errorf("[%s] bad interger value [%s]", o.name(), args[0])
246-
}
247-
*o.result.(*[]int) = append(*o.result.(*[]int), val)
248-
o.parsed = true
249-
//data of []float64 type is for FloatList argument with set of int parameters
326+
err = o.parseIntList(args)
250327
case *[]float64:
251-
switch {
252-
case len(args) < 1:
253-
return fmt.Errorf("[%s] must be followed by a string representation of integer", o.name())
254-
case len(args) > 1:
255-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
256-
}
257-
val, err := strconv.ParseFloat(args[0], 64)
258-
if err != nil {
259-
return fmt.Errorf("[%s] bad floating point value [%s]", o.name(), args[0])
260-
}
261-
*o.result.(*[]float64) = append(*o.result.(*[]float64), val)
262-
o.parsed = true
263-
//data of []os.File type is for FileList argument with set of int parameters
328+
err = o.parseFloatList(args)
264329
case *[]os.File:
265-
switch {
266-
case len(args) < 1:
267-
return fmt.Errorf("[%s] must be followed by a path to file", o.name())
268-
case len(args) > 1:
269-
return fmt.Errorf("[%s] followed by too many arguments", o.name())
270-
}
271-
f, err := os.OpenFile(args[0], o.fileFlag, o.filePerm)
330+
err = o.parseFileList(args)
331+
default:
332+
err = fmt.Errorf("unsupported type [%t]", o.result)
333+
}
334+
return err
335+
}
336+
337+
func (o *arg) parse(args []string, argCount int) error {
338+
// If unique do not allow more than one time
339+
if o.unique && (o.parsed || argCount > 1) {
340+
return fmt.Errorf("[%s] can only be present once", o.name())
341+
}
342+
343+
// If validation function provided -- execute, on error return it immediately
344+
if o.opts != nil && o.opts.Validate != nil {
345+
err := o.opts.Validate(args)
272346
if err != nil {
273-
//if one of FileList's file opening have been failed, close all other in this list
274-
errs := make([]string, 0, len(*o.result.(*[]os.File)))
275-
for _, f := range *o.result.(*[]os.File) {
276-
if err := f.Close(); err != nil {
277-
//almost unreal, but what if another process closed this file
278-
errs = append(errs, err.Error())
279-
}
280-
}
281-
if len(errs) > 0 {
282-
err = fmt.Errorf("while handling error: %v, other errors occured: %#v", err.Error(), errs)
283-
}
284-
*o.result.(*[]os.File) = []os.File{}
285347
return err
286348
}
287-
*o.result.(*[]os.File) = append(*o.result.(*[]os.File), *f)
288-
o.parsed = true
289-
default:
290-
return fmt.Errorf("unsupported type [%t]", o.result)
291349
}
292-
return nil
350+
return o.parseSomeType(args, argCount)
293351
}
294352

295353
func (o *arg) name() string {

0 commit comments

Comments
 (0)