diff options
author | Louis Pilfold <louis@lpil.uk> | 2021-09-09 21:25:11 +0100 |
---|---|---|
committer | Louis Pilfold <louis@lpil.uk> | 2021-09-09 21:25:11 +0100 |
commit | bb88a32d105da31e5cdd2ad713016c88b96ac0ce (patch) | |
tree | 5f233af161c86fcc3813bee4d006fe35125f5bdd | |
parent | 70136ec67863b0c97b9845edc13c6841eee033fc (diff) | |
download | gleam_stdlib-bb88a32d105da31e5cdd2ad713016c88b96ac0ce.tar.gz gleam_stdlib-bb88a32d105da31e5cdd2ad713016c88b96ac0ce.zip |
JS dynamic element
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/gleam/dynamic.gleam | 49 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 3 | ||||
-rw-r--r-- | src/gleam_stdlib.js | 26 | ||||
-rw-r--r-- | test/gleam/dynamic_test.gleam | 82 |
5 files changed, 109 insertions, 53 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 14654fc..5d1d19c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ permissive to other null values. - The `dynamic.result` function has been made more permissive to other result values. - The `dynamic.thunk` function has been removed. +- The `dynamic.element` label `postion` was renamed to `get`. +- The `dynamic.element` now accepts negative indexes. - The `io.get_line` function has been moved to the `gleam_erlang` library. - The `atom` module has been moved to the `gleam_erlang` library. - Prelude types like `Result`, `List` etc. are no longer redefined in their diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam index 903341a..d494550 100644 --- a/src/gleam/dynamic.gleam +++ b/src/gleam/dynamic.gleam @@ -341,27 +341,40 @@ if erlang { /// pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, DecodeError) = "gleam_stdlib" "decode_field" +} - /// Checks to see if the Dynamic value is a tuple large enough to have a certain - /// index, and return the value of that index if it is. - /// - /// ## Examples - /// - /// > element(from(#(1, 2)), 0) - /// Ok(from(1)) - /// - /// > element(from(#(1, 2)), 2) - /// Error(DecodeError(expected: "3 element tuple", found: "2 element tuple")) - /// - /// > element(from(""), 2) - /// Error(DecodeError(expected: "Tuple", found: "String")) - /// - pub external fn element( - from: Dynamic, - position: Int, - ) -> Result(Dynamic, DecodeError) = +/// Checks to see if the Dynamic value is a tuple large enough to have a certain +/// index, and return the value of that index if it is. +/// +/// ## Examples +/// +/// > element(from(#(1, 2)), 0) +/// Ok(from(1)) +/// +/// > element(from(#(1, 2)), 2) +/// Error(DecodeError(expected: "3 element tuple", found: "2 element tuple")) +/// +/// > element(from(""), 2) +/// Error(DecodeError(expected: "Tuple", found: "String")) +/// +pub fn element( + from data: Dynamic, + get index: Int, +) -> Result(Dynamic, DecodeError) { + decode_element(data, index) +} + +if erlang { + external fn decode_element(Dynamic, Int) -> Result(a, DecodeError) = "gleam_stdlib" "decode_element" +} +if javascript { + external fn decode_element(Dynamic, Int) -> Result(a, DecodeError) = + "../gleam_stdlib.js" "decode_element" +} + +if erlang { /// Checks to see if the Dynamic value is a 2 element tuple. /// /// If you do not wish to decode all the elements in the tuple use the diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index 9429f71..92cae8e 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -111,7 +111,8 @@ decode_field(Data, Key) -> decode_element(Data, Position) when is_tuple(Data) -> case catch element(Position + 1, Data) of {'EXIT', _Reason} -> - decode_error_msg(["a tuple of at least ", integer_to_list(Position + 1), " size"], Data); + Msg = ["Tuple of at least ", integer_to_list(Position + 1), " elements"], + decode_error_msg(list_to_binary(Msg), Data); Value -> {ok, Value} diff --git a/src/gleam_stdlib.js b/src/gleam_stdlib.js index 0982f62..9a80a6d 100644 --- a/src/gleam_stdlib.js +++ b/src/gleam_stdlib.js @@ -476,8 +476,12 @@ function classify_dynamic(data) { return "List"; } else if (Number.isInteger(data)) { return "Int"; + } else if (Array.isArray(data)) { + return `Tuple of ${data.length} elements`; } else if (BitString.isBitString(data)) { return "BitString"; + } else if (data instanceof Map) { + return "Map"; } else if (typeof data === "number") { return "Float"; } else { @@ -513,3 +517,25 @@ export function decode_bit_string(data) { ? new Ok(data) : decoder_error("BitString", data); } + +export function decode_element(data, index) { + let error = (size) => + decoder_error( + `Tuple of at least ${size} element${size > 1 ? "s" : ""}`, + data + ); + if (!Array.isArray(data)) return error(index < 0 ? 1 : index + 1); + if (index >= 0) { + if (index < data.length) { + return new Ok(data[index]); + } else { + return error(index + 1); + } + } else { + if (Math.abs(index) <= data.length) { + return new Ok(data[data.length + index]); + } else { + return error(Math.abs(index)); + } + } +} diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam index c65f98c..4ab3d65 100644 --- a/test/gleam/dynamic_test.gleam +++ b/test/gleam/dynamic_test.gleam @@ -1,11 +1,11 @@ import gleam/should import gleam/dynamic.{DecodeError} import gleam/bit_string +import gleam/map if erlang { import gleam/list import gleam/result - import gleam/map import gleam/option.{None, Some} } @@ -86,11 +86,6 @@ pub fn int_test() { |> dynamic.from |> dynamic.int |> should.equal(Error(DecodeError(expected: "Int", found: "List"))) - - <<1>> - |> dynamic.from - |> dynamic.int - |> should.equal(Error(DecodeError(expected: "Int", found: "BitString"))) } pub fn float_test() { @@ -259,42 +254,61 @@ if erlang { |> dynamic.field([]) |> should.be_error } +} - pub fn element_test() { - let ok_one_tuple = #("ok", 1) +pub fn element_test() { + let ok_one_tuple = #("ok", 1) - ok_one_tuple - |> dynamic.from - |> dynamic.element(0) - |> should.equal(Ok(dynamic.from("ok"))) + ok_one_tuple + |> dynamic.from + |> dynamic.element(0) + |> should.equal(Ok(dynamic.from("ok"))) - ok_one_tuple - |> dynamic.from - |> dynamic.element(1) - |> should.equal(Ok(dynamic.from(1))) + ok_one_tuple + |> dynamic.from + |> dynamic.element(1) + |> should.equal(Ok(dynamic.from(1))) - ok_one_tuple - |> dynamic.from - |> dynamic.element(2) - |> should.be_error + ok_one_tuple + |> dynamic.from + |> dynamic.element(2) + |> should.equal(Error(DecodeError( + expected: "Tuple of at least 3 elements", + found: "Tuple of 2 elements", + ))) - ok_one_tuple - |> dynamic.from - |> dynamic.element(-1) - |> should.be_error + ok_one_tuple + |> dynamic.from + |> dynamic.element(-1) + |> should.equal(Ok(dynamic.from(1))) - 1 - |> dynamic.from - |> dynamic.element(0) - |> should.be_error + ok_one_tuple + |> dynamic.from + |> dynamic.element(-3) + |> should.equal(Error(DecodeError( + expected: "Tuple of at least 3 elements", + found: "Tuple of 2 elements", + ))) - map.new() - |> map.insert(1, "ok") - |> dynamic.from - |> dynamic.element(0) - |> should.be_error - } + 1 + |> dynamic.from + |> dynamic.element(0) + |> should.equal(Error(DecodeError( + expected: "Tuple of at least 1 element", + found: "Int", + ))) + + map.new() + |> map.insert(1, "ok") + |> dynamic.from + |> dynamic.element(0) + |> should.equal(Error(DecodeError( + expected: "Tuple of at least 1 element", + found: "Map", + ))) +} +if erlang { pub fn tuple2_test() { #(1, 2) |> dynamic.from |