clapper

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Oct 31, 2024 License: MIT Imports: 7 Imported by: 0

README

Clapper 👏

Yes there is clap, but this is clapper (pun intended).

A more complete command line parser with optionals, tagged-defaults and auto-help.

Differences to clap

A lot. Like pointer receivers (optionals), defaults, auto-help, etc. I know that clap originally deals with defaults by assigning them inside the struct on init. It did not like it. However, I liked clap as a command line parser but was missing some of these features and the pre-defined order so I always struggled with it.

Maturity

NOTE with version 1.0.0 this package must be included like

import "github.com/Dirk007/clapper"

the pkg/clapper-Path has been removed.

Expectations could be assured from the argument-parser- and interpreter tests which are nopefully exhautive enough.

If you find a bug feel free to add a test and file a PR.

Usage

Define your clapper-tag like this:

type Foo struct {

    // gets --some-defaulted-value - or -s
    SomeDefaultedValue int     `clapper:"short,long,default=42,help='Set this to have some value here instead of 42'"`
    // getsd
    OptionalValue      *string `clapper:"long"`
    MandatoryValue     string  `clapper:"long`
    FlagValueOptional  bool    `clapper:"short`
    IgnoredValue       bool
}

var foo Foo
trailing, err := clapper.Parse(&foo)

the inner order of the tag does not matter at all. The given example gives command line options -s and --some-value, defaulting to value 42 if not given. OptionalValue is optional.

Guarantees and rules

  • If no arguments than the target have been given to Parse(), the os.Arguemnts will be taken.
  • All value properties except bool are mandatory unless a default ist given.
  • All pointer properties are optional. default applies.
  • A bool proerty not given will remain untouched.
  • At least short or long name must be provided.
    • If both are given, the long-name provided value has higher priority. --some 1 -s 2 -> 1.
  • If a flag is provided several times with different values and the property is not a slice, only the first value will be taken. --foo 1 --foo 2 -> foo=1
  • If a flag is provided several times and the property is a slice, the values are appended in the given order. --foo 1 --foo 2 -> foo=[1,2]
  • Slice properties can also be filled like --foo a b c -d. -> foo=[a,b,c]
  • Short flags -s -a -d can be combined as -sad and will be interpreted as -s -a -d.
  • If combined short-flags are provided with a value -sad 123, the value will be bound to the last short-flag. d=123
  • Unknown but given flags are silently discared.
  • Short flags are always -[char] - one dash, one character
  • Long flags have to be always --[some-string] two dahes, longer than 1 char.
  • Boolean properties can be set to true if the flag is given by command line. -f.
    • Values for bools are not accepted. Defined means true.
  • Command line input like --foo=bar or --foo bar are interpreted as the same.
  • If the last command line parameters are assigned to a slice --foo a b c then all these parameters will be appended to the slice. There are no trailing parameters then.
    • In opposite if there is a slice --foo a b c --bar baz 1 2 3, then the trailing parameters 1 2 3 will be returned from the Parse.

Tag-Options

short

Given only as short, assumes that the first lowercased-letter of the property is taken as the short parameter. For exmaple Something becomes -s.

someprogram -s "hello world"

To override the default assumption, you can write short=X where X would be the overriden short parameter.

someprogram -X "hello world"
long

Given as long, assumes that the Kebab-Case-converted name of the property is the paramter name. For example FooBar becomes --foo-bar

someprogram --foo-bar "Hello World"

Also here, the name assumption can be overriden by paramter. long=not-so-foo

someprogram --not-so-foo "Hello World"
default

The default value taken if the parameter is not provided via command line. Set this to have all mandatory flags to be optional with this default.

If default is defined for a pointer-value, the default will also be applied then.

help

Clapper has a auto-help feature and this optional tag-option can be set to let your users have some extra idea of the meaning of your flag.

Exmaple:

type Foo struct {
    WeirdParameter int `clappper:"short,help='Set to the value you whish to have on your bank account.'"`
}

help := clapper.HelpDefault()
fmt.Println(help)

Call clapper.Help() to print out the avaiable options with their help text.

FYI cllapper HelpDefault() will use the originally designed help format and prints out the parameters only. You may want to have a

type Foo struct {
    // ...
    ShowHelp bool `clapper:"long=help"`
}

in order to check that and display the help. But it is up to you.

Trailing?

Clapper works different from clap and does not include trailing as a struct property. Trailing parameters are returned from the Parse() command. It is up to you to do whatever you like with them.

Documentation

Index

Constants

View Source
const (
	TagName = "clapper"
)

Variables

View Source
var (
	ErrNoStruct                        = errors.New("target is not a struct")
	ErrEmptyArgument                   = errors.New("empty argument")
	ErrUnexpectedValue                 = errors.New("expected flag not value")
	ErrFieldCanNotBeSet                = errors.New("field can't be set")
	ErrNoFlagSpecifier                 = errors.New("no flag specified for struct field")
	ErrShortOverrideCanOnlyBeOneLetter = errors.New("short override can only be one letter")
	ErrLongMustBeMoreThanOne           = errors.New("long name must be more than one character")
)

Functions

func DefaultHelpFormatter

func DefaultHelpFormatter(item *HelpItem, formatting *HelpFormatting) string

func Help

func Help[T any](target *T, formatter FormatterFn) (string, error)

func HelpDefault

func HelpDefault[T any](target *T) (string, error)

func Parse

func Parse[T any](target *T, rawArgs ...string) (trailing []string, err error)

func StringReflect

func StringReflect(field reflect.StructField, fieldValue reflect.Value, values []string) (int, error)

func ValueFromString

func ValueFromString(fieldType reflect.Type, inputs []string) (*reflect.Value, int, error)

Types

type ArgsParser

type ArgsParser struct {
	Params   map[string][]string
	Trailing []string
	// contains filtered or unexported fields
}

func NewArgsParser

func NewArgsParser() *ArgsParser

func (*ArgsParser) Add

func (pa *ArgsParser) Add(arg string) error

func (*ArgsParser) Parse

func (pa *ArgsParser) Parse(args []string) (*ArgsParser, error)

func (*ArgsParser) PopTrailing

func (pa *ArgsParser) PopTrailing(took int) *ArgsParser

func (*ArgsParser) ValuesEqualWith

func (pa *ArgsParser) ValuesEqualWith(other *ArgsParser) bool

func (*ArgsParser) With

func (pa *ArgsParser) With(modifier func(args *ArgsParser)) *ArgsParser

type ArgsState

type ArgsState int
const (
	ArgsStart ArgsState = iota
	ArgsShort
	ArgsLong
)

type FormatterFn

type FormatterFn = func(item *HelpItem, formatting *HelpFormatting) string

type HelpFormatting

type HelpFormatting struct {
	InvokationMax int
	DefaultMax    int
}

func DefaultHelpFormatting

func DefaultHelpFormatting() *HelpFormatting

func (*HelpFormatting) Update

func (h *HelpFormatting) Update(item *HelpItem) *HelpFormatting

type HelpItem

type HelpItem struct {
	Invokation string
	Default    *string
	Help       *string
}

func HelpItemFromTags

func HelpItemFromTags(tags map[TagType]Tag) *HelpItem

func (*HelpItem) Display

func (h *HelpItem) Display(formatting HelpFormatting) string

type MandatoryParameterError

type MandatoryParameterError struct {
	Name string
}

func NewMandatoryParameterError

func NewMandatoryParameterError(name string) MandatoryParameterError

func (MandatoryParameterError) Error

func (e MandatoryParameterError) Error() string

type ParseError

type ParseError struct {
	Index   int
	Name    string
	TagLine string
	// contains filtered or unexported fields
}

func NewParseError

func NewParseError(from error, index int, name string, tagLine string) ParseError

func (ParseError) Error

func (e ParseError) Error() string

func (ParseError) Underlying

func (e ParseError) Underlying() error

type Tag

type Tag struct {
	Type  TagType
	Name  string
	Value string
	Index int
}

func NewTag

func NewTag(tag string, fieldName string, index int) (*Tag, error)

func (*Tag) DeriveName

func (t *Tag) DeriveName(fieldName string) string

func (*Tag) HasValue

func (t *Tag) HasValue() bool

func (*Tag) Validate

func (t *Tag) Validate() error

type TagType

type TagType int
const (
	TagShort TagType = iota
	TagLong
	TagDefault
	TagHelp
)

func GetTagType

func GetTagType(tag string) (TagType, error)

type UnsupportedReflectTypeError

type UnsupportedReflectTypeError struct {
	Type string
}

func NewUnsupportedReflectTypeError

func NewUnsupportedReflectTypeError(t string) UnsupportedReflectTypeError

func (UnsupportedReflectTypeError) Error

Directories

Path Synopsis
example
simple command

Jump to

Keyboard shortcuts

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