...

Source file src/github.com/noirbizarre/gonja/exec/varargs.go

Documentation: github.com/noirbizarre/gonja/exec

     1  package exec
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  
     7  	"github.com/pkg/errors"
     8  )
     9  
    10  // VarArgs represents pythonic variadic args/kwargs
    11  type VarArgs struct {
    12  	Args   []*Value
    13  	KwArgs map[string]*Value
    14  }
    15  
    16  func NewVarArgs() *VarArgs {
    17  	return &VarArgs{
    18  		Args:   []*Value{},
    19  		KwArgs: map[string]*Value{},
    20  	}
    21  }
    22  
    23  // First returns the first argument or nil AsValue
    24  func (va *VarArgs) First() *Value {
    25  	if len(va.Args) > 0 {
    26  		return va.Args[0]
    27  	}
    28  	return AsValue(nil)
    29  }
    30  
    31  // GetKwarg gets a keyword arguments with fallback on default value
    32  func (va *VarArgs) GetKwarg(key string, fallback interface{}) *Value {
    33  	value, ok := va.KwArgs[key]
    34  	if ok {
    35  		return value
    36  	}
    37  	return AsValue(fallback)
    38  }
    39  
    40  type KwArg struct {
    41  	Name    string
    42  	Default interface{}
    43  }
    44  
    45  // Expect validates VarArgs against an expected signature
    46  func (va *VarArgs) Expect(args int, kwargs []*KwArg) *ReducedVarArgs {
    47  	rva := &ReducedVarArgs{VarArgs: va}
    48  	reduced := &VarArgs{
    49  		Args:   va.Args,
    50  		KwArgs: map[string]*Value{},
    51  	}
    52  	reduceIdx := -1
    53  	unexpectedArgs := []string{}
    54  	if len(va.Args) < args {
    55  		// Priority on missing arguments
    56  		if args > 1 {
    57  			rva.error = errors.Errorf(`Expected %d arguments, got %d`, args, len(va.Args))
    58  		} else {
    59  			rva.error = errors.Errorf(`Expected an argument, got %d`, len(va.Args))
    60  		}
    61  		return rva
    62  	} else if len(va.Args) > args {
    63  		reduced.Args = va.Args[:args]
    64  		for idx, arg := range va.Args[args:] {
    65  			if len(kwargs) > idx {
    66  				reduced.KwArgs[kwargs[idx].Name] = arg
    67  				reduceIdx = idx + 1
    68  			} else {
    69  				unexpectedArgs = append(unexpectedArgs, arg.String())
    70  			}
    71  		}
    72  	}
    73  
    74  	unexpectedKwArgs := []string{}
    75  Loop:
    76  	for key, value := range va.KwArgs {
    77  		for idx, kwarg := range kwargs {
    78  			if key == kwarg.Name {
    79  				if reduceIdx < 0 || idx >= reduceIdx {
    80  					reduced.KwArgs[key] = value
    81  					continue Loop
    82  				} else {
    83  					rva.error = errors.Errorf(`Keyword '%s' has been submitted twice`, key)
    84  					break Loop
    85  				}
    86  			}
    87  		}
    88  		kv := strings.Join([]string{key, value.String()}, "=")
    89  		unexpectedKwArgs = append(unexpectedKwArgs, kv)
    90  	}
    91  	sort.Strings(unexpectedKwArgs)
    92  
    93  	if rva.error != nil {
    94  		return rva
    95  	}
    96  
    97  	switch {
    98  	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 0:
    99  	case len(unexpectedArgs) == 1 && len(unexpectedKwArgs) == 0:
   100  		rva.error = errors.Errorf(`Unexpected argument '%s'`, unexpectedArgs[0])
   101  	case len(unexpectedArgs) > 1 && len(unexpectedKwArgs) == 0:
   102  		rva.error = errors.Errorf(`Unexpected arguments '%s'`, strings.Join(unexpectedArgs, ", "))
   103  	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) == 1:
   104  		rva.error = errors.Errorf(`Unexpected keyword argument '%s'`, unexpectedKwArgs[0])
   105  	case len(unexpectedArgs) == 0 && len(unexpectedKwArgs) > 0:
   106  		rva.error = errors.Errorf(`Unexpected keyword arguments '%s'`, strings.Join(unexpectedKwArgs, ", "))
   107  	default:
   108  		rva.error = errors.Errorf(`Unexpected arguments '%s, %s'`,
   109  			strings.Join(unexpectedArgs, ", "),
   110  			strings.Join(unexpectedKwArgs, ", "),
   111  		)
   112  	}
   113  
   114  	if rva.error != nil {
   115  		return rva
   116  	}
   117  	// fill defaults
   118  	for _, kwarg := range kwargs {
   119  		_, exists := reduced.KwArgs[kwarg.Name]
   120  		if !exists {
   121  			reduced.KwArgs[kwarg.Name] = AsValue(kwarg.Default)
   122  		}
   123  	}
   124  	rva.VarArgs = reduced
   125  	return rva
   126  }
   127  
   128  // ExpectArgs ensures VarArgs receive only arguments
   129  func (va *VarArgs) ExpectArgs(args int) *ReducedVarArgs {
   130  	return va.Expect(args, []*KwArg{})
   131  }
   132  
   133  // ExpectNothing ensures VarArgs does not receive any argument
   134  func (va *VarArgs) ExpectNothing() *ReducedVarArgs {
   135  	return va.ExpectArgs(0)
   136  }
   137  
   138  // ExpectKwArgs allow to specify optionnaly expected KwArgs
   139  func (va *VarArgs) ExpectKwArgs(kwargs []*KwArg) *ReducedVarArgs {
   140  	return va.Expect(0, kwargs)
   141  }
   142  
   143  // ReducedVarArgs represents pythonic variadic args/kwargs
   144  // but values are reduced (ie. kwargs given as args are accessible by name)
   145  type ReducedVarArgs struct {
   146  	*VarArgs
   147  	error error
   148  }
   149  
   150  // IsError returns true if there was an error on Expect call
   151  func (rva *ReducedVarArgs) IsError() bool {
   152  	return rva.error != nil
   153  }
   154  
   155  func (rva *ReducedVarArgs) Error() string {
   156  	if rva.IsError() {
   157  		return rva.error.Error()
   158  	}
   159  	return ""
   160  }
   161  

View as plain text