diff options
author | Louis Pilfold <louis@lpil.uk> | 2021-09-10 20:32:50 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2021-09-10 20:32:50 +0100 |
commit | a6b75f614c97f7cf2bede89b5769bfcd13c31571 (patch) | |
tree | c6db67376e64f69759051488134f7c8dc8267d65 | |
parent | 72889a32caa561ffe083a7c921f856c23c0ee5f6 (diff) | |
download | gleam_stdlib-a6b75f614c97f7cf2bede89b5769bfcd13c31571.tar.gz gleam_stdlib-a6b75f614c97f7cf2bede89b5769bfcd13c31571.zip |
Optional
-rw-r--r-- | src/gleam/dynamic.gleam | 78 | ||||
-rw-r--r-- | src/gleam_stdlib.js | 12 | ||||
-rw-r--r-- | test/gleam/dynamic_test.gleam | 40 |
3 files changed, 78 insertions, 52 deletions
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam index 726fbeb..2175461 100644 --- a/src/gleam/dynamic.gleam +++ b/src/gleam/dynamic.gleam @@ -6,10 +6,7 @@ import gleam/option import gleam/result import gleam/string_builder import gleam/map.{Map} - -if erlang { - import gleam/option.{Option} -} +import gleam/option.{Option} /// `Dynamic` data is data that we don't know the type of yet. /// We likely get data like this from interop with Erlang, or from @@ -339,36 +336,53 @@ pub fn typed_list( |> result.then(list.try_map(_, decoder_type)) } +/// Checks to see if a Dynamic value is a nullable version of a particular +/// type, and return the Option if it is. +/// +/// ## Examples +/// +/// > option(from("Hello"), string) +/// Ok(Some("Hello")) +/// +/// > option(from("Hello"), string) +/// Ok(Some("Hello")) +/// +/// > option(from(atom.from_string("null")), string) +/// Ok(None) +/// +/// > option(from(atom.from_string("nil")), string) +/// Ok(None) +/// +/// > option(from(atom.from_string("undefined")), string) +/// Ok(None) +/// +/// > option(from(123), string) +/// Error(DecodeError(expected: "BitString", found: "Int")) +/// +pub fn optional( + from value: Dynamic, + of decode: Decoder(inner), +) -> Result(Option(inner), DecodeError) { + decode_optional(value, decode) +} + if erlang { - /// Checks to see if a Dynamic value is a nullable version of a particular - /// type, and return the Option if it is. - /// - /// ## Examples - /// - /// > option(from("Hello"), string) - /// Ok(Some("Hello")) - /// - /// > option(from("Hello"), string) - /// Ok(Some("Hello")) - /// - /// > option(from(atom.from_string("null")), string) - /// Ok(None) - /// - /// > option(from(atom.from_string("nil")), string) - /// Ok(None) - /// - /// > option(from(atom.from_string("undefined")), string) - /// Ok(None) - /// - /// > option(from(123), string) - /// Error(DecodeError(expected: "BitString", found: "Int")) - /// - pub external fn optional( - from: Dynamic, - of: Decoder(inner), - ) -> Result(Option(inner), DecodeError) = - "gleam_stdlib" "decode_optional" + external fn decode_optional( + Dynamic, + Decoder(Option(a)), + ) -> Result(a, DecodeError) = + "gleam_stdlib" "decode_optionl" +} +if javascript { + external fn decode_optional( + Dynamic, + Decoder(a), + ) -> Result(Option(a), DecodeError) = + "../gleam_stdlib.js" "decode_option" +} + +if erlang { /// Checks to see if a Dynamic value is a map with a specific field, and return /// the value of the field if it is. /// diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js index 4c52daf..37f071a 100644 --- a/src/gleam_stdlib.js +++ b/src/gleam_stdlib.js @@ -540,3 +540,15 @@ export function decode_result(data) { export function decode_map(data) { return data instanceof Map ? new Ok(data) : decoder_error("Map", data); } + +export function decode_option(data, decoder) { + if (data === null || data === undefined || data instanceof None) + return new Ok(new None()); + if (data instanceof Some) data = data[0]; + let result = decoder(data); + if (result.isOk()) { + return new Ok(new Some(result[0])); + } else { + return result; + } +} diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam index 2fb4a2a..c062d91 100644 --- a/test/gleam/dynamic_test.gleam +++ b/test/gleam/dynamic_test.gleam @@ -2,11 +2,11 @@ import gleam/should import gleam/dynamic.{DecodeError} import gleam/bit_string import gleam/map +import gleam/option.{None, Some} if erlang { import gleam/list import gleam/result - import gleam/option.{None, Some} } pub fn bit_string_test() { @@ -202,29 +202,29 @@ pub fn typed_list_test() { |> should.be_error } -if erlang { - pub fn optional_test() { - 1 - |> dynamic.from - |> dynamic.optional(dynamic.int) - |> should.equal(Ok(Some(1))) +pub fn optional_test() { + 1 + |> dynamic.from + |> dynamic.optional(dynamic.int) + |> should.equal(Ok(Some(1))) - option.None - |> dynamic.from - |> dynamic.optional(dynamic.int) - |> should.equal(Ok(None)) + option.None + |> dynamic.from + |> dynamic.optional(dynamic.int) + |> should.equal(Ok(None)) - Nil - |> dynamic.from - |> dynamic.optional(dynamic.int) - |> should.equal(Ok(None)) + Nil + |> dynamic.from + |> dynamic.optional(dynamic.int) + |> should.equal(Ok(None)) - 1 - |> dynamic.from - |> dynamic.optional(dynamic.string) - |> should.be_error - } + 1 + |> dynamic.from + |> dynamic.optional(dynamic.string) + |> should.be_error +} +if erlang { pub fn field_test() { map.new() |> map.insert("ok", 1) |