Skip to content

Commit 6ff8c60

Browse files
committed
adding to design docs, pulling some old twisted docstring material in (still might move it)
1 parent e4d2631 commit 6ff8c60

1 file changed

Lines changed: 60 additions & 18 deletions

File tree

docs/design.rst

Lines changed: 60 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,31 @@ strikes a unique balance of correctness and usability.
88
A Tale of Two Representations
99
-----------------------------
1010

11-
The URL is a powerful construct with two canonical representations
12-
that have historically caused some confusion: the URI and the
13-
IRI. (The W3C even recognized this themselves.) Hyperlink's URL sets
14-
this record straight. Simply:
11+
The URL is a powerful construct, designed to be used by both humans
12+
and computers.
1513

16-
* URI: Fully-encoded, suitable for network transfer
17-
* IRI: Fully-decoded, suitable for display (e.g., in a browser bar)
14+
This important dual purpose has resulted in two canonical
15+
representations which have historically caused some confusion: the URI
16+
and the IRI.
17+
18+
Even though the W3C themselves have recognized the confusion this can
19+
cause, Hyperlink's URL makes the distinction quite natural. Simply:
20+
21+
* **URI**: Fully-encoded, ASCII-only, suitable for network transfer
22+
* **IRI**: Fully-decoded, Unicode-friendly, suitable for display (e.g., in a browser bar)
23+
24+
Hyperlink's dual support in action::
1825

1926
>>> url = URL.from_text('http://example.com/café')
2027
>>> url.to_uri().to_text()
2128
u'http://example.com/caf%C3%A9'
2229

23-
Ah, there's that percent encoding, characteristic of URIs. Still,
24-
Hyperlink's distinction between URIs and IRIs is limited to
25-
output. Input can contain any mix of percent encoding and Unicode,
30+
We construct a URL from text containing Unicode, then transform it
31+
using :meth:`~URL.to_uri()`. This results in ASCII-only
32+
percent-encoding characteristic of URIs.
33+
34+
Still, Hyperlink's distinction between URIs and IRIs is limited to
35+
output. Input can contain *any mix* of percent encoding and Unicode,
2636
without issue:
2737

2838
>>> url = URL.from_text('http://example.com/caf%C3%A9/au láit')
@@ -31,26 +41,32 @@ without issue:
3141
>>> print(url.to_uri().to_text())
3242
http://example.com/caf%C3%A9/au%20l%C3%A1it
3343

34-
Note that the URI and IRI representation of the same resource are
35-
still different URLs:
44+
Note that even when a URI and IRI point to the same resource, they can
45+
still easily be different URLs:
3646

3747
>>> url.to_uri() == url.to_iri()
3848
False
3949

4050
Immutability
4151
------------
4252

43-
Hyperlink's URL is also notable for being an immutable
44-
representation. Once constructed, instances are not changed. Methods
45-
like :meth:`~URL.click()`, :meth:`~URL.set()`, and
46-
:meth:`~URL.replace()`, all return new URL objects. This enables URLs
47-
to be used in sets, as well as dictionary keys.
53+
Hyperlink's URL is notable for being an immutable representation. Once
54+
constructed, instances are not changed. Methods like
55+
:meth:`~URL.click()`, :meth:`~URL.set()`, and :meth:`~URL.replace()`,
56+
all return new URL objects. This enables URLs to be used in sets, as
57+
well as dictionary keys.
58+
59+
.. TODO links for RFCs, "immutable", "multidict", "GET parameters",
60+
twisted.python.url, boltons.urlutils, from "immutable" in the API
61+
doc to the design doc. "BNF grammar"
4862
4963
Query Parameters
5064
----------------
5165

52-
One of the URL format's most powerful features is query parameters,
53-
encoded in the query string portion of the URL.
66+
One of the URL format's most useful features is the mapping formed
67+
by the query parameters, sometimes called "query arguments" or "GET
68+
parameters". Regardless of what you call them, they are encoded in
69+
the query string portion of the URL, and they are very powerful.
5470

5571
Query parameters are actually a type of "multidict", where a given key
5672
can have multiple values. This is why the :meth:`~URL.get()` method
@@ -95,3 +111,29 @@ Hyperlink's URL is descended directly from twisted.python.url.URL (in
95111
all but the literal code-inheritance sense). Care has been taken to
96112
maintain backwards-compatibility in all legacy APIs, making hyperlink
97113
a drop-in replacement for Twisted's URL class.
114+
115+
Versus text
116+
-----------
117+
118+
There are two major advantages of using :class:`~hyperlink.URL` over
119+
representing URLs as strings. The first is that it's really easy to
120+
evaluate a relative hyperlink, for example, when crawling documents,
121+
to figure out what is linked::
122+
123+
>>> URL.from_text(u'https://example.com/base/uri/').click(u"/absolute")
124+
URL.from_text(u'https://example.com/absolute')
125+
>>> URL.from_text(u'https://example.com/base/uri/').click(u"rel/path")
126+
URL.from_text(u'https://example.com/base/uri/rel/path')
127+
128+
The other is that URLs have two normalizations. One representation is
129+
suitable for humans to read, because it can represent data from many
130+
character sets - this is the Internationalized, or IRI, normalization.
131+
The other is the older, US-ASCII-only representation, which is
132+
necessary for most contexts where you would need to put a URI. You
133+
can convert *between* these representations according to certain
134+
rules. :class:`~hyperlink.URL` exposes these conversions as methods::
135+
136+
>>> URL.from_text(u"https://→example.com/foo⇧bar/").to_uri()
137+
URL.from_text(u'https://xn--example-dk9c.com/foo%E2%87%A7bar/')
138+
>>> URL.from_text(u'https://xn--example-dk9c.com/foo%E2%87%A7bar/').to_iri()
139+
URL.from_text(u'https://\\u2192example.com/foo\\u21e7bar/')

0 commit comments

Comments
 (0)