@@ -8,21 +8,31 @@ strikes a unique balance of correctness and usability.
88A 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,
2636without 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
4050Immutability
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
5571Query parameters are actually a type of "multidict", where a given key
5672can 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
95111all but the literal code-inheritance sense). Care has been taken to
96112maintain backwards-compatibility in all legacy APIs, making hyperlink
97113a 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