opds 0.2.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/samples/entry.txt ADDED
@@ -0,0 +1,32 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <entry xmlns:dcterms="http://purl.org/dc/terms/" xmlns="http://www.w3.org/2005/Atom" xmlns:thr="http://purl.org/syndication/thread/1.0">
3
+ <title>War and Peace</title>
4
+ <id>http://www.feedbooks.com/book/83</id>
5
+ <author>
6
+ <name>Lev Nikolayevich Tolstoy</name>
7
+ <uri>http://www.feedbooks.com/author/28</uri>
8
+ </author>
9
+ <updated>2010-06-13T12:06:51Z</updated>
10
+ <dcterms:language>en</dcterms:language>
11
+ <dcterms:issued>1869</dcterms:issued>
12
+ <category term="FBFIC000000" label="Fiction"/>
13
+ <category term="FBFIC014000" label="Historical"/>
14
+ <category term="FBFIC032000" label="War"/>
15
+ <summary>War and Peace is a novel by Leo Tolstoy, first published from 1865 to 1869 in Russkii Vestnik, which tells the story of Russian society during the Napoleonic Era. It is usually described as one of Tolstoy's two major masterpieces (the other being Anna Karenina) as well as one of the world's greatest novels.
16
+ War and Peace offered a new kind of fiction, with a great many characters caught up in a plot that covered nothing less than the grand subjects indicated by the title, combined with the equally large topics of youth, marriage, age, and death. Though it is often called a novel today, it broke so many conventions of the form that it was not considered a novel in its time. Indeed, Tolstoy himself considered Anna Karenina (1878) to be his first attempt at a novel in the European sense.</summary>
17
+ <dcterms:extent>561,304 words</dcterms:extent>
18
+ <dcterms:source>Wikisource</dcterms:source>
19
+ <link type="text/html" href="http://www.feedbooks.com/book/83" rel="alternate" title="View on Feedbooks"/>
20
+ <link type="application/epub+zip" href="http://www.feedbooks.com/book/83.epub" rel="http://opds-spec.org/acquisition"/>
21
+ <link type="application/x-mobipocket-ebook" href="http://www.feedbooks.com/book/83.mobi" rel="http://opds-spec.org/acquisition"/>
22
+ <link type="application/pdf" href="http://www.feedbooks.com/book/83.pdf" rel="http://opds-spec.org/acquisition"/>
23
+ <link type="image/jpeg" href="http://covers.feedbooks.net/book/83.jpg?t=1276430811" rel="http://opds-spec.org/cover"/>
24
+ <link type="image/jpeg" href="http://covers.feedbooks.net/book/83.jpg?size=thumbnail&amp;t=1276430811" rel="http://opds-spec.org/thumbnail"/>
25
+ <link type="application/atom+xml" href="http://www.feedbooks.com/author/28/books/top.atom" rel="related" title="Other books from the same author"/>
26
+ <link type="application/atom+xml" href="http://www.feedbooks.com/book/83/similar.atom" rel="related" title="People also downloaded..."/>
27
+ <link type="application/atom+xml" href="http://www.feedbooks.com/book/83/lists.atom" rel="related" title="Reading lists for this book"/>
28
+ <link type="application/atom+xml" href="http://www.feedbooks.com/book/83/categories.atom" rel="related" title="Categories for this book"/>
29
+ <link type="application/atom+xml" href="http://www.feedbooks.com/book/83/comments.atom" rel="replies" title="Comments for this book (0)" thr:count="0" thr:updated="2009-08-18T01:17:01Z"/>
30
+ <link type="text/html" href="http://www.goodreads.com/mobile/book/isbn/067003469X" rel="related" title="View on Goodreads"/>
31
+ <link type="application/atom+xml" href="http://www.feedbooks.com/book/83/contents.atom" rel="contents"/>
32
+ </entry>
@@ -0,0 +1,46 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <feed xmlns:dcterms="http://purl.org/dc/terms/" xmlns:opds="http://opds-spec.org/2010/catalog" xml:lang="en" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:app="http://www.w3.org/2007/app" xmlns="http://www.w3.org/2005/Atom" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
3
+ <id>http://www.feedbooks.com/catalog.atom</id>
4
+ <link type="text/html" href="http://www.feedbooks.com/site/catalog" rel="alternate"/>
5
+ <link type="application/atom+xml" href="http://www.feedbooks.com/catalog.atom" rel="self"/>
6
+ <title>Feedbooks | OPDS Catalog</title>
7
+ <updated>2010-08-08T13:44:22Z</updated>
8
+ <icon>http://www.feedbooks.com/favicon.ico</icon>
9
+ <author>
10
+ <name>Feedbooks</name>
11
+ <uri>http://www.feedbooks.com</uri>
12
+ <email>support@feedbooks.com</email>
13
+ </author>
14
+ <link type="application/atom+xml" href="/catalog.atom" rel="start" title="OPDS Catalog"/>
15
+ <link type="application/opensearchdescription+xml" href="/opensearch.xml" rel="search" title="Search on Feedbooks"/>
16
+ <link type="application/atom+xml" href="https://www.feedbooks.com/user/bookshelf.atom" rel="http://opds-spec.org/shelf" title="Bookshelf"/>
17
+ <link type="application/atom+xml" href="https://www.feedbooks.com/user/subscriptions.atom" rel="http://opds-spec.org/subscriptions" title="Subscriptions"/>
18
+ <link type="application/atom+xml" href="http://www.feedbooks.com/books/recent.atom" rel="http://opds-spec.org/sort/new" title="New Public Domain Books"/>
19
+ <link type="application/atom+xml" href="http://www.feedbooks.com/books/top.atom?range=month" rel="http://opds-spec.org/sort/popular" title="Top Public Domain Books"/>
20
+ <link type="application/atom+xml" href="http://www.feedbooks.com/userbooks/recent.atom" rel="http://opds-spec.org/sort/new" title="New Original Books"/>
21
+ <link type="application/atom+xml" href="http://www.feedbooks.com/userbooks/top.atom?range=month" rel="http://opds-spec.org/sort/popular" title="Top Original Books"/>
22
+ <entry>
23
+ <title>Public Domain Books</title>
24
+ <link type="application/atom+xml" href="http://www.feedbooks.com/publicdomain/catalog.atom"/>
25
+ <updated>2010-08-08T13:44:22Z</updated>
26
+ <id>http://www.feedbooks.com/publicdomain/catalog.atom</id>
27
+ <link type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIASURBVDjLpVPPaxNREJ6Vt01caH4oWk1T0ZKlGIo9RG+BUsEK4kEP/Q8qPXnpqRdPBf8A8Wahhx7FQ0GF9FJ6UksqwfTSBDGyB5HkkphC9tfb7jfbtyQQTx142byZ75v5ZnZWC4KALmICPy+2DkvKIX2f/POz83LxCL7nrz+WPNcll49DrhM9v7xdO9JW330DuXrrqkFSgig5iR2Cfv3t3gNxOnv5BwU+eZ5HuON5/PMPJZKJ+yKQfpW0S7TxdC6WJaWkyvff1LDaFRAeLZj05MHsiPTS6hua0PUqtwC5sHq9zv9RYWl+nu5cETcnJ1M0M5WlWq3GsX6/T+VymRzHDluZiGYAAsw0TQahV8uyyGq1qFgskm0bHIO/1+sx1rFtchJhArwEyIQ1Gg2WD2A6nWawHQJVDIWgIJfLhQowTIeE9D0mKAU8qPC0220afsWFQoH93W6X7yCDJ+DEBeBmsxnPIJVKxWQVUwry+XyUwBlKMKwA8jqdDhOVCqVAzQDVvXAXhOdGBFgymYwrGoZBmUyGjxCCdF0fSahaFdgoTHRxfTveMCXvWfkuE3Y+f40qhgT/nMitupzApdvT18bu+YeDQwY9Xl4aG9/d/URiMBhQq/dvZMeVghtT17lSZW9/rAKsvPa/r9Fc2dw+Pe0/xI6kM9mT5vtXy+Nw2kU/5zOGRpvuMIu0YAAAAABJRU5ErkJggg==" rel="http://opds-spec.org/thumbnail"/>
28
+ <content type="text">Free classics and CC-licensed books</content>
29
+ </entry>
30
+ <entry>
31
+ <title>Original Books</title>
32
+ <link type="application/atom+xml" href="http://www.feedbooks.com/original/catalog.atom"/>
33
+ <updated>2010-08-08T13:44:22Z</updated>
34
+ <id>http://www.feedbooks.com/original/catalog.atom</id>
35
+ <link type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAIASURBVDjLpVPPaxNREJ6Vt01caH4oWk1T0ZKlGIo9RG+BUsEK4kEP/Q8qPXnpqRdPBf8A8Wahhx7FQ0GF9FJ6UksqwfTSBDGyB5HkkphC9tfb7jfbtyQQTx142byZ75v5ZnZWC4KALmICPy+2DkvKIX2f/POz83LxCL7nrz+WPNcll49DrhM9v7xdO9JW330DuXrrqkFSgig5iR2Cfv3t3gNxOnv5BwU+eZ5HuON5/PMPJZKJ+yKQfpW0S7TxdC6WJaWkyvff1LDaFRAeLZj05MHsiPTS6hua0PUqtwC5sHq9zv9RYWl+nu5cETcnJ1M0M5WlWq3GsX6/T+VymRzHDluZiGYAAsw0TQahV8uyyGq1qFgskm0bHIO/1+sx1rFtchJhArwEyIQ1Gg2WD2A6nWawHQJVDIWgIJfLhQowTIeE9D0mKAU8qPC0220afsWFQoH93W6X7yCDJ+DEBeBmsxnPIJVKxWQVUwry+XyUwBlKMKwA8jqdDhOVCqVAzQDVvXAXhOdGBFgymYwrGoZBmUyGjxCCdF0fSahaFdgoTHRxfTveMCXvWfkuE3Y+f40qhgT/nMitupzApdvT18bu+YeDQwY9Xl4aG9/d/URiMBhQq/dvZMeVghtT17lSZW9/rAKsvPa/r9Fc2dw+Pe0/xI6kM9mT5vtXy+Nw2kU/5zOGRpvuMIu0YAAAAABJRU5ErkJggg==" rel="http://opds-spec.org/thumbnail"/>
36
+ <content type="text">Self-Published on Feedbooks</content>
37
+ </entry>
38
+ <entry>
39
+ <title>Profile</title>
40
+ <link type="application/atom+xml" href="https://www.feedbooks.com/user/profile.atom"/>
41
+ <updated>2010-08-08T13:44:22Z</updated>
42
+ <id>https://www.feedbooks.com/user/profile.atom</id>
43
+ <link type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJ3SURBVDjLpZNtSNNRFIcNKunF1rZWBMJqKaSiX9RP1dClsjldA42slW0q5oxZiuHrlqllLayoaJa2jbm1Lc3QUZpKFmmaTMsaRp+kMgjBheSmTL2//kqMBJlFHx44XM7vOfdyuH4A/P6HFQ9zo7cpa/mM6RvCrVDzaVDy6C5JJKv6rwSnIhlFd0R0Up/GwF2KWyl01CTSkM/dQoQRzAurCjRCGnRUUE2FaoSL0HExiYVzsQwcj6RNrSqo4W5Gh6Yc4+1qDDTkIy+GhYK4nTgdz0H2PrrHUJzs71NQn86enPn+CVN9GnzruoYR63mMPbkC59gQzDl7pt7rc9f7FNyUhPY6Bx9gwt4E9zszhWWpdg6ZcS8j3O7zCTuEpnXB+3MNZkUUZu0NmHE8XsL91oSWwiiEc3MeseLrN6woYCWa/Zl8ozyQ3w3Hl2lYy0SwlCUvsVi/Gv2JwITnYPDun2Hy6jYuEzAF1jUBCVYpO6kXo+NuGMeBAgcgfwNkvgBOPgUqXgKvP7rBFvRhE1crp8Vq1noFYSlacVyqGk0D86gbART9BDk9BFnPCNJbCY5aCFL1Cyhtp0RWAp74MsKSrkq9guHyvfMTtmLc1togpZoyqYmyNoITzVTYRJCiXYBIQ3CwFqi83o3JDhX6C0M8XsGIMoQ4OyuRlq1DdZcLkmbgGDX1iIEKNxAcbgTEOqC4ZRaJ6Ub86K7CYFEo8Qo+GBQlQyXBczLZpbloaQ9k1NUz/kD2myBBKxRZpa5hVcQslalatoUxizxAVVrN3CW21bFj9F858Q9dnIRmDyeuybM71uxmH9BNBB1q6zybV7H9s1Ue4PM3/gu/AEbfqfWy2twsAAAAAElFTkSuQmCC" rel="http://opds-spec.org/thumbnail"/>
44
+ <content type="text">Your personal content</content>
45
+ </entry>
46
+ </feed>
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe OPDS::Support::Browser do
4
+ it "should be able to access google.com" do
5
+ lambda { subject.go_to("http://www.google.com") }.should_not raise_error
6
+ subject.should be_ok
7
+
8
+ end
9
+
10
+ it "should not find an empty body on google.com" do
11
+ subject.go_to("http://www.google.com")
12
+ subject.body.should_not ==""
13
+ end
14
+
15
+
16
+ it "should not be able to access http://foo.bar" do
17
+ lambda { subject.go_to("http://foo.bar") }.should raise_error
18
+ subject.should_not be_ok
19
+ end
20
+
21
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ def sample(type)
4
+ File.open( File.expand_path(File.dirname(__FILE__) + "/../samples/#{type}.txt"))
5
+ end
6
+
7
+ describe OPDS::Entry do
8
+
9
+
10
+ subject do
11
+ OPDS::Entry.from_nokogiri(Nokogiri::XML(sample(:entry)))
12
+ end
13
+
14
+ it "should have a title "do
15
+ subject.title.size.should_not be(0)
16
+ end
17
+
18
+ it "should have an id"do
19
+ subject.id.size.should_not be(0)
20
+ end
21
+
22
+ it "should have a summary "do
23
+ subject.summary.size.should_not be(0)
24
+ end
25
+
26
+ it "should have a update date "do
27
+ subject.updated.day.should be(13)
28
+ end
29
+
30
+ it "should have an author "do
31
+ subject.author.size.should_not be(0)
32
+ end
33
+
34
+ it "should have links "do
35
+ subject.links.size.should_not be(0)
36
+ end
37
+
38
+ it "should have dc:meta" do
39
+
40
+ subject.dcmetas.size.should_not be(0)
41
+ end
42
+
43
+ it "should have categories" do
44
+
45
+ subject.categories.size.should_not be(0)
46
+ end
47
+
48
+ it "should not be partial" do
49
+ subject.should_not be_partial()
50
+ end
51
+ end
@@ -0,0 +1,34 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe OPDS::Support::LinkSet do
4
+ before(:each) do
5
+ subject.push('root','http://feedbooks.com','Racine','application/atom+xml')
6
+ subject.push('subsection','http://feedbooks.com/publicdomain','Domaine pub','application/atom+xml')
7
+ subject.push('subsection','http://feedbooks.com/original','Original','application/atom+xml')
8
+ subject.push('subsection','http://feedbooks.com/feed','feeds')
9
+ subject.push('http://opds-spec.org/shelf','http://feedbooks.com/shelf','shelf')
10
+ subject.push('related','http://feedbooks.com/shelf',nil)
11
+ end
12
+
13
+ it do
14
+ subject.size.should be(6)
15
+ end
16
+
17
+ it do
18
+ subject.map(&:first).size.should be(6)
19
+ end
20
+
21
+ it "should find 3 subsection" do
22
+ subject['subsection'].size.should be(3)
23
+ subject.by(:rel)['subsection'].size.should be(3)
24
+ end
25
+
26
+ it "should give root url" do
27
+ subject.link_url(:rel => 'root').should == ('http://feedbooks.com')
28
+ subject.by(:rel)['root'].first[1].should == ('http://feedbooks.com')
29
+ end
30
+
31
+ it "get all text values" do
32
+ subject.texts.size.should be(6)
33
+ end
34
+ end
@@ -0,0 +1,73 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ def sample(type)
4
+ File.open( File.expand_path(File.dirname(__FILE__) + "/../samples/#{type}.txt"))
5
+ end
6
+
7
+ describe OPDS::OPDSParser do
8
+
9
+ [:entry, :acquisition, :navigation].each do |feed_type|
10
+ it "should parse entry without error" do
11
+ lambda { subject.parse(sample(feed_type)) }.should_not raise_error
12
+ end
13
+
14
+ it "should sniff entry" do
15
+ subject.parse(sample(feed_type))
16
+ subject.sniffed_type.should be(feed_type)
17
+ end
18
+
19
+ it "should return an instance of the correct class " do
20
+ subject.parse(sample(feed_type)).class.should be({:entry => OPDS::Entry, :navigation => OPDS::NavigationFeed,:acquisition => OPDS::AcquisitionFeed}[feed_type])
21
+ end
22
+ end
23
+
24
+ [ :acquisition, :navigation].each do |feed_type|
25
+ it "should have a feed title" do
26
+ subject.parse(sample(feed_type)).title.size.should_not be(0)
27
+ end
28
+
29
+ it "should have a feed icon" do
30
+ subject.parse(sample(feed_type)).icon.size.should_not be(0)
31
+ end
32
+
33
+ it "should have feed links" do
34
+ subject.parse(sample(feed_type)).links.size.should_not be(0)
35
+ end
36
+
37
+ it "should have feed id" do
38
+ subject.parse(sample(feed_type)).id.size.should_not be(0)
39
+ end
40
+ it "should have a feed author" do
41
+ auth=subject.parse(sample(feed_type)).author
42
+ auth[:name].should == ('Feedbooks')
43
+ auth[:uri].should == ('http://www.feedbooks.com')
44
+ auth[:email].should == ('support@feedbooks.com')
45
+ end
46
+
47
+ it "should have entries" do
48
+ subject.parse(sample(feed_type)).entries.size.should_not be(0)
49
+ end
50
+
51
+
52
+
53
+ end
54
+
55
+ it do
56
+ subject.parse(sample(:acquisition)).should be_paginated()
57
+ end
58
+
59
+ it do
60
+ subject.parse(sample(:acquisition)).should be_first_page()
61
+ end
62
+
63
+ it "should have partial entries" do
64
+ subject.parse(sample(:acquisition)).entries.any?(&:partial?).should be()
65
+ end
66
+
67
+ it do
68
+ feed=nil
69
+ lambda { feed=subject.parse(sample(:acquisition)).next_page }.should_not raise_error
70
+
71
+ feed.class.should be(OPDS::AcquisitionFeed)
72
+ end
73
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,9 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'opds'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+
9
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opds
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 2
9
+ - 0
10
+ version: 0.2.0
11
+ platform: ruby
12
+ authors:
13
+ - Benoit Larroque
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-08-31 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 13
30
+ segments:
31
+ - 1
32
+ - 2
33
+ - 9
34
+ version: 1.2.9
35
+ type: :development
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: nokogiri
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :runtime
50
+ version_requirements: *id002
51
+ description: ruby lib to access OPDS feeds
52
+ email: benoit dot larroque at feedbooks dot com
53
+ executables: []
54
+
55
+ extensions: []
56
+
57
+ extra_rdoc_files:
58
+ - LICENSE
59
+ - README.md
60
+ files:
61
+ - .document
62
+ - .gitignore
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - VERSION
67
+ - lib/opds.rb
68
+ - lib/opds/acquisition_feed.rb
69
+ - lib/opds/entry.rb
70
+ - lib/opds/feed.rb
71
+ - lib/opds/navigation_feed.rb
72
+ - lib/opds/opds.rb
73
+ - lib/opds/parser.rb
74
+ - lib/opds/support/browser.rb
75
+ - lib/opds/support/linkset.rb
76
+ - lib/opds/support/logging.rb
77
+ - opds.gemspec
78
+ - samples/acquisition.txt
79
+ - samples/entry.txt
80
+ - samples/navigation.txt
81
+ - spec/browser_spec.rb
82
+ - spec/entry_spec.rb
83
+ - spec/linkset_spec.rb
84
+ - spec/opdsparser_spec.rb
85
+ - spec/spec.opts
86
+ - spec/spec_helper.rb
87
+ has_rdoc: true
88
+ homepage: http://github.com/zetaben/opds
89
+ licenses: []
90
+
91
+ post_install_message:
92
+ rdoc_options:
93
+ - --charset=UTF-8
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ hash: 3
102
+ segments:
103
+ - 0
104
+ version: "0"
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ hash: 3
111
+ segments:
112
+ - 0
113
+ version: "0"
114
+ requirements: []
115
+
116
+ rubyforge_project:
117
+ rubygems_version: 1.3.7
118
+ signing_key:
119
+ specification_version: 3
120
+ summary: ruby lib to read OPDS feeds
121
+ test_files:
122
+ - spec/spec_helper.rb
123
+ - spec/entry_spec.rb
124
+ - spec/browser_spec.rb
125
+ - spec/linkset_spec.rb
126
+ - spec/opdsparser_spec.rb