From 596026ae92b47b0509975ebde964c5a45d4d3996 Mon Sep 17 00:00:00 2001 From: andrey1s Date: Sun, 1 Nov 2020 18:57:35 +0300 Subject: [PATCH] add map input --- console.go | 3 +- input/argument/argument.go | 7 +- input/argv.go | 20 +----- input/array.go | 110 +++++++----------------------- input/chain.go | 7 +- input/map.go | 87 +++++++++++++++++++++++ input/option/option.go | 7 +- input/validator/not_blank_test.go | 2 +- input/value/empty.go | 8 ++- 9 files changed, 128 insertions(+), 123 deletions(-) create mode 100644 input/map.go diff --git a/console.go b/console.go index dd869f1..0f075a7 100644 --- a/console.go +++ b/console.go @@ -3,7 +3,6 @@ package console import ( "context" "errors" - "log" "os" "gitoa.ru/go-4devs/console/input" @@ -117,7 +116,7 @@ func showHelp(ctx context.Context, cmd *Command, in input.Input, out output.Outp if err != nil { return err } - log.Println(a) + w := input.Chain(a, in) return Run(ctx, help, w, out) diff --git a/input/argument/argument.go b/input/argument/argument.go index 27a8a21..b5f42bb 100644 --- a/input/argument/argument.go +++ b/input/argument/argument.go @@ -1,6 +1,7 @@ package argument import ( + "gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value/flag" ) @@ -45,13 +46,9 @@ func (a Argument) IsArray() bool { func (a Argument) Validate(v value.Value) error { for _, valid := range a.Valid { if err := valid(v); err != nil { - return Error(a.Name, err) + return errs.Argument(a.Name, err) } } return nil } - -func Error(name string, err error) error { - return err -} diff --git a/input/argv.go b/input/argv.go index bf1238b..d239fca 100644 --- a/input/argv.go +++ b/input/argv.go @@ -7,7 +7,6 @@ import ( "gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/option" - "gitoa.ru/go-4devs/console/input/value" ) const doubleDash = `--` @@ -72,9 +71,7 @@ func (i *Argv) parseLongOption(arg string, def *Definition) error { } func (i *Argv) appendOption(name string, data *string, opt option.Option) error { - v, ok := i.GetOption(name) - - if ok && !opt.IsArray() { + if i.HasOption(name) && !opt.IsArray() { return fmt.Errorf("%w: got: array, expect: %s", errs.ErrUnexpectedType, opt.Flag.Type()) } @@ -92,12 +89,7 @@ func (i *Argv) appendOption(name string, data *string, opt option.Option) error return errs.Option(name, errs.ErrRequired) } - if !ok { - v = value.ByFlag(opt.Flag) - i.SetOption(name, v) - } - - if err := v.Append(val); err != nil { + if err := i.AppendOption(opt.Flag, name, val); err != nil { return errs.Option(name, err) } @@ -139,13 +131,7 @@ func (i *Argv) parseArgument(arg string, def *Definition) error { return err } - v, ok := i.GetArgument(opt.Name) - if !ok { - v = value.ByFlag(opt.Flag) - i.SetArgument(opt.Name, v) - } - - if err := v.Append(arg); err != nil { + if err := i.AppendArgument(opt.Flag, opt.Name, arg); err != nil { return errs.Argument(opt.Name, err) } diff --git a/input/array.go b/input/array.go index 72b5b8e..4f8649e 100644 --- a/input/array.go +++ b/input/array.go @@ -2,78 +2,56 @@ package input import ( "context" - "sync" "gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/value" ) type Array struct { - defaults array - value array + Map + defaults Map } -func (a *Array) GetOption(name string) (value.Append, bool) { - return a.value.GetOption(name) -} - -func (a *Array) SetOption(name string, v interface{}) { - a.value.SetOption(name, v) -} - -func (a *Array) LenArguments() int { - return a.value.LenArguments() -} - -func (a *Array) GetArgument(name string) (value.Append, bool) { - return a.value.GetArgument(name) -} - -func (a *Array) SetArgument(name string, v interface{}) { - a.value.SetArgument(name, v) -} - -func (a *Array) Option(_ context.Context, name string) value.Value { - if v, ok := a.value.GetOption(name); ok { +func (a *Array) Option(ctx context.Context, name string) value.Value { + if v := a.Map.Option(ctx, name); !value.IsEmpty(v) { return v } - if v, ok := a.defaults.GetOption(name); ok { + if v := a.defaults.Option(ctx, name); !value.IsEmpty(v) { return v } - return value.Empty + return value.Empty() } -func (a *Array) Argument(_ context.Context, name string) value.Value { - if v, ok := a.value.GetArgument(name); ok { +func (a *Array) Argument(ctx context.Context, name string) value.Value { + if v := a.Map.Argument(ctx, name); !value.IsEmpty(v) { return v } - if v, ok := a.defaults.GetArgument(name); ok { + if v := a.defaults.Argument(ctx, name); !value.IsEmpty(v) { return v } - return value.Empty + return value.Empty() } func (a *Array) Bind(ctx context.Context, d *Definition) error { - if err := a.bindArguments(d); err != nil { + if err := a.bindArguments(ctx, d); err != nil { return err } - return a.bindOption(d) + return a.bindOption(ctx, d) } -func (a *Array) bindOption(def *Definition) error { +func (a *Array) bindOption(ctx context.Context, def *Definition) error { for _, name := range def.Options() { opt, err := def.Option(name) if err != nil { return err } - v, ok := a.value.GetOption(name) - if !ok { + if !a.HasOption(name) { switch { case opt.HasDefault(): a.defaults.SetOption(name, opt.Default) @@ -86,7 +64,10 @@ func (a *Array) bindOption(def *Definition) error { } } - a.SetOption(name, v) + v := a.Map.Option(ctx, name) + if value.IsEmpty(v) { + continue + } if err := opt.Validate(v); err != nil { return errs.Option(name, err) @@ -96,15 +77,14 @@ func (a *Array) bindOption(def *Definition) error { return nil } -func (a *Array) bindArguments(def *Definition) error { +func (a *Array) bindArguments(ctx context.Context, def *Definition) error { for pos, name := range def.Arguments() { arg, err := def.Argument(pos) if err != nil { return err } - v, ok := a.value.GetArgument(name) - if !ok { + if !a.HasArgument(name) { switch { case arg.HasDefault(): a.defaults.SetArgument(name, arg.Default) @@ -117,54 +97,12 @@ func (a *Array) bindArguments(def *Definition) error { } } - if err := arg.Validate(v); err != nil { - return errs.Argument(name, err) + if v := a.Map.Argument(ctx, name); !value.IsEmpty(v) { + if err := arg.Validate(v); err != nil { + return errs.Argument(name, err) + } } - - a.SetArgument(name, v) } return nil } - -type array struct { - opts map[string]value.Append - args map[string]value.Append - mu sync.Mutex -} - -func (a *array) GetOption(name string) (value.Append, bool) { - v, ok := a.opts[name] - - return v, ok -} - -func (a *array) SetOption(name string, v interface{}) { - if a.opts == nil { - a.opts = make(map[string]value.Append) - } - - a.mu.Lock() - a.opts[name] = value.New(v) - a.mu.Unlock() -} - -func (a *array) LenArguments() int { - return len(a.args) -} - -func (a *array) GetArgument(name string) (value.Append, bool) { - v, ok := a.args[name] - - return v, ok -} - -func (a *array) SetArgument(name string, v interface{}) { - if a.args == nil { - a.args = make(map[string]value.Append) - } - - a.mu.Lock() - a.args[name] = value.New(v) - a.mu.Unlock() -} diff --git a/input/chain.go b/input/chain.go index 19fb504..6b33098 100644 --- a/input/chain.go +++ b/input/chain.go @@ -2,7 +2,6 @@ package input import ( "context" - "log" "gitoa.ru/go-4devs/console/input/value" ) @@ -14,15 +13,13 @@ func Chain(c ...Input) Input { type chain []Input func (c chain) Option(ctx context.Context, name string) value.Value { - log.Println(name, len(c)) for _, in := range c { - log.Printf("%T\n", in) if val := in.Option(ctx, name); !value.IsEmpty(val) { return val } } - return value.Empty + return value.Empty() } func (c chain) Argument(ctx context.Context, name string) value.Value { @@ -32,7 +29,7 @@ func (c chain) Argument(ctx context.Context, name string) value.Value { } } - return value.Empty + return value.Empty() } func (c chain) Bind(ctx context.Context, def *Definition) error { diff --git a/input/map.go b/input/map.go new file mode 100644 index 0000000..4fdcfda --- /dev/null +++ b/input/map.go @@ -0,0 +1,87 @@ +package input + +import ( + "context" + "sync" + + "gitoa.ru/go-4devs/console/input/value" + "gitoa.ru/go-4devs/console/input/value/flag" +) + +type Map struct { + opts map[string]value.Append + args map[string]value.Append + sync.Mutex +} + +func (m *Map) Option(_ context.Context, name string) value.Value { + m.Lock() + defer m.Unlock() + + return m.opts[name] +} + +func (m *Map) Argument(_ context.Context, name string) value.Value { + m.Lock() + defer m.Unlock() + + return m.args[name] +} + +func (m *Map) Bind(_ context.Context, _ *Definition) error { + return nil +} + +func (m *Map) LenArguments() int { + return len(m.args) +} + +func (m *Map) HasOption(name string) bool { + _, ok := m.opts[name] + + return ok +} + +func (m *Map) SetOption(name string, v interface{}) { + m.Lock() + defer m.Unlock() + + if m.opts == nil { + m.opts = make(map[string]value.Append) + } + + m.opts[name] = value.New(v) +} + +func (m *Map) HasArgument(name string) bool { + _, ok := m.args[name] + + return ok +} + +func (m *Map) SetArgument(name string, v interface{}) { + m.Lock() + defer m.Unlock() + + if m.args == nil { + m.args = make(map[string]value.Append) + } + + m.args[name] = value.New(v) +} + +func (m *Map) AppendOption(f flag.Flag, name, val string) error { + if _, ok := m.opts[name]; !ok { + m.SetOption(name, value.ByFlag(f)) + } + + return m.opts[name].Append(val) +} + +func (m *Map) AppendArgument(f flag.Flag, name, val string) error { + if _, ok := m.args[name]; !ok { + m.SetArgument(name, value.ByFlag(f)) + } + + return m.args[name].Append(val) +} diff --git a/input/option/option.go b/input/option/option.go index 9c66324..a4b659e 100644 --- a/input/option/option.go +++ b/input/option/option.go @@ -1,6 +1,7 @@ package option import ( + "gitoa.ru/go-4devs/console/input/errs" "gitoa.ru/go-4devs/console/input/value" "gitoa.ru/go-4devs/console/input/value/flag" ) @@ -88,13 +89,9 @@ func (o Option) IsRequired() bool { func (o Option) Validate(v value.Value) error { for _, valid := range o.Valid { if err := valid(v); err != nil { - return Error(o.Name, err) + return errs.Option(o.Name, err) } } return nil } - -func Error(name string, err error) error { - return err -} diff --git a/input/validator/not_blank_test.go b/input/validator/not_blank_test.go index 3b205a0..1aca789 100644 --- a/input/validator/not_blank_test.go +++ b/input/validator/not_blank_test.go @@ -99,7 +99,7 @@ func TestNotBlank(t *testing.T) { } if ca.empty == nil { - ca.empty = value.Empty + ca.empty = value.Empty() } if err := valid(ca.empty); err == nil || !errors.Is(err, validator.ErrNotBlank) { diff --git a/input/value/empty.go b/input/value/empty.go index b6735c9..f1fa4ee 100644 --- a/input/value/empty.go +++ b/input/value/empty.go @@ -6,11 +6,15 @@ import ( // nolint: gochecknoglobals var ( - Empty = &empty{} + emptyValue = &empty{} ) +func Empty() Value { + return emptyValue +} + func IsEmpty(v Value) bool { - return v == nil || v == Empty + return v == nil || v == emptyValue } type empty struct{}