Skip to content

Commit 5ad2ab3

Browse files
author
Ryan Miville
authored
Merge pull request #4 from ryanmiville/dynamic-decode
use dynamic/decode
2 parents d8e3c2b + fb18a17 commit 5ad2ab3

File tree

7 files changed

+107
-145
lines changed

7 files changed

+107
-145
lines changed

README.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@ This program is in the [examples directory](https://github.com/ryanmiville/clad/
2525
```gleam
2626
import argv
2727
import clad
28-
import decode/zero
28+
import gleam/dynamic/decode
2929
3030
pub type Student {
3131
Student(name: String, age: Int, enrolled: Bool, classes: List(String))
3232
}
3333
3434
pub fn main() {
3535
let decoder = {
36-
use name <- zero.field("name", zero.string)
37-
use age <- zero.field("age", zero.int)
38-
use enrolled <- zero.field("enrolled", zero.bool)
39-
use classes <- zero.field("class", zero.list(zero.string))
40-
zero.success(Student(name:, age:, enrolled:, classes:))
36+
use name <- decode.field("name", decode.string)
37+
use age <- decode.field("age", decode.int)
38+
use enrolled <- decode.field("enrolled", decode.bool)
39+
use classes <- decode.field("class", decode.list(decode.string))
40+
decode.success(Student(name:, age:, enrolled:, classes:))
4141
}
4242
4343
// args: --name Lucy --age 8 --enrolled true --class math --class art
@@ -51,19 +51,19 @@ Or, for more flexibility:
5151
```gleam
5252
import argv
5353
import clad
54-
import decode/zero
54+
import gleam/dynamic/decode
5555
5656
pub type Student {
5757
Student(name: String, age: Int, enrolled: Bool, classes: List(String))
5858
}
5959
6060
pub fn main() {
6161
let decoder = {
62-
use name <- clad.opt("name", "n", zero.string)
63-
use age <- clad.opt("age", "a", zero.int)
62+
use name <- clad.opt("name", "n", decode.string)
63+
use age <- clad.opt("age", "a", decode.int)
6464
use enrolled <- clad.flag("enrolled", "e")
65-
use classes <- clad.opt("class", "c", clad.list(zero.string))
66-
zero.success(Student(name:, age:, enrolled:, classes:))
65+
use classes <- clad.opt("class", "c", clad.list(decode.string))
66+
decode.success(Student(name:, age:, enrolled:, classes:))
6767
}
6868
6969
// args: --name=Lucy -ea8 -c math -c art

gleam.toml

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name = "clad"
2-
version = "0.3.1"
2+
version = "1.0.0"
33

44
# Fill out these fields if you intend to generate HTML documentation or publish
55
# your project to the Hex package manager.
@@ -14,7 +14,6 @@ repository = { type = "github", user = "ryanmiville", repo = "clad" }
1414

1515
[dependencies]
1616
gleam_stdlib = ">= 0.34.0 and < 2.0.0"
17-
decode = ">= 0.4.1 and < 1.0.0"
1817
gleam_regexp = ">= 1.0.0 and < 2.0.0"
1918

2019
[dev-dependencies]

manifest.toml

+2-4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,14 @@
33

44
packages = [
55
{ name = "argv", version = "1.0.2", build_tools = ["gleam"], requirements = [], otp_app = "argv", source = "hex", outer_checksum = "BA1FF0929525DEBA1CE67256E5ADF77A7CDDFE729E3E3F57A5BDCAA031DED09D" },
6-
{ name = "decode", version = "0.5.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "decode", source = "hex", outer_checksum = "05E14DC95A550BA51B8774485B04894B87A898C588B9B1C920104B110AED218B" },
7-
{ name = "gleam_json", version = "2.1.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "0A57FB5666E695FD2BEE74C0428A98B0FC11A395D2C7B4CDF5E22C5DD32C74C6" },
6+
{ name = "gleam_json", version = "2.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "093214EB186A88D301795A94F0A8128C2E24CF1423997ED31A6C6CC67FC3E1A1" },
87
{ name = "gleam_regexp", version = "1.0.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "A3655FDD288571E90EE9C4009B719FEF59FA16AFCDF3952A76A125AF23CF1592" },
9-
{ name = "gleam_stdlib", version = "0.46.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "53940A91251A6BE9AEBB959D46E1CB45B510551D81342A52213850947732D4AB" },
8+
{ name = "gleam_stdlib", version = "0.51.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "14AFA8D3DDD7045203D422715DBB822D1725992A31DF35A08D97389014B74B68" },
109
{ name = "gleeunit", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "F7A7228925D3EE7D0813C922E062BFD6D7E9310F0BEE585D3A42F3307E3CFD13" },
1110
]
1211

1312
[requirements]
1413
argv = { version = ">= 1.0.2 and < 2.0.0" }
15-
decode = { version = ">= 0.4.1 and < 1.0.0" }
1614
gleam_json = { version = ">= 2.0.0 and < 3.0.0" }
1715
gleam_regexp = { version = ">= 1.0.0 and < 2.0.0" }
1816
gleam_stdlib = { version = ">= 0.34.0 and < 2.0.0" }

src/clad.gleam

+53-87
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//// This module encodes a list of command line arguments as a `dynamic.Dynamic` and
2-
//// provides functions to decode those arguments using a `decode/zero.Decoder`.
2+
//// provides functions to decode those arguments using a `dynamic/decode.Decoder`.
33
////
44
//// # Encoding
55
////
@@ -24,17 +24,17 @@
2424
////
2525
//// # Decoding
2626
////
27-
//// Arguments can be decoded with a normal `zero.Decoder`
27+
//// Arguments can be decoded with a normal `dynamic/decode.Decoder`
2828
////
2929
//// ```gleam
3030
//// // args: --name Lucy --age 8 --enrolled true --class math --class art
3131
////
3232
//// let decoder = {
33-
//// use name <- zero.field("name", zero.string)
34-
//// use age <- zero.field("age", zero.int)
35-
//// use enrolled <- zero.field("enrolled", zero.bool)
36-
//// use classes <- zero.field("class", zero.list(zero.string))
37-
//// zero.success(Student(name:, age:, enrolled:, classes:))
33+
//// use name <- decode.field("name", decode.string)
34+
//// use age <- decode.field("age", decode.int)
35+
//// use enrolled <- decode.field("enrolled", decode.bool)
36+
//// use classes <- decode.field("class", decode.list(decode.string))
37+
//// decode.success(Student(name:, age:, enrolled:, classes:))
3838
//// }
3939
////
4040
//// let result = clad.decode(args, decoder)
@@ -55,43 +55,16 @@
5555
//// // args: --name Lucy --age 8 --enrolled true --class math
5656
////
5757
//// let decoder = {
58-
//// use name <- zero.field("name", zero.string)
59-
//// use age <- zero.field("age", zero.int)
60-
//// use enrolled <- zero.field("enrolled", zero.bool)
61-
//// use classes <- zero.field("class", clad.list(zero.string))
62-
//// zero.success(Student(name:, age:, enrolled:, classes:))
58+
//// use name <- decode.field("name", decode.string)
59+
//// use age <- decode.field("age", decode.int)
60+
//// use enrolled <- decode.field("enrolled", decode.bool)
61+
//// use classes <- decode.field("class", clad.list(decode.string))
62+
//// decode.success(Student(name:, age:, enrolled:, classes:))
6363
//// }
6464
////
6565
//// let result = clad.decode(args, decoder)
6666
//// assert result == Ok(Student("Lucy", 8, True, ["math"]))
6767
//// ```
68-
//// ## Boolean Flags
69-
////
70-
//// CLI's commonly represent boolean flags just by the precense or absence of the
71-
//// option. Since Clad has no knowledge of your target record, it cannot encode
72-
//// missing flags as False.
73-
////
74-
//// Clad provides the `flag()` decoder to handle this case.
75-
////
76-
//// ```gleam
77-
//// // args1: --name Lucy --age 8 --class math --class art --enrolled
78-
//// // args2: --name Bob --age 3 --class math
79-
////
80-
//// let decoder = {
81-
//// use name <- zero.field("name", zero.string)
82-
//// use age <- zero.field("age", zero.int)
83-
//// use enrolled <- zero.field("enrolled", clad.flag())
84-
//// use classes <- zero.field("class", clad.list(zero.string))
85-
//// zero.success(Student(name:, age:, enrolled:, classes:))
86-
//// }
87-
////
88-
//// let result = clad.decode(args1, decoder)
89-
//// assert result == Ok(Student("Lucy", 8, True, ["math", "art"]))
90-
////
91-
//// let result = clad.decode(args2, decoder)
92-
//// assert result == Ok(Student("Bob", 3, False, ["math"]))
93-
//// ```
94-
////
9568
//// ## Alternate Names
9669
////
9770
//// It is also common for CLI's to support long names and short names for options
@@ -100,15 +73,15 @@
10073
//// Clad provides the `opt()` function for this.
10174
////
10275
//// ```gleam
103-
//// // args1: -n Lucy -a 8 -e -c math -c art
104-
//// // args2: --name Bob --age 3 --class math
76+
//// // args1: -n Lucy -a 8 -e true -c math -c art
77+
//// // args2: --name Bob --age 3 --enrolled false --class math
10578
////
10679
//// let decoder = {
107-
//// use name <- clad.opt(long_name: "name", short_name: "n", zero.string)
108-
//// use age <- clad.opt(long_name: "age", short_name: "a", zero.int)
109-
//// use enrolled <- clad.opt(long_name: "enrolled", short_name: "e" clad.flag())
110-
//// use classes <- clad.opt(long_name: "class", short_name: "c", clad.list(zero.string))
111-
//// zero.success(Student(name:, age:, enrolled:, classes:))
80+
//// use name <- clad.opt(long_name: "name", short_name: "n", decode.string)
81+
//// use age <- clad.opt(long_name: "age", short_name: "a", decode.int)
82+
//// use enrolled <- clad.opt(long_name: "enrolled", short_name: "e", decode.bool)
83+
//// use classes <- clad.opt(long_name: "class", short_name: "c", clad.list(decode.string))
84+
//// decode.success(Student(name:, age:, enrolled:, classes:))
11285
//// }
11386
////
11487
//// let result = clad.decode(args1, decoder)
@@ -117,43 +90,36 @@
11790
//// let result = clad.decode(args2, decoder)
11891
//// assert result == Ok(Student("Bob", 3, False, ["math"]))
11992
//// ```
93+
//// ## Boolean Flags
12094
////
121-
//// ## Positional Arguments
95+
//// CLI's commonly represent boolean flags just by the precense or absence of the
96+
//// option. Since Clad has no knowledge of your target record, it cannot encode
97+
//// missing flags as False.
12298
////
123-
//// A CLI may also support positional arguments. These are any arguments that are
124-
//// not attributed to a named option. Clad provides the `positional_arguments()` decoder to
125-
//// retrieve these values. All arguments followed by a `--` will be added to the positional arguemnts.
99+
//// Clad provides the `flag()` decoder to handle this case.
126100
////
127101
//// ```gleam
128-
//// // args1: -n Lucy -ea8 -c math -c art -- Lucy is a star student!
129-
//// // args2: --name Bob who is --age 3 --class math Bob -- -idk
102+
//// // args1: --name Lucy --age 8 --class math --class art --enrolled
103+
//// // args2: --name Bob --age 3 --class math
130104
////
131105
//// let decoder = {
132-
//// use name <- clad.opt("name", "n", zero.string)
133-
//// use age <- clad.opt("age", "a", zero.int)
134-
//// use enrolled <- clad.opt("enrolled", "e" clad.flag())
135-
//// use classes <- clad.opt(long_name: "class", short_name: "c", clad.list(zero.string))
136-
//// use notes <- clad.positional_arguments()
137-
//// let notes = string.join(notes, " ")
138-
//// zero.success(Student(name:, age:, enrolled:, classes:, notes:))
106+
//// use name <- clad.opt(long_name: "name", short_name: "n", decode.string)
107+
//// use age <- clad.opt(long_name: "age", short_name: "a", decode.int)
108+
//// use enrolled <- clad.flag(long_name: "enrolled", short_name: "e")
109+
//// use classes <- clad.opt(long_name: "class", short_name: "c", clad.list(decode.string))
110+
//// decode.success(Student(name:, age:, enrolled:, classes:))
139111
//// }
140112
////
141113
//// let result = clad.decode(args1, decoder)
142-
//// let assert Ok(Student(
143-
//// "Lucy",
144-
//// 8,
145-
//// True,
146-
//// ["math", "art"],
147-
//// "Lucy is a star student!",
148-
//// )) = result
114+
//// assert result == Ok(Student("Lucy", 8, True, ["math", "art"]))
149115
////
150116
//// let result = clad.decode(args2, decoder)
151-
//// assert result == Ok(Student("Bob", 3, False, ["math"], "who is Bob -idk"))
117+
//// assert result == Ok(Student("Bob", 3, False, ["math"]))
152118
//// ```
153119

154-
import decode/zero.{type Decoder}
155120
import gleam/dict.{type Dict}
156-
import gleam/dynamic.{type Dynamic}
121+
import gleam/dynamic
122+
import gleam/dynamic/decode.{type DecodeError, type Decoder, type Dynamic}
157123
import gleam/float
158124
import gleam/int
159125
import gleam/list
@@ -182,8 +148,8 @@ type State {
182148
/// // args: --name Lucy [email protected]
183149
///
184150
/// let decoder = {
185-
/// use name <- zero.field("name", dynamic.string)
186-
/// use email <- zero.field("email", dynamic.string),
151+
/// use name <- decode.field("name", dynamic.string)
152+
/// use email <- decode.field("email", dynamic.string),
187153
/// clad.decoded(SignUp(name:, email:))
188154
/// }
189155
///
@@ -193,10 +159,10 @@ type State {
193159
pub fn decode(
194160
args: List(String),
195161
decoder: Decoder(t),
196-
) -> Result(t, List(dynamic.DecodeError)) {
162+
) -> Result(t, List(DecodeError)) {
197163
parse(args)
198164
|> to_dynamic
199-
|> zero.run(decoder)
165+
|> decode.run(decoder)
200166
}
201167

202168
/// Get all of the unnamed, positional arguments
@@ -205,7 +171,7 @@ pub fn decode(
205171
/// ```gleam
206172
/// let decoder = {
207173
/// use positional <- clad.positional_arguments
208-
/// zero.success(positional)
174+
/// decode.success(positional)
209175
/// }
210176
/// let result = clad.decode(["-a1", "hello", "-b", "2", "world"], decoder)
211177
/// assert result == Ok(["hello", "world"])
@@ -219,15 +185,15 @@ pub fn decode(
219185
pub fn positional_arguments(
220186
next: fn(List(String)) -> Decoder(final),
221187
) -> Decoder(final) {
222-
use args <- zero.field(positional_arg_name, zero.list(zero.string))
188+
use args <- decode.field(positional_arg_name, decode.list(decode.string))
223189
next(args)
224190
}
225191

226192
/// Decode a command line flag as a Bool. Returns False if value is not present
227193
/// ```gleam
228194
/// let decoder = {
229-
/// use verbose <- clad.flag("verbose", "v", clad.flag())
230-
/// zero.success(verbose)
195+
/// use verbose <- clad.flag("verbose", "v", decode.bool)
196+
/// decode.success(verbose)
231197
/// }
232198
/// let result = clad.decode(["-v"], decoder)
233199
/// assert result == Ok(True)
@@ -243,10 +209,10 @@ pub fn flag(
243209
short_name: String,
244210
next: fn(Bool) -> Decoder(final),
245211
) -> Decoder(final) {
246-
use value <- optional_field(long_name, zero.bool)
212+
use value <- optional_field(long_name, decode.bool)
247213
case value {
248214
Some(v) -> next(v)
249-
None -> zero.optional_field(short_name, False, zero.bool, next)
215+
None -> decode.optional_field(short_name, False, decode.bool, next)
250216
}
251217
}
252218

@@ -255,14 +221,14 @@ fn optional_field(
255221
field_decoder: Decoder(t),
256222
next: fn(Option(t)) -> Decoder(final),
257223
) -> Decoder(final) {
258-
zero.optional_field(field_name, None, zero.optional(field_decoder), next)
224+
decode.optional_field(field_name, None, decode.optional(field_decoder), next)
259225
}
260226

261227
/// Decode a command line option by either a long name or short name
262228
/// ```gleam
263229
/// let decoder = {
264-
/// use name <- clad.opt("name", "n", zero.string)
265-
/// zero.success(name)
230+
/// use name <- clad.opt("name", "n", decode.string)
231+
/// decode.success(name)
266232
/// }
267233
///
268234
/// let result = clad.decode(["--name", "Lucy"], decoder)
@@ -280,7 +246,7 @@ pub fn opt(
280246
use value <- optional_field(long_name, field_decoder)
281247
case value {
282248
Some(v) -> next(v)
283-
None -> zero.field(short_name, field_decoder, next)
249+
None -> decode.field(short_name, field_decoder, next)
284250
}
285251
}
286252

@@ -289,15 +255,15 @@ pub fn opt(
289255
/// encoded as the inner type rather than a list.
290256
/// ```gleam
291257
/// let decoder = {
292-
/// use classes <- zero.field("class", clad.list(zero.string))
293-
/// zero.success(classes)
258+
/// use classes <- decode.field("class", clad.list(decode.string))
259+
/// decode.success(classes)
294260
/// }
295261
/// let result = clad.decode(["--class", "art"], decoder)
296262
/// assert result == Ok(["art"])
297263
/// ```
298264
pub fn list(of inner: Decoder(a)) -> Decoder(List(a)) {
299-
let single = inner |> zero.map(list.wrap)
300-
zero.one_of(zero.list(inner), [single])
265+
let single = inner |> decode.map(list.wrap)
266+
decode.one_of(decode.list(inner), [single])
301267
}
302268

303269
fn parse(args: List(String)) -> State {

0 commit comments

Comments
 (0)