atom-tools 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -7,81 +7,74 @@ require "spec/rake/spectask"
7
7
  require "rake/clean"
8
8
 
9
9
  NAME = "atom-tools"
10
- VERS = "2.0.3"
11
-
12
- # the following from markaby-0.5's tools/rakehelp
13
- def setup_tests
14
- Rake::TestTask.new do |t|
15
- t.libs << "test"
16
- t.test_files = FileList['test/test*.rb']
17
- t.verbose = true
18
- end
19
- end
10
+ VERS = "2.0.4"
11
+
12
+ task :default => [:spec]
13
+
14
+ # For historical reasons, atom-tools has both rspec specs and test/unit tests.
15
+ # This is silly (and there's a lot of duplication), but I have better things to
16
+ # do than rewrite the tests.
17
+ #
18
+ # Ideally all the tests should be runnable with one command, but for now you
19
+ # have to run "rake test" and "rake spec"
20
20
 
21
- def setup_rdoc files
22
- Rake::RDocTask.new do |rdoc|
23
- rdoc.title = NAME + " documentation"
24
- rdoc.rdoc_dir = 'doc'
25
- rdoc.options << '--line-numbers'
26
- rdoc.options << '--inline-source'
27
- rdoc.rdoc_files.add(files)
28
- end
21
+ # spec task
22
+ desc 'Run all specs (see also "test" task)'
23
+ Spec::Rake::SpecTask.new('spec')
24
+
25
+ # test task
26
+ Rake::TestTask.new do |t|
27
+ t.libs << "test"
28
+ t.test_files = FileList['test/test*.rb']
29
+ t.verbose = true
29
30
  end
30
31
 
31
- def setup_gem(pkg_name, pkg_version, author, summary, dependencies, test_file)
32
- pkg_version = pkg_version
33
- pkg_name = pkg_name
34
- pkg_file_name = "#{pkg_name}-#{pkg_version}"
35
-
36
- spec = Gem::Specification.new do |s|
37
- s.name = pkg_name
38
- s.version = pkg_version
39
- s.platform = Gem::Platform::RUBY
40
- s.author = author
41
- s.email = 'whateley@gmail.com'
42
- s.homepage = 'http://code.necronomicorp.com/atom-tools'
43
- s.rubyforge_project = 'ibes'
44
- s.summary = summary
45
- s.test_file = test_file
46
- s.has_rdoc = true
47
- s.extra_rdoc_files = [ "README" ]
48
- dependencies.each do |dep|
49
- s.add_dependency(*dep)
50
- end
51
- s.files = %w(COPYING README Rakefile setup.rb) +
52
- Dir.glob("{bin,doc,test,lib}/**/*") +
53
- Dir.glob("ext/**/*.{h,c,rb}") +
54
- Dir.glob("examples/**/*.rb") +
55
- Dir.glob("tools/*.rb")
56
-
57
- s.require_path = "lib"
58
- s.extensions = FileList["ext/**/extconf.rb"].to_a
59
-
60
- s.bindir = "bin"
61
- end
62
-
63
- Rake::GemPackageTask.new(spec) do |p|
64
- p.gem_spec = spec
65
- p.need_tar = true
66
- end
67
-
68
- task :install do
69
- sh %{rake package}
70
- sh %{gem install pkg/#{pkg_name}-#{pkg_version}}
71
- end
32
+ Rake::RDocTask.new do |rdoc|
33
+ rdoc.title = 'atom-tools documentation'
34
+ rdoc.main = 'README'
35
+ rdoc.rdoc_files.include 'README', 'lib/**/*.rb'
36
+ rdoc.rdoc_dir = 'doc'
72
37
  end
73
38
 
74
- task :default => [:spec]
75
- desc 'Run all specs and generate report for spec results and code coverage'
76
- Spec::Rake::SpecTask.new('spec') do |t|
77
- t.spec_opts = ["--format", "html:report.html", '--diff']
78
- t.fail_on_error = false
79
- t.rcov = true
39
+ spec = Gem::Specification.new do |s|
40
+ s.name = NAME
41
+ s.version = VERS
42
+ s.platform = Gem::Platform::RUBY
43
+ s.author = "Brendan Taylor"
44
+ s.email = 'whateley@gmail.com'
45
+ s.homepage = 'http://github.com/bct/atom-tools/wikis'
46
+
47
+ s.rubyforge_project = 'ibes'
48
+
49
+ s.summary = 'Tools for working with Atom Entries, Feeds and Collections.'
50
+ s.description = 'atom-tools is an all-in-one Atom library. It parses and builds Atom (RFC 4287) entries and feeds, and manipulates Atom Publishing Protocol (RFC 5023) Collections.
51
+
52
+ It also comes with a set of commandline utilities for working with AtomPub Collections.
53
+
54
+ It is not the fastest Ruby Atom library, but it is comprehensive and makes handling extensions to the Atom format very easy.'
55
+
56
+ s.test_file = "test/runtests.rb" # TODO: should have the spec here instead?
57
+ s.has_rdoc = true
58
+ s.extra_rdoc_files = [ "README" ]
59
+
60
+ s.files = %w(COPYING README Rakefile setup.rb) +
61
+ Dir.glob("{bin,doc,test,spec,lib}/**/*") +
62
+ Dir.glob("ext/**/*.{h,c,rb}") +
63
+ Dir.glob("examples/**/*.rb") +
64
+ Dir.glob("tools/*.rb")
65
+
66
+ s.require_path = "lib"
67
+ s.extensions = FileList["ext/**/extconf.rb"].to_a
68
+
69
+ s.bindir = "bin"
80
70
  end
81
71
 
82
- setup_tests
83
- setup_rdoc ['README', 'lib/**/*.rb']
72
+ Rake::GemPackageTask.new(spec) do |p|
73
+ p.gem_spec = spec
74
+ p.need_tar = true
75
+ end
84
76
 
85
- summary = "Tools for working with Atom Entries, Feeds and Collections"
86
- test_file = "test/runtests.rb"
87
- setup_gem(NAME, VERS, "Brendan Taylor", summary, [], test_file)
77
+ task :install do
78
+ sh %{rake package}
79
+ sh %{gem install pkg/#{NAME}-#{VERS}}
80
+ end
@@ -8,6 +8,7 @@ Usage: atom-post [options] destination [file]
8
8
  'file' is the path to a file to POST (default is stdin)
9
9
  =end
10
10
 
11
+ require 'rubygems'
11
12
  require 'atom/tools'
12
13
  include Atom::Tools
13
14
 
@@ -507,7 +507,7 @@ module Atom # :nodoc:
507
507
  @attrs
508
508
  end
509
509
 
510
- self.class.initters do |init|
510
+ self.class.run_initters do |init|
511
511
  self.instance_eval &init
512
512
  end
513
513
 
@@ -521,9 +521,8 @@ module Atom # :nodoc:
521
521
  @on_init << block
522
522
  end
523
523
 
524
- def self.initters &block
525
- @on_init ||= []
526
- @on_init.each &block
524
+ def self.run_initters &block
525
+ @on_init.each(&block) if @on_init
527
526
  end
528
527
 
529
528
  # appends an element named 'name' in namespace 'ns' to 'root'
@@ -644,4 +643,43 @@ module Atom # :nodoc:
644
643
  class Contributor < Atom::Person
645
644
  is_atom_element :contributor
646
645
  end
646
+
647
+ module HasLinks
648
+ def HasLinks.included(klass)
649
+ klass.atom_elements :link, :links, Atom::Link
650
+ end
651
+
652
+ def find_link(criteria)
653
+ self.links.find do |l|
654
+ criteria.all? { |k,v| l.send(k) == v }
655
+ end
656
+ end
657
+ end
658
+
659
+ module HasCategories
660
+ def HasCategories.included(klass)
661
+ klass.atom_elements :category, :categories, Atom::Category
662
+ end
663
+
664
+ # categorize the entry with each of an array or a space-separated
665
+ # string
666
+ def tag_with(tags, delimiter = ' ')
667
+ return if not tags or tags.empty?
668
+
669
+ tag_list = unless tags.is_a?(String)
670
+ tags
671
+ else
672
+ tags = tags.split(delimiter)
673
+ tags.map! { |t| t.strip }
674
+ tags.reject! { |t| t.empty? }
675
+ tags.uniq
676
+ end
677
+
678
+ tag_list.each do |tag|
679
+ unless categories.any? { |c| c.term == tag }
680
+ categories.new :term => tag
681
+ end
682
+ end
683
+ end
684
+ end
647
685
  end
@@ -3,7 +3,21 @@ require "rexml/document"
3
3
  require "atom/element"
4
4
  require "atom/text"
5
5
 
6
+ require 'atom/feed'
7
+
6
8
  module Atom
9
+ # this is just a forward declaration since atom/entry includes atom/feed and vice-versa.
10
+ class Feed < Atom::Element # :nodoc:
11
+ end
12
+
13
+ class Source < Atom::Feed
14
+ is_atom_element :source
15
+
16
+ # TODO: this shouldn't be necessary, but on_init doesn't get inherited the
17
+ # way I would like it to.
18
+ @on_init = Atom::Feed.instance_variable_get '@on_init'
19
+ end
20
+
7
21
  class Control < Atom::Element
8
22
  attr_accessor :draft
9
23
 
@@ -21,45 +35,6 @@ module Atom
21
35
  end
22
36
  end
23
37
 
24
- module HasCategories
25
- def HasCategories.included(klass)
26
- klass.atom_elements :category, :categories, Atom::Category
27
- end
28
-
29
- # categorize the entry with each of an array or a space-separated
30
- # string
31
- def tag_with(tags, delimiter = ' ')
32
- return if not tags or tags.empty?
33
-
34
- tag_list = unless tags.is_a?(String)
35
- tags
36
- else
37
- tags = tags.split(delimiter)
38
- tags.map! { |t| t.strip }
39
- tags.reject! { |t| t.empty? }
40
- tags.uniq
41
- end
42
-
43
- tag_list.each do |tag|
44
- unless categories.any? { |c| c.term == tag }
45
- categories.new :term => tag
46
- end
47
- end
48
- end
49
- end
50
-
51
- module HasLinks
52
- def HasLinks.included(klass)
53
- klass.atom_elements :link, :links, Atom::Link
54
- end
55
-
56
- def find_link(criteria)
57
- self.links.find do |l|
58
- criteria.all? { |k,v| l.send(k) == v }
59
- end
60
- end
61
- end
62
-
63
38
  # An individual entry in a feed. As an Atom::Element, it can be
64
39
  # manipulated using accessors for each of its child elements. You
65
40
  # should be able to set them using an instance of any class that
@@ -94,7 +69,7 @@ module Atom
94
69
 
95
70
  atom_element :rights, Atom::Rights
96
71
 
97
- # element :source, Atom::Feed # XXX complicated, eg. serialization
72
+ atom_element :source, Atom::Source
98
73
 
99
74
  atom_time :published
100
75
  atom_time :updated
@@ -5,6 +5,10 @@ require "atom/entry"
5
5
  require "atom/http"
6
6
 
7
7
  module Atom
8
+ # this is just a forward declaration since atom/entry includes atom/feed and vice-versa.
9
+ class Entry < Atom::Element # :nodoc:
10
+ end
11
+
8
12
  class FeedGone < RuntimeError # :nodoc:
9
13
  end
10
14
 
@@ -17,7 +17,7 @@ class String # :nodoc:
17
17
  end
18
18
 
19
19
  module Atom
20
- TOOLS_VERSION = '2.0.3'
20
+ TOOLS_VERSION = '2.0.4'
21
21
  UA = "atom-tools " + TOOLS_VERSION
22
22
 
23
23
  module DigestAuth
@@ -0,0 +1,353 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'atom/entry'
4
+
5
+ module TestsXML
6
+ def read_entry_xml xpath
7
+ REXML::XPath.first(@entry.to_xml, xpath, { 'atom' => Atom::NS, 'app' => Atom::PP_NS })
8
+ end
9
+ end
10
+
11
+ describe Atom::Entry do
12
+ describe 'when parsing' do
13
+ before(:each) do
14
+ @entry = Atom::Entry.parse(fixtures(:entry))
15
+ @empty_entry = '<entry xmlns="http://www.w3.org/2005/Atom" />'
16
+ end
17
+
18
+ it 'should read & parse input from an IO object' do
19
+ input = mock('IO')
20
+ input.should_receive(:read).and_return(@empty_entry)
21
+ Atom::Entry.parse(input).should be_an_instance_of(Atom::Entry)
22
+ end
23
+
24
+ it 'should read & parse input from a string' do
25
+ input = mock('string')
26
+ input.should_receive(:to_s).and_return(@empty_entry)
27
+ Atom::Entry.parse(input).should be_an_instance_of(Atom::Entry)
28
+ end
29
+
30
+ it 'should raise ParseError when invalid entry' do
31
+ lambda { Atom::Entry.parse('<entry/>') }.should raise_error(Atom::ParseError)
32
+ end
33
+
34
+ it 'should parse title element correctly' do
35
+ @entry.title.should be_is_a(Atom::Text)
36
+ @entry.title['type'].should == 'text'
37
+ @entry.title.to_s.should == 'Atom draft-07 snapshot'
38
+ end
39
+
40
+ it 'should parse id element correctly' do
41
+ @entry.id.should == 'tag:example.org,2003:3.2397'
42
+ end
43
+
44
+ it 'should parse updated element correctly' do
45
+ @entry.updated.should == Time.parse('2005-07-31T12:29:29Z')
46
+ end
47
+
48
+ it 'should parse published element correctly' do
49
+ @entry.published.should == Time.parse('2003-12-13T08:29:29-04:00')
50
+ end
51
+
52
+ it 'should parse app:edited element correctly' do
53
+ @entry.edited.should == Time.parse('2005-07-31T12:29:29Z')
54
+ end
55
+
56
+ it 'should parse app:control/draft element correctly' do
57
+ @entry.draft?.should be_true
58
+ end
59
+
60
+ it 'should parse rights element correctly' do
61
+ @entry.rights.should be_is_a(Atom::Text)
62
+ @entry.rights['type'].should == 'text'
63
+ @entry.rights.to_s.should == 'Copyright (c) 2003, Mark Pilgrim'
64
+ end
65
+
66
+ it 'should parse author element correctly' do
67
+ @entry.authors.length.should == 1
68
+ @entry.authors.first.name.should == 'Mark Pilgrim'
69
+ @entry.authors.first.email.should == 'f8dy@example.com'
70
+ @entry.authors.first.uri.should == 'http://example.org/'
71
+ end
72
+
73
+ it 'should parse contributor element correctly' do
74
+ @entry.contributors.length.should == 2
75
+ @entry.contributors.first.name.should == 'Sam Ruby'
76
+ @entry.contributors[1].name.should == 'Joe Gregorio'
77
+ end
78
+
79
+ it 'should parse content element correctly' do
80
+ @entry.content.should be_an_instance_of(Atom::Content)
81
+ @entry.content['type'].should == 'xhtml'
82
+ @entry.content.base.should == 'http://diveintomark.org/'
83
+ @entry.content.to_s.strip.should == '<p><i>[Update: The Atom draft is finished.]</i></p>'
84
+ end
85
+
86
+ it 'should parse summary element correctly' do
87
+ @entry.summary['type'].should == 'text'
88
+ @entry.summary.to_s.should == 'Some text.'
89
+ end
90
+
91
+ it 'should parse links element correctly' do
92
+ @entry.links.length.should == 2
93
+ alternates = @entry.links.select { |l| l['rel'] == 'alternate' }
94
+ alternates.length.should == 1
95
+ alternates.first['href'].should == 'http://example.org/2005/04/02/atom'
96
+ alternates.first['type'].should == 'text/html'
97
+ @entry.links.last['rel'].should == 'enclosure'
98
+ @entry.links.last['href'].should == 'http://example.org/audio/ph34r_my_podcast.mp3'
99
+ @entry.links.last['type'].should == 'audio/mpeg'
100
+ end
101
+
102
+ it 'should parse category element correctly' do
103
+ @entry.categories.first['term'].should == 'ann'
104
+ @entry.categories.first['scheme'].should == 'http://example.org/cats'
105
+ end
106
+
107
+ it 'should parse source element correctly' do
108
+ @entry.source.title.to_s.should == 'Atom Sample Feed'
109
+ @entry.source.id.should == 'tag:example.org,2003:/'
110
+
111
+ @entry.source.links.length.should == 1
112
+ @entry.source.links.first.rel == 'self'
113
+
114
+ @entry.source.authors.length.should == 0
115
+
116
+ @entry.source.contributors.length.should == 1
117
+ @entry.source.contributors.first.name == 'Mark Pilgrim'
118
+ end
119
+ end
120
+
121
+ describe 'title element' do
122
+ before(:each) do
123
+ @entry = Atom::Entry.new
124
+ end
125
+
126
+ it 'should be nil if not defined' do
127
+ @entry.title.should be_nil
128
+
129
+ @entry.title.to_s.should == ''
130
+ end
131
+
132
+ it 'should accept a simple string' do
133
+ @entry.title = '<clever thing here>'
134
+
135
+ @entry.title.type.should == 'text'
136
+
137
+ @entry.title.to_s.should == '<clever thing here>'
138
+ @entry.title.html.should =~ /^&lt;clever thing/
139
+ @entry.title.to_xml.to_s.should =~ /&lt;clever thing/
140
+ end
141
+
142
+ it 'should accept an HTML string' do
143
+ @entry.title = 'even <em>cleverer</em>'
144
+ @entry.title.type = 'html'
145
+
146
+ @entry.title.type.should == 'html'
147
+
148
+ @entry.title.to_s.should =~ /even <em>clever/
149
+ @entry.title.html.should =~ /even <em>clever/
150
+ @entry.title.to_xml.to_s.should =~ /even &lt;em/
151
+ end
152
+
153
+ it 'should accept an XHTML string' do
154
+ @entry.title = 'the <strong>cleverest</strong>'
155
+ @entry.title.type = 'xhtml'
156
+
157
+ @entry.title.to_xml.to_s.should =~ /w3.org\/1999\/xhtml.>the <strong>/
158
+ @entry.title.html.should =~ /the <strong>cleverest/
159
+ end
160
+
161
+ it 'should reject an ill-formed XHTML string' do
162
+ @entry.title = 'the <strong>cleverest'
163
+ lambda { @entry.title.type = 'xhtml' }.should raise_error(Atom::ParseError)
164
+ end
165
+
166
+ it 'should accept something like Atom::Text' do
167
+ title = Atom::Title.new '<3'
168
+
169
+ @entry.title = title
170
+ @entry.title.type.should == 'text'
171
+
172
+ @entry.title.to_xml.to_s.should =~ /&lt;3/
173
+ end
174
+ end
175
+
176
+ describe 'updated element' do
177
+ before(:each) do
178
+ @entry = Atom::Entry.new
179
+ end
180
+
181
+ it 'should be nil if not defined' do
182
+ @entry.updated.should be_nil
183
+ end
184
+
185
+ it 'should be definable' do
186
+ @entry.updated = '1990-04-07'
187
+ @entry.updated.should == Time.parse('1990-04-07')
188
+ end
189
+
190
+ it 'should be an xsd:DateTime' do
191
+ @entry.updated = '1990-04-07'
192
+ @entry.updated.to_s.should =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
193
+ end
194
+
195
+ it 'should be declarable as updated using #updated!' do
196
+ @entry.updated!
197
+ @entry.updated.should > Time.parse('1990-04-07')
198
+ end
199
+ end
200
+
201
+ describe 'app:edited element' do
202
+ include TestsXML
203
+
204
+ before(:each) do
205
+ @entry = Atom::Entry.new
206
+ end
207
+
208
+ it 'should be nil if not defined' do
209
+ @entry.edited.should be_nil
210
+ end
211
+
212
+ it 'should be definable' do
213
+ @entry.edited = '1990-04-07'
214
+ @entry.edited.should == Time.parse('1990-04-07')
215
+ end
216
+
217
+ it 'should be an xsd:DateTime' do
218
+ @entry.edited = '1990-04-07'
219
+ @entry.edited.to_s.should =~ /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/
220
+ end
221
+
222
+ it 'should have APP namespace' do
223
+ @entry.edited = '1990-04-07'
224
+ read_entry_xml('app:edited').namespace.should == Atom::PP_NS
225
+ end
226
+
227
+ it 'should be declarable as edited using #edited!' do
228
+ @entry.edited!
229
+ @entry.edited.should > Time.parse('1990-04-07')
230
+ end
231
+ end
232
+
233
+ describe 'category element' do
234
+ before(:each) do
235
+ @entry = Atom::Entry.new
236
+ end
237
+
238
+ it 'should have no category on intializing' do
239
+ @entry.categories.should be_empty
240
+ end
241
+
242
+ it 'should increase total count when adding a new category' do
243
+ @count = @entry.categories.length
244
+ @entry.categories.new['term'] = 'foo'
245
+ @entry.categories.length.should == @count + 1
246
+ end
247
+
248
+ it 'should find category' do
249
+ category = @entry.categories.new
250
+ category['scheme'] = 'http://example.org/categories'
251
+ category['term'] = 'bar'
252
+ @entry.categories.select { |c| c['scheme'] == 'http://example.org/categories' }.should == [category]
253
+ end
254
+
255
+ describe 'when using tags' do
256
+ before(:each) do
257
+ @tags = %w(chunky bacon ruby)
258
+ end
259
+
260
+ it 'should set categories from an array of tags' do
261
+ @entry.tag_with(@tags)
262
+ @entry.categories.length.should == 3
263
+ @tags.each { |tag| @entry.categories.any? { |c| c['term'] == tag }.should be_true }
264
+ end
265
+
266
+ it 'should set categories from a space-sperated string of tags' do
267
+ @entry.tag_with(@tags.join(' '))
268
+ @entry.categories.length.should == 3
269
+ @tags.each { |tag| @entry.categories.any? { |c| c['term'] == tag }.should be_true }
270
+ end
271
+
272
+ it 'should be possible to specify the delimiter when passing tags as a string' do
273
+ @entry.tag_with(@tags.join(','), ',')
274
+ @entry.categories.length.should == 3
275
+ @tags.each { |tag| @entry.categories.any? { |c| c['term'] == tag }.should be_true }
276
+ end
277
+
278
+ it 'should create a category only once' do
279
+ @entry.tag_with(@tags)
280
+ @entry.tag_with(@tags.first)
281
+ @entry.categories.length.should == 3
282
+ end
283
+ end
284
+ end
285
+
286
+ describe 'edit url' do
287
+ before(:each) do
288
+ @entry = Atom::Entry.new
289
+ end
290
+
291
+ it 'should be nil on initializing' do
292
+ @entry.edit_url.should be_nil
293
+ end
294
+
295
+ it 'should be easily definable' do
296
+ @entry.edit_url = 'http://example.org/entries/foo'
297
+ @entry.edit_url.should == 'http://example.org/entries/foo'
298
+ end
299
+
300
+ it 'should not erase other links' do
301
+ link = @entry.links.new :rel => 'related', :href => 'http://example.org'
302
+
303
+ @entry.edit_url = 'http://example.com/entries/foo'
304
+ @entry.links.length.should == 2
305
+ @entry.links.should include(link)
306
+ end
307
+
308
+ it 'should accept a URI object' do
309
+ @entry.edit_url = URI.parse('http://example.com/entries/foo')
310
+ @entry.to_s.should =~ /example.com\/entries/
311
+ end
312
+ end
313
+
314
+ describe 'draft element' do
315
+ include TestsXML
316
+
317
+ before(:each) do
318
+ @entry = Atom::Entry.new
319
+ end
320
+
321
+ it 'should not be a draft by default' do
322
+ @entry.should_not be_draft
323
+ end
324
+
325
+ it 'should be definable using draft=' do
326
+ @entry.draft = true
327
+ @entry.should be_draft
328
+ @entry.draft = false
329
+ @entry.should_not be_draft
330
+ end
331
+
332
+ it 'should be declarable as a draft using #draft!' do
333
+ @entry.draft!
334
+ @entry.should be_draft
335
+ end
336
+
337
+ it 'should have APP namespace' do
338
+ @entry.draft!
339
+ read_entry_xml('app:control/app:draft').namespace.should == Atom::PP_NS
340
+ end
341
+ end
342
+
343
+
344
+ describe 'extensions' do
345
+ before(:each) do
346
+ @entry = Atom::Entry.parse(fixtures('entry-w-ext'))
347
+ end
348
+
349
+ it 'should preserve namespaces' do
350
+ @entry.to_s.should =~ /purl/
351
+ end
352
+ end
353
+ end
@@ -0,0 +1,42 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'atom/entry'
4
+
5
+ module Atom
6
+ THR_NS = "http://purl.org/syndication/thread/1.0"
7
+ SLUG_NS = 'http://example.org/ns/slug'
8
+
9
+ class InReplyTo < Atom::Element
10
+ is_element THR_NS, :"in-reply-to"
11
+
12
+ atom_attrb :ref
13
+ atom_attrb :href
14
+ atom_attrb :type
15
+ atom_attrb :source
16
+ end
17
+
18
+ class Entry
19
+ attrb ['sl', SLUG_NS], 'slug'
20
+ element ['thr', THR_NS], :"in-reply-to", InReplyTo
21
+ end
22
+ end
23
+
24
+ describe Atom::Entry do
25
+ it 'should correctly write extension attributes' do
26
+ entry = Atom::Entry.new
27
+ entry.slug = 'hallo'
28
+
29
+ entry.to_s.should =~ /sl:slug/
30
+ entry.to_s.should =~ /xmlns:sl='#{Atom::SLUG_NS}'/
31
+ end
32
+
33
+ describe 'in-reply-to' do
34
+ it 'should be written with the correct namespace' do
35
+ entry = Atom::Entry.new
36
+ entry.in_reply_to = { :ref => 'http://example.org/some-entry' }
37
+
38
+ entry.to_s.should =~ /ref='http:\/\/example.org/
39
+ entry.to_s.should =~ Regexp.new(Atom::THR_NS)
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'atom/feed'
4
+
5
+ describe Atom::Entry do
6
+ describe 'extensions' do
7
+ before(:each) do
8
+ @feed = Atom::Feed.parse(fixtures('feed-w-ext'))
9
+ end
10
+
11
+ it 'should preserve namespaces' do
12
+ @feed.to_s.should =~ /purl/
13
+
14
+ feed2 = Atom::Feed.new
15
+ feed2.merge! @feed
16
+
17
+ feed2.to_s.should =~ /purl/
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,15 @@
1
+ <entry xmlns="http://www.w3.org/2005/Atom"
2
+ xml:base='http://www.example.org/'
3
+ xmlns:thr='http://purl.org/syndication/thread/1.0'
4
+ xml:lang='en-us'>
5
+ <title>Extendy</title>
6
+ <link rel='replies' thr:count='2' type='application/xhtml+xml' href='Extendy#comments' />
7
+ <id>http://www.example.org/Extendy.atom</id>
8
+ <published>2008-03-15T02:00:00-07:00</published>
9
+ <updated>2008-03-15T18:10:25-07:00</updated>
10
+ <content type='xhtml'>
11
+ <div xmlns='http://www.w3.org/1999/xhtml'>
12
+ <p>Extensions ahoy!</p>
13
+ </div>
14
+ </content>
15
+ </entry>
@@ -0,0 +1,42 @@
1
+ <entry xmlns="http://www.w3.org/2005/Atom"
2
+ xmlns:app="http://www.w3.org/2007/app">
3
+ <title>Atom draft-07 snapshot</title>
4
+ <link rel="alternate" type="text/html"
5
+ href="http://example.org/2005/04/02/atom"/>
6
+ <link rel="enclosure" type="audio/mpeg" length="1337"
7
+ href="http://example.org/audio/ph34r_my_podcast.mp3"/>
8
+ <source>
9
+ <title>Atom Sample Feed</title>
10
+ <id>tag:example.org,2003:/</id>
11
+ <link rel="self" href="http://example.org/feed"/>
12
+ <contributor>
13
+ <name>Mark Pilgrim</name>
14
+ </contributor>
15
+ </source>
16
+ <rights>Copyright (c) 2003, Mark Pilgrim</rights>
17
+ <id>tag:example.org,2003:3.2397</id>
18
+ <updated>2005-07-31T12:29:29Z</updated>
19
+ <published>2003-12-13T08:29:29-04:00</published>
20
+ <app:edited>2005-07-31T12:29:29Z</app:edited>
21
+ <app:control><app:draft>yes</app:draft></app:control>
22
+ <author>
23
+ <name>Mark Pilgrim</name>
24
+ <uri>http://example.org/</uri>
25
+ <email>f8dy@example.com</email>
26
+ </author>
27
+ <contributor>
28
+ <name>Sam Ruby</name>
29
+ </contributor>
30
+ <contributor>
31
+ <name>Joe Gregorio</name>
32
+ </contributor>
33
+ <summary>Some text.</summary>
34
+ <category scheme="http://example.org/cats" term="ann" />
35
+ <content type="xhtml" xml:lang="en"
36
+ xml:base="http://diveintomark.org/">
37
+ <div xmlns="http://www.w3.org/1999/xhtml">
38
+ <p><i>[Update: The Atom draft is finished.]</i></p>
39
+ </div>
40
+ </content>
41
+ </entry>
42
+
@@ -0,0 +1,33 @@
1
+ <feed xmlns='http://www.w3.org/2005/Atom'
2
+ xmlns:thr='http://purl.org/syndication/thread/1.0'
3
+ xml:base='http://www.tbray.org/ongoing/ongoing.atom'
4
+ xml:lang='en-us'>
5
+ <title>ongoing</title>
6
+ <id>http://www.tbray.org/ongoing/</id>
7
+ <link href='./' />
8
+ <link rel='self' href='' />
9
+ <link rel='replies' thr:count='101' href='/home/tbray.org/www/html/ongoing/comments.atom' />
10
+ <logo>rsslogo.jpg</logo>
11
+ <icon>/favicon.ico</icon>
12
+ <updated>2008-03-17T02:04:49-07:00</updated>
13
+ <author><name>Tim Bray</name></author>
14
+ <subtitle>ongoing fragmented essay by Tim Bray</subtitle>
15
+ <rights>All content written by Tim Bray and photos by Tim Bray Copyright Tim Bray, some rights reserved, see /ongoing/misc/Copyright</rights>
16
+ <generator uri='/misc/Colophon'>Generated from XML source code using Perl, Expat, Emacs, Mysql, Ruby, Java, and ImageMagick. Industrial-strength technology, baby.</generator>
17
+ <entry xml:base='When/200x/2008/03/13/'>
18
+ <title>Maui Bound</title>
19
+ <link href='Maui' />
20
+ <link rel='replies' thr:count='1' type='application/xhtml+xml' href='Maui#comments' />
21
+ <id>http://www.tbray.org/ongoing/When/200x/2008/03/13/Maui</id>
22
+ <published>2008-03-13T02:00:00-07:00</published>
23
+ <updated>2008-03-13T17:23:47-07:00</updated>
24
+ <category scheme='http://www.tbray.org/ongoing/What/' term='The World/Places/Hawaii' />
25
+ <category scheme='http://www.tbray.org/ongoing/What/' term='The World' />
26
+ <category scheme='http://www.tbray.org/ongoing/What/' term='Places' />
27
+ <category scheme='http://www.tbray.org/ongoing/What/' term='Hawaii' />
28
+ <content type='xhtml'><div xmlns='http://www.w3.org/1999/xhtml'>
29
+ <p>I’m off with the family tomorrow for ten days in Maui, 15th through the
30
+ 24th. We’ll be meeting an Aussie friend. Anyone else I know who’ll be there,
31
+ drop me a line and we’ll get together for a Mai Tai.</p>
32
+ </div></content></entry>
33
+ </feed>
@@ -0,0 +1,21 @@
1
+ <?xml version="1.0"?>
2
+ <service xmlns="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xhtml="http://www.w3.org/1999/xhtml">
3
+ <workspace title="Yulup Demo">
4
+ <atom:title type="text">Yulup Demo</atom:title>
5
+
6
+ <collection title="Releases" href="../entries/?yanel.resource.viewid=atom">
7
+ <atom:title type="html">Early Yulup &lt;i>Releases&lt;/i></atom:title>
8
+ </collection>
9
+ </workspace>
10
+
11
+ <workspace title="Yulup Website">
12
+ <atom:title type="text">Yulup Website</atom:title>
13
+
14
+ <collection title="Releases" href="http://www.yulup.org/download/release-atom-entries/?yanel.resource.viewid=atom">
15
+ <atom:title type="xhtml"><xhtml:div>Yulup <xhtml:b>Releases</xhtml:b>
16
+ </xhtml:div>
17
+ </atom:title>
18
+
19
+ </collection>
20
+ </workspace>
21
+ </service>
@@ -0,0 +1,36 @@
1
+ <?xml version="1.0" encoding='utf-8'?>
2
+ <service xmlns="http://www.w3.org/2007/app"
3
+ xmlns:atom="http://www.w3.org/2005/Atom">
4
+ <workspace>
5
+ <atom:title>Main Site</atom:title>
6
+ <collection
7
+ href="http://example.org/blog/main" >
8
+ <atom:title>My Blog Entries</atom:title>
9
+ <categories
10
+ href="http://example.com/cats/forMain.cats" />
11
+ </collection>
12
+ <collection
13
+ href="http://example.org/blog/pic" >
14
+ <atom:title>Pictures</atom:title>
15
+ <accept>image/png</accept>
16
+ <accept>image/jpeg</accept>
17
+ <accept>image/gif</accept>
18
+ </collection>
19
+ </workspace>
20
+ <workspace>
21
+ <atom:title>Sidebar Blog</atom:title>
22
+ <collection
23
+ href="http://example.org/sidebar/list" >
24
+ <atom:title>Remaindered Links</atom:title>
25
+ <accept>application/atom+xml;type=entry</accept>
26
+ <categories fixed="yes">
27
+ <atom:category
28
+ scheme="http://example.org/extra-cats/"
29
+ term="joke" />
30
+ <atom:category
31
+ scheme="http://example.org/extra-cats/"
32
+ term="serious" />
33
+ </categories>
34
+ </collection>
35
+ </workspace>
36
+ </service>
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ require 'atom/service'
4
+
5
+ describe Atom::Service do
6
+ describe 'when parsing' do
7
+ before(:each) do
8
+ @service = Atom::Service.parse(fixtures(:service))
9
+ end
10
+
11
+ it 'should parse workspace elements correctly' do
12
+ @service.workspaces.length.should == 2
13
+ end
14
+
15
+ it 'should absolutize relative hrefs' do
16
+ svc = Atom::Service.parse(
17
+ fixtures('service-w-xhtml-ns'),
18
+ 'http://example.org/introspection/')
19
+
20
+ coll = svc.workspaces.first.collections.first
21
+ coll.href.should == "http://example.org/entries/?yanel.resource.viewid=atom"
22
+ end
23
+
24
+ it 'should parse XHTML outside the default namespace correctly' do
25
+ xhtml_svc = Atom::Service.parse(fixtures('service-w-xhtml-ns'))
26
+
27
+ xhtml_svc.workspaces.length.should == 2
28
+ xhtml_coll = xhtml_svc.workspaces.last.collections.first
29
+ xhtml_coll.title.html.strip.should == 'Yulup <b>Releases</b>'
30
+ end
31
+ end
32
+ end
33
+
34
+ describe Atom::Workspace do
35
+ describe 'when parsing' do
36
+ before(:each) do
37
+ svc = Atom::Service.parse(fixtures(:service))
38
+ @main = svc.workspaces.first
39
+ @sidebar = svc.workspaces.last
40
+ end
41
+
42
+ it 'should parse title element correctly' do
43
+ @main.title.to_s.should == 'Main Site'
44
+ @sidebar.title.to_s.should == 'Sidebar Blog'
45
+ end
46
+
47
+ it 'should parse collection elements correctly' do
48
+ @main.collections.length.should == 2
49
+ @sidebar.collections.length.should == 1
50
+ end
51
+ end
52
+ end
53
+
54
+ describe Atom::Collection do
55
+ describe 'when parsing' do
56
+ before(:each) do
57
+ svc = Atom::Service.parse(fixtures(:service))
58
+ @entries = svc.workspaces.first.collections.first
59
+ @pictures = svc.workspaces.first.collections.last
60
+ @links = svc.workspaces.last.collections.first
61
+ end
62
+
63
+ it 'should parse href correctly' do
64
+ @entries.href.should == 'http://example.org/blog/main'
65
+ @entries.feed.uri.to_s.should == 'http://example.org/blog/main'
66
+
67
+ @pictures.href.should == 'http://example.org/blog/pic'
68
+ @links.href.should == 'http://example.org/sidebar/list'
69
+ end
70
+
71
+ it 'should parse title element correctly' do
72
+ @entries.title.to_s.should == 'My Blog Entries'
73
+ @pictures.title.to_s.should == 'Pictures'
74
+ @links.title.to_s.should == 'Remaindered Links'
75
+ end
76
+
77
+ it 'should parse accept elements correctly' do
78
+ @entries.accepts.should == ['application/atom+xml;type=entry']
79
+ @pictures.accepts.should == ['image/png', 'image/jpeg', 'image/gif']
80
+ @links.accepts.should == ['application/atom+xml;type=entry']
81
+ end
82
+ end
83
+ end
84
+
85
+ describe Atom::Categories do
86
+ describe 'when parsing' do
87
+ before(:each) do
88
+ svc = Atom::Service.parse(fixtures(:service))
89
+ @ool = svc.workspaces.first.collections.first.categories.first
90
+ @il = svc.workspaces.last.collections.first.categories.first
91
+ end
92
+
93
+ it 'should parse out-of-line categories correctly' do
94
+ @ool.href.should == 'http://example.com/cats/forMain.cats'
95
+ end
96
+
97
+ it 'should parse inline categories correctly' do
98
+ @il.fixed.should be_true
99
+
100
+ @il.list.length.should == 2
101
+
102
+ @il.list.first.scheme.should == 'http://example.org/extra-cats/'
103
+ @il.list.first.term.should == 'joke'
104
+
105
+ @il.list.last.term.should == 'serious'
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,9 @@
1
+ require 'rubygems'
2
+ require 'spec'
3
+
4
+ $:.unshift 'lib/', File.dirname(__FILE__) + '/../lib'
5
+
6
+ def fixtures(name)
7
+ File.read(File.dirname(__FILE__) + "/fixtures/#{name}.xml")
8
+ end
9
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: atom-tools
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brendan Taylor
@@ -9,11 +9,16 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-05-01 00:00:00 -06:00
12
+ date: 2009-08-15 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description:
16
+ description: |-
17
+ atom-tools is an all-in-one Atom library. It parses and builds Atom (RFC 4287) entries and feeds, and manipulates Atom Publishing Protocol (RFC 5023) Collections.
18
+
19
+ It also comes with a set of commandline utilities for working with AtomPub Collections.
20
+
21
+ It is not the fastest Ruby Atom library, but it is comprehensive and makes handling extensions to the Atom format very easy.
17
22
  email: whateley@gmail.com
18
23
  executables: []
19
24
 
@@ -34,7 +39,6 @@ files:
34
39
  - test/runtests.rb
35
40
  - test/test_feed.rb
36
41
  - test/test_protocol.rb
37
- - test/conformance
38
42
  - test/conformance/updated.rb
39
43
  - test/conformance/xmlnamespace.rb
40
44
  - test/conformance/title.rb
@@ -43,7 +47,16 @@ files:
43
47
  - test/test_xml.rb
44
48
  - test/test_http.rb
45
49
  - test/test_general.rb
46
- - lib/atom
50
+ - spec/entry_spec.rb
51
+ - spec/ext_spec.rb
52
+ - spec/spec_helper.rb
53
+ - spec/feed_spec.rb
54
+ - spec/fixtures/feed-w-ext.xml
55
+ - spec/fixtures/service-w-xhtml-ns.xml
56
+ - spec/fixtures/entry-w-ext.xml
57
+ - spec/fixtures/service.xml
58
+ - spec/fixtures/entry.xml
59
+ - spec/service_spec.rb
47
60
  - lib/atom/cache.rb
48
61
  - lib/atom/feed.rb
49
62
  - lib/atom/text.rb
@@ -54,7 +67,9 @@ files:
54
67
  - lib/atom/element.rb
55
68
  - lib/atom/http.rb
56
69
  has_rdoc: true
57
- homepage: http://code.necronomicorp.com/atom-tools
70
+ homepage: http://github.com/bct/atom-tools/wikis
71
+ licenses: []
72
+
58
73
  post_install_message:
59
74
  rdoc_options: []
60
75
 
@@ -75,9 +90,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
75
90
  requirements: []
76
91
 
77
92
  rubyforge_project: ibes
78
- rubygems_version: 1.3.1
93
+ rubygems_version: 1.3.2
79
94
  signing_key:
80
- specification_version: 2
81
- summary: Tools for working with Atom Entries, Feeds and Collections
95
+ specification_version: 3
96
+ summary: Tools for working with Atom Entries, Feeds and Collections.
82
97
  test_files:
83
98
  - test/runtests.rb