From 1ee8dbf4c7e5abf831e3118f8953b24c4043e70f Mon Sep 17 00:00:00 2001 From: Louis Pilfold Date: Tue, 19 May 2020 19:20:48 +0100 Subject: dynamic.map --- src/gleam/dynamic.gleam | 28 +++++++++++++++++++----- src/gleam/gleam_uri_native.erl | 27 ------------------------ src/gleam/uri.gleam | 48 +++++++++++++++++++++++++++++++----------- src/gleam_stdlib.erl | 5 ++++- 4 files changed, 63 insertions(+), 45 deletions(-) delete mode 100644 src/gleam/gleam_uri_native.erl (limited to 'src') diff --git a/src/gleam/dynamic.gleam b/src/gleam/dynamic.gleam index e7e665d..89826ec 100644 --- a/src/gleam/dynamic.gleam +++ b/src/gleam/dynamic.gleam @@ -1,5 +1,6 @@ import gleam/list as list_mod import gleam/atom +import gleam/map.{Map} import gleam/result /// `Dynamic` data is data that we don"t know the type of yet. @@ -167,7 +168,7 @@ pub external fn field(from: Dynamic, named: a) -> Result(Dynamic, String) = /// Error("Expected a tuple of at least 3 size, got a tuple of 2 size") /// /// > element(from(""), 2) -/// Error("Expected a Tuple, got a binary") +/// Error("Expected a tuple, got a binary") /// pub external fn element( from: Dynamic, @@ -186,7 +187,7 @@ pub external fn element( /// Error("Expected a 2 element tuple") /// /// > tuple2(from("")) -/// Error("Expected a Tuple, got a binary") +/// Error("Expected a tuple, got a binary") /// pub external fn tuple2( from: Dynamic, @@ -204,11 +205,11 @@ pub external fn tuple2( /// > 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(tuple(1, 2, 3)), int, float) +/// Error("Expected a 2 element tuple, got a 3 element tuple") /// /// > tuple2_of(from(""), int, float) -/// Error("Expected a Tuple, got a binary") +/// Error("Expected a tuple, got a binary") /// pub fn tuple2_of( from tup: Dynamic, @@ -232,3 +233,20 @@ pub fn tuple2_of( }, ) } + +/// Check to see if the Dynamic value is map. +/// +/// ## Examples +/// +/// > import gleam/map as map_mod +/// > map(from(map_mod.new())) +/// Ok(map_mod.new()) +/// +/// > map(from(1)) +/// Error("Expected a 2 element tuple, got an int") +/// +/// > map(from("")) +/// Error("Expected a map, got a binary") +/// +pub external fn map(from: Dynamic) -> Result(Map(Dynamic, Dynamic), String) = + "gleam_stdlib" "decode_map" diff --git a/src/gleam/gleam_uri_native.erl b/src/gleam/gleam_uri_native.erl deleted file mode 100644 index dafd406..0000000 --- a/src/gleam/gleam_uri_native.erl +++ /dev/null @@ -1,27 +0,0 @@ --module (gleam_uri_native). --export ([parse/1]). - -find_key(Key, Map) -> - case maps:find(Key, Map) of - {ok, Value} -> - {ok, Value}; - error -> - {error, nil} - end. - -parse(String) -> - case uri_string:parse(String) of - {error, _Reason, _Term} -> - {error, nil}; - Map -> - {ok, { - uri, - find_key(scheme, Map), - find_key(userinfo, Map), - find_key(host, Map), - find_key(port, Map), - maps:get(path, Map), - find_key(query, Map), - find_key(fragment, Map) - }} - end. diff --git a/src/gleam/uri.gleam b/src/gleam/uri.gleam index a62cf3c..19feb27 100644 --- a/src/gleam/uri.gleam +++ b/src/gleam/uri.gleam @@ -28,13 +28,47 @@ pub type Uri { ) } +pub external fn erl_parse(String) -> Dynamic = + "uri_string" "parse" + +type UriKey { + Scheme + Userinfo + Host + Port + Path + Query + Fragment +} + /// Parses a complient URI string into the `Uri` Type. /// If the string is not a valid URI string then an error is returned. /// /// The opposite operation is `uri.to_string` /// -pub external fn parse(String) -> Result(Uri, Nil) = - "gleam_uri_native" "parse" +pub fn parse(string: String) -> Result(Uri, Nil) { + case dynamic.map(erl_parse(string)) { + Error(_) -> Error(Nil) + Ok(uri_map) -> { + let get = fn(k, decoder: dynamic.Decoder(t)) { + uri_map + |> map.get(dynamic.from(k)) + |> result.then(fn(x) { result.map_error(decoder(x), fn(_) { Nil }) }) + } + + let uri = Uri( + scheme: get(Scheme, dynamic.string), + userinfo: get(Userinfo, dynamic.string), + host: get(Host, dynamic.string), + port: get(Port, dynamic.int), + path: result.unwrap(get(Path, dynamic.string), ""), + query: get(Query, dynamic.string), + fragment: get(Fragment, dynamic.string), + ) + Ok(uri) + } + } +} external fn erl_parse_query(String) -> Dynamic = "uri_string" "dissect_query" @@ -101,16 +135,6 @@ pub fn path_segments(path) { do_path_segments(string.split(path, "/"), []) } -type UriKey { - Scheme - Userinfo - Host - Port - Path - Query - Fragment -} - external fn erl_to_string(Map(UriKey, Dynamic)) -> Dynamic = "uri_string" "recompose" diff --git a/src/gleam_stdlib.erl b/src/gleam_stdlib.erl index e12ee87..e78d60e 100644 --- a/src/gleam_stdlib.erl +++ b/src/gleam_stdlib.erl @@ -9,7 +9,7 @@ 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]). + string_pad/4, decode_tuple2/1, decode_map/1]). should_equal(Actual, Expected) -> ?assertEqual(Expected, Actual). should_not_equal(Actual, Expected) -> ?assertNotEqual(Expected, Actual). @@ -56,6 +56,9 @@ classify(_) -> "some other type". decode_tuple2({_, _} = T) -> {ok, T}; decode_tuple2(Data) -> decode_error_msg("a 2 element tuple", Data). +decode_map(Data) when is_map(Data) -> {ok, Data}; +decode_map(Data) -> decode_error_msg("a map", Data). + decode_atom(Data) when is_atom(Data) -> {ok, Data}; decode_atom(Data) -> decode_error_msg("an atom", Data). -- cgit v1.2.3