atom-tools 0.9.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require "rake/gempackagetask"
6
6
  require "rake/clean"
7
7
 
8
8
  NAME = "atom-tools"
9
- VERS = "0.9.4"
9
+ VERS = "1.0.0"
10
10
 
11
11
  # the following from markaby-0.5's tools/rakehelp
12
12
  def setup_tests
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
- # delete bits the person doesn't need to see
83
+ # human readability
69
84
  yaml.delete "id"
70
85
 
71
86
  if yaml["links"]
72
- yaml["links"].find_all { |l| ["alternate", "edit"].member? l["rel"] }.each { |l| yaml["links"].delete(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
- if yaml["content"] #and not yaml["type"]
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
- REXML::Document.new(xml.to_s).to_atom_entry(base)
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
- REXML::Document.new(xml.to_s).to_atom_feed(base)
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
@@ -14,7 +14,7 @@ class String # :nodoc:
14
14
  end
15
15
 
16
16
  module Atom
17
- UA = "atom-tools 0.9.3"
17
+ UA = "atom-tools 1.0.0"
18
18
 
19
19
  module DigestAuth
20
20
  CNONCE = Digest::MD5.hexdigest("%x" % (Time.now.to_i + rand(65535)))
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
- REXML::Document.new(xml)
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
- coll.accepts = (accepts ? accepts.text : "entry")
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 = REXML::Element.new "accepts"
73
- accepts.text = coll.accepts
74
- el << accepts
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" # XXX needs to handle redirects, &c.
106
- raise WrongResponse, "service document URL responded with unexpected code #{res.code}"
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 WrongNamespace, "this isn't an atom service document!"
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
- unless self.class == Atom::Content and self["src"]
109
- c = convert_contents e
108
+ c = convert_contents e
110
109
 
111
- if c.is_a? String
112
- e.text = c
113
- elsif c.is_a? REXML::Element
114
- e << c.dup
115
- else
116
- raise RuntimeError, "atom:#{local_name} can't contain type #{@content.class}"
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 TypeError, "this isn't an atom:entry! (name: #{self.name}, ns: #{self.namespace})"
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 TypeError, "this isn't an atom:feed! (name: #{self.name}, ns: #{self.namespace})"
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
@@ -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:accepts", nses)
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:accepts", nses)
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 test_extensive_enty_parsing
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.9.4
7
- date: 2007-08-11 00:00:00 -06:00
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