atom-tools 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. data/COPYING +18 -0
  2. data/README +103 -0
  3. data/Rakefile +77 -0
  4. data/bin/atom-client.rb +246 -0
  5. data/bin/atom-server.rb~ +71 -0
  6. data/doc/classes/Atom/App.html +217 -0
  7. data/doc/classes/Atom/Author.html +130 -0
  8. data/doc/classes/Atom/Category.html +128 -0
  9. data/doc/classes/Atom/Collection.html +322 -0
  10. data/doc/classes/Atom/Content.html +129 -0
  11. data/doc/classes/Atom/Contributor.html +119 -0
  12. data/doc/classes/Atom/Element.html +325 -0
  13. data/doc/classes/Atom/Entry.html +365 -0
  14. data/doc/classes/Atom/Feed.html +585 -0
  15. data/doc/classes/Atom/HTTP.html +374 -0
  16. data/doc/classes/Atom/Link.html +137 -0
  17. data/doc/classes/Atom/Text.html +229 -0
  18. data/doc/classes/XHTML.html +118 -0
  19. data/doc/created.rid +1 -0
  20. data/doc/files/README.html +213 -0
  21. data/doc/files/lib/atom/app_rb.html +110 -0
  22. data/doc/files/lib/atom/collection_rb.html +110 -0
  23. data/doc/files/lib/atom/element_rb.html +109 -0
  24. data/doc/files/lib/atom/entry_rb.html +111 -0
  25. data/doc/files/lib/atom/feed_rb.html +112 -0
  26. data/doc/files/lib/atom/http_rb.html +109 -0
  27. data/doc/files/lib/atom/text_rb.html +108 -0
  28. data/doc/files/lib/atom/xml_rb.html +110 -0
  29. data/doc/files/lib/atom/yaml_rb.html +109 -0
  30. data/doc/fr_class_index.html +39 -0
  31. data/doc/fr_file_index.html +36 -0
  32. data/doc/fr_method_index.html +62 -0
  33. data/doc/index.html +24 -0
  34. data/doc/rdoc-style.css +208 -0
  35. data/lib/atom/app.rb +87 -0
  36. data/lib/atom/collection.rb +75 -0
  37. data/lib/atom/element.rb +277 -0
  38. data/lib/atom/entry.rb +135 -0
  39. data/lib/atom/feed.rb +229 -0
  40. data/lib/atom/http.rb +132 -0
  41. data/lib/atom/text.rb +163 -0
  42. data/lib/atom/xml.rb +200 -0
  43. data/lib/atom/yaml.rb +101 -0
  44. data/setup.rb +1585 -0
  45. data/test/conformance/order.rb +117 -0
  46. data/test/conformance/title.rb +108 -0
  47. data/test/conformance/updated.rb +33 -0
  48. data/test/conformance/xhtmlcontentdiv.rb +18 -0
  49. data/test/conformance/xmlnamespace.rb +54 -0
  50. data/test/runtests.rb +14 -0
  51. data/test/test_constructs.rb +91 -0
  52. data/test/test_feed.rb +128 -0
  53. data/test/test_general.rb +99 -0
  54. data/test/test_http.rb +86 -0
  55. data/test/test_protocol.rb +69 -0
  56. data/test/test_xml.rb +353 -0
  57. metadata +107 -0
@@ -0,0 +1,36 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Files
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Files</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Files</h1>
22
+ <div id="index-entries">
23
+ <a href="files/README.html">README</a><br />
24
+ <a href="files/lib/atom/app_rb.html">lib/atom/app.rb</a><br />
25
+ <a href="files/lib/atom/collection_rb.html">lib/atom/collection.rb</a><br />
26
+ <a href="files/lib/atom/element_rb.html">lib/atom/element.rb</a><br />
27
+ <a href="files/lib/atom/entry_rb.html">lib/atom/entry.rb</a><br />
28
+ <a href="files/lib/atom/feed_rb.html">lib/atom/feed.rb</a><br />
29
+ <a href="files/lib/atom/http_rb.html">lib/atom/http.rb</a><br />
30
+ <a href="files/lib/atom/text_rb.html">lib/atom/text.rb</a><br />
31
+ <a href="files/lib/atom/xml_rb.html">lib/atom/xml.rb</a><br />
32
+ <a href="files/lib/atom/yaml_rb.html">lib/atom/yaml.rb</a><br />
33
+ </div>
34
+ </div>
35
+ </body>
36
+ </html>
@@ -0,0 +1,62 @@
1
+
2
+ <?xml version="1.0" encoding="iso-8859-1"?>
3
+ <!DOCTYPE html
4
+ PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
5
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
6
+
7
+ <!--
8
+
9
+ Methods
10
+
11
+ -->
12
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
13
+ <head>
14
+ <title>Methods</title>
15
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
16
+ <link rel="stylesheet" href="rdoc-style.css" type="text/css" />
17
+ <base target="docwin" />
18
+ </head>
19
+ <body>
20
+ <div id="index">
21
+ <h1 class="section-bar">Methods</h1>
22
+ <div id="index-entries">
23
+ <a href="classes/Atom/Feed.html#M000015"><< (Atom::Feed)</a><br />
24
+ <a href="classes/Atom/Element.html#M000032">[] (Atom::Element)</a><br />
25
+ <a href="classes/Atom/Element.html#M000033">[]= (Atom::Element)</a><br />
26
+ <a href="classes/Atom/HTTP.html#M000024">delete (Atom::HTTP)</a><br />
27
+ <a href="classes/Atom/Collection.html#M000029">delete! (Atom::Collection)</a><br />
28
+ <a href="classes/Atom/Feed.html#M000009">each (Atom::Feed)</a><br />
29
+ <a href="classes/Atom/Entry.html#M000002">edit_url (Atom::Entry)</a><br />
30
+ <a href="classes/Atom/Entry.html#M000001">from_yaml (Atom::Entry)</a><br />
31
+ <a href="classes/Atom/HTTP.html#M000021">get (Atom::HTTP)</a><br />
32
+ <a href="classes/Atom/HTTP.html#M000019">get_atom_entry (Atom::HTTP)</a><br />
33
+ <a href="classes/Atom/Feed.html#M000010">get_everything! (Atom::Feed)</a><br />
34
+ <a href="classes/Atom/Text.html#M000017">html (Atom::Text)</a><br />
35
+ <a href="classes/Atom/Feed.html#M000013">merge (Atom::Feed)</a><br />
36
+ <a href="classes/Atom/Feed.html#M000012">merge! (Atom::Feed)</a><br />
37
+ <a href="classes/Atom/Feed.html#M000011">merge_entries! (Atom::Feed)</a><br />
38
+ <a href="classes/Atom/Feed.html#M000008">new (Atom::Feed)</a><br />
39
+ <a href="classes/Atom/Collection.html#M000026">new (Atom::Collection)</a><br />
40
+ <a href="classes/Atom/App.html#M000006">new (Atom::App)</a><br />
41
+ <a href="classes/Atom/Entry.html#M000003">parse (Atom::Entry)</a><br />
42
+ <a href="classes/Atom/Feed.html#M000007">parse (Atom::Feed)</a><br />
43
+ <a href="classes/Atom/HTTP.html#M000022">post (Atom::HTTP)</a><br />
44
+ <a href="classes/Atom/Collection.html#M000027">post! (Atom::Collection)</a><br />
45
+ <a href="classes/Atom/Collection.html#M000030">post_media! (Atom::Collection)</a><br />
46
+ <a href="classes/Atom/HTTP.html#M000023">put (Atom::HTTP)</a><br />
47
+ <a href="classes/Atom/Collection.html#M000028">put! (Atom::Collection)</a><br />
48
+ <a href="classes/Atom/HTTP.html#M000020">put_atom_entry (Atom::HTTP)</a><br />
49
+ <a href="classes/Atom/Collection.html#M000031">put_media! (Atom::Collection)</a><br />
50
+ <a href="classes/Atom/Entry.html#M000005">tag_with (Atom::Entry)</a><br />
51
+ <a href="classes/Atom/Element.html#M000034">to_element (Atom::Element)</a><br />
52
+ <a href="classes/Atom/Text.html#M000016">to_s (Atom::Text)</a><br />
53
+ <a href="classes/Atom/Element.html#M000036">to_s (Atom::Element)</a><br />
54
+ <a href="classes/Atom/Element.html#M000035">to_xml (Atom::Element)</a><br />
55
+ <a href="classes/Atom/Feed.html#M000014">update! (Atom::Feed)</a><br />
56
+ <a href="classes/Atom/Entry.html#M000004">updated! (Atom::Entry)</a><br />
57
+ <a href="classes/Atom/HTTP.html#M000025">when_auth (Atom::HTTP)</a><br />
58
+ <a href="classes/Atom/Text.html#M000018">xml (Atom::Text)</a><br />
59
+ </div>
60
+ </div>
61
+ </body>
62
+ </html>
data/doc/index.html ADDED
@@ -0,0 +1,24 @@
1
+ <?xml version="1.0" encoding="iso-8859-1"?>
2
+ <!DOCTYPE html
3
+ PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
4
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
5
+
6
+ <!--
7
+
8
+ atom-tools documentation
9
+
10
+ -->
11
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
12
+ <head>
13
+ <title>atom-tools documentation</title>
14
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
15
+ </head>
16
+ <frameset rows="20%, 80%">
17
+ <frameset cols="25%,35%,45%">
18
+ <frame src="fr_file_index.html" title="Files" name="Files" />
19
+ <frame src="fr_class_index.html" name="Classes" />
20
+ <frame src="fr_method_index.html" name="Methods" />
21
+ </frameset>
22
+ <frame src="files/README.html" name="docwin" />
23
+ </frameset>
24
+ </html>
@@ -0,0 +1,208 @@
1
+
2
+ body {
3
+ font-family: Verdana,Arial,Helvetica,sans-serif;
4
+ font-size: 90%;
5
+ margin: 0;
6
+ margin-left: 40px;
7
+ padding: 0;
8
+ background: white;
9
+ }
10
+
11
+ h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12
+ h1 { font-size: 150%; }
13
+ h2,h3,h4 { margin-top: 1em; }
14
+
15
+ a { background: #eef; color: #039; text-decoration: none; }
16
+ a:hover { background: #039; color: #eef; }
17
+
18
+ /* Override the base stylesheet's Anchor inside a table cell */
19
+ td > a {
20
+ background: transparent;
21
+ color: #039;
22
+ text-decoration: none;
23
+ }
24
+
25
+ /* and inside a section title */
26
+ .section-title > a {
27
+ background: transparent;
28
+ color: #eee;
29
+ text-decoration: none;
30
+ }
31
+
32
+ /* === Structural elements =================================== */
33
+
34
+ div#index {
35
+ margin: 0;
36
+ margin-left: -40px;
37
+ padding: 0;
38
+ font-size: 90%;
39
+ }
40
+
41
+
42
+ div#index a {
43
+ margin-left: 0.7em;
44
+ }
45
+
46
+ div#index .section-bar {
47
+ margin-left: 0px;
48
+ padding-left: 0.7em;
49
+ background: #ccc;
50
+ font-size: small;
51
+ }
52
+
53
+
54
+ div#classHeader, div#fileHeader {
55
+ width: auto;
56
+ color: white;
57
+ padding: 0.5em 1.5em 0.5em 1.5em;
58
+ margin: 0;
59
+ margin-left: -40px;
60
+ border-bottom: 3px solid #006;
61
+ }
62
+
63
+ div#classHeader a, div#fileHeader a {
64
+ background: inherit;
65
+ color: white;
66
+ }
67
+
68
+ div#classHeader td, div#fileHeader td {
69
+ background: inherit;
70
+ color: white;
71
+ }
72
+
73
+
74
+ div#fileHeader {
75
+ background: #057;
76
+ }
77
+
78
+ div#classHeader {
79
+ background: #048;
80
+ }
81
+
82
+
83
+ .class-name-in-header {
84
+ font-size: 180%;
85
+ font-weight: bold;
86
+ }
87
+
88
+
89
+ div#bodyContent {
90
+ padding: 0 1.5em 0 1.5em;
91
+ }
92
+
93
+ div#description {
94
+ padding: 0.5em 1.5em;
95
+ background: #efefef;
96
+ border: 1px dotted #999;
97
+ }
98
+
99
+ div#description h1,h2,h3,h4,h5,h6 {
100
+ color: #125;;
101
+ background: transparent;
102
+ }
103
+
104
+ div#validator-badges {
105
+ text-align: center;
106
+ }
107
+ div#validator-badges img { border: 0; }
108
+
109
+ div#copyright {
110
+ color: #333;
111
+ background: #efefef;
112
+ font: 0.75em sans-serif;
113
+ margin-top: 5em;
114
+ margin-bottom: 0;
115
+ padding: 0.5em 2em;
116
+ }
117
+
118
+
119
+ /* === Classes =================================== */
120
+
121
+ table.header-table {
122
+ color: white;
123
+ font-size: small;
124
+ }
125
+
126
+ .type-note {
127
+ font-size: small;
128
+ color: #DEDEDE;
129
+ }
130
+
131
+ .xxsection-bar {
132
+ background: #eee;
133
+ color: #333;
134
+ padding: 3px;
135
+ }
136
+
137
+ .section-bar {
138
+ color: #333;
139
+ border-bottom: 1px solid #999;
140
+ margin-left: -20px;
141
+ }
142
+
143
+
144
+ .section-title {
145
+ background: #79a;
146
+ color: #eee;
147
+ padding: 3px;
148
+ margin-top: 2em;
149
+ margin-left: -30px;
150
+ border: 1px solid #999;
151
+ }
152
+
153
+ .top-aligned-row { vertical-align: top }
154
+ .bottom-aligned-row { vertical-align: bottom }
155
+
156
+ /* --- Context section classes ----------------------- */
157
+
158
+ .context-row { }
159
+ .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160
+ .context-item-value { font-size: small; color: #448; }
161
+ .context-item-desc { color: #333; padding-left: 2em; }
162
+
163
+ /* --- Method classes -------------------------- */
164
+ .method-detail {
165
+ background: #efefef;
166
+ padding: 0;
167
+ margin-top: 0.5em;
168
+ margin-bottom: 1em;
169
+ border: 1px dotted #ccc;
170
+ }
171
+ .method-heading {
172
+ color: black;
173
+ background: #ccc;
174
+ border-bottom: 1px solid #666;
175
+ padding: 0.2em 0.5em 0 0.5em;
176
+ }
177
+ .method-signature { color: black; background: inherit; }
178
+ .method-name { font-weight: bold; }
179
+ .method-args { font-style: italic; }
180
+ .method-description { padding: 0 0.5em 0 0.5em; }
181
+
182
+ /* --- Source code sections -------------------- */
183
+
184
+ a.source-toggle { font-size: 90%; }
185
+ div.method-source-code {
186
+ background: #262626;
187
+ color: #ffdead;
188
+ margin: 1em;
189
+ padding: 0.5em;
190
+ border: 1px dashed #999;
191
+ overflow: hidden;
192
+ }
193
+
194
+ div.method-source-code pre { color: #ffdead; overflow: hidden; }
195
+
196
+ /* --- Ruby keyword styles --------------------- */
197
+
198
+ .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199
+
200
+ .ruby-constant { color: #7fffd4; background: transparent; }
201
+ .ruby-keyword { color: #00ffff; background: transparent; }
202
+ .ruby-ivar { color: #eedd82; background: transparent; }
203
+ .ruby-operator { color: #00ffee; background: transparent; }
204
+ .ruby-identifier { color: #ffdead; background: transparent; }
205
+ .ruby-node { color: #ffa07a; background: transparent; }
206
+ .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207
+ .ruby-regexp { color: #ffa07a; background: transparent; }
208
+ .ruby-value { color: #7fffd4; background: transparent; }
data/lib/atom/app.rb ADDED
@@ -0,0 +1,87 @@
1
+ require "uri"
2
+
3
+ require "atom/http"
4
+ require "atom/collection"
5
+
6
+ module Atom
7
+ PP_NS = "http://purl.org/atom/app#"
8
+
9
+ class WrongNamespace < RuntimeError #:nodoc:
10
+ end
11
+ class WrongMimetype < RuntimeError # :nodoc:
12
+ end
13
+ class WrongResponse < RuntimeError # :nodoc:
14
+ end
15
+
16
+ # Atom::App represents an Atom Publishing Protocol introspection
17
+ # document.
18
+ class App
19
+ # collections referred to by the introspection document
20
+ attr_reader :collections
21
+
22
+ # retrieves and parses an Atom introspection document.
23
+ def initialize(introspection_url, http = Atom::HTTP.new)
24
+ i_url = URI.parse(introspection_url)
25
+
26
+ rxml = nil
27
+
28
+ res = http.get(i_url)
29
+
30
+ unless res.code == "200" # redirects, &c.
31
+ raise WrongResponse, "introspection document responded with unexpected code #{res.code}"
32
+ end
33
+
34
+ unless res.content_type == "application/atomserv+xml"
35
+ raise WrongMimetype, "this isn't an introspection document!"
36
+ end
37
+
38
+ rxml = REXML::Document.new(res.body)
39
+
40
+ unless rxml.root.namespace == PP_NS
41
+ raise WrongNamespace, "this isn't an introspection document!"
42
+ end
43
+
44
+ # TODO: expose workspaces
45
+ colls = REXML::XPath.match( rxml,
46
+ "/app:service/app:workspace/app:collection",
47
+ {"app" => Atom::PP_NS} )
48
+
49
+ @collections = []
50
+
51
+ colls.each do |collection|
52
+ # absolutize relative URLs
53
+ url = i_url + URI.parse(collection.attributes["href"])
54
+
55
+ coll = Atom::Collection.new(url, http)
56
+
57
+ # XXX this is a Text Construct, and should be parsed as such
58
+ coll.title = REXML::XPath.first( collection,
59
+ "./atom:title",
60
+ {"app" => Atom::PP_NS,
61
+ "atom" => Atom::NS } ).text
62
+
63
+ accepts = REXML::XPath.first( collection,
64
+ "./app:accept",
65
+ {"app" => Atom::PP_NS} )
66
+ coll.accepts = (accepts ? accepts.text : "entry")
67
+
68
+ @collections << coll
69
+ end
70
+ end
71
+ end
72
+
73
+ class Entry
74
+ # the @href of an entry's link[@rel="edit"]
75
+ def edit_url
76
+ begin
77
+ edit_link = self.links.find do |link|
78
+ link["rel"] == "edit"
79
+ end
80
+
81
+ edit_link["href"]
82
+ rescue
83
+ nil
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,75 @@
1
+ require "atom/http"
2
+ require "atom/feed"
3
+
4
+ # so we can do some mimetype guessing
5
+ require "webrick/httputils"
6
+
7
+ module Atom
8
+ # represents an Atom Publishing Protocol Collection
9
+ class Collection < Feed
10
+ # comma separated string that contains a list of media types
11
+ # accepted by a collection.
12
+ #
13
+ # XXX I should parse this in some way, but I'm not sure what's useful
14
+ attr_accessor :accepts
15
+
16
+ def initialize(uri, http = Atom::HTTP.new)
17
+ super uri, http
18
+ end
19
+
20
+ # POST an entry to the collection, with a slug
21
+ def post!(entry, slug = nil)
22
+ raise "Cowardly refusing to POST a non-Atom::Entry" unless entry.is_a? Atom::Entry
23
+ headers = {"Content-Type" => "application/atom+xml" }
24
+ headers["Slug"] = slug if slug
25
+
26
+ @http.post(@uri, entry.to_s, headers)
27
+ end
28
+
29
+ # PUT an updated version of an entry to the collection
30
+ def put!(entry, url = entry.edit_url)
31
+ @http.put_atom_entry(entry, url)
32
+ end
33
+
34
+ # DELETE an entry from the collection
35
+ def delete!(entry, url = entry.edit_url)
36
+ @http.delete(url)
37
+ end
38
+
39
+ # POST a media item to the collection
40
+ def post_media!(data, content_type, slug = nil)
41
+ headers = {"Content-Type" => content_type}
42
+ headers["Slug"] = slug if slug
43
+
44
+ @http.post(@uri, data, headers)
45
+ end
46
+
47
+ # PUT a media item to the collection
48
+ def put_media!(data, content_type, slug = nil)
49
+ headers = {"Content-Type" => content_type}
50
+
51
+ @http.put(url, data, headers)
52
+ end
53
+ end
54
+
55
+ class HTTP
56
+ # GET a URL and turn it into an Atom::Entry
57
+ def get_atom_entry(url)
58
+ res = get(url)
59
+
60
+ if res.code != "200" or res.content_type != "application/atom+xml"
61
+ raise Atom::HTTPException, "expected Atom::Entry, didn't get it"
62
+ end
63
+
64
+ Atom::Entry.parse(res.body, url)
65
+ end
66
+
67
+ # PUT an Atom::Entry to a URL
68
+ def put_atom_entry(entry, url = entry.edit_url)
69
+ raise "Cowardly refusing to PUT a non-Atom::Entry (#{entry.class})" unless entry.is_a? Atom::Entry
70
+ headers = {"Content-Type" => "application/atom+xml" }
71
+
72
+ put(url, entry.to_s, headers)
73
+ end
74
+ end
75
+ end