atom-tools 0.9.0 → 2.0.5

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 (93) hide show
  1. data/COPYING +3 -3
  2. data/README +9 -49
  3. data/Rakefile +65 -62
  4. data/bin/atom-cp +159 -0
  5. data/bin/atom-grep +78 -0
  6. data/bin/atom-post +73 -0
  7. data/bin/atom-purge +82 -0
  8. data/doc/classes/Atom/AttrEl.html +163 -0
  9. data/doc/classes/Atom/Author.html +2 -19
  10. data/doc/classes/Atom/AutodiscoveryFailure.html +111 -0
  11. data/doc/classes/Atom/Categories.html +168 -0
  12. data/doc/classes/Atom/Category.html +10 -1
  13. data/doc/classes/Atom/Collection.html +194 -91
  14. data/doc/classes/Atom/Content.html +42 -1
  15. data/doc/classes/Atom/Contributor.html +2 -8
  16. data/doc/classes/Atom/Control.html +126 -0
  17. data/doc/classes/Atom/Converters.html +571 -0
  18. data/doc/classes/Atom/DigestAuth.html +285 -0
  19. data/doc/classes/Atom/Element.html +673 -106
  20. data/doc/classes/Atom/FileCache.html +287 -0
  21. data/doc/classes/Atom/HTTP.html +211 -95
  22. data/doc/classes/Atom/HTTPResponse.html +190 -0
  23. data/doc/classes/Atom/HasCategories.html +187 -0
  24. data/doc/classes/Atom/HasLinks.html +168 -0
  25. data/doc/classes/Atom/Link.html +80 -3
  26. data/doc/classes/Atom/NilCache.html +202 -0
  27. data/doc/classes/Atom/ParseError.html +111 -0
  28. data/doc/classes/Atom/Parsers.html +311 -0
  29. data/doc/classes/Atom/Person.html +130 -0
  30. data/doc/classes/Atom/Rights.html +113 -0
  31. data/doc/classes/Atom/Service.html +298 -0
  32. data/doc/{files/lib/atom/yaml_rb.html → classes/Atom/Source.html} +26 -24
  33. data/doc/classes/Atom/Subtitle.html +113 -0
  34. data/doc/classes/Atom/Summary.html +113 -0
  35. data/doc/classes/Atom/Text.html +196 -53
  36. data/doc/classes/Atom/Title.html +113 -0
  37. data/doc/classes/Atom/Tools.html +525 -0
  38. data/doc/classes/Atom/Workspace.html +121 -0
  39. data/doc/classes/Object.html +204 -0
  40. data/doc/created.rid +1 -1
  41. data/doc/files/README.html +9 -49
  42. data/doc/files/lib/atom/cache_rb.html +302 -0
  43. data/doc/files/lib/atom/collection_rb.html +1 -2
  44. data/doc/files/lib/atom/element_rb.html +2 -1
  45. data/doc/files/lib/atom/entry_rb.html +2 -2
  46. data/doc/files/lib/atom/feed_rb.html +1 -2
  47. data/doc/files/lib/atom/http_rb.html +6 -1
  48. data/doc/files/lib/atom/{xml_rb.html → service_rb.html} +8 -6
  49. data/doc/files/lib/atom/text_rb.html +2 -1
  50. data/doc/files/lib/atom/{app_rb.html → tools_rb.html} +4 -6
  51. data/doc/fr_class_index.html +23 -3
  52. data/doc/fr_file_index.html +3 -3
  53. data/doc/fr_method_index.html +111 -36
  54. data/lib/atom/cache.rb +178 -0
  55. data/lib/atom/collection.rb +90 -40
  56. data/lib/atom/element.rb +569 -161
  57. data/lib/atom/entry.rb +63 -89
  58. data/lib/atom/feed.rb +65 -67
  59. data/lib/atom/http.rb +421 -49
  60. data/lib/atom/service.rb +106 -0
  61. data/lib/atom/text.rb +138 -61
  62. data/lib/atom/tools.rb +163 -0
  63. data/spec/entry_spec.rb +364 -0
  64. data/spec/ext_spec.rb +42 -0
  65. data/spec/feed_spec.rb +39 -0
  66. data/spec/fixtures/contacts-feed.xml +34 -0
  67. data/spec/fixtures/entry-w-ext.xml +15 -0
  68. data/spec/fixtures/entry-w-xml.xml +24 -0
  69. data/spec/fixtures/entry.xml +42 -0
  70. data/spec/fixtures/feed-w-ext.xml +33 -0
  71. data/spec/fixtures/service-w-xhtml-ns.xml +21 -0
  72. data/spec/fixtures/service.xml +36 -0
  73. data/spec/service_spec.rb +108 -0
  74. data/spec/spec_helper.rb +9 -0
  75. data/test/conformance/order.rb +11 -10
  76. data/test/conformance/title.rb +9 -9
  77. data/test/conformance/updated.rb +2 -1
  78. data/test/runtests.rb +0 -0
  79. data/test/test_constructs.rb +78 -8
  80. data/test/test_feed.rb +35 -29
  81. data/test/test_general.rb +3 -30
  82. data/test/test_http.rb +248 -34
  83. data/test/test_protocol.rb +143 -24
  84. data/test/test_xml.rb +145 -53
  85. metadata +116 -62
  86. data/bin/atom-client.rb +0 -246
  87. data/bin/atom-server.rb~ +0 -71
  88. data/doc/classes/Atom/App.html +0 -217
  89. data/doc/classes/Atom/Entry.html +0 -365
  90. data/doc/classes/Atom/Feed.html +0 -585
  91. data/lib/atom/app.rb +0 -87
  92. data/lib/atom/xml.rb +0 -200
  93. data/lib/atom/yaml.rb +0 -101
data/lib/atom/app.rb DELETED
@@ -1,87 +0,0 @@
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
data/lib/atom/xml.rb DELETED
@@ -1,200 +0,0 @@
1
- require "atom/entry"
2
- require "atom/feed"
3
- require "uri"
4
-
5
- # Two big, interrelated problems:
6
- #
7
- # * I probably shouldn't be playing around in REXML's namespace
8
- # * REXML isn't a great parser, and other options would be nice
9
- #
10
- # This shouldn't be hard to do, it's just tedious and non-critical
11
- module REXML # :nodoc: all
12
- class Document
13
- def to_atom_entry base = ""
14
- self.root.to_atom_entry base
15
- end
16
- def to_atom_feed base = ""
17
- self.root.to_atom_feed base
18
- end
19
- end
20
- class Element
21
- def get_atom_element name
22
- XPath.first(self, "./atom:#{name}", { "atom" => Atom::NS })
23
- end
24
-
25
- def each_atom_element name
26
- XPath.each(self, "./atom:#{name}", { "atom" => Atom::NS }) do |elem|
27
- yield elem
28
- end
29
- end
30
-
31
- def get_extensions
32
- # XXX also look for attributes
33
- children.find_all { |child| child.respond_to? :namespace and child.namespace != Atom::NS }
34
- end
35
-
36
- # get the text content of a descendant element in the Atom namespace
37
- def get_atom_text name
38
- elem = get_atom_element name
39
- if elem
40
- elem.text
41
- else
42
- nil
43
- end
44
- end
45
-
46
- # a workaround for the odd way in which REXML handles namespaces
47
- # returns the value of the attribute +name+ that's in the same namespace as this element
48
- def ns_attr name
49
- if not self.prefix.empty?
50
- attr = self.prefix + ":" + name
51
- else
52
- attr = name
53
- end
54
-
55
- self.attributes[attr]
56
- end
57
-
58
- def fill_text_construct(entry, name)
59
- text = get_atom_element(name)
60
- if text
61
- type = text.ns_attr("type")
62
- src = text.ns_attr("src")
63
-
64
- if src and name == :content
65
- # the only content is out of line
66
- entry.send( "#{name}=".to_sym, "")
67
- entry.send(name.to_sym)["src"] = src
68
- elsif type == "xhtml"
69
- div = XPath.first(text, "./xhtml:div", { "xhtml" => XHTML::NS })
70
- unless div
71
- raise "Refusing to parse type='xhtml' with no <div/> wrapper"
72
- end
73
-
74
- # content is the serialized content of the <div> wrapper
75
- entry.send( "#{name}=".to_sym, div )
76
- else
77
- raw = text.text
78
- entry.send( "#{name}=", raw )
79
- end
80
-
81
- if text.attributes["xml:base"]
82
- entry.send(name.to_sym).base = text.attributes["xml:base"]
83
- end
84
-
85
- if type and type != "text"
86
- entry.send(name.to_sym)["type"] = type
87
- end
88
- end
89
- end
90
-
91
- def fill_elem_element(top, kind)
92
- each_atom_element(kind) do |elem|
93
- person = top.send("#{kind}s".to_sym).new
94
-
95
- ["name", "uri", "email"].each do |name|
96
- person.send("#{name}=".to_sym, elem.get_atom_text(name))
97
- end
98
- end
99
- end
100
-
101
- def fill_attr_element(top, array, kind)
102
- each_atom_element(kind) do |elem|
103
- thing = array.new
104
-
105
- thing.class.attrs.each do |name,req|
106
- value = elem.ns_attr name.to_s
107
- if value and name == :href
108
- thing[name.to_s] = (URI.parse(top.base) + value).to_s
109
- elsif value
110
- thing[name.to_s] = value
111
- end
112
- end
113
- end
114
- end
115
-
116
- # 'base' is the URI that you fetched this document from.
117
- def to_atom_entry base = ""
118
- unless self.name == "entry" and self.namespace == Atom::NS
119
- raise TypeError, "this isn't an atom:entry! (name: #{self.name}, ns: #{self.namespace})"
120
- end
121
-
122
- entry = Atom::Entry.new
123
-
124
- entry.base = if attributes["xml:base"]
125
- (URI.parse(base) + attributes["xml:base"]).to_s
126
- else
127
- # go with the URL we were passed in
128
- base
129
- end
130
-
131
- # Text constructs
132
- entry.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r|
133
- fill_text_construct(entry, n)
134
- end
135
-
136
- ["id", "published", "updated"].each do |name|
137
- entry.send("#{name}=".to_sym, get_atom_text(name))
138
- end
139
-
140
- ["author", "contributor"].each do |type|
141
- fill_elem_element(entry, type)
142
- end
143
-
144
- {"link" => entry.links, "category" => entry.categories}.each do |k,v|
145
- fill_attr_element(entry, v, k)
146
- end
147
-
148
- # extension elements
149
- get_extensions.each do |elem|
150
- entry.extensions << elem.dup # otherwise they get removed from the doc
151
- end
152
-
153
- entry
154
- end
155
-
156
- # 'base' is the URI that you fetched this document from.
157
- def to_atom_feed base = ""
158
- unless self.name == "feed" and self.namespace == Atom::NS
159
- raise TypeError, "this isn't an atom:feed! (name: #{self.name}, ns: #{self.namespace})"
160
- end
161
-
162
- feed = Atom::Feed.new
163
-
164
- feed.base = if attributes["xml:base"]
165
- (URI.parse(base) + attributes["xml:base"]).to_s
166
- else
167
- # go with the URL we were passed in
168
- base
169
- end
170
-
171
- # Text constructs
172
- feed.class.elements.find_all { |n,k,r| k.ancestors.member? Atom::Text }.each do |n,k,r|
173
- fill_text_construct(feed, n)
174
- end
175
-
176
- ["id", "updated", "generator", "icon", "logo"].each do |name|
177
- feed.send("#{name}=".to_sym, get_atom_text(name))
178
- end
179
-
180
- ["author", "contributor"].each do |type|
181
- fill_elem_element(feed, type)
182
- end
183
-
184
- {"link" => feed.links, "category" => feed.categories}.each do |k,v|
185
- fill_attr_element(feed, v, k)
186
- end
187
-
188
- each_atom_element("entry") do |elem|
189
- feed << elem.to_atom_entry(feed.base)
190
- end
191
-
192
- get_extensions.each do |elem|
193
- # have to duplicate them, or they'll get removed from the doc
194
- feed.extensions << elem.dup
195
- end
196
-
197
- feed
198
- end
199
- end
200
- end
data/lib/atom/yaml.rb DELETED
@@ -1,101 +0,0 @@
1
- require "atom/entry"
2
- require "yaml"
3
-
4
- module Atom
5
- class Time
6
- def taguri; nil end
7
- end
8
-
9
- class Element < Hash
10
- def taguri # :nodoc:
11
- end
12
-
13
- def to_yaml_properties # :nodoc:
14
- self.class.elements.find_all do |n,k,r|
15
- v = get(n)
16
- v and not (v.respond_to? :empty? and v.empty?)
17
- end.map { |n,k,r| "@#{n}" }
18
- end
19
-
20
- def to_yaml( opts = {} ) # :nodoc:
21
- YAML::quick_emit( object_id, opts ) do |out|
22
- out.map( taguri, to_yaml_style ) do |map|
23
- self.to_yaml_properties.each do |m|
24
- map.add( m[1..-1], instance_variable_get( m ) )
25
- end
26
- end
27
- end
28
- end
29
- end
30
-
31
- class AttrEl < Atom::Element
32
- def to_yaml( opts = {} )
33
- YAML::quick_emit( object_id, opts ) do |out|
34
- out.map( nil, to_yaml_style ) do |map|
35
- self.class.attrs.each do |n,r|
36
- map.add( n.to_s, self[n.to_s] ) if self[n.to_s]
37
- end
38
- end
39
- end
40
- end
41
- end
42
-
43
- class Text < Atom::Element
44
- def taguri # :nodoc:
45
- end
46
-
47
- def to_yaml( opts = {} ) # :nodoc:
48
- YAML::quick_emit( object_id, opts ) do |out|
49
- out.scalar(taguri, to_s, to_yaml_style)
50
- end
51
- end
52
- def to_yaml_style # :nodoc:
53
- if @content.match("\n")
54
- :fold
55
- else
56
- :plain
57
- end
58
- end
59
- end
60
-
61
- class Entry
62
- def to_yaml_type # :nodoc:
63
- '!necronomicorp.com,2006/entry'
64
- end
65
-
66
- # parses an Atom::Entry from YAML
67
- def self.from_yaml yaml
68
- hash = if yaml.kind_of?(Hash); yaml else YAML.load(yaml); end
69
-
70
- entry = Atom::Entry.new
71
-
72
- entry.title = hash["title"]
73
- entry.summary = hash["summary"]
74
-
75
- elem_constructs = {"authors" => entry.authors, "contributors" => entry.contributors, "links" => entry.links, "categories" => entry.categories}
76
-
77
- elem_constructs.each do |type,ary|
78
- hash[type] ||= []
79
-
80
- hash[type].each do |yelem|
81
- elem = ary.new
82
-
83
- elem.class.attrs.each do |attrb,req|
84
- elem[attrb.to_s] = yelem[attrb.to_s]
85
- end
86
-
87
- elem.class.elements.each do |name,kind,req|
88
- elem.send("#{name}=".to_sym, yelem[name.to_s])
89
- end
90
- end
91
- end
92
-
93
- # this adds more categories, and could cause conflicts
94
- entry.tag_with hash["tags"]
95
- entry.content = hash["content"]
96
- entry.content["type"] = hash["type"] if hash["type"]
97
-
98
- entry
99
- end
100
- end
101
- end