Skip to content

Commit 8ac0679

Browse files
Add *url.URL as an argable type (#184)
1 parent d9fa3c9 commit 8ac0679

10 files changed

Lines changed: 57 additions & 3 deletions

File tree

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ The types you can currently use for positional args are:
281281
- `float32`
282282
- `float64`
283283
- `string`
284+
- `*url.URL`
284285
- `bool`
285286
- `[]byte` (interpreted as a hex string)
286287
- `time.Time`

arg/arg.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package arg
33

44
import (
55
"net"
6+
"net/url"
67
"time"
78
)
89

@@ -24,6 +25,7 @@ type Argable interface {
2425
float32 |
2526
float64 |
2627
string |
28+
*url.URL |
2729
bool |
2830
[]byte |
2931
time.Time |

docs/img/namedargs.gif

-730 Bytes
Loading

docs/img/quickstart.gif

986 Bytes
Loading

docs/img/subcommands.gif

22 KB
Loading

examples/subcommands/cli.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"fmt"
5+
"net/url"
56
"strings"
67
"time"
78

@@ -76,7 +77,7 @@ type doOptions struct {
7677
func buildDoCommand() (*cli.Command, error) {
7778
var options doOptions
7879

79-
var thing string
80+
var thing *url.URL
8081

8182
return cli.New(
8283
"do",

internal/arg/arg.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"errors"
99
"fmt"
1010
"net"
11+
"net/url"
1112
"strconv"
1213
"strings"
1314
"time"
@@ -97,6 +98,8 @@ func (a Arg[T]) Default() string {
9798
return format.Float64(typ)
9899
case string:
99100
return typ
101+
case *url.URL:
102+
return typ.String()
100103
case bool:
101104
return strconv.FormatBool(typ)
102105
case []byte:
@@ -149,6 +152,8 @@ func (a Arg[T]) String() string {
149152
return format.Float64(typ)
150153
case string:
151154
return typ
155+
case *url.URL:
156+
return typ.String()
152157
case bool:
153158
return strconv.FormatBool(typ)
154159
case []byte:
@@ -201,6 +206,8 @@ func (a Arg[T]) Type() string {
201206
return format.TypeFloat64
202207
case string:
203208
return format.TypeString
209+
case *url.URL:
210+
return format.TypeURL
204211
case bool:
205212
return format.TypeBool
206213
case []byte:
@@ -346,6 +353,15 @@ func (a Arg[T]) Set(str string) error {
346353
val := str
347354
*a.value = *parse.Cast[T](&val)
348355

356+
return nil
357+
case *url.URL:
358+
val, err := url.ParseRequestURI(str)
359+
if err != nil {
360+
return parse.Error(parse.KindArgument, a.name, str, typ, err)
361+
}
362+
363+
*a.value = *parse.Cast[T](&val)
364+
349365
return nil
350366
case bool:
351367
val, err := strconv.ParseBool(str)

internal/arg/arg_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"errors"
66
"net"
7+
"net/url"
78
"testing"
89
"time"
910

@@ -384,6 +385,39 @@ func TestArgableTypes(t *testing.T) {
384385
test.Equal(t, strArg.String(), "newvalue")
385386
})
386387

388+
t.Run("url valid", func(t *testing.T) {
389+
var u *url.URL
390+
391+
urlArg, err := arg.New(&u, "url", "Set a url value", arg.Config[*url.URL]{})
392+
test.Ok(t, err)
393+
394+
rawURL := "https://github.com/FollowTheProcess/cli"
395+
396+
want, err := url.ParseRequestURI(rawURL)
397+
test.Ok(t, err)
398+
399+
err = urlArg.Set(rawURL)
400+
test.Ok(t, err)
401+
test.Equal(t, u.Scheme, want.Scheme)
402+
test.Equal(t, u.Host, want.Host)
403+
test.Equal(t, u.Path, want.Path)
404+
405+
test.Equal(t, urlArg.Type(), format.TypeURL)
406+
test.Equal(t, urlArg.Usage(), "Set a url value")
407+
test.Equal(t, urlArg.String(), rawURL)
408+
})
409+
410+
t.Run("url invalid", func(t *testing.T) {
411+
var u *url.URL
412+
413+
urlArg, err := arg.New(&u, "url", "Set a url value", arg.Config[*url.URL]{})
414+
test.Ok(t, err)
415+
416+
err = urlArg.Set("word")
417+
test.Err(t, err)
418+
test.True(t, errors.Is(err, parse.Err))
419+
})
420+
387421
t.Run("byte slice valid", func(t *testing.T) {
388422
var byt []byte
389423

internal/flag/flag.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -251,8 +251,6 @@ func (f Flag[T]) Type() string { //nolint:cyclop // No other way of doing this r
251251
return format.TypeFloat32Slice
252252
case []float64:
253253
return format.TypeFloat64Slice
254-
case []string:
255-
return format.TypeStringSlice
256254
default:
257255
return fmt.Sprintf("%T", typ)
258256
}

internal/format/format.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ const (
4141
TypeFloat32 = "float32"
4242
TypeFloat64 = "float64"
4343
TypeString = "string"
44+
TypeURL = "url"
4445
TypeBool = "bool"
4546
TypeBytesHex = "bytesHex"
4647
TypeTime = "time"
@@ -58,6 +59,7 @@ const (
5859
TypeFloat32Slice = slice + TypeFloat32
5960
TypeFloat64Slice = slice + TypeFloat64
6061
TypeStringSlice = slice + TypeString
62+
TypeURLSlice = slice + TypeURL
6163
)
6264

6365
// True is the literal boolean true as a string.

0 commit comments

Comments
 (0)