1
+ import clad/internal/args
1
2
import gleam/dict
2
3
import gleam/dynamic . {
3
4
type DecodeError , type DecodeErrors , type Decoder , type Dynamic , DecodeError ,
@@ -6,11 +7,34 @@ import gleam/float
6
7
import gleam/int
7
8
import gleam/list
8
9
import gleam/result
9
- import internal/args
10
10
11
+ /// Run a decoder on a list of command line arguments, decoding the value if it
12
+ /// is of the desired type, or returning errors.
13
+ ///
14
+ /// This function works well with the argv package.
15
+ ///
16
+ /// # Examples
17
+ /// ```gleam
18
+ /// dynamic.decode2(
19
+ /// SignUp,
20
+ /// clad.string(long_name: "name", short_name: "n"),
21
+ /// clad.string(long_name: "email", short_name: "e"),
22
+ /// )
23
+ /// |> clad.decode(["-n", "Lucy", "[email protected] "])
24
+ /// // -> Ok(SignUp(name: "Lucy", email: "[email protected] "))
25
+ /// ```
26
+ /// with argv:
27
+ /// ```gleam
28
+ /// dynamic.decode2(
29
+ /// SignUp,
30
+ /// clad.string(long_name: "name", short_name: "n"),
31
+ /// clad.string(long_name: "email", short_name: "e"),
32
+ /// )
33
+ /// |> clad.decode(argv.load().arguments)
34
+ /// ```
11
35
pub fn decode (
12
- from arguments : List ( String ) ,
13
- using decoder : Decoder ( t ) ,
36
+ decoder : Decoder ( t ) ,
37
+ arguments : List ( String ) ,
14
38
) -> Result ( t, DecodeErrors ) {
15
39
use arguments <- result . try ( prepare_arguments ( arguments ) )
16
40
object ( arguments )
@@ -36,28 +60,97 @@ fn prepare_arguments(
36
60
result . all ( chunked )
37
61
}
38
62
39
- pub fn flag ( long_name long_name : String , short_name short_name : String ) {
40
- arg ( long_name , short_name , dynamic . bool ) |> with_default ( False )
63
+ /// A decoder that decodes String arguments.
64
+ /// # Examples
65
+ /// ```gleam
66
+ /// clad.string(long_name: "name", short_name: "n")
67
+ /// |> clad.decode(["-n", "Lucy"])
68
+ /// // -> Ok("Lucy")
69
+ /// ```
70
+ pub fn string (
71
+ long_name long_name : String ,
72
+ short_name short_name : String ,
73
+ ) -> Decoder ( String ) {
74
+ arg ( long_name , short_name , dynamic . string )
41
75
}
42
76
43
- pub fn arg (
77
+ /// A decoder that decodes Int arguments.
78
+ /// # Examples
79
+ /// ```gleam
80
+ /// clad.int(long_name: "count", short_name: "c")
81
+ /// |> clad.decode(["-c", "2"])
82
+ /// // -> Ok(2)
83
+ /// ```
84
+ pub fn int (
44
85
long_name long_name : String ,
45
86
short_name short_name : String ,
46
- of decoder : Decoder ( t) ,
47
- ) {
48
- dynamic . any ( [
49
- do_long_name ( long_name , decoder ) ,
50
- do_short_name ( short_name , decoder ) ,
51
- ] )
87
+ ) -> Decoder ( Int ) {
88
+ arg ( long_name , short_name , dynamic . int )
52
89
}
53
90
91
+ /// A decoder that decodes Float arguments.
92
+ /// # Examples
93
+ /// ```gleam
94
+ /// clad.float(long_name: "price", short_name: "p")
95
+ /// |> clad.decode(["--price", "2.50"])
96
+ /// // -> Ok(2.5)
97
+ /// ```
98
+ pub fn float (
99
+ long_name long_name : String ,
100
+ short_name short_name : String ,
101
+ ) -> Decoder ( Float ) {
102
+ arg ( long_name , short_name , dynamic . float )
103
+ }
104
+
105
+ /// A decoder that decodes Bool arguments.
106
+ /// # Examples
107
+ /// ```gleam
108
+ /// clad.bool(long_name: "verbose", short_name: "v")
109
+ /// |> clad.decode(["-v"])
110
+ /// // -> Ok(True)
111
+ /// ```
112
+ /// ```gleam
113
+ /// clad.bool(long_name: "verbose", short_name: "v")
114
+ /// |> clad.decode([])
115
+ /// // -> Ok(False)
116
+ /// ```
117
+ pub fn bool (
118
+ long_name long_name : String ,
119
+ short_name short_name : String ,
120
+ ) -> Decoder ( Bool ) {
121
+ arg ( long_name , short_name , dynamic . bool ) |> with_default ( False )
122
+ }
123
+
124
+ /// Provide a default value for a decoder.
125
+ /// # Examples
126
+ /// ```gleam
127
+ /// clad.int(long_name: "count", short_name: "c") |> clad.with_default(1)
128
+ /// |> clad.decode([])
129
+ /// // -> Ok(1)
130
+ /// ```
131
+ /// ```gleam
132
+ /// clad.int(long_name: "count", short_name: "c") |> clad.with_default(1)
133
+ /// |> clad.decode(["-c", "2"])
134
+ /// // -> Ok(2)
135
+ /// ```
54
136
pub fn with_default ( decoder : Decoder ( t) , default : t) -> Decoder ( t) {
55
137
fn ( data ) {
56
138
use _ <- result . try_recover ( decoder ( data ) )
57
139
Ok ( default )
58
140
}
59
141
}
60
142
143
+ fn arg (
144
+ long_name long_name : String ,
145
+ short_name short_name : String ,
146
+ of decoder : Decoder ( t) ,
147
+ ) -> Decoder ( t) {
148
+ dynamic . any ( [
149
+ do_long_name ( long_name , decoder ) ,
150
+ do_short_name ( short_name , decoder ) ,
151
+ ] )
152
+ }
153
+
61
154
fn do_long_name ( long_name : String , decoder : Decoder ( t) ) {
62
155
dynamic . field ( "--" <> long_name , decoder )
63
156
}
@@ -71,23 +164,23 @@ fn fail(expected: String, found: String) {
71
164
}
72
165
73
166
fn parse ( input : String ) -> Dynamic {
74
- try_float ( input )
75
- |> result . or ( try_int ( input ) )
76
- |> result . or ( try_bool ( input ) )
167
+ try_parse_float ( input )
168
+ |> result . or ( try_parse_int ( input ) )
169
+ |> result . or ( try_parse_bool ( input ) )
77
170
|> result . unwrap ( dynamic . from ( input ) )
78
171
}
79
172
80
- fn try_float ( input : String ) {
173
+ fn try_parse_float ( input : String ) {
81
174
float . parse ( input )
82
175
|> result . map ( dynamic . from )
83
176
}
84
177
85
- fn try_int ( input : String ) {
178
+ fn try_parse_int ( input : String ) {
86
179
int . parse ( input )
87
180
|> result . map ( dynamic . from )
88
181
}
89
182
90
- fn try_bool ( input : String ) {
183
+ fn try_parse_bool ( input : String ) {
91
184
case input {
92
185
"true" | "True" -> Ok ( dynamic . from ( True ) )
93
186
"false" | "False" -> Ok ( dynamic . from ( False ) )
0 commit comments