atom-tools 0.9.4 → 1.0.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.
- data/Rakefile +1 -1
- data/bin/atom-client.rb +19 -23
- data/lib/atom/element.rb +1 -1
- data/lib/atom/entry.rb +5 -1
- data/lib/atom/feed.rb +10 -2
- data/lib/atom/http.rb +1 -1
- data/lib/atom/service.rb +20 -14
- data/lib/atom/text.rb +16 -9
- data/lib/atom/xml.rb +7 -3
- data/test/test_protocol.rb +9 -9
- data/test/test_xml.rb +1 -1
- metadata +5 -5
data/Rakefile
CHANGED
data/bin/atom-client.rb
CHANGED
@@ -32,6 +32,7 @@ require "atom/service"
|
|
32
32
|
require "atom/http"
|
33
33
|
|
34
34
|
require "rubygems"
|
35
|
+
require "bluecloth"
|
35
36
|
|
36
37
|
require "time"
|
37
38
|
|
@@ -62,26 +63,34 @@ class String
|
|
62
63
|
end
|
63
64
|
|
64
65
|
class Atom::Entry
|
66
|
+
def prepare_for_output
|
67
|
+
filter_hook
|
68
|
+
|
69
|
+
updated!
|
70
|
+
end
|
71
|
+
|
72
|
+
def filter_hook
|
73
|
+
# so much for actual text content...
|
74
|
+
if @content and @content["type"] == "text"
|
75
|
+
self.content = BlueCloth.new( @content.to_s ).to_html
|
76
|
+
@content["type"] = "xhtml"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
65
80
|
def edit
|
66
81
|
yaml = YAML.load(self.to_yaml)
|
67
82
|
|
68
|
-
#
|
83
|
+
# human readability
|
69
84
|
yaml.delete "id"
|
70
85
|
|
71
86
|
if yaml["links"]
|
72
|
-
yaml["links"].find_all { |l| ["
|
87
|
+
yaml["links"].find_all { |l| l["rel"] == "alternate" or l["rel"] == "edit" }.each { |l| yaml["links"].delete(l) }
|
73
88
|
yaml.delete("links") if yaml["links"].empty?
|
74
89
|
end
|
75
|
-
|
76
|
-
if self.content
|
77
|
-
yaml["content"] = $text_filter_before.call(self.content.html)
|
78
|
-
end
|
79
|
-
|
90
|
+
|
80
91
|
new_yaml, entry = write_entry(yaml.to_yaml)
|
81
92
|
|
82
|
-
# restore deleted bits
|
83
93
|
entry.id = self.id
|
84
|
-
self.links.each { |l| entry.links << l }
|
85
94
|
|
86
95
|
[new_yaml["slug"], entry]
|
87
96
|
end
|
@@ -136,12 +145,7 @@ def write_entry(editstring = "")
|
|
136
145
|
|
137
146
|
entry = Atom::Entry.from_yaml yaml
|
138
147
|
|
139
|
-
|
140
|
-
entry.content, type = $text_filter_after.call(yaml["content"])
|
141
|
-
entry.content["type"] = (type || "text")
|
142
|
-
end
|
143
|
-
|
144
|
-
entry.updated!
|
148
|
+
entry.prepare_for_output
|
145
149
|
|
146
150
|
# XXX disabled until the APP WG can decide what a valid entry is
|
147
151
|
=begin
|
@@ -183,14 +187,6 @@ url = if options[:url]
|
|
183
187
|
options[:url]
|
184
188
|
else
|
185
189
|
yaml = YAML.load(File.read("#{ENV["HOME"]}/.atom-client"))
|
186
|
-
|
187
|
-
# leave it the way it came in
|
188
|
-
i = Proc.new { |x| x }
|
189
|
-
$text_filter_before = eval(yaml["text_filter_before"])
|
190
|
-
$text_filter_before ||= i
|
191
|
-
$text_filter_after = eval(yaml["text_filter_after"])
|
192
|
-
$text_filter_after ||= i
|
193
|
-
|
194
190
|
collections = yaml["collections"]
|
195
191
|
|
196
192
|
puts "which collection?"
|
data/lib/atom/element.rb
CHANGED
@@ -170,7 +170,7 @@ module Atom # :nodoc:
|
|
170
170
|
|
171
171
|
self.class.attrs.each do |name,req|
|
172
172
|
value = self[name.to_s]
|
173
|
-
elem.attributes[name.to_s] = value if value
|
173
|
+
elem.attributes[name.to_s] = value.to_s if value
|
174
174
|
end
|
175
175
|
|
176
176
|
self.extensions.children.each do |element|
|
data/lib/atom/entry.rb
CHANGED
@@ -66,7 +66,11 @@ module Atom
|
|
66
66
|
elsif xml.respond_to? :read
|
67
67
|
self.parse(xml.read)
|
68
68
|
else
|
69
|
-
|
69
|
+
begin
|
70
|
+
REXML::Document.new(xml.to_s).to_atom_entry(base)
|
71
|
+
rescue REXML::ParseException
|
72
|
+
raise Atom::ParseError
|
73
|
+
end
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
data/lib/atom/feed.rb
CHANGED
@@ -73,7 +73,11 @@ module Atom
|
|
73
73
|
elsif xml.respond_to? :read
|
74
74
|
self.parse(xml.read)
|
75
75
|
else
|
76
|
-
|
76
|
+
begin
|
77
|
+
REXML::Document.new(xml.to_s).to_atom_feed(base)
|
78
|
+
rescue REXML::ParseException
|
79
|
+
raise Atom::ParseError
|
80
|
+
end
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
@@ -96,6 +100,10 @@ module Atom
|
|
96
100
|
@entries.each &block
|
97
101
|
end
|
98
102
|
|
103
|
+
def empty?
|
104
|
+
@entries.empty?
|
105
|
+
end
|
106
|
+
|
99
107
|
# gets everything in the logical feed (could be a lot of stuff)
|
100
108
|
# (see <http://www.ietf.org/internet-drafts/draft-nottingham-atompub-feed-history-05.txt>)
|
101
109
|
def get_everything!
|
@@ -130,7 +138,7 @@ module Atom
|
|
130
138
|
|
131
139
|
# like #merge, but in place
|
132
140
|
def merge! other_feed
|
133
|
-
[:id, :title, :subtitle, :updated, :rights].each { |p|
|
141
|
+
[:id, :title, :subtitle, :updated, :rights, :logo, :icon].each { |p|
|
134
142
|
self.send("#{p}=", other_feed.send("#{p}"))
|
135
143
|
}
|
136
144
|
|
data/lib/atom/http.rb
CHANGED
data/lib/atom/service.rb
CHANGED
@@ -5,11 +5,6 @@ require "atom/element"
|
|
5
5
|
require "atom/collection"
|
6
6
|
|
7
7
|
module Atom
|
8
|
-
class WrongNamespace < RuntimeError #:nodoc:
|
9
|
-
end
|
10
|
-
class WrongResponse < RuntimeError # :nodoc:
|
11
|
-
end
|
12
|
-
|
13
8
|
# an Atom::Workspace has a #title (Atom::Text) and #collections, an Array of Atom::Collection s
|
14
9
|
class Workspace < Atom::Element
|
15
10
|
element :collections, Atom::Multiple(Atom::Collection)
|
@@ -23,7 +18,11 @@ module Atom
|
|
23
18
|
elsif xml.is_a? REXML::Element
|
24
19
|
xml
|
25
20
|
else
|
26
|
-
|
21
|
+
begin
|
22
|
+
REXML::Document.new(xml)
|
23
|
+
rescue REXML::ParseException
|
24
|
+
raise Atom::ParseError
|
25
|
+
end
|
27
26
|
end
|
28
27
|
|
29
28
|
xml.fill_text_construct(ws, "title")
|
@@ -42,7 +41,12 @@ module Atom
|
|
42
41
|
"./app:accept",
|
43
42
|
{"app" => Atom::PP_NS} )
|
44
43
|
|
45
|
-
|
44
|
+
accepts = []
|
45
|
+
REXML::XPath.each(col_el, "./app:accept", {"app" => Atom::PP_NS}) do |a|
|
46
|
+
accepts << a.texts.join
|
47
|
+
end
|
48
|
+
|
49
|
+
coll.accepts = (accepts.empty? ? ["application/atom+xml;type=entry"] : accepts)
|
46
50
|
|
47
51
|
ws.collections << coll
|
48
52
|
end
|
@@ -62,16 +66,18 @@ module Atom
|
|
62
66
|
self.collections.each do |coll|
|
63
67
|
el = REXML::Element.new "collection"
|
64
68
|
|
65
|
-
el.attributes["href"] = coll.uri
|
69
|
+
el.attributes["href"] = coll.uri.to_s
|
66
70
|
|
67
71
|
title = coll.title.to_element
|
68
72
|
title.name = "atom:title"
|
69
73
|
el << title
|
70
74
|
|
71
75
|
unless coll.accepts.nil?
|
72
|
-
accepts
|
73
|
-
|
74
|
-
|
76
|
+
coll.accepts.each do |acc|
|
77
|
+
accept = REXML::Element.new "accept"
|
78
|
+
accept.text = acc
|
79
|
+
el << accept
|
80
|
+
end
|
75
81
|
end
|
76
82
|
|
77
83
|
root << el
|
@@ -102,8 +108,8 @@ module Atom
|
|
102
108
|
res = @http.get(base, "Accept" => "application/atomsvc+xml")
|
103
109
|
res.validate_content_type(["application/atomsvc+xml"])
|
104
110
|
|
105
|
-
unless res.code == "200"
|
106
|
-
raise
|
111
|
+
unless res.code == "200"
|
112
|
+
raise Atom::HTTPException, "Unexpected HTTP response code: #{res.code}"
|
107
113
|
end
|
108
114
|
|
109
115
|
parse(res.body, base)
|
@@ -128,7 +134,7 @@ module Atom
|
|
128
134
|
end
|
129
135
|
|
130
136
|
unless rxml.root.namespace == PP_NS
|
131
|
-
raise
|
137
|
+
raise Atom::ParseError, "this isn't an atom service document! (wrong namespace: #{rxml.root.namespace})"
|
132
138
|
end
|
133
139
|
|
134
140
|
REXML::XPath.match( rxml, "/app:service/app:workspace", {"app" => Atom::PP_NS} ).each do |ws_el|
|
data/lib/atom/text.rb
CHANGED
@@ -105,16 +105,14 @@ module Atom
|
|
105
105
|
end
|
106
106
|
|
107
107
|
# this should be done via inheritance
|
108
|
-
|
109
|
-
c = convert_contents e
|
108
|
+
c = convert_contents e
|
110
109
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
end
|
110
|
+
if c.is_a? String
|
111
|
+
e.text = c
|
112
|
+
elsif c.is_a? REXML::Element
|
113
|
+
e << c.dup
|
114
|
+
else
|
115
|
+
raise RuntimeError, "atom:#{local_name} can't contain type #{@content.class}"
|
118
116
|
end
|
119
117
|
|
120
118
|
e
|
@@ -176,6 +174,15 @@ module Atom
|
|
176
174
|
end
|
177
175
|
end
|
178
176
|
|
177
|
+
def to_element
|
178
|
+
if self["src"]
|
179
|
+
element_super = Element.instance_method(:to_element)
|
180
|
+
return element_super.bind(self).call
|
181
|
+
end
|
182
|
+
|
183
|
+
super
|
184
|
+
end
|
185
|
+
|
179
186
|
private
|
180
187
|
def valid_type? type
|
181
188
|
super or type.match(/\//)
|
data/lib/atom/xml.rb
CHANGED
@@ -2,6 +2,8 @@ require "atom/entry"
|
|
2
2
|
require "atom/feed"
|
3
3
|
require "uri"
|
4
4
|
|
5
|
+
class Atom::ParseError < StandardError; end
|
6
|
+
|
5
7
|
# Two big, interrelated problems:
|
6
8
|
#
|
7
9
|
# * I probably shouldn't be playing around in REXML's namespace
|
@@ -11,9 +13,11 @@ require "uri"
|
|
11
13
|
module REXML # :nodoc: all
|
12
14
|
class Document
|
13
15
|
def to_atom_entry base = ""
|
16
|
+
raise Atom::ParseError unless self.root
|
14
17
|
self.root.to_atom_entry base
|
15
18
|
end
|
16
19
|
def to_atom_feed base = ""
|
20
|
+
raise Atom::ParseError unless self.root
|
17
21
|
self.root.to_atom_feed base
|
18
22
|
end
|
19
23
|
end
|
@@ -79,7 +83,7 @@ module REXML # :nodoc: all
|
|
79
83
|
elsif type == "xhtml"
|
80
84
|
div = XPath.first(text, "./xhtml:div", { "xhtml" => XHTML::NS })
|
81
85
|
unless div
|
82
|
-
raise "Refusing to parse type='xhtml' with no <div/> wrapper"
|
86
|
+
raise Atom::ParseError, "Refusing to parse type='xhtml' with no <div/> wrapper"
|
83
87
|
end
|
84
88
|
|
85
89
|
# content is the serialized content of the <div> wrapper
|
@@ -131,7 +135,7 @@ module REXML # :nodoc: all
|
|
131
135
|
# 'base' is the URI that you fetched this document from.
|
132
136
|
def to_atom_entry base = ""
|
133
137
|
unless self.name == "entry" and self.namespace == Atom::NS
|
134
|
-
raise
|
138
|
+
raise Atom::ParseError, "this isn't an atom:entry! (name: #{self.name}, ns: #{self.namespace})"
|
135
139
|
end
|
136
140
|
|
137
141
|
entry = Atom::Entry.new
|
@@ -168,7 +172,7 @@ module REXML # :nodoc: all
|
|
168
172
|
# 'base' is the URI that you fetched this document from.
|
169
173
|
def to_atom_feed base = ""
|
170
174
|
unless self.name == "feed" and self.namespace == Atom::NS
|
171
|
-
raise
|
175
|
+
raise Atom::ParseError, "this isn't an atom:feed! (name: #{self.name}, ns: #{self.namespace})"
|
172
176
|
end
|
173
177
|
|
174
178
|
feed = Atom::Feed.new
|
data/test/test_protocol.rb
CHANGED
@@ -43,14 +43,14 @@ END
|
|
43
43
|
assert_equal "My Blog", ws.title.to_s
|
44
44
|
|
45
45
|
coll = ws.collections.first
|
46
|
-
assert_equal URI.parse("http://example.org/myblog/entries"), coll.uri
|
47
|
-
assert_equal "Entries", coll.title.to_s
|
48
|
-
assert_equal "entry", coll.accepts
|
46
|
+
assert_equal URI.parse("http://example.org/myblog/entries"), coll.uri
|
47
|
+
assert_equal "Entries", coll.title.to_s
|
48
|
+
assert_equal ["application/atom+xml;type=entry"], coll.accepts
|
49
49
|
|
50
50
|
coll = ws.collections.last
|
51
|
-
assert_equal URI.parse("http://example.org/myblog/fotes"), coll.uri
|
52
|
-
assert_equal "Photos", coll.title.to_s
|
53
|
-
assert_equal "image/*", coll.accepts
|
51
|
+
assert_equal URI.parse("http://example.org/myblog/fotes"), coll.uri
|
52
|
+
assert_equal "Photos", coll.title.to_s
|
53
|
+
assert_equal ["image/*"], coll.accepts
|
54
54
|
|
55
55
|
http = service.instance_variable_get(:@http)
|
56
56
|
assert_instance_of Atom::HTTP, http
|
@@ -74,7 +74,7 @@ END
|
|
74
74
|
|
75
75
|
coll = Atom::Collection.new "http://example.org/audio"
|
76
76
|
coll.title = "Audio"
|
77
|
-
coll.accepts = "audio/*"
|
77
|
+
coll.accepts = ["audio/*"]
|
78
78
|
ws.collections << coll
|
79
79
|
|
80
80
|
nses = { "app" => Atom::PP_NS, "atom" => Atom::NS }
|
@@ -102,7 +102,7 @@ END
|
|
102
102
|
title = REXML::XPath.first(entries, "./atom:title", nses)
|
103
103
|
assert_equal "Entries", title.text
|
104
104
|
|
105
|
-
accepts = REXML::XPath.first(entries, "./app:
|
105
|
+
accepts = REXML::XPath.first(entries, "./app:accept", nses)
|
106
106
|
assert_nil accepts
|
107
107
|
|
108
108
|
audio = colls.last
|
@@ -112,7 +112,7 @@ END
|
|
112
112
|
title = REXML::XPath.first(audio, "./atom:title", nses)
|
113
113
|
assert_equal "Audio", title.text
|
114
114
|
|
115
|
-
accepts = REXML::XPath.first(audio, "./app:
|
115
|
+
accepts = REXML::XPath.first(audio, "./app:accept", nses)
|
116
116
|
assert_equal "audio/*", accepts.text
|
117
117
|
end
|
118
118
|
|
data/test/test_xml.rb
CHANGED
@@ -146,7 +146,7 @@ class AtomTest < Test::Unit::TestCase
|
|
146
146
|
assert entry.draft
|
147
147
|
end
|
148
148
|
|
149
|
-
def
|
149
|
+
def test_extensive_entry_parsing
|
150
150
|
str = '<entry xmlns="http://www.w3.org/2005/Atom">
|
151
151
|
<title>Atom draft-07 snapshot</title>
|
152
152
|
<link rel="alternate" type="text/html"
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
|
|
3
3
|
specification_version: 1
|
4
4
|
name: atom-tools
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2007-11-10 00:00:00 -07:00
|
8
8
|
summary: Tools for working with Atom Entries, Feeds and Collections
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -39,14 +39,14 @@ files:
|
|
39
39
|
- test/test_feed.rb
|
40
40
|
- test/test_protocol.rb
|
41
41
|
- test/conformance
|
42
|
-
- test/test_xml.rb
|
43
|
-
- test/test_http.rb
|
44
|
-
- test/test_general.rb
|
45
42
|
- test/conformance/updated.rb
|
46
43
|
- test/conformance/xmlnamespace.rb
|
47
44
|
- test/conformance/title.rb
|
48
45
|
- test/conformance/order.rb
|
49
46
|
- test/conformance/xhtmlcontentdiv.rb
|
47
|
+
- test/test_xml.rb
|
48
|
+
- test/test_http.rb
|
49
|
+
- test/test_general.rb
|
50
50
|
- lib/atom
|
51
51
|
- lib/atom/yaml.rb
|
52
52
|
- lib/atom/feed.rb
|