aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2022-01-01 23:27:58 +0000
committerLouis Pilfold <louis@lpil.uk>2022-01-01 23:27:58 +0000
commit9d40cdf444e0c73c192561658855f259cab6b507 (patch)
treee5caf8ed92dc4ae6cac4fda5d176e2d8117d118c
parent54d0699156d3d2ab7ac70c4099c7665381ba01b0 (diff)
downloadgleam_stdlib-9d40cdf444e0c73c192561658855f259cab6b507.tar.gz
gleam_stdlib-9d40cdf444e0c73c192561658855f259cab6b507.zip
Tuple decoders set path
-rw-r--r--CHANGELOG.md2
-rw-r--r--src/gleam/dynamic.gleam93
-rw-r--r--test/gleam/dynamic_test.gleam10
3 files changed, 80 insertions, 25 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a74ee6a..85afcef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,8 @@
- The `dynamic.typed_tuple*` functions have been renamed to `dynamic.tuple*`.
- The `dynamic.field` and `dynamic.element` functions now requires the type of
the field to be specified.
+- The `dynamic.DecodeError` now has a `path` field.
+- The decoder functions of the `dynamic` module now return multiple errors.
## v0.18.1 - 2021-12-19
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam
index 81a7a92..9a626dc 100644
--- a/src/gleam/dynamic.gleam
+++ b/src/gleam/dynamic.gleam
@@ -530,8 +530,12 @@ pub fn tuple2(
) -> Result(#(a, b), DecodeErrors) {
try _ = assert_is_tuple(value, 2)
let #(first, second) = unsafe_coerce(value)
- try a = decode_first(first)
- try b = decode_second(second)
+ try a =
+ decode_first(first)
+ |> map_errors(push_path(_, "0"))
+ try b =
+ decode_second(second)
+ |> map_errors(push_path(_, "1"))
Ok(#(a, b))
}
@@ -556,6 +560,19 @@ fn put_expected(error: DecodeError, expected: String) -> DecodeError {
DecodeError(..error, expected: expected)
}
+fn push_path(error: DecodeError, name: t) -> DecodeError {
+ let name = from(name)
+ let decoder = any(_, [string, fn(x) { result.map(int(x), int.to_string) }])
+ let name = case decoder(name) {
+ Ok(name) -> name
+ Error(_) ->
+ ["<", classify(name), ">"]
+ |> string_builder.from_strings
+ |> string_builder.to_string
+ }
+ DecodeError(..error, path: [name, ..error.path])
+}
+
/// Checks to see if a `Dynamic` value is a 3-element tuple containing
/// specifically typed elements.
///
@@ -581,9 +598,15 @@ pub fn tuple3(
) -> Result(#(a, b, c), DecodeErrors) {
try _ = assert_is_tuple(value, 3)
let #(first, second, third) = unsafe_coerce(value)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
+ try a =
+ decode_first(first)
+ |> map_errors(push_path(_, "0"))
+ try b =
+ decode_second(second)
+ |> map_errors(push_path(_, "1"))
+ try c =
+ decode_third(third)
+ |> map_errors(push_path(_, "2"))
Ok(#(a, b, c))
}
@@ -614,10 +637,18 @@ pub fn tuple4(
) -> Result(#(a, b, c, d), DecodeErrors) {
try _ = assert_is_tuple(value, 4)
let #(first, second, third, fourth) = unsafe_coerce(value)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
+ try a =
+ decode_first(first)
+ |> map_errors(push_path(_, "0"))
+ try b =
+ decode_second(second)
+ |> map_errors(push_path(_, "1"))
+ try c =
+ decode_third(third)
+ |> map_errors(push_path(_, "2"))
+ try d =
+ decode_fourth(fourth)
+ |> map_errors(push_path(_, "3"))
Ok(#(a, b, c, d))
}
@@ -648,11 +679,21 @@ pub fn tuple5(
) -> Result(#(a, b, c, d, e), DecodeErrors) {
try _ = assert_is_tuple(value, 5)
let #(first, second, third, fourth, fifth) = unsafe_coerce(value)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
- try e = decode_fifth(fifth)
+ try a =
+ decode_first(first)
+ |> map_errors(push_path(_, "0"))
+ try b =
+ decode_second(second)
+ |> map_errors(push_path(_, "1"))
+ try c =
+ decode_third(third)
+ |> map_errors(push_path(_, "2"))
+ try d =
+ decode_fourth(fourth)
+ |> map_errors(push_path(_, "3"))
+ try e =
+ decode_fifth(fifth)
+ |> map_errors(push_path(_, "4"))
Ok(#(a, b, c, d, e))
}
@@ -684,12 +725,24 @@ pub fn tuple6(
) -> Result(#(a, b, c, d, e, f), DecodeErrors) {
try _ = assert_is_tuple(value, 6)
let #(first, second, third, fourth, fifth, sixth) = unsafe_coerce(value)
- try a = decode_first(first)
- try b = decode_second(second)
- try c = decode_third(third)
- try d = decode_fourth(fourth)
- try e = decode_fifth(fifth)
- try f = decode_sixth(sixth)
+ try a =
+ decode_first(first)
+ |> map_errors(push_path(_, "0"))
+ try b =
+ decode_second(second)
+ |> map_errors(push_path(_, "1"))
+ try c =
+ decode_third(third)
+ |> map_errors(push_path(_, "2"))
+ try d =
+ decode_fourth(fourth)
+ |> map_errors(push_path(_, "3"))
+ try e =
+ decode_fifth(fifth)
+ |> map_errors(push_path(_, "4"))
+ try f =
+ decode_sixth(sixth)
+ |> map_errors(push_path(_, "5"))
Ok(#(a, b, c, d, e, f))
}
diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam
index f6622aa..7d490dc 100644
--- a/test/gleam/dynamic_test.gleam
+++ b/test/gleam/dynamic_test.gleam
@@ -380,7 +380,7 @@ pub fn tuple2_test() {
|> dynamic.from
|> dynamic.tuple2(dynamic.int, dynamic.int)
|> should.equal(Error([
- DecodeError(expected: "Int", found: "String", path: []),
+ DecodeError(expected: "Int", found: "String", path: ["1"]),
]))
#(1, 2, 3)
@@ -417,7 +417,7 @@ pub fn tuple3_test() {
|> dynamic.from
|> dynamic.tuple3(dynamic.int, dynamic.int, dynamic.int)
|> should.equal(Error([
- DecodeError(expected: "Int", found: "String", path: []),
+ DecodeError(expected: "Int", found: "String", path: ["2"]),
]))
#(1, 2)
@@ -454,7 +454,7 @@ pub fn tuple4_test() {
|> dynamic.from
|> dynamic.tuple4(dynamic.int, dynamic.int, dynamic.int, dynamic.int)
|> should.equal(Error([
- DecodeError(expected: "Int", found: "String", path: []),
+ DecodeError(expected: "Int", found: "String", path: ["3"]),
]))
#(1, 2)
@@ -509,7 +509,7 @@ pub fn tuple5_test() {
dynamic.int,
)
|> should.equal(Error([
- DecodeError(expected: "Int", found: "String", path: []),
+ DecodeError(expected: "Int", found: "String", path: ["4"]),
]))
#(1, 2)
@@ -579,7 +579,7 @@ pub fn tuple6_test() {
dynamic.int,
)
|> should.equal(Error([
- DecodeError(expected: "Int", found: "String", path: []),
+ DecodeError(expected: "Int", found: "String", path: ["5"]),
]))
#(1, 2)