aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLouis Pilfold <louis@lpil.uk>2020-05-19 18:27:10 +0100
committerLouis Pilfold <louis@lpil.uk>2020-05-19 19:22:49 +0100
commitcbf07061be7524aa049864b6dec49715e641499a (patch)
tree8a409378ba4e94461ad13d29d97b29d3a6322bdc /src
parentf3c4b7a3170fb4beb7483bba929d1eca616f48df (diff)
downloadgleam_stdlib-cbf07061be7524aa049864b6dec49715e641499a.tar.gz
gleam_stdlib-cbf07061be7524aa049864b6dec49715e641499a.zip
dynamic.{tuple2, tuple2_of}
Diffstat (limited to 'src')
-rw-r--r--src/gleam/dynamic.gleam63
-rw-r--r--src/gleam/uri.gleam13
-rw-r--r--src/gleam_stdlib.erl20
3 files changed, 84 insertions, 12 deletions
diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam
index bab30d3..e7e665d 100644
--- a/src/gleam/dynamic.gleam
+++ b/src/gleam/dynamic.gleam
@@ -7,6 +7,9 @@ import gleam/result
/// IO with the outside world.
pub external type Dynamic
+pub type Decoder(t) =
+ fn(Dynamic) -> Result(t, String)
+
/// Convert any Gleam data into `Dynamic` data.
///
pub external fn from(a) -> Dynamic =
@@ -158,7 +161,7 @@ pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, String) =
/// ## Examples
///
/// > element(from(tuple(1, 2)), 0)
-/// Ok(Dynamic)
+/// Ok(from(1))
///
/// > element(from(tuple(1, 2)), 2)
/// Error("Expected a tuple of at least 3 size, got a tuple of 2 size")
@@ -171,3 +174,61 @@ pub external fn element(
position: Int,
) -> Result(Dynamic, String) =
"gleam_stdlib" "decode_element"
+
+/// Check to see if the Dynamic value is a 2 element tuple.
+///
+/// ## Examples
+///
+/// > tuple2(from(tuple(1, 2)))
+/// Ok(tuple(from(1), from(2)))
+///
+/// > tuple2(from(tuple(1, 2)))
+/// Error("Expected a 2 element tuple")
+///
+/// > tuple2(from(""))
+/// Error("Expected a Tuple, got a binary")
+///
+pub external fn tuple2(
+ from: Dynamic,
+) -> Result(tuple(Dynamic, Dynamic), String) =
+ "gleam_stdlib" "decode_tuple2"
+
+/// Check to see if the Dynamic value is a 2 element tuple containing two
+/// specifically typed elements.
+///
+/// ## Examples
+///
+/// > tuple2_of(from(tuple(1, 2)), int, int)
+/// Ok(tuple(1, 2))
+///
+/// > tuple2_of(from(tuple(1, 2.0)), int, float)
+/// Ok(tuple(1, 2.0))
+///
+/// > tuple2_of(from(tuple(1, 2)), int, float)
+/// Error("Expected a 2 element tuple")
+///
+/// > tuple2_of(from(""), int, float)
+/// Error("Expected a Tuple, got a binary")
+///
+pub fn tuple2_of(
+ from tup: Dynamic,
+ first decode_first: Decoder(a),
+ second decode_second: Decoder(b),
+) -> Result(tuple(a, b), String) {
+ tup
+ |> tuple2
+ |> result.then(
+ fn(tup) {
+ let tuple(first, second) = tup
+ decode_first(first)
+ |> result.map(fn(first) { tuple(first, second) })
+ },
+ )
+ |> result.then(
+ fn(tup) {
+ let tuple(first, second) = tup
+ decode_second(second)
+ |> result.map(fn(second) { tuple(first, second) })
+ },
+ )
+}
diff --git a/src/gleam/uri.gleam b/src/gleam/uri.gleam
index 21145df..8536d98 100644
--- a/src/gleam/uri.gleam
+++ b/src/gleam/uri.gleam
@@ -35,15 +35,20 @@ pub type Uri {
pub external fn parse(String) -> Result(Uri, Nil) =
"gleam_uri_native" "parse"
+external fn erl_parse_query(String) -> Dynamic =
+ "uri_string" "dissect_query"
+
/// Parses an urlencoded query string into a list of key value pairs.
/// Returns an error for invalid encoding.
///
/// The opposite operation is `uri.query_to_string`.
///
-pub external fn parse_query(
- String,
-) -> Result(List(tuple(String, String)), Nil) =
- "gleam_uri_native" "parse_query"
+pub fn parse_query(query: String) -> Option(List(tuple(String, String))) {
+ query
+ |> erl_parse_query
+ |> dynamic.list(dynamic.tuple2_of(_, dynamic.string, dynamic.string))
+ |> result.map_error(fn(_) { Nil })
+}
type Encoding {
Utf8
diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl
index bbf7630..e12ee87 100644
--- a/src/gleam_stdlib.erl
+++ b/src/gleam_stdlib.erl
@@ -1,13 +1,15 @@
-module(gleam_stdlib).
-include_lib("eunit/include/eunit.hrl").
--export([should_equal/2, should_not_equal/2, should_be_true/1, should_be_false/1,
- should_be_ok/1, should_be_error/1, atom_from_string/1,
- atom_create_from_string/1, atom_to_string/1, map_get/2,
- iodata_append/2, iodata_prepend/2, identity/1, decode_int/1,
- decode_string/1, decode_bool/1, decode_float/1, decode_thunk/1, decode_atom/1,
- decode_list/1, decode_field/2, decode_element/2, parse_int/1, parse_float/1, compare_strings/2,
- string_contains/2, string_starts_with/2, string_ends_with/2, string_pad/4]).
+-export([should_equal/2, should_not_equal/2, should_be_true/1,
+ should_be_false/1, should_be_ok/1, should_be_error/1,
+ atom_from_string/1, atom_create_from_string/1, atom_to_string/1,
+ map_get/2, iodata_append/2, iodata_prepend/2, identity/1,
+ decode_int/1, decode_string/1, decode_bool/1, decode_float/1,
+ decode_thunk/1, decode_atom/1, decode_list/1, decode_field/2,
+ decode_element/2, parse_int/1, parse_float/1, compare_strings/2,
+ string_contains/2, string_starts_with/2, string_ends_with/2,
+ string_pad/4, decode_tuple2/1]).
should_equal(Actual, Expected) -> ?assertEqual(Expected, Actual).
should_not_equal(Actual, Expected) -> ?assertNotEqual(Expected, Actual).
@@ -48,8 +50,12 @@ classify(X) when is_float(X) -> "a float";
classify(X) when is_list(X) -> "a list";
classify(X) when is_boolean(X) -> "a bool";
classify(X) when is_function(X, 0) -> "a zero arity function";
+classify(X) when is_tuple(X) -> ["a ", integer_to_list(tuple_size(X)), " element tuple"];
classify(_) -> "some other type".
+decode_tuple2({_, _} = T) -> {ok, T};
+decode_tuple2(Data) -> decode_error_msg("a 2 element tuple", Data).
+
decode_atom(Data) when is_atom(Data) -> {ok, Data};
decode_atom(Data) -> decode_error_msg("an atom", Data).