aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Porto <s@porto5.com>2020-10-31 22:20:20 +1100
committerGitHub <noreply@github.com>2020-10-31 12:20:20 +0100
commit33fd0fb3130bf1f11947385c42e8bfadb3c753e1 (patch)
treebb05d3c339787f796add38add8ad932f5c0ee7be
parent8e421527ad59a4bcea656ca1cdd6c643c99771c9 (diff)
downloadgleam_stdlib-33fd0fb3130bf1f11947385c42e8bfadb3c753e1.tar.gz
gleam_stdlib-33fd0fb3130bf1f11947385c42e8bfadb3c753e1.zip
Add percent_encode and percent_decode (#121)
-rw-r--r--CHANGELOG.md3
-rw-r--r--src/gleam/uri.gleam28
-rw-r--r--test/gleam/uri_test.gleam74
3 files changed, 104 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9c9dfe..06389e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,9 +5,10 @@
- The `function` module gains `curry2` to `curry6`.
- The `list` module gains the `each`, and `partition` functions.
- The `int` and `float` modules gain the `negate` function.
+- The `int` module gains the `to_float` function.
- The `result` module gains the `all` function.
- The `dynamic` module gains the `option` function.
-- The `int` module gains the `to_float` function.
+- The `uri` module gains the `percent_encode` and `percent_decode` functions.
## v0.11.0 - 2020-08-22
diff --git a/src/gleam/uri.gleam b/src/gleam/uri.gleam
index 32910b5..2ff542a 100644
--- a/src/gleam/uri.gleam
+++ b/src/gleam/uri.gleam
@@ -14,6 +14,7 @@ import gleam/string
import gleam/dynamic.{Dynamic}
import gleam/map.{Map}
import gleam/function
+import gleam/pair
/// Type representing holding the parsed components of an URI.
/// All components of a URI are optional, except the path.
@@ -119,6 +120,33 @@ pub fn query_to_string(query: List(tuple(String, String))) -> String {
|> result.unwrap("")
}
+/// Encode a string into a percent encoded representation.
+/// Note that this encodes space as +.
+///
+/// ## Example
+///
+/// percent_encode("100% great")
+/// > "100%25+great"
+///
+pub fn percent_encode(value: String) -> String {
+ query_to_string([tuple("k", value)])
+ |> string.replace(each: "k=", with: "")
+}
+
+/// Decode a percent encoded string.
+///
+/// ## Example
+///
+/// percent_decode("100%25+great")
+/// > Ok("100% great")
+///
+pub fn percent_decode(value: String) -> Result(String, Nil) {
+ string.concat(["k=", value])
+ |> parse_query
+ |> result.then(list.head)
+ |> result.map(pair.second)
+}
+
fn do_remove_dot_segments(
input: List(String),
accumulator: List(String),
diff --git a/test/gleam/uri_test.gleam b/test/gleam/uri_test.gleam
index 55a4bd6..779e078 100644
--- a/test/gleam/uri_test.gleam
+++ b/test/gleam/uri_test.gleam
@@ -1,5 +1,7 @@
import gleam/uri
import gleam/should
+import gleam/string
+import gleam/list
import gleam/option.{None, Some}
pub fn full_parse_test() {
@@ -92,6 +94,78 @@ pub fn empty_query_to_string_test() {
should.equal(query_string, "")
}
+fn percent_codec_fixtures() {
+ [
+ tuple(" ", "+"),
+ tuple(",", "%2C"),
+ tuple(";", "%3B"),
+ tuple(":", "%3A"),
+ tuple("!", "%21"),
+ tuple("?", "%3F"),
+ tuple("'", "%27"),
+ tuple("(", "%28"),
+ tuple(")", "%29"),
+ tuple("[", "%5B"),
+ tuple("@", "%40"),
+ tuple("/", "%2F"),
+ tuple("\\", "%5C"),
+ tuple("&", "%26"),
+ tuple("#", "%23"),
+ tuple("=", "%3D"),
+ tuple("~", "%7E"),
+ tuple("ñ", "%C3%B1"),
+ // Allowed chars
+ tuple("-", "-"),
+ tuple("_", "_"),
+ tuple(".", "."),
+ tuple("*", "*"),
+ tuple("100% great", "100%25+great"),
+ ]
+}
+
+pub fn percent_encode_test() {
+ percent_codec_fixtures()
+ |> list.map(fn(t) {
+ let tuple(a, b) = t
+ uri.percent_encode(a)
+ |> should.equal(b)
+ })
+}
+
+pub fn percent_encode_consistency_test() {
+ let k = "foo bar[]"
+ let v = "ñaña (,:*~)"
+
+ assert query_string = uri.query_to_string([tuple(k, v)])
+
+ let encoded_key = uri.percent_encode(k)
+ let encoded_value = uri.percent_encode(v)
+ let manual_query_string = string.concat([encoded_key, "=", encoded_value])
+
+ should.equal(query_string, manual_query_string)
+}
+
+pub fn percent_decode_test() {
+ percent_codec_fixtures()
+ |> list.map(fn(t) {
+ let tuple(a, b) = t
+ uri.percent_decode(b)
+ |> should.equal(Ok(a))
+ })
+}
+
+pub fn percent_decode_consistency_test() {
+ let k = "foo+bar[]"
+ let v = "%C3%B6rebro"
+ let query = string.concat([k, "=", v])
+ assert Ok(parsed) = uri.parse_query(query)
+
+ assert Ok(decoded_key) = uri.percent_decode(k)
+ assert Ok(decoded_value) = uri.percent_decode(v)
+
+ should.equal(parsed, [tuple(decoded_key, decoded_value)])
+}
+
pub fn parse_segments_test() {
should.equal(uri.path_segments("/"), [])
should.equal(uri.path_segments("/foo/bar"), ["foo", "bar"])