psetter

package
v5.19.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 3, 2023 License: MIT Imports: 12 Imported by: 5

Documentation

Overview

Package psetter contains a collection of useful types that can be used to set parameter values of a program.

Each type satisfies the param.Setter interface. These can be used to supply the second argument of a PSet Add or AddByPos method - the action associated with the parameter. When the parameter is found while parsing the params the appropriate Set method will be called.

A typical Setter is used to set the value of a parameter to the program. For example below, a bool variable

exitOnErrors

is set to true by the Bool object's Set method if the parameter

exit-on-error

is found among the command line arguments:

var exitOnErrors bool
ps, err := paramset.New()
p := ps.Add("exit-on-errors",
    psetter.Bool{Value: &exitOnErrors},
    "Errors make the program exit if this flag is set to true")

It is expected that the most common use of this package will be to pass instances of the various setters as a parameter to the Add(...) method.

Index

Examples

Constants

View Source
const (
	TimeFmtDefault   = "2006/Jan/02T15:04:05"
	TimeFmtHMS       = "15:04:05"
	TimeFmtHoursMins = "15:04"
	TimeFmtDateOnly  = "2006/Jan/02"
	TimeFmtTimestamp = "20060102.150405"
	TimeFmtISO8601   = "2006-01-02T15:04:05"
)

Time Formats given here can be used to set the Format member of the Time struct

View Source
const (
	StrListDefaultSep = ","
)

StrListDefaultSep is the default separator for a list of strings. it is set to a comma

Variables

This section is empty.

Functions

func HasChecks

func HasChecks(cc CheckCounter) string

HasChecks returns a string reporting whether or not the number of checks is zero. This is suitable for constructing a string to be returned by an AllowedValues function.

func NilValueMessage

func NilValueMessage(paramName, setterType string) string

NilValueMessage returns a standard message documenting that a Value is nil. This is used by the psetter CheckSetter methods and should be used to report nil Value fields by any implementation of the CheckSetter method so as to provide a consistent user experience.

Types

type Aliases

type Aliases map[string][]string

Aliases - this maps strings to lists of strings. It is expected that the keys are not in the set of allowed values and the entries in the associated value are allowed.

It can be used as a mixin type that can be embedded in a Setter to provide alternative names for allowed values or to provide several names in one.

It is recommended that you should use string constants for setting the aliases and the entries in the slice of values they correspond to. This will avoid possible errors.

The advantages of const values are:

- typos become compilation errors rather than silently failing.

- the name of the constant value can distinguish between the string value and it's meaning as a semantic element representing a flag used to choose program behaviour.

- the name that you give the const value can distinguish between identical strings and show which of various flags with the same string value you actually mean.

func (Aliases) AliasVal

func (a Aliases) AliasVal(name string) []string

AliasVal returns a copy of the value of the alias

func (Aliases) AllowedValuesAliasMap

func (a Aliases) AllowedValuesAliasMap() Aliases

AllowedValuesAliasMap returns a copy of the map of aliases. This will be used by the standard help package to generate a list of allowed values.

func (Aliases) Check

func (a Aliases) Check(av AllowedVals) error

Check returns a nil error if the map is "good" or an error with an explanation of the problem otherwise.

A map is "good" if each key does not exist in the AllowedVals but each entry in the associated list is in the AllowedVals. Also, an empty alias is not allowed.

func (Aliases) IsAnAlias

func (a Aliases) IsAnAlias(val string) bool

IsAnAlias returns true if the passed value is a key in the aliases map

func (Aliases) Keys

func (a Aliases) Keys() ([]string, int)

Keys returns an unsorted list of keys to the Aliases map and the length of the longest key.

func (Aliases) String

func (a Aliases) String() string

String returns a string documenting the entries in the map - each entry is on a separate line

type AllowedVals

type AllowedVals map[string]string

AllowedVals - this maps allowed values for an enumerated parameter to explanatory text. It forms part of the usage documentation of the program. It is also used to validate a supplied parameter.

It can be used as a mixin type that can be embedded in a Setter to provide a restricted set of allowed values.

It is recommended that you should use string constants for setting the map entries.

The advantages of const values are:

- typos become compilation errors rather than silently failing.

- the name of the constant value can distinguish between the string value and it's meaning as a semantic element representing a flag used to choose program behaviour.

- the name that you give the const value can distinguish between identical strings and show which of various flags with the same string value you actually mean.

func (AllowedVals) AllowedValuesMap

func (av AllowedVals) AllowedValuesMap() AllowedVals

AllowedValuesMap returns a copy of the map of allowed values. This will be used by the standard help package to generate a list of allowed values.

func (AllowedVals) Check

func (av AllowedVals) Check() error

Check returns a nil error if the map is "good" or an error with an explanation of the problem otherwise.

A map is "good" if it has more than one entry. A set of allowed values with one or fewer entries is obviously a mistake: if no entries are valid then the parameter can never be set correctly and if it only has a single entry then the current (initial) value is the only allowed value and so there is no need for a parameter as no alternative can ever be allowed.

func (AllowedVals) Keys

func (av AllowedVals) Keys() ([]string, int)

Keys returns an unsorted list of keys to the AllowedVals map and the length of the longest key.

func (AllowedVals) String

func (av AllowedVals) String() string

String returns a string documenting the entries in the map - each entry is on a separate line

func (AllowedVals) ValueAllowed

func (av AllowedVals) ValueAllowed(val string) bool

ValueAllowed returns true if the passed value is a key in the allowed values map

type AllowedValuesAliasMapper

type AllowedValuesAliasMapper interface {
	AllowedValuesAliasMap() Aliases
}

AllowedValuesAliasMapper is the interface to be satisfied by a type having aliases

type AllowedValuesMapper

type AllowedValuesMapper interface {
	AllowedValuesMap() AllowedVals
}

AllowedValuesMapper is the interface to be satisfied by a type having a map of allowed values.

type Bool

type Bool struct {
	ValueReqOptional

	// Value must be set, the program will panic if not. This is the boolean
	// that the setter is setting.
	Value *bool

	// Invert reverses the normal meaning of the boolean parameter so that
	// the Value will be set to false when no value is given or the negation
	// of the given value when one is given.
	Invert bool
}

Bool is used to set boolean flags

The Invert flag is used to invert the normal meaning of a boolean parameter. It is useful where you want to have a parameter of the form 'dont-xxx' but use it to set the value of a bool variable (default value: true) such as 'xxx' which you can then test by saying:

if xxx { doXXX() }

rather than having to set the value of a variable which you would have to call dontXXX and then test by saying:

if !dontXXX { doXXX() }

The benefit is that you can avoid the ugly (and error prone) double negative.

Example (Inverted)

ExampleBool_inverted demonstrates the use of a Bool setter with the Invert flag set to true. The standard behaviour will set the value to true when no explicit value is given but with this flag set the value is set to false. Any value given is inverted. This is useful for turning off some default behaviour rather than turning it on as the standard action of this setter would do.

ps := newPSetForTesting() // use paramset.NewOrPanic()

p1 := true

ps.Add("dont-do-this", psetter.Bool{Value: &p1, Invert: true}, "help text")

fmt.Printf("Before parsing    p1: %v\n", p1)
ps.Parse([]string{"-dont-do-this"})
fmt.Printf("After  parsing    p1: %v\n", p1)
Output:

Before parsing    p1: true
After  parsing    p1: false
Example (Standard)

ExampleBool_standard demonstrates the use of a Bool setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var p1 bool

ps.Add("do-this", psetter.Bool{Value: &p1}, "help text")

fmt.Printf("Before parsing    p1: %v\n", p1)
ps.Parse([]string{"-do-this"})
fmt.Printf("After  parsing    p1: %v\n", p1)
Output:

Before parsing    p1: false
After  parsing    p1: true
Example (WithBadValue)

ExampleBool_withBadValue demonstrates the use of a Bool setter showing the behaviour when an argument is supplied that cannot be translated into a bool value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

p1 := true

ps.Add("do-this", psetter.Bool{Value: &p1}, "help text")

fmt.Printf("Before parsing    p1: %v\n", p1)
// Parse the arguments. Note that the value after the '=' cannot be
// translated into a bool value.
errMap := ps.Parse([]string{"-do-this=blah"})
// We expect to see an error reported.
logErrs(errMap)
// There was an error with the parameter so the value will be unchanged
fmt.Printf("After  parsing    p1: %v\n", p1)
Output:

Before parsing    p1: true
Errors for: do-this
	: cannot interpret 'blah' as either true or false
At: [command line]: Supplied Parameter:1: "-do-this=blah"
After  parsing    p1: true
Example (WithNilValue)

ExampleBool_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the bool Value has not been initialised
ps.Add("do-this", psetter.Bool{}, "help text")
Output:

panic
do-this: psetter.Bool Check failed: the Value to be set is nil
Example (WithValue)

ExampleBool_withValue demonstrates the use of a Bool setter showing how the value of the flag can be set to an explicit value by passing the value required after the parameter (following an "=").

ps := newPSetForTesting() // use paramset.NewOrPanic()

p1 := true

ps.Add("do-this", psetter.Bool{Value: &p1}, "help text")

fmt.Printf("Before parsing    p1: %v\n", p1)
ps.Parse([]string{"-do-this=false"})
fmt.Printf("After  parsing    p1: %v\n", p1)
Output:

Before parsing    p1: true
After  parsing    p1: false

func (Bool) AllowedValues

func (s Bool) AllowedValues() string

AllowedValues returns a description of the allowed values.

func (Bool) CheckSetter

func (s Bool) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil

func (Bool) CurrentValue

func (s Bool) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Bool) Set

func (s Bool) Set(_ string) error

Set sets the parameter value to true

func (Bool) SetWithVal

func (s Bool) SetWithVal(_, val string) error

SetWithVal should be called when a value is given for the parameter

type CheckCounter

type CheckCounter interface {
	CountChecks() int
}

CheckCounter can be used if you want to report the number of checks that a type has

type Duration

type Duration struct {
	ValueReqMandatory

	// Value must be set, the program will panic if not. This is the
	// time.Duration that the setter is setting.
	Value *time.Duration
	// The Checks, if any, are applied to the new Duration and the Value will
	// only be updated if they all return a nil error.
	Checks []check.Duration
}

Duration allows you to specify a parameter that can be used to set a time.Duration value. You can also supply check functions that will validate the Value. See the check package for some common pre-defined checks.

Example (Basic)

ExampleDuration_basic demonstrates the use of a Duration setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var v time.Duration

ps.Add("how-long", psetter.Duration{Value: &v}, "help text")

fmt.Printf("Before parsing    v: %v\n", v)
ps.Parse([]string{"-how-long", "1h"})
fmt.Printf("After  parsing    v: %v\n", v)
Output:

Before parsing    v: 0s
After  parsing    v: 1h0m0s
Example (WithFailingChecks)

ExampleDuration_withFailingChecks demonstrates how to specify additional checks for a Duration value and shows the error that you can expect to see if a value is supplied which fails any of the checks. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var v time.Duration

ps.Add("how-long",
	psetter.Duration{
		Value: &v,
		Checks: []check.Duration{
			check.ValGT[time.Duration](2 * time.Hour),
		},
	},
	"help text")

fmt.Printf("Before parsing    v: %v\n", v)
// Parse the arguments. Note that the duration given (1 hour) is less
// than the minimum value given by the check function.
errMap := ps.Parse([]string{"-how-long", "1h"})
// The check will fail so we expect to see errors reported
logErrs(errMap)
// There was an error with the parameter so the value will be unchanged
fmt.Printf("After  parsing    v: %v\n", v)
Output:

Before parsing    v: 0s
Errors for: how-long
	: the value (1h0m0s) must be greater than 2h0m0s
At: [command line]: Supplied Parameter:2: "-how-long" "1h"
After  parsing    v: 0s
Example (WithNilValue)

ExampleDuration_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the Duration Value has not been
// initialised
ps.Add("how-long", psetter.Duration{}, "help text")
Output:

panic
how-long: psetter.Duration Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleDuration_withPassingChecks demonstrates how to specify additional checks for a Duration value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var v time.Duration

ps.Add("how-long",
	psetter.Duration{
		Value: &v,
		Checks: []check.Duration{
			check.ValBetween[time.Duration](time.Duration(0), 2*time.Hour),
		},
	},
	"help text")

fmt.Printf("Before parsing    v: %v\n", v)
ps.Parse([]string{"-how-long", "1h"})
fmt.Printf("After  parsing    v: %v\n", v)
Output:

Before parsing    v: 0s
After  parsing    v: 1h0m0s

func (Duration) AllowedValues

func (s Duration) AllowedValues() string

AllowedValues returns a string describing the allowed values.

func (Duration) CheckSetter

func (s Duration) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Duration) CountChecks

func (s Duration) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Duration) CurrentValue

func (s Duration) CurrentValue() string

CurrentValue returns the current setting of the parameter value.

func (Duration) SetWithVal

func (s Duration) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to a duration, if it cannot be parsed successfully it returns an error. If there is a check and the check is violated it returns an error. Only if the value is parsed successfully and the checks are not violated is the Value set.

type Editor

type Editor interface {
	Edit(string, string) (string, error)
}

Editor defines an interface providing an Edit function. This is used to edit a parameter value before setting the value. The expected use by the Setter is for the Setter to pass the parameter name as the first value, the parameter value as the second and for Edit to return the modified value. It is expected that the Setter will check the error value and if it is not nil it will return it and abort the setting of the value.

type Enum

type Enum struct {
	ValueReqMandatory
	// The AllowedVals must be set, the program will panic if not. The Value
	// is guaranteed to take one of these values.
	AllowedVals
	// Value must be set, the program will panic if not. This is the value
	// being set
	Value *string
	// AllowInvalidInitialValue can be set to relax the checks on the initial
	// Value. It can be set to allow, for instance, an empty initial value to
	// signify that no choice has yet been made.
	AllowInvalidInitialValue bool
}

Enum allows you to give a parameter that will only allow one of an enumerated range of values which are specified in the AllowedVals map.

It is recommended that you should use string constants for setting the value and for initialising the allowed values map to avoid possible errors.

The advantages of const values are:

- typos become compilation errors rather than silently failing.

- the name of the constant value can distinguish between the string value and it's meaning as a semantic element representing a flag used to choose program behaviour.

- the name that you give the const value can distinguish between identical strings and show which of various flags with the same string value you actually mean.

Example (Standard)

ExampleEnum_standard demonstrates the use of an Enum setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

s := XOption

ps.Add("my-string",
	psetter.Enum{
		Value: &s,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\ts = %s\n", s)

ps.Parse([]string{"-my-string", "y"})

fmt.Println("After  parsing")
fmt.Printf("\ts = %s\n", s)
Output:

Before parsing
	s = x
After  parsing
	s = y
Example (WithBadInitialValue)

ExampleEnum_withBadInitialValue demonstrates the behaviour of the package when the initial value is invalid (not in the list of allowed values). Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

s := "z"

// we expect this to panic because the Value has an invalid initial value
ps.Add("my-string",
	psetter.Enum{
		Value: &s,
		AllowedVals: psetter.AllowedVals{ // Note there's no 'z' value
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")
Output:

panic
my-string: psetter.Enum Check failed: the initial value (z) is not valid
Example (WithBadVal)

ExampleEnum_withBadVal demonstrates the behaviour when a value not given in the AllowedValues is passed as a parameter. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

s := XOption

ps.Add("my-string",
	psetter.Enum{
		Value: &s,
		AllowedVals: psetter.AllowedVals{ // Note there's no 'z' value
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\ts = %s\n", s)

// Parse the arguments. We supply a value but note that it is not in the
// list of allowed values.
errMap := ps.Parse([]string{"-my-string", "z"})

// We expect to see an error reported.
logErrs(errMap)

// The value is unchanged due to the error.
fmt.Println("After  parsing")
fmt.Printf("\ts = %s\n", s)
Output:

Before parsing
	s = x
Errors for: my-string
	: value not allowed: "z"
At: [command line]: Supplied Parameter:2: "-my-string" "z"
After  parsing
	s = x
Example (WithNilValue)

ExampleEnum_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

// we expect this to panic because the Value has not been initialised
ps.Add("my-string",
	psetter.Enum{
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")
Output:

panic
my-string: psetter.Enum Check failed: the Value to be set is nil

func (Enum) AllowedValues

func (s Enum) AllowedValues() string

AllowedValues returns a string listing the allowed values

func (Enum) CheckSetter

func (s Enum) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil or there are no allowed values.

func (Enum) CurrentValue

func (s Enum) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Enum) SetWithVal

func (s Enum) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks the value for validity and only if it is in the allowed values list does it set the Value. It returns an error if the value is invalid.

func (Enum) ValDescribe added in v5.9.0

func (s Enum) ValDescribe() string

ValDescribe returns a brief description of the allowed values suitable for appearing after the parameter name. Note that the full list of values is truncated if it gets too long.

type EnumList

type EnumList struct {
	ValueReqMandatory
	// The AllowedVals must be set, the program will panic if not. These are
	// the only values that will be allowed in the slice of strings.
	AllowedVals

	// The Aliases need not be given but if they are then each alias must not
	// be in AllowedVals and all of the resulting values must be in
	// AllowedVals.
	Aliases

	// Value must be set, the program will panic if not. This is the slice of
	// values that this setter is setting.
	Value *[]string
	// The StrListSeparator allows you to override the default separator
	// between list elements.
	StrListSeparator
	// The Checks, if any, are applied to the list of new values and the
	// Value will only be updated if they all return a nil error.
	Checks []check.StringSlice
}

EnumList sets the values in a slice of strings. The values must be in the allowed values map.

It is recommended that you should use string constants for setting the list entries and for initialising the allowed values map to avoid possible errors.

The advantages of const values are:

- typos become compilation errors rather than silently failing.

- the name of the constant value can distinguish between the string value and it's meaning as a semantic element representing a flag used to choose program behaviour.

- the name that you give the const value can distinguish between identical strings and show which of various flags with the same string value you actually mean.

Example (Standard)

ExampleEnumList_standard demonstrates the use of an EnumList setter

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

var ss []string

ps.Add("my-list",
	psetter.EnumList{
		Value: &ss,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}

ps.Parse([]string{"-my-list", "x,y"})

fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
After  parsing
	ss[0] = "x"
	ss[1] = "y"
Example (WithBadVals)

ExampleEnumList_withBadVals demonstrates the behaviour when a value not given in the AllowedValues is passed. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

var ss []string

ps.Add("my-list",
	psetter.EnumList{
		Value: &ss,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}

// Parse the arguments. We supply a list of strings but note that one of
// them is not in the list of allowed values.
errMap := ps.Parse([]string{"-my-list", "x,z"})

// We expect to see an error reported.
logErrs(errMap)

// The slice of strings is unchanged due to the error.
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
Errors for: my-list
	: value is not allowed: "z"
At: [command line]: Supplied Parameter:2: "-my-list" "x,z"
After  parsing
Example (WithFailingChecks)

ExampleEnumList_withFailingChecks demonstrates the behaviour of the package when an invalid value is given. In this case the resulting list is not of the required length. It demonstrates the checks that can be supplied to ensure that the resulting list is as expected. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

var ss []string

ps.Add("my-list",
	psetter.EnumList{
		Value: &ss,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
		Checks: []check.StringSlice{
			check.SliceLength[[]string](check.ValEQ(2)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}

// Parse the arguments. We supply a list of strings, each of which is
// allowed. The resulting slice is of the wrong length.
errMap := ps.Parse([]string{"-my-list", "x"})

// We expect to see an error reported.
logErrs(errMap)

// The slice of strings is unchanged due to the error.
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
Errors for: my-list
	: the length of the list (1) is incorrect: the value (1) must equal 2
At: [command line]: Supplied Parameter:2: "-my-list" "x"
After  parsing
Example (WithNilValue)

ExampleEnumList_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

// we expect this to panic because the list Value has not been initialised
ps.Add("my-list",
	psetter.EnumList{
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")
Output:

panic
my-list: psetter.EnumList Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleEnumList_withPassingChecks demonstrates how you can specify additional checks to be applied to the passed arguments before the value is set.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

var ss []string

ps.Add("my-list",
	psetter.EnumList{
		Value: &ss,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
		Checks: []check.StringSlice{
			check.SliceLength[[]string](check.ValEQ(2)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}

ps.Parse([]string{"-my-list", "x,y"})

fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
After  parsing
	ss[0] = "x"
	ss[1] = "y"

func (EnumList) AllowedValues

func (s EnumList) AllowedValues() string

AllowedValues returns a string listing the allowed values

func (EnumList) CheckSetter

func (s EnumList) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil or there are no allowed values or the initial value is not allowed.

func (EnumList) CountChecks

func (s EnumList) CountChecks() int

CountChecks returns the number of check functions this setter has

func (EnumList) CurrentValue

func (s EnumList) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (EnumList) SetWithVal

func (s EnumList) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) splits the value using the list separator. It then checks all the values for validity and only if all the values are in the allowed values list does it add them to the slice of strings pointed to by the Value. It returns a error for the first invalid value or if a check is breached.

type EnumMap

type EnumMap struct {
	ValueReqMandatory
	// The AllowedVals must be set, the program will panic if not. These are
	// the allowed keys in the Values map
	AllowedVals

	// The Aliases need not be given but if they are then each alias must not
	// be in AllowedVals and all of the resulting values must be in
	// AllowedVals.
	Aliases

	// Value must be set, the program will panic if not. This is the map of
	// values that this setter is setting
	Value *map[string]bool
	// AllowHiddenMapEntries can be set to relax the checks on the initial
	// entries in the Values map
	AllowHiddenMapEntries bool
	// The StrListSeparator allows you to override the default separator
	// between list elements.
	StrListSeparator
}

EnumMap sets the entry in a map of strings. The values initially set in the map must be in the allowed values map unless AllowHiddenMapEntries is set to true. Only values with keys in the allowed values map can be set. If you allow hidden values then you can have entries in your map which cannot be set through this interface but this will still only allow values to be set which are in the allowed values map.

It is recommended that you should use string constants for setting and accessing the map entries and for initialising the allowed values map to avoid possible errors.

The advantages of const values are:

- typos become compilation errors rather than silently failing.

- the name of the constant value can distinguish between the string value and it's meaning as a semantic element representing a flag used to choose program behaviour.

- the name that you give the const value can distinguish between identical strings and show which of various flags with the same string value you actually mean.

Example (FixingInitialValue)

ExampleEnumMap_fixingInitialValue demonstrates how an initial value may be changed through the command line. That is, it is possible to change the value of a map entry to false as well as to true.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

m := map[string]bool{"x": true}
keys := []string{XOption, YOption}

ps.Add("my-map",
	psetter.EnumMap{
		Value: &m,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}

ps.Parse([]string{"-my-map", "x=false,y"})

fmt.Println("After  parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
Output:

Before parsing
	m[x] = true
After  parsing
	m[x] = false
	m[y] = true
Example (HiddenMapEntries)

ExampleEnumMap_hiddenMapEntries demonstrates the behaviour of the package when the AllowHiddenMapEntries flag is set. In this case the Value to be set has an entry with a key not in the allowed values but no error is reported. Note that it is not possible to set such a map value as the key will be rejected as invalid.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

m := map[string]bool{"z": true}
keys := []string{XOption, YOption, "z"}

ps.Add("my-map",
	psetter.EnumMap{
		Value: &m,
		AllowedVals: psetter.AllowedVals{ // Note there's no 'z' value
			XOption: "a description of this option",
			YOption: "what this option means",
		},

		// Setting AllowHiddenMapEntries to true prevents the 'z' entry
		// causing an error
		AllowHiddenMapEntries: true,
	}, "help text")

fmt.Println("Before parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}

ps.Parse([]string{"-my-map", "y"})

fmt.Println("After  parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
Output:

Before parsing
	m[z] = true
After  parsing
	m[y] = true
	m[z] = true
Example (Standard)

ExampleEnumMap_standard demonstrates the use of an EnumMap setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

var m map[string]bool
keys := []string{XOption, YOption}

ps.Add("my-map",
	psetter.EnumMap{
		Value: &m,
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")

fmt.Println("Before parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}

ps.Parse([]string{"-my-map", "x"})

fmt.Println("After  parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
Output:

Before parsing
After  parsing
	m[x] = true
Example (WithBadKey)

ExampleEnumMap_withBadKey demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has an entry with a key not in the allowed values. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

m := map[string]bool{"z": true}

// we expect this to panic because the map has an entry which is not in
// the allowed values
ps.Add("my-map",
	psetter.EnumMap{
		Value: &m,
		AllowedVals: psetter.AllowedVals{ // Note there's no 'z' value
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")
Output:

panic
my-map: psetter.EnumMap Check failed: the map entry with key "z" is invalid - it is not in the allowed values map
Example (WithNilValue)

ExampleEnumMap_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

const (
	XOption = "x"
	YOption = "y"
)

// we expect this to panic because the map Value has not been initialised
ps.Add("my-map",
	psetter.EnumMap{
		AllowedVals: psetter.AllowedVals{
			XOption: "a description of this option",
			YOption: "what this option means",
		},
	}, "help text")
Output:

panic
my-map: psetter.EnumMap Check failed: the Value to be set is nil

func (EnumMap) AllowedValues

func (s EnumMap) AllowedValues() string

AllowedValues returns a string listing the allowed values

func (EnumMap) CheckSetter

func (s EnumMap) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil or the map has not been created yet or if there are no allowed values.

func (EnumMap) CurrentValue

func (s EnumMap) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (EnumMap) SetWithVal

func (s EnumMap) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) splits the value using the list separator. It then checks all the values for validity and only if all the values are in the allowed values list does it set the entries in the map of strings pointed to by the Value. It returns a error for the first invalid value.

func (EnumMap) ValDescribe added in v5.12.0

func (s EnumMap) ValDescribe() string

ValDescribe returns a brief description of the allowed values suitable for appearing after the parameter name. Note that the full list of values is truncated if it gets too long.

type Float64

type Float64 struct {
	ValueReqMandatory

	// Value must be set, the program will panic if not. This is the value
	// being set
	Value *float64
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error
	Checks []check.Float64
}

Float64 allows you to give a parameter that can be used to set a float64 value.

Example (Standard)

ExampleFloat64_standard demonstrates the use of a Float64 setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var f float64

ps.Add("my-float",
	psetter.Float64{
		Value: &f,
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\tf = %5.3f\n", f)
ps.Parse([]string{"-my-float", "1.23"})
fmt.Println("After  parsing")
fmt.Printf("\tf = %5.3f\n", f)
Output:

Before parsing
	f = 0.000
After  parsing
	f = 1.230
Example (WithFailingChecks)

ExampleFloat64_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var f float64

ps.Add("my-float",
	psetter.Float64{
		Value: &f,
		Checks: []check.Float64{
			check.ValGT[float64](5.0),
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\tf = %5.3f\n", f)
// Parse the arguments. We supply a float value but note that it does not
// satisfy the check for this parameter.
errMap := ps.Parse([]string{"-my-float", "1.23"})
// We expect to see an error reported.
logErrs(errMap)
// The float value is unchanged due to the error.
fmt.Println("After  parsing")
fmt.Printf("\tf = %5.3f\n", f)
Output:

Before parsing
	f = 0.000
Errors for: my-float
	: the value (1.23) must be greater than 5
At: [command line]: Supplied Parameter:2: "-my-float" "1.23"
After  parsing
	f = 0.000
Example (WithNilValue)

ExampleFloat64_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the map Value has not been initialised
ps.Add("my-float", psetter.Float64{}, "help text")
Output:

panic
my-float: psetter.Float64 Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleFloat64_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var f float64

ps.Add("my-float",
	psetter.Float64{
		Value: &f,
		Checks: []check.Float64{
			check.ValGT[float64](5.0),
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\tf = %5.3f\n", f)
ps.Parse([]string{"-my-float", "6.23"})
fmt.Println("After  parsing")
fmt.Printf("\tf = %5.3f\n", f)
Output:

Before parsing
	f = 0.000
After  parsing
	f = 6.230

func (Float64) AllowedValues

func (s Float64) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (Float64) CheckSetter

func (s Float64) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Float64) CountChecks

func (s Float64) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Float64) CurrentValue

func (s Float64) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Float64) SetWithVal

func (s Float64) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to a float, if it cannot be parsed successfully it returns an error. The Checks, if any, are called with the value to be applied and if any of them return a non-nil error the Value is not updated and the error is returned. Only if the parameter value is parsed successfully and no checks fail is the Value set.

type Int64

type Int64 struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is a pointer
	// to the int64 value that the setter is setting.
	Value *int64
	// The Checks, if any, are applied to the supplied parameter value and
	// the Value will only be update if they all return a nil error.
	Checks []check.Int64
}

Int64 allows you to give a parameter that can be used to set an int64 value.

Example (Standard)

ExampleInt64_standard demonstrates the use of a Int64 setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var i int64

ps.Add("my-int",
	psetter.Int64{
		Value: &i,
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\ti = %d\n", i)
ps.Parse([]string{"-my-int", "1"})
fmt.Println("After  parsing")
fmt.Printf("\ti = %d\n", i)
Output:

Before parsing
	i = 0
After  parsing
	i = 1
Example (WithFailingChecks)

ExampleInt64_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var i int64

ps.Add("my-int",
	psetter.Int64{
		Value: &i,
		Checks: []check.Int64{
			check.ValGT[int64](5),
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\ti = %d\n", i)
// Parse the arguments. We supply a int value but note that it does not
// satisfy the check for this parameter.
errMap := ps.Parse([]string{"-my-int", "1"})
// We expect to see an error reported.
logErrs(errMap)
// The int value is unchanged due to the error.
fmt.Println("After  parsing")
fmt.Printf("\ti = %d\n", i)
Output:

Before parsing
	i = 0
Errors for: my-int
	: the value (1) must be greater than 5
At: [command line]: Supplied Parameter:2: "-my-int" "1"
After  parsing
	i = 0
Example (WithNilValue)

ExampleInt64_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the map Value has not been initialised
ps.Add("my-int", psetter.Int64{}, "help text")
Output:

panic
my-int: psetter.Int64 Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleInt64_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var i int64

ps.Add("my-int",
	psetter.Int64{
		Value: &i,
		Checks: []check.Int64{
			check.ValGT[int64](5),
		},
	}, "help text")

fmt.Println("Before parsing")
fmt.Printf("\ti = %d\n", i)
ps.Parse([]string{"-my-int", "6"})
fmt.Println("After  parsing")
fmt.Printf("\ti = %d\n", i)
Output:

Before parsing
	i = 0
After  parsing
	i = 6

func (Int64) AllowedValues

func (s Int64) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (Int64) CheckSetter

func (s Int64) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Int64) CountChecks

func (s Int64) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Int64) CurrentValue

func (s Int64) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Int64) SetWithVal

func (s Int64) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to an integer, if it cannot be parsed successfully it returns an error. If there are checks and any check is violated it returns an error. Only if the value is parsed successfully and no checks are violated is the Value set.

type Int64List

type Int64List struct {
	ValueReqMandatory

	// Value must be set, the program will panic if not. This is the slice of
	// int64's that the setter is setting.
	Value *[]int64
	// The StrListSeparator allows you to override the default separator
	// between list elements.
	StrListSeparator
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error
	Checks []check.Int64Slice
}

Int64List allows you to give a parameter that can be used to set a list (a slice) of int64's.

Example (Standard)

ExampleInt64List_standard demonstrates the use of a Int64List setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

il := []int64{42}

ps.Add("my-ints",
	psetter.Int64List{
		Value: &il,
	}, "help text")

fmt.Println("Before parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
ps.Parse([]string{"-my-ints", "1,23"})
fmt.Println("After  parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
Output:

Before parsing
	il[0] = 42
After  parsing
	il[0] = 1
	il[1] = 23
Example (WithFailingChecks)

ExampleInt64List_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

il := []int64{42}

ps.Add("my-ints",
	psetter.Int64List{
		Value: &il,
		Checks: []check.Int64Slice{
			check.SliceAll[[]int64, int64](check.ValGT[int64](5)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
// Parse the arguments. We supply a float value but note that it does not
// satisfy the check for this parameter.
errMap := ps.Parse([]string{"-my-ints", "1,23"})
// We expect to see an error reported.
logErrs(errMap)
// The float value is unchanged due to the error.
fmt.Println("After  parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
Output:

Before parsing
	il[0] = 42
Errors for: my-ints
	: list entry: 0 (1) does not pass the test: the value (1) must be greater than 5
At: [command line]: Supplied Parameter:2: "-my-ints" "1,23"
After  parsing
	il[0] = 42
Example (WithNilValue)

ExampleInt64List_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the map Value has not been initialised
ps.Add("my-ints", psetter.Int64List{}, "help text")
Output:

panic
my-ints: psetter.Int64List Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleInt64List_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

il := []int64{42}

ps.Add("my-ints",
	psetter.Int64List{
		Value: &il,
		Checks: []check.Int64Slice{
			check.SliceAll[[]int64, int64](check.ValGT[int64](5)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
ps.Parse([]string{"-my-ints", "6,23"})
fmt.Println("After  parsing")
for i, v := range il {
	fmt.Printf("\til[%d] = %d\n", i, v)
}
Output:

Before parsing
	il[0] = 42
After  parsing
	il[0] = 6
	il[1] = 23

func (Int64List) AllowedValues

func (s Int64List) AllowedValues() string

AllowedValues returns a description of the allowed values. It includes the separator to be used

func (Int64List) CheckSetter

func (s Int64List) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Int64List) CountChecks

func (s Int64List) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Int64List) CurrentValue

func (s Int64List) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Int64List) SetWithVal

func (s Int64List) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) splits the value into a slice of int64's and sets the Value accordingly. The Checks, if any, are run against the new list of int64's and if any Check returns a non-nil error the Value is not updated and the error is returned.

type Map

type Map struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the map
	// of strings to bool that the setter is setting
	Value *map[string]bool
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error
	Checks []check.MapStringBool
	// The Editor, if present, is applied to the parameter value after any
	// checks are applied and allows the programmer to modify the value
	// supplied before using it to set the Value.
	Editor Editor
	// The StrListSeparator allows you to override the default separator
	// between list elements.
	StrListSeparator
}

Map sets the entry in a map of strings. Each value from the parameter is used as a key in the map with the map entry set to true.

Example (FixingInitialValue)

ExampleMap_fixingInitialValue demonstrates how an initial value may be changed through the command line. That is, it is possible to change the value of a map entry to false as well as to true.

ps := newPSetForTesting() // use paramset.NewOrPanic()

m := map[string]bool{"x": true}
keys := []string{"x", "y"}

ps.Add("my-map", psetter.Map{Value: &m}, "help text")

fmt.Println("Before parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
ps.Parse([]string{"-my-map", "x=false,y"})
fmt.Println("After  parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
Output:

Before parsing
	m[x] = true
After  parsing
	m[x] = false
	m[y] = true
Example (Standard)

ExampleMap_standard demonstrates the use of an Map setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var m map[string]bool
keys := []string{"x", "y"}

ps.Add("my-map", psetter.Map{Value: &m}, "help text")

fmt.Println("Before parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
ps.Parse([]string{"-my-map", "x"})
fmt.Println("After  parsing")
for _, k := range keys {
	if v, ok := m[k]; ok {
		fmt.Printf("\tm[%s] = %v\n", k, v)
	}
}
Output:

Before parsing
After  parsing
	m[x] = true
Example (WithNilValue)

ExampleMap_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the map Value has not been initialised
ps.Add("my-map", psetter.Map{}, "help text")
Output:

panic
my-map: psetter.Map Check failed: the Value to be set is nil

func (Map) AllowedValues

func (s Map) AllowedValues() string

AllowedValues returns a string listing the allowed values

func (Map) CheckSetter

func (s Map) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil or the map has not been created yet.

func (Map) CountChecks

func (s Map) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Map) CurrentValue

func (s Map) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Map) SetWithVal

func (s Map) SetWithVal(paramName string, paramVal string) error

SetWithVal (called when a value follows the parameter) splits the value using the list separator. For each of these values it will try to split it into two parts around an '='. The first part has the Editor (if any) applied to it and the name is replaced with the edited value. If the Editor returns a non-nil error then that is returned and the value is unchanged. If there is only one part the named map entry is set to true, otherwise it will try to parse the second part as a bool. If it can be so parsed then the named map entry will be set to that value, otherwise it will return the parsing error. It will run the checks (if any) against the map and if any check returns a non-nil error that is returned. Finally it will update the Value with the new entries.

Note that the Value map is not replaced compmletely, just updated.

type Nil

type Nil struct {
	ValueReqNone
}

Nil is used if no value is to be set. It can be useful if the only effect is to be through the PostAction.

Example (Standard)

ExampleNil_standard demonstrates how you might use a Nil setter. Note that the Nil setter does nothing itself; any effect takes place through associated action functions

ps := newPSetForTesting() // use paramset.NewOrPanic()

var flag1 bool
var flag2 bool

ps.Add("my-param", psetter.Nil{}, "help text",
	param.PostAction(paction.SetVal(&flag1, true)),
	param.PostAction(paction.SetVal(&flag2, true)),
)

fmt.Println("Before parsing")
fmt.Printf("\tflag1 = %v\n", flag1)
fmt.Printf("\tflag2 = %v\n", flag2)
ps.Parse([]string{"-my-param"})
fmt.Println("After  parsing")
fmt.Printf("\tflag1 = %v\n", flag1)
fmt.Printf("\tflag2 = %v\n", flag2)
Output:

Before parsing
	flag1 = false
	flag2 = false
After  parsing
	flag1 = true
	flag2 = true

func (Nil) AllowedValues

func (s Nil) AllowedValues() string

AllowedValues returns a description of the allowed values.

func (Nil) CheckSetter

func (s Nil) CheckSetter(_ string)

CheckSetter does nothing.

func (Nil) CurrentValue

func (s Nil) CurrentValue() string

CurrentValue returns the current setting of the parameter value, in this case there is never any current value.

func (Nil) Set

func (s Nil) Set(_ string) error

Set does nothing.

type Pathname

type Pathname struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the
	// pathname that the setter is setting.
	Value *string
	// Expectation allows you to set some file-specific checks.
	Expectation filecheck.Provisos
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error.
	Checks []check.String
	// ForceAbsolute, if set, causes any pathname value to be passed
	// to filepath.Abs before setting the value.
	ForceAbsolute bool
}

Pathname allows you to give a parameter that can be used to set a pathname value.

Example (Standard)

ExamplePathname_standard demonstrates the use of a Pathname setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var pathname string

ps.Add("my-pathname", psetter.Pathname{Value: &pathname}, "help text")

fmt.Printf("Before parsing    pathname: %q\n", pathname)
ps.Parse([]string{"-my-pathname", "testdata/noSuchFile.go"})
fmt.Printf("After  parsing    pathname: %q\n", pathname)
Output:

Before parsing    pathname: ""
After  parsing    pathname: "testdata/noSuchFile.go"
Example (WithFailingExpectation)

ExamplePathname_withFailingExpectation demonstrates the use of a Pathname setter which has the Expectation set. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var pathname string

ps.Add("my-pathname",
	psetter.Pathname{
		Value:       &pathname,
		Expectation: filecheck.FileExists(),
	},
	"help text")

fmt.Printf("Before parsing    pathname: %q\n", pathname)
errMap := ps.Parse([]string{"-my-pathname", "testdata/noSuchFile.go"})
// We expect to see an error reported.
logErrs(errMap)
// There was an error with the parameter so the value will be unchanged
fmt.Printf("After  parsing    pathname: %q\n", pathname)
Output:

Before parsing    pathname: ""
Errors for: my-pathname
	: path: "testdata/noSuchFile.go" should exist but doesn't
At: [command line]: Supplied Parameter:2: "-my-pathname" "testdata/noSuchFile.go"
After  parsing    pathname: ""
Example (WithNilValue)

ExamplePathname_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the bool Value has not been initialised
ps.Add("do-this", psetter.Pathname{}, "help text")
Output:

panic
do-this: psetter.Pathname Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExamplePathname_withPassingChecks demonstrates the use of a Pathname setter which has Checks. Note that it also has the Expectation set.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var pathname string

ps.Add("my-pathname",
	psetter.Pathname{
		Value:       &pathname,
		Expectation: filecheck.IsNew(),
		Checks: []check.String{
			check.StringHasSuffix[string](".go"),
		},
	},
	"help text")

fmt.Printf("Before parsing    pathname: %q\n", pathname)
ps.Parse([]string{"-my-pathname", "testdata/noSuchFile.go"})
fmt.Printf("After  parsing    pathname: %q\n", pathname)
Output:

Before parsing    pathname: ""
After  parsing    pathname: "testdata/noSuchFile.go"
Example (WithPassingExpectation)

ExamplePathname_withPassingExpectation demonstrates the use of a Pathname setter which has the Expectation set.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var pathname string

ps.Add("my-pathname",
	psetter.Pathname{
		Value:       &pathname,
		Expectation: filecheck.IsNew(),
	},
	"help text")

fmt.Printf("Before parsing    pathname: %q\n", pathname)
ps.Parse([]string{"-my-pathname", "testdata/noSuchFile.go"})
fmt.Printf("After  parsing    pathname: %q\n", pathname)
Output:

Before parsing    pathname: ""
After  parsing    pathname: "testdata/noSuchFile.go"

func (Pathname) AllowedValues

func (s Pathname) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (Pathname) CheckSetter

func (s Pathname) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Pathname) CountChecks

func (s Pathname) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Pathname) CurrentValue

func (s Pathname) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Pathname) SetWithVal

func (s Pathname) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks first that the value can be converted into a pathname (a tilda at the start of the path is converted to the appropriate home directory). Then it confirms that the file conforms to the supplied provisos. The Checks, if any, are run and if any check returns a non-nil error the Value is not updated and the error is returned. Only if the value is converted successfully, the Expectations are all met and no checks fail is the Value set and a nil error is returned.

type PathnameListAppender added in v5.0.5

type PathnameListAppender struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the slice
	// of strings that the setter is appending to.
	Value *[]string
	// Expectation allows you to set some file-specific checks.
	Expectation filecheck.Provisos
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be added to the list only if they all return a
	// nil error.
	Checks []check.String
	// Prepend will change the behaviour so that any new values are added at
	// the start of the list of pathnames rather than the end.
	Prepend bool
	// ForceAbsolute, if set, causes any pathname value to be passed
	// to filepath.Abs before setting the value.
	ForceAbsolute bool
}

PathnameListAppender allows you to specify a parameter that can be used to add to a list (a slice) of pathnames.

The user of the program which has a parameter of this type can pass multiple parameters and each will add to the list of values rather than replacing it each time. Note that each value must be passed separately; there is no way to pass multiple values at the same time. Also note that there is no way to reset the value, if this feature is required another parameter could be set up that will do this.

Example (Standard)

ExamplePathnameListAppender_standard demonstrates the use of a PathnameListAppender

ps := newPSetForTesting() // use paramset.NewOrPanic()

ss := []string{"testdata/pathname/nonesuch.go"}

ps.Add("next",
	psetter.PathnameListAppender{
		Value:       &ss,
		Expectation: filecheck.IsNew(),
		Checks: []check.String{
			check.StringHasSuffix[string](".go"),
		},
	},
	"help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
ps.Parse([]string{"-next", "testdata/pathname/nonesuch2.go"})
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
	ss[0] = "testdata/pathname/nonesuch.go"
After  parsing
	ss[0] = "testdata/pathname/nonesuch.go"
	ss[1] = "testdata/pathname/nonesuch2.go"
Example (WithNilValue)

ExamplePathnameListAppender_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the list Value has not been initialised
ps.Add("my-list", psetter.PathnameListAppender{}, "help text")
Output:

panic
my-list: psetter.PathnameListAppender Check failed: the Value to be set is nil

func (PathnameListAppender) AllowedValues added in v5.0.5

func (s PathnameListAppender) AllowedValues() string

AllowedValues returns a description of the allowed values. It includes the separator to be used

func (PathnameListAppender) CheckSetter added in v5.0.5

func (s PathnameListAppender) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (PathnameListAppender) CountChecks added in v5.0.5

func (s PathnameListAppender) CountChecks() int

CountChecks returns the number of check functions this setter has

func (PathnameListAppender) CurrentValue added in v5.0.5

func (s PathnameListAppender) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (PathnameListAppender) SetWithVal added in v5.0.5

func (s PathnameListAppender) SetWithVal(_, paramVal string) error

SetWithVal (called when a value follows the parameter) takes the parameter value and runs the checks against it. If any check returns a non-nil error it will return the error. Otherwise it will apply the Editor (if there is one) to the parameter value. If the Editor returns a non-nil error then that is returned and the Value is left unchanged. Finally, it will append the checked and possibly edited value to the slice of strings.

func (PathnameListAppender) ValDescribe added in v5.5.0

func (s PathnameListAppender) ValDescribe() string

ValDescribe returns a brief description of the expected value

type Regexp

type Regexp struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. Note that this is
	// a pointer to a pointer, you should initialise it with the address of
	// the Regexp pointer.
	Value **regexp.Regexp
}

Regexp allows you to give a parameter that can be used to set an regexp value.

Example (Standard)

ExampleRegexp_standard demonstrates the use of a Regexp setter.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var re *regexp.Regexp

ps.Add("my-re", psetter.Regexp{Value: &re}, "help text")

fmt.Printf("Before parsing    re: ")
if re == nil {
	fmt.Printf(" nil\n")
} else {
	fmt.Printf(" non-nil [%s]\n", re.String())
}
ps.Parse([]string{"-my-re", `.*\.go`})
fmt.Printf("After  parsing    re: ")
if re == nil {
	fmt.Printf(" nil\n")
} else {
	fmt.Printf(" non-nil [%s]\n", re.String())
}
Output:

Before parsing    re:  nil
After  parsing    re:  non-nil [.*\.go]
Example (WithNilValue)

ExampleRegexp_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the regexp pointer Value has not been
// initialised
ps.Add("do-this", psetter.Regexp{}, "help text")
Output:

panic
do-this: psetter.Regexp Check failed: the Value to be set is nil

func (Regexp) AllowedValues

func (s Regexp) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (Regexp) CheckSetter

func (s Regexp) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Regexp) CurrentValue

func (s Regexp) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Regexp) SetWithVal

func (s Regexp) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to regular expression, if it cannot be parsed successfully it returns an error. Only if the value is parsed successfully is the Value set.

type StrList

type StrList struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the
	// string that the setter is setting.
	Value *[]string
	StrListSeparator
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error.
	Checks []check.StringSlice
	// The Editor, if present, is applied to each of the listed parameter
	// values after any checks are applied and allows the programmer to
	// modify the value supplied before using it to set the Value.
	Editor Editor
}

StrList allows you to specify a parameter that can be used to set a list (a slice) of strings.

If only certain, predefined, values are allowed you might prefer to use EnumList

Example (Standard)

ExampleStrList_standard demonstrates the use of a StrList setter

ps := newPSetForTesting() // use paramset.NewOrPanic()

var ss []string

ps.Add("my-list",
	psetter.StrList{
		Value: &ss,
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
ps.Parse([]string{"-my-list", "x,y"})
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
After  parsing
	ss[0] = "x"
	ss[1] = "y"
Example (WithEditor)

ExampleStrList_withEditor demonstrates the behaviour of the Editor.

package main

import (
	"errors"
	"fmt"

	"github.com/nickwells/param.mod/v5/param"
	"github.com/nickwells/param.mod/v5/param/psetter"
)

type myEditorStrList struct{}

// Edit switches on the parameter name to reset the parameter value
func (myEditorStrList) Edit(paramName, paramVal string) (string, error) {
	switch paramName {
	case "hello":
		return "Hello, " + paramVal, nil
	case "en":
		return "Hi, " + paramVal, nil
	case "fr":
		return "Bonjour, " + paramVal, nil
	case "es":
		return "Hola, " + paramVal, nil
	case "de":
		return "Guten Tag, " + paramVal, nil
	}
	return "", errors.New("Unknown language: " + paramName)
}

// ExampleStrList_withEditor demonstrates the behaviour of the Editor.
func main() {
	ps := newPSetForTesting() // use paramset.NewOrPanic()

	var ss []string
	var myE myEditorStrList

	ps.Add("hello",
		psetter.StrList{
			Value:  &ss,
			Editor: myE,
		}, "help text",
		param.AltNames("en", "fr", "es", "de"),
	)

	fmt.Println("Before parsing")
	for i, v := range ss {
		fmt.Printf("\tss[%d] = %q\n", i, v)
	}
	ps.Parse([]string{"-fr", "Nick,Pascal,Amelie"})
	fmt.Println("After  parsing")
	for i, v := range ss {
		fmt.Printf("\tss[%d] = %q\n", i, v)
	}
}
Output:

Before parsing
After  parsing
	ss[0] = "Bonjour, Nick"
	ss[1] = "Bonjour, Pascal"
	ss[2] = "Bonjour, Amelie"
Example (WithFailingChecks)

ExampleStrList_withFailingChecks demonstrates the behaviour of the package when an invalid value is given. In this case the resulting list is not of the required length. It demonstrates the checks that can be supplied to ensure that the resulting list is as expected. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var ss []string

ps.Add("my-list",
	psetter.StrList{
		Value: &ss,
		Checks: []check.StringSlice{
			check.SliceLength[[]string, string](check.ValEQ(2)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
// Parse the arguments. We supply a list of strings, each of which is
// allowed. The resulting slice is of the wrong length.
errMap := ps.Parse([]string{"-my-list", "x"})
// We expect to see an error reported.
logErrs(errMap)
// The slice of strings is unchanged due to the error.
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
Errors for: my-list
	: the length of the list (1) is incorrect: the value (1) must equal 2
At: [command line]: Supplied Parameter:2: "-my-list" "x"
After  parsing
Example (WithNilValue)

ExampleStrList_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the list Value has not been initialised
ps.Add("my-list", psetter.StrList{}, "help text")
Output:

panic
my-list: psetter.StrList Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleStrList_withPassingChecks demonstrates how you can specify additional checks to be applied to the passed arguments before the value is set.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var ss []string

ps.Add("my-list",
	psetter.StrList{
		Value: &ss,
		Checks: []check.StringSlice{
			check.SliceLength[[]string, string](check.ValEQ(2)),
		},
	}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
ps.Parse([]string{"-my-list", "x,y"})
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
After  parsing
	ss[0] = "x"
	ss[1] = "y"

func (StrList) AllowedValues

func (s StrList) AllowedValues() string

AllowedValues returns a description of the allowed values. It includes the separator to be used

func (StrList) CheckSetter

func (s StrList) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (StrList) CountChecks

func (s StrList) CountChecks() int

CountChecks returns the number of check functions this setter has

func (StrList) CurrentValue

func (s StrList) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (StrList) SetWithVal

func (s StrList) SetWithVal(paramName, paramVal string) error

SetWithVal (called when a value follows the parameter) splits the value into a slice of strings and sets the Value accordingly. The Checks, if any, will be applied and if any of them return an error the Value will not be updated and the error will be returned. If the Editor is non-nil then it is applied to each of the listed parameter values. If the Editor returns an error for any of the listed values then the Value will not be updated and the error is returned.

type StrListAppender

type StrListAppender struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the slice
	// of strings that the setter is appending to.
	Value *[]string
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be added to the list only if they all return a
	// nil error.
	Checks []check.String
	// The Editor, if present, is applied to the parameter value after any
	// checks are applied and allows the programmer to modify the value
	// supplied before using it to set the Value.
	Editor Editor
	// Prepend will change the behaviour so that any new values are added at
	// the start of the list of strings rather than the end.
	Prepend bool
}

StrListAppender allows you to specify a parameter that can be used to add to a list (a slice) of strings.

The user of the program which has a parameter of this type can pass multiple parameters and each will add to the list of values rather than replacing it each time. Note that each value must be passed separately; there is no way to pass multiple values at the same time. Also note that there is no way to reset the value, if this feature is required another parameter could be set up that will do this.

Example (Standard)

ExampleStrListAppender_standard demonstrates the use of a StrListAppender

ps := newPSetForTesting() // use paramset.NewOrPanic()

ss := []string{"Hello"}

ps.Add("next", psetter.StrListAppender{Value: &ss}, "help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
ps.Parse([]string{"-next", "darkness", "-next", "my old friend"})
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
	ss[0] = "Hello"
After  parsing
	ss[0] = "Hello"
	ss[1] = "darkness"
	ss[2] = "my old friend"
Example (WithEditor)

ExampleStrListAppender_withEditor demonstrates the behaviour of the Editor.

package main

import (
	"errors"
	"fmt"

	"github.com/nickwells/param.mod/v5/param"
	"github.com/nickwells/param.mod/v5/param/psetter"
)

type myEditorMult struct{}

// Edit switches on the parameter name to reset the parameter value
func (myEditorMult) Edit(paramName, paramVal string) (string, error) {
	switch paramName {
	case "next":
		return paramVal, nil
	case "next2":
		return paramVal + ", " + paramVal, nil
	case "next3":
		return paramVal + ", " + paramVal + ", " + paramVal, nil
	}
	return "", errors.New("Unexpected parameter: " + paramName)
}

// ExampleStrListAppender_withEditor demonstrates the behaviour of the Editor.
func main() {
	ps := newPSetForTesting() // use paramset.NewOrPanic()

	ss := []string{"Hello"}
	var myE myEditorMult

	ps.Add("next",
		psetter.StrListAppender{
			Value:  &ss,
			Editor: myE,
		}, "help text",
		param.AltNames("next2", "next3"),
	)

	fmt.Println("Before parsing")
	for i, v := range ss {
		fmt.Printf("\tss[%d] = %q\n", i, v)
	}
	ps.Parse([]string{"-next", "darkness", "-next3", "darkness"})
	fmt.Println("After  parsing")
	for i, v := range ss {
		fmt.Printf("\tss[%d] = %q\n", i, v)
	}
}
Output:

Before parsing
	ss[0] = "Hello"
After  parsing
	ss[0] = "Hello"
	ss[1] = "darkness"
	ss[2] = "darkness, darkness, darkness"
Example (WithFailingChecks)

ExampleStrListAppender_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

ss := []string{"Hello"}

ps.Add("next",
	psetter.StrListAppender{
		Value: &ss,
		Checks: []check.String{
			check.StringLength[string](check.ValLT(10)),
		},
	},
	"help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
errMap := ps.Parse([]string{"-next", "darkness", "-next", "my old friend"})
// We expect to see an error reported.
logErrs(errMap)
// The value does not include the second parameter due to the error.
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
	ss[0] = "Hello"
Errors for: next
	: the length of the string (13) is incorrect: the value (13) must be less than 10
At: [command line]: Supplied Parameter:4: "-next" "my old friend"
After  parsing
	ss[0] = "Hello"
	ss[1] = "darkness"
Example (WithNilValue)

ExampleStrListAppender_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

// we expect this to panic because the list Value has not been initialised
ps.Add("my-list", psetter.StrListAppender{}, "help text")
Output:

panic
my-list: psetter.StrListAppender Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleStrListAppender_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

ss := []string{"Hello"}

ps.Add("next",
	psetter.StrListAppender{
		Value: &ss,
		Checks: []check.String{
			check.StringLength[string](check.ValGT(5)),
		},
	},
	"help text")

fmt.Println("Before parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
ps.Parse([]string{"-next", "darkness", "-next", "my old friend"})
fmt.Println("After  parsing")
for i, v := range ss {
	fmt.Printf("\tss[%d] = %q\n", i, v)
}
Output:

Before parsing
	ss[0] = "Hello"
After  parsing
	ss[0] = "Hello"
	ss[1] = "darkness"
	ss[2] = "my old friend"

func (StrListAppender) AllowedValues

func (s StrListAppender) AllowedValues() string

AllowedValues returns a description of the allowed values. It includes the separator to be used

func (StrListAppender) CheckSetter

func (s StrListAppender) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (StrListAppender) CountChecks

func (s StrListAppender) CountChecks() int

CountChecks returns the number of check functions this setter has

func (StrListAppender) CurrentValue

func (s StrListAppender) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (StrListAppender) SetWithVal

func (s StrListAppender) SetWithVal(paramName, paramVal string) error

SetWithVal (called when a value follows the parameter) takes the parameter value and runs the checks against it. If any check returns a non-nil error it will return the error. Otherwise it will apply the Editor (if there is one) to the parameter value. If the Editor returns a non-nil error then that is returned and the Value is left unchanged. Finally, it will append the checked and possibly edited value to the slice of strings.

type StrListSeparator

type StrListSeparator struct {
	Sep string
}

StrListSeparator holds the separator value

func (StrListSeparator) GetSeparator

func (sls StrListSeparator) GetSeparator() string

GetSeparator returns the separator or the default value (a comma) if it is an empty string

func (StrListSeparator) ListValDesc

func (sls StrListSeparator) ListValDesc(name string) string

ListValDesc returns that fragment of the description of what values are allowed which explains how the list values are separated from one another.

type String

type String struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the
	// string that the setter is setting.
	Value *string
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error.
	Checks []check.String
	// The Editor, if present, is applied to the parameter value after any
	// checks are applied and allows the programmer to modify the value
	// supplied before using it to set the Value.
	Editor Editor
}

String is the type for setting string values from parameters

Example (Standard)

ExampleString_standard demonstrates the use of a String setter

ps := newPSetForTesting() // use paramset.NewOrPanic()

var s string

ps.Add("my-string", psetter.String{Value: &s}, "help text")

fmt.Printf("Before parsing: s = %q\n", s)
ps.Parse([]string{"-my-string", "Hello, World!"})
fmt.Printf("After  parsing: s = %q\n", s)
Output:

Before parsing: s = ""
After  parsing: s = "Hello, World!"
Example (WithEditor)

ExampleString_withEditor demonstrates the behaviour of the Editor.

package main

import (
	"errors"
	"fmt"

	"github.com/nickwells/param.mod/v5/param"
	"github.com/nickwells/param.mod/v5/param/psetter"
)

type myEditor struct{}

// Edit switches on the parameter name to reset the parameter value
func (myEditor) Edit(paramName, paramVal string) (string, error) {
	switch paramName {
	case "hello":
		return "Hello, " + paramVal, nil
	case "en":
		return "Hi, " + paramVal, nil
	case "fr":
		return "Bonjour, " + paramVal, nil
	case "es":
		return "Hola, " + paramVal, nil
	case "de":
		return "Guten Tag, " + paramVal, nil
	}
	return "", errors.New("Unknown language: " + paramName)
}

// ExampleString_withEditor demonstrates the behaviour of the Editor.
func main() {
	ps := newPSetForTesting() // use paramset.NewOrPanic()

	var s string
	var myE myEditor

	ps.Add("hello",
		psetter.String{
			Value:  &s,
			Editor: myE,
		}, "help text",
		param.AltNames("en", "fr", "es", "de"),
	)

	fmt.Printf("Before parsing: s = %q\n", s)
	ps.Parse([]string{"-fr", "Nick!"})
	fmt.Printf("After  parsing: s = %q\n", s)
}
Output:

Before parsing: s = ""
After  parsing: s = "Bonjour, Nick!"
Example (WithFailingChecks)

ExampleString_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var s string

ps.Add("my-string",
	psetter.String{
		Value: &s,
		Checks: []check.String{
			check.StringLength[string](check.ValGT(5)),
		},
	}, "help text")

fmt.Printf("Before parsing: s = %q\n", s)
// Parse the arguments. Note that the string supplied is too short to
// satisfy the check for this parameter.
errMap := ps.Parse([]string{"-my-string", "Hi!"})
// We expect to see an error reported.
logErrs(errMap)
// The value is unchanged due to the error.
fmt.Printf("After  parsing: s = %q\n", s)
Output:

Before parsing: s = ""
Errors for: my-string
	: the length of the string (3) is incorrect: the value (3) must be greater than 5
At: [command line]: Supplied Parameter:2: "-my-string" "Hi!"
After  parsing: s = ""
Example (WithNilValue)

ExampleString_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

ps.Add("my-string", psetter.String{}, "help text")
Output:

panic
my-string: psetter.String Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleString_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var s string

ps.Add("my-string",
	psetter.String{
		Value: &s,
		Checks: []check.String{
			check.StringLength[string](check.ValGT(5)),
		},
	}, "help text")

fmt.Printf("Before parsing: s = %q\n", s)
ps.Parse([]string{"-my-string", "Hello, World!"})
fmt.Printf("After  parsing: s = %q\n", s)
Output:

Before parsing: s = ""
After  parsing: s = "Hello, World!"

func (String) AllowedValues

func (s String) AllowedValues() string

AllowedValues simply returns "any string" since String does not check its value

func (String) CheckSetter

func (s String) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (String) CountChecks

func (s String) CountChecks() int

CountChecks returns the number of check functions this setter has

func (String) CurrentValue

func (s String) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (String) SetWithVal

func (s String) SetWithVal(paramName, paramVal string) error

SetWithVal checks that the parameter value meets the checks if any. It returns an error if the check is not satisfied. Only if the check is not violated is the Value set.

type Time

type Time struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. This is the
	// Time that the setter is setting.
	Value *time.Time
	// The Format is used to convert the string parameter value into a Time
	// suitable for setting the Value. If no Format is given the default
	// value will be used, see TimeFmtDefault.
	Format string
	// The Checks, if any, are applied to the time.Time value and the new
	// parameter will be applied only if they all return a nil error.
	Checks []check.Time
}

Time allows you to give a parameter that can be used to set a time.Time value.

Example (Standard)

ExampleTime_standard demonstrates the use of a Time setter

ps := newPSetForTesting() // use paramset.NewOrPanic()

var t time.Time

ps.Add("my-time", psetter.Time{Value: &t}, "help text")

fmt.Printf("Before parsing: time = %s\n", t.Format("15:04"))
ps.Parse([]string{"-my-time", "2000/Jan/01T15:00:00"})
fmt.Printf("After  parsing: time = %s\n", t.Format("15:04"))
Output:

Before parsing: time = 00:00
After  parsing: time = 15:00
Example (WithFailingChecks)

ExampleTime_withFailingChecks demonstrates how to add checks to be applied to the value. Note that there is normally no need to examine the return from ps.Parse as the standard Helper will report any errors and abort the program.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var t time.Time

ps.Add("my-time",
	psetter.Time{
		Value: &t,
		Checks: []check.Time{
			check.TimeIsOnDOW(time.Friday),
		},
	},
	"help text")

fmt.Printf("Before parsing: time = %s\n", t.Weekday())
// Parse the arguments. Note that the time given is not on a Friday.
errMap := ps.Parse([]string{"-my-time", "2020/Apr/25T12:00:00"})
// We expect to see an error reported.
logErrs(errMap)
// The value is unchanged due to the error.
fmt.Printf("After  parsing: time = %s\n", t.Weekday())
Output:

Before parsing: time = Monday
Errors for: my-time
	: the day of the week (Saturday) must be a Friday
At: [command line]: Supplied Parameter:2: "-my-time" "2020/Apr/25T12:00:00"
After  parsing: time = Monday
Example (WithFormat)

ExampleTime_withFormat demonstrates the use of a Time setter with a non-default Format value

ps := newPSetForTesting() // use paramset.NewOrPanic()

var t time.Time

ps.Add("my-time",
	psetter.Time{
		Value:  &t,
		Format: psetter.TimeFmtHMS,
	},
	"help text")

fmt.Printf("Before parsing: time = %s\n", t.Format("15:04:05"))
ps.Parse([]string{"-my-time", "15:01:02"})
fmt.Printf("After  parsing: time = %s\n", t.Format("15:04:05"))
Output:

Before parsing: time = 00:00:00
After  parsing: time = 15:01:02
Example (WithNilValue)

ExampleTime_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

ps.Add("my-time", psetter.Time{}, "help text")
Output:

panic
my-time: psetter.Time Check failed: the Value to be set is nil
Example (WithPassingChecks)

ExampleTime_withPassingChecks demonstrates how to add checks to be applied to the value.

ps := newPSetForTesting() // use paramset.NewOrPanic()

var t time.Time

ps.Add("my-time",
	psetter.Time{
		Value: &t,
		Checks: []check.Time{
			check.TimeIsOnDOW(time.Friday),
		},
	},
	"help text")

fmt.Printf("Before parsing: time = %s\n", t.Weekday())
ps.Parse([]string{"-my-time", "2020/Apr/24T12:00:00"})
fmt.Printf("After  parsing: time = %s\n", t.Weekday())
Output:

Before parsing: time = Monday
After  parsing: time = Friday

func (Time) AllowedValues

func (s Time) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (Time) CheckSetter

func (s Time) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (Time) CountChecks

func (s Time) CountChecks() int

CountChecks returns the number of check functions this setter has

func (Time) CurrentValue

func (s Time) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (Time) SetWithVal

func (s Time) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to a time, if it cannot be parsed successfully it returns an error. If there is a check and the check is violated it returns an error. Only if the value is parsed successfully and the check is not violated is the Value set.

type TimeLocation

type TimeLocation struct {
	ValueReqMandatory

	// You must set a Value, the program will panic if not. Note that this is
	// a pointer to the pointer to the Location, you should initialise it
	// with the address of the Location pointer.
	Value **time.Location
	// The Checks, if any, are applied to the supplied parameter value and
	// the new parameter will be applied only if they all return a nil error.
	Checks []check.TimeLocation
}

TimeLocation allows you to give a parameter that can be used to set a time.Location pointer. You can also supply check functions that will validate the Value.

Example (Standard)

ExampleTimeLocation_standard demonstrates the use of a TimeLocation setter

ps := newPSetForTesting() // use paramset.NewOrPanic()

var loc *time.Location

ps.Add("location", psetter.TimeLocation{Value: &loc}, "help text")

fmt.Printf("Before parsing   location: %v\n", loc)
ps.Parse([]string{"-location", "Europe/London"})
fmt.Printf("After  parsing   location: %v\n", loc)
Output:

Before parsing   location: UTC
After  parsing   location: Europe/London
Example (WithNilValue)

ExampleTimeLocation_withNilValue demonstrates the behaviour of the package when an invalid setter is provided. In this case the Value to be set has not been initialised. Note that in production code you should not recover from the panic, instead you should fix the code that caused it.

defer func() { // For test purposes only - do not recover in live code
	if p := recover(); p != nil {
		fmt.Println("panic")
		fmt.Println(p)
	}
}()

ps := newPSetForTesting() // use paramset.NewOrPanic()

ps.Add("location", psetter.TimeLocation{}, "help text")
Output:

panic
location: psetter.TimeLocation Check failed: the Value to be set is nil

func (TimeLocation) AllowedValues

func (s TimeLocation) AllowedValues() string

AllowedValues returns a string describing the allowed values

func (TimeLocation) CheckSetter

func (s TimeLocation) CheckSetter(name string)

CheckSetter panics if the setter has not been properly created - if the Value is nil.

func (TimeLocation) CountChecks

func (s TimeLocation) CountChecks() int

CountChecks returns the number of check functions this setter has

func (TimeLocation) CurrentValue

func (s TimeLocation) CurrentValue() string

CurrentValue returns the current setting of the parameter value

func (TimeLocation) SetWithVal

func (s TimeLocation) SetWithVal(_ string, paramVal string) error

SetWithVal (called when a value follows the parameter) checks that the value can be parsed to a Location (note that it will try to replace any spaces with underscores if the first attempt fails). If it cannot be parsed successfully it returns an error. The Checks, if any, will be applied and if any of them return a non-nil error the Value will not be updated and the error will be returned.

type ValDescriber added in v5.3.0

type ValDescriber interface {
	ValDescribe() string
}

ValDescriber is an interface for a function which can be added as a method on an existing Setter and if it is present its return value will be used to describe the parameter value to be supplied. It only makes sense to provide such a method if the parameter can take a value.

type ValueReqMandatory

type ValueReqMandatory struct{}

ValueReqMandatory is a mixin type that can be embedded in a Setter to provide suitable default values for a Setter where the parameter must have a value following it.

func (ValueReqMandatory) Set

func (v ValueReqMandatory) Set(name string) error

Set returns an error because if the value is Mandatory then a value must follow the parameter for this setter.

func (ValueReqMandatory) ValueReq

func (v ValueReqMandatory) ValueReq() param.ValueReq

ValueReq returns the Mandatory value of the ValueReq type to indicate that a value must follow the parameter for this setter.

type ValueReqNone

type ValueReqNone struct{}

ValueReqNone is a mixin type that can be embedded in a Setter to provide suitable default values for a Setter where the parameter must not have a following value.

func (ValueReqNone) SetWithVal

func (v ValueReqNone) SetWithVal(name, _ string) error

SetWithVal returns an error because if the value is None then a value must not follow the parameter for this setter.

func (ValueReqNone) ValueReq

func (v ValueReqNone) ValueReq() param.ValueReq

ValueReq returns the None value of the ValueReq type to indicate that a value must not follow the parameter for this setter.

type ValueReqOptional

type ValueReqOptional struct{}

ValueReqOptional is a mixin type that can be embedded in a Setter to provide suitable default values for a Setter where the following parameter is optional.

func (ValueReqOptional) ValueReq

func (v ValueReqOptional) ValueReq() param.ValueReq

ValueReq returns the Optional value of the ValueReq type to indicate that a value may follow the parameter for this setter but need not.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL