better docs: uri (#10373)

This commit is contained in:
Thomas T. Jarløv
2019-01-19 15:31:14 +01:00
committed by Miran
parent 4a04470450
commit bfeade9791

View File

@@ -8,6 +8,35 @@
#
## This module implements URI parsing as specified by RFC 3986.
##
## A Uniform Resource Identifier (URI) provides a simple and extensible
## means for identifying a resource. A URI can be further classified
## as a locator, a name, or both. The term “Uniform Resource Locator”
## (URL) refers to the subset of URIs.
##
## Basic usage
## ===========
##
## Combine URIs
## -------------
## .. code-block::
## import uri
## let host = parseUri("https://nim-lang.org")
## let blog = "/blog.html"
## let bloguri = host / blog
## assert $host == "https://nim-lang.org"
## assert $bloguri == "https://nim-lang.org/blog.html"
##
## Access URI item
## ---------------
## .. code-block::
## import uri
## let res = parseUri("sftp://127.0.0.1:4343")
## if isAbsolute(res):
## echo "Connect to port: " & res.port
## # --> Connect to port: 4343
## else:
## echo "Wrong format"
import strutils, parseutils
type
@@ -24,11 +53,18 @@ proc encodeUrl*(s: string, usePlus=true): string =
## This means that characters in the set
## ``{'a'..'z', 'A'..'Z', '0'..'9', '-', '.', '_', '~'}`` are
## carried over to the result.
## All other characters are encoded as ``''%xx'`` where ``xx``
## All other characters are encoded as ``%xx`` where ``xx``
## denotes its hexadecimal value.
##
## As a special rule, when the value of ``usePlus`` is true,
## spaces are encoded as ``'+'`` instead of ``'%20'``.
## spaces are encoded as ``+`` instead of ``%20``.
##
## **See also:**
## * `decodeUrl proc<#decodeUrl,string>`_
runnableExamples:
assert encodeUrl("https://nim-lang.org") == "https%3A%2F%2Fnim-lang.org"
assert encodeUrl("https://nim-lang.org/this is a test") == "https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test"
assert encodeUrl("https://nim-lang.org/this is a test", false) == "https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test"
result = newStringOfCap(s.len + s.len shr 2) # assume 12% non-alnum-chars
let fromSpace = if usePlus: "+" else: "%20"
for c in s:
@@ -43,12 +79,19 @@ proc encodeUrl*(s: string, usePlus=true): string =
proc decodeUrl*(s: string, decodePlus=true): string =
## Decodes a URL according to RFC3986.
##
## This means that any ``'%xx'`` (where ``xx`` denotes a hexadecimal
## This means that any ``%xx`` (where ``xx`` denotes a hexadecimal
## value) are converted to the character with ordinal number ``xx``,
## and every other character is carried over.
##
## As a special rule, when the value of ``decodePlus`` is true, ``'+'``
## As a special rule, when the value of ``decodePlus`` is true, ``+``
## characters are converted to a space.
##
## **See also:**
## * `encodeUrl proc<#encodeUrl,string>`_
runnableExamples:
assert decodeUrl("https%3A%2F%2Fnim-lang.org") == "https://nim-lang.org"
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis+is+a+test") == "https://nim-lang.org/this is a test"
assert decodeUrl("https%3A%2F%2Fnim-lang.org%2Fthis%20is%20a%20test", false) == "https://nim-lang.org/this is a test"
proc handleHexChar(c: char, x: var int) {.inline.} =
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@@ -123,7 +166,14 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
i.inc parseUntil(uri, result.anchor, {}, i)
proc initUri*(): Uri =
## Initializes a URI.
## Initializes a URI with ``scheme``, ``username``, ``password``,
## ``hostname``, ``port``, ``path``, ``query`` and ``anchor``.
##
## **See also:**
## * `Uri type <#Uri>`_ for available fields in the URI type
runnableExamples:
var uri: Uri
assert initUri() == uri
result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
path: "", query: "", anchor: "")
@@ -136,6 +186,16 @@ proc resetUri(uri: var Uri) =
proc parseUri*(uri: string, result: var Uri) =
## Parses a URI. The `result` variable will be cleared before.
##
## **See also:**
## * `Uri type <#Uri>`_ for available fields in the URI type
## * `initUri proc <#initUri,>`_ for initializing a URI
runnableExamples:
var res = initUri()
parseUri("https://nim-lang.org/docs/manual.html", res)
assert res.scheme == "https"
assert res.hostname == "nim-lang.org"
assert res.path == "/docs/manual.html"
resetUri(result)
var i = 0
@@ -174,6 +234,14 @@ proc parseUri*(uri: string, result: var Uri) =
proc parseUri*(uri: string): Uri =
## Parses a URI and returns it.
##
## **See also:**
## * `Uri type <#Uri>`_ for available fields in the URI type
runnableExamples:
let res = parseUri("ftp://Username:Password@Hostname")
assert res.username == "Username"
assert res.password == "Password"
assert res.scheme == "ftp"
result = initUri()
parseUri(uri, result)
@@ -224,22 +292,18 @@ proc combine*(base: Uri, reference: Uri): Uri =
## This uses the algorithm specified in
## `section 5.2.2 of RFC 3986 <http://tools.ietf.org/html/rfc3986#section-5.2.2>`_.
##
## This means that the slashes inside the base URI's path as well as reference
## URI's path affect the resulting URI.
## This means that the slashes inside the base URIs path as well as reference
## URIs path affect the resulting URI.
##
## For building URIs you may wish to use \`/\` instead.
##
## Examples:
##
## .. code-block::
## let foo = combine(parseUri("http://example.com/foo/bar"), parseUri("/baz"))
## assert foo.path == "/baz"
##
## let bar = combine(parseUri("http://example.com/foo/bar"), parseUri("baz"))
## assert bar.path == "/foo/baz"
##
## let bar = combine(parseUri("http://example.com/foo/bar/"), parseUri("baz"))
## assert bar.path == "/foo/bar/baz"
## **See also:**
## * `/ proc <#/,Uri,string>`_ for building URIs
runnableExamples:
let foo = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("/baz"))
assert foo.path == "/baz"
let bar = combine(parseUri("https://nim-lang.org/foo/bar"), parseUri("baz"))
assert bar.path == "/foo/baz"
let qux = combine(parseUri("https://nim-lang.org/foo/bar/"), parseUri("baz"))
assert qux.path == "/foo/bar/baz"
template setAuthority(dest, src): untyped =
dest.hostname = src.hostname
@@ -275,32 +339,42 @@ proc combine*(base: Uri, reference: Uri): Uri =
proc combine*(uris: varargs[Uri]): Uri =
## Combines multiple URIs together.
##
## **See also:**
## * `/ proc <#/,Uri,string>`_ for building URIs
runnableExamples:
let foo = combine(parseUri("https://nim-lang.org/blog.html"), parseUri("/install.html"))
assert foo.hostname == "nim-lang.org"
assert foo.path == "/install.html"
result = uris[0]
for i in 1 ..< uris.len:
result = combine(result, uris[i])
proc isAbsolute*(uri: Uri): bool =
## returns true if URI is absolute, false otherwise
## Returns true if URI is absolute, false otherwise.
runnableExamples:
let foo = parseUri("https://nim-lang.org")
assert isAbsolute(foo) == true
let bar = parseUri("nim-lang")
assert isAbsolute(bar) == false
return uri.scheme != "" and (uri.hostname != "" or uri.path != "")
proc `/`*(x: Uri, path: string): Uri =
## Concatenates the path specified to the specified URI's path.
## Concatenates the path specified to the specified URIs path.
##
## Contrary to the ``combine`` procedure you do not have to worry about
## the slashes at the beginning and end of the path and URI's path
## Contrary to the `combine proc <#combine,Uri,Uri>`_ you do not have to worry about
## the slashes at the beginning and end of the path and URIs path
## respectively.
##
## Examples:
##
## .. code-block::
## let foo = parseUri("http://example.com/foo/bar") / "/baz"
## assert foo.path == "/foo/bar/baz"
##
## let bar = parseUri("http://example.com/foo/bar") / "baz"
## assert bar.path == "/foo/bar/baz"
##
## let bar = parseUri("http://example.com/foo/bar/") / "baz"
## assert bar.path == "/foo/bar/baz"
## **See also:**
## * `combine proc <#combine,Uri,Uri>`_
runnableExamples:
let foo = parseUri("https://nim-lang.org/foo/bar") / "/baz"
assert foo.path == "/foo/bar/baz"
let bar = parseUri("https://nim-lang.org/foo/bar") / "baz"
assert bar.path == "/foo/bar/baz"
let qux = parseUri("https://nim-lang.org/foo/bar/") / "baz"
assert qux.path == "/foo/bar/baz"
result = x
if result.path.len == 0:
@@ -321,6 +395,9 @@ proc `/`*(x: Uri, path: string): Uri =
proc `$`*(u: Uri): string =
## Returns the string representation of the specified URI object.
runnableExamples:
let foo = parseUri("https://nim-lang.org")
assert $foo == "https://nim-lang.org"
result = ""
if u.scheme.len > 0:
result.add(u.scheme)