diff options
-rw-r--r-- | CHANGELOG.md | 2 | ||||
-rw-r--r-- | src/gleam/dynamic.gleam | 28 | ||||
-rw-r--r-- | src/gleam/gleam_uri_native.erl | 27 | ||||
-rw-r--r-- | src/gleam/uri.gleam | 48 | ||||
-rw-r--r-- | src/gleam_stdlib.erl | 5 | ||||
-rw-r--r-- | test/gleam/dynamic_test.gleam | 12 |
6 files changed, 76 insertions, 46 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ed6646..ba5202a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ `ends_with`, `slice`, `pad_left` and `pad_right` functions. - `uri` module created with `parse`, `parse_query`, `path_segments`, `query_to_string` and `to_string`. -- The `dynamic` module gains the `tuple2`, and `tuple2_of` functions. +- The `dynamic` module gains the `map`, `tuple2`, and `tuple2_of` functions. - The `list` module gains the `filter_map` function. ## v0.8.0 - 2020-04-28 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). diff --git a/test/gleam/dynamic_test.gleam b/test/gleam/dynamic_test.gleam index 4f314e9..5b5a88c 100644 --- a/test/gleam/dynamic_test.gleam +++ b/test/gleam/dynamic_test.gleam @@ -304,3 +304,15 @@ pub fn tuple2_of_test() { |> dynamic.tuple2 |> should.equal(Error("Expected a 2 element tuple, got an int")) } + +pub fn map_test() { + map.new() + |> dynamic.from + |> dynamic.map + |> should.equal(Ok(map.new())) + + 1 + |> dynamic.from + |> dynamic.map + |> should.equal(Error("Expected a map, got an int")) +} |