feed_duck 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/feed_duck.gemspec +25 -0
- data/lib/feed_duck/atom_feed.rb +87 -0
- data/lib/feed_duck/parser.rb +28 -0
- data/lib/feed_duck/rss_feed.rb +91 -0
- data/lib/feed_duck/version.rb +3 -0
- data/lib/feed_duck.rb +7 -0
- data/spec/feed_duck/atom_feed_spec.rb +131 -0
- data/spec/feed_duck/rss_feed_spec.rb +125 -0
- data/spec/feed_duck_spec.rb +31 -0
- data/spec/fixtures/feed_fixture.atom +27 -0
- data/spec/fixtures/feed_fixture.rss +19 -0
- metadata +109 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ebb32ab10d88d6c9d5163ad9dea64a42b833cb42
|
4
|
+
data.tar.gz: 054bce52d43621e34943be4a7bc1673924d7fdc8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4cd209d9c6668395c953ffd3d21b184da5ab34c22882a14d7e4aab74b3006f611a6b9dab2bff31c50766e9518400e756d9ade2cfd20a91b439474daddee9ad06
|
7
|
+
data.tar.gz: 21bb65d81c354edcd65fa88e9fddbd408e00d13563cf333e1a8ab3ff8abb02b4aaf4c3b3872515976f7c1a9e81a302e76d8720b4df95fed78c01d624efcbbae9
|
data/.gitignore
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
.DS_Store
|
7
|
+
Gemfile.lock
|
8
|
+
InstalledFiles
|
9
|
+
_yardoc
|
10
|
+
coverage
|
11
|
+
doc/
|
12
|
+
lib/bundler/man
|
13
|
+
pkg
|
14
|
+
rdoc
|
15
|
+
spec/reports
|
16
|
+
test/tmp
|
17
|
+
test/version_tmp
|
18
|
+
tmp
|
19
|
+
*.bundle
|
20
|
+
*.so
|
21
|
+
*.o
|
22
|
+
*.a
|
23
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 André Bernardes
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# FeedDuck
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'feed_duck'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install feed_duck
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it ( https://github.com/[my-github-username]/feed_duck/fork )
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/feed_duck.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'feed_duck/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "feed_duck"
|
8
|
+
spec.version = FeedDuck::VERSION
|
9
|
+
spec.authors = ["André Bernardes"]
|
10
|
+
spec.email = ["abernardes@gmail.com"]
|
11
|
+
spec.summary = %q{This gem parses RSS and Atom feeds into Ruby objects.}
|
12
|
+
spec.description = %q{This gem parses RSS and Atom feeds and provides an uniform ruby-object interface to access data from
|
13
|
+
both feed standards.}
|
14
|
+
spec.homepage = "https://github.com/abernardes/feed_duck"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.6"
|
23
|
+
spec.add_development_dependency "rake"
|
24
|
+
spec.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module FeedDuck
|
2
|
+
class AtomFeed
|
3
|
+
def initialize(parsed_feed)
|
4
|
+
@parsed_feed = parsed_feed
|
5
|
+
end
|
6
|
+
|
7
|
+
def title
|
8
|
+
parsed_feed.title.content
|
9
|
+
end
|
10
|
+
|
11
|
+
def url
|
12
|
+
parsed_feed.links.reject { |link| link.rel == "self" }.first.href
|
13
|
+
end
|
14
|
+
|
15
|
+
def subtitle
|
16
|
+
parsed_feed.subtitle.content
|
17
|
+
end
|
18
|
+
|
19
|
+
def entries
|
20
|
+
parsed_feed.entries.map { |entry| AtomEntry.new(entry) }
|
21
|
+
end
|
22
|
+
|
23
|
+
alias :description :subtitle
|
24
|
+
|
25
|
+
def to_h
|
26
|
+
attributes_hash.merge(entries: entries.map(&:to_h))
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
attr_reader :parsed_feed
|
32
|
+
|
33
|
+
def attributes_hash
|
34
|
+
public_attributes.each_with_object(Hash.new) do |attr, attribute_hash|
|
35
|
+
attribute_hash[attr] = send(attr)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def public_attributes
|
40
|
+
[:title, :url, :description, :subtitle]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class AtomEntry
|
45
|
+
def initialize(parsed_entry)
|
46
|
+
@parsed_entry = parsed_entry
|
47
|
+
end
|
48
|
+
|
49
|
+
def title
|
50
|
+
parsed_entry.title.content
|
51
|
+
end
|
52
|
+
|
53
|
+
def content
|
54
|
+
parsed_entry.content.content
|
55
|
+
end
|
56
|
+
|
57
|
+
def published_at
|
58
|
+
parsed_entry.updated.content
|
59
|
+
end
|
60
|
+
|
61
|
+
def author
|
62
|
+
parsed_entry.author.name.content
|
63
|
+
end
|
64
|
+
|
65
|
+
def url
|
66
|
+
parsed_entry.link.href
|
67
|
+
end
|
68
|
+
|
69
|
+
def id
|
70
|
+
parsed_entry.id.content
|
71
|
+
end
|
72
|
+
|
73
|
+
def to_h
|
74
|
+
public_attributes.each_with_object(Hash.new) do |attr, attribute_hash|
|
75
|
+
attribute_hash[attr] = send(attr)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
attr_reader :parsed_entry
|
82
|
+
|
83
|
+
def public_attributes
|
84
|
+
[:title, :content, :published_at, :author, :url, :id]
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module FeedDuck
|
2
|
+
class Parser
|
3
|
+
attr_reader :feed
|
4
|
+
|
5
|
+
def initialize(feed)
|
6
|
+
@feed = feed
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.parse(feed)
|
10
|
+
new(feed).parse
|
11
|
+
end
|
12
|
+
|
13
|
+
def parse
|
14
|
+
parsed_feed = RSS::Parser.parse(feed)
|
15
|
+
map_feed(parsed_feed)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def map_feed(parsed_feed)
|
21
|
+
if parsed_feed.is_a?(RSS::Rss)
|
22
|
+
RSSFeed.new(parsed_feed)
|
23
|
+
else
|
24
|
+
AtomFeed.new(parsed_feed)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module FeedDuck
|
2
|
+
class RSSFeed
|
3
|
+
def initialize(parsed_feed)
|
4
|
+
@parsed_feed = parsed_feed
|
5
|
+
end
|
6
|
+
|
7
|
+
def title
|
8
|
+
parsed_feed.channel.title
|
9
|
+
end
|
10
|
+
|
11
|
+
def url
|
12
|
+
parsed_feed.channel.link
|
13
|
+
end
|
14
|
+
|
15
|
+
def description
|
16
|
+
parsed_feed.channel.description
|
17
|
+
end
|
18
|
+
|
19
|
+
def language
|
20
|
+
parsed_feed.channel.language
|
21
|
+
end
|
22
|
+
|
23
|
+
def entries
|
24
|
+
parsed_feed.items.map do |item|
|
25
|
+
RSSEntry.new(item)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_h
|
30
|
+
attributes_hash.merge(entries: entries.map(&:to_h))
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
attr_reader :parsed_feed
|
36
|
+
|
37
|
+
def attributes_hash
|
38
|
+
public_attributes.each_with_object(Hash.new) do |attr, attribute_hash|
|
39
|
+
attribute_hash[attr] = send(attr)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def public_attributes
|
44
|
+
[:title, :url, :description]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class RSSEntry
|
49
|
+
def initialize(parsed_feed_entry)
|
50
|
+
@parsed_feed_entry = parsed_feed_entry
|
51
|
+
end
|
52
|
+
|
53
|
+
def title
|
54
|
+
parsed_feed_entry.title
|
55
|
+
end
|
56
|
+
|
57
|
+
def content
|
58
|
+
parsed_feed_entry.description
|
59
|
+
end
|
60
|
+
|
61
|
+
def published_at
|
62
|
+
parsed_feed_entry.pubDate
|
63
|
+
end
|
64
|
+
|
65
|
+
def author
|
66
|
+
parsed_feed_entry.author
|
67
|
+
end
|
68
|
+
|
69
|
+
def url
|
70
|
+
parsed_feed_entry.link
|
71
|
+
end
|
72
|
+
|
73
|
+
def id
|
74
|
+
parsed_feed_entry.guid.content
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_h
|
78
|
+
public_attributes.each_with_object(Hash.new) do |attr, attribute_hash|
|
79
|
+
attribute_hash[attr] = send(attr)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
attr_reader :parsed_feed_entry
|
86
|
+
|
87
|
+
def public_attributes
|
88
|
+
[:title, :content, :published_at, :author, :url, :id]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
data/lib/feed_duck.rb
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
require 'rss'
|
2
|
+
require 'feed_duck/atom_feed'
|
3
|
+
|
4
|
+
describe FeedDuck::AtomFeed do
|
5
|
+
let(:atom_feed) do
|
6
|
+
File.open('spec/fixtures/feed_fixture.atom', 'r') do |rss|
|
7
|
+
RSS::Parser.parse(rss)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { described_class.new(atom_feed) }
|
12
|
+
|
13
|
+
describe "#title" do
|
14
|
+
it "returns the feed title" do
|
15
|
+
expect(subject.title).to eq "Example Feed"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#url" do
|
20
|
+
it "returns the feed's url" do
|
21
|
+
expect(subject.url).to eq "http://example.org/"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#subtitle" do
|
26
|
+
it "returns the feed's subtitle" do
|
27
|
+
expect(subject.subtitle).to eq "A subtitle."
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#description" do
|
32
|
+
it "returns the feed's subtitle" do
|
33
|
+
expect(subject.description).to eq "A subtitle."
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#entries" do
|
38
|
+
it "return an array with the feed entries" do
|
39
|
+
expect(subject.entries.count).to eq 1
|
40
|
+
end
|
41
|
+
|
42
|
+
it "return instances of FeedDuck::AtomEntry" do
|
43
|
+
expect(subject.entries.first). to be_a FeedDuck::AtomEntry
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#to_h" do
|
48
|
+
it "returns a hash representation of the feed" do
|
49
|
+
expect(subject.to_h).to eq ({
|
50
|
+
title: "Example Feed",
|
51
|
+
url: "http://example.org/",
|
52
|
+
subtitle: "A subtitle.",
|
53
|
+
description: "A subtitle.",
|
54
|
+
entries: [{
|
55
|
+
title: "Atom-Powered Robots Run Amok",
|
56
|
+
content: "Some interesting content.",
|
57
|
+
published_at: Time.utc(2003, 12, 13, 18, 30, 02),
|
58
|
+
author: "John Doe",
|
59
|
+
url: "http://example.org/2003/12/13/atom03",
|
60
|
+
id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"
|
61
|
+
}],
|
62
|
+
})
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe FeedDuck::AtomEntry do
|
68
|
+
let(:atom_feed) do
|
69
|
+
File.open('spec/fixtures/feed_fixture.atom', 'r') do |rss|
|
70
|
+
RSS::Parser.parse(rss)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
let(:feed) { FeedDuck::AtomFeed.new(atom_feed) }
|
75
|
+
|
76
|
+
subject { feed.entries.first }
|
77
|
+
|
78
|
+
it "has a FeedDuck::AtomEntry type" do
|
79
|
+
expect(subject).to be_a FeedDuck::AtomEntry
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "#title" do
|
83
|
+
it "returns the entry's title" do
|
84
|
+
expect(subject.title).to eq "Atom-Powered Robots Run Amok"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "#content" do
|
89
|
+
it "returns the entry's content" do
|
90
|
+
expect(subject.content).to eq "Some interesting content."
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe "#published_at" do
|
95
|
+
it "returns the entry's published date" do
|
96
|
+
expect(subject.published_at).to eq Time.utc(2003, 12, 13, 18, 30, 02)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "#author" do
|
101
|
+
it "returns the entry's author name" do
|
102
|
+
expect(subject.author).to eq "John Doe"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe "#url" do
|
107
|
+
it "returns the entry's url" do
|
108
|
+
expect(subject.url).to eq "http://example.org/2003/12/13/atom03"
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
describe "#id" do
|
113
|
+
it "returns the entry id" do
|
114
|
+
expect(subject.id).to eq "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe "#to_h" do
|
119
|
+
it "returns a hash representation of the entry" do
|
120
|
+
expect(subject.to_h).to eq({
|
121
|
+
title: "Atom-Powered Robots Run Amok",
|
122
|
+
content: "Some interesting content.",
|
123
|
+
published_at: Time.utc(2003, 12, 13, 18, 30, 02),
|
124
|
+
author: "John Doe",
|
125
|
+
url: "http://example.org/2003/12/13/atom03",
|
126
|
+
id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
|
127
|
+
})
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'rss'
|
2
|
+
require 'feed_duck/rss_feed'
|
3
|
+
|
4
|
+
describe FeedDuck::RSSFeed do
|
5
|
+
let(:rss_feed) do
|
6
|
+
File.open('spec/fixtures/feed_fixture.rss', 'r') do |rss|
|
7
|
+
RSS::Parser.parse(rss)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
subject { described_class.new(rss_feed) }
|
12
|
+
|
13
|
+
describe "#title" do
|
14
|
+
it "returns the RSS feed channel title" do
|
15
|
+
expect(subject.title).to eq "RubyFlow"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#url" do
|
20
|
+
it "returns the RSS feed channel url" do
|
21
|
+
expect(subject.url).to eq "http://www.rubyflow.com/"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "#description" do
|
26
|
+
it "returns the RSS feed channel description" do
|
27
|
+
expect(subject.description).to eq "Ruby Links"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#language" do
|
32
|
+
it "returns the RSS feed channel language" do
|
33
|
+
expect(subject.language).to eq "en-us"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#entries" do
|
38
|
+
it "returns an array with all the RSS feed items" do
|
39
|
+
expect(subject.entries.length).to eq 1
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#to_h" do
|
44
|
+
it "returns a hash representation of the feed" do
|
45
|
+
expect(subject.to_h).to eq({
|
46
|
+
title: "RubyFlow",
|
47
|
+
url: "http://www.rubyflow.com/",
|
48
|
+
description: "Ruby Links",
|
49
|
+
entries: [{
|
50
|
+
title: "A Guide to Choosing the Best Gems for Your Ruby Project",
|
51
|
+
content: "If you need something done in Ruby, a gem for it probably exists.",
|
52
|
+
published_at: Time.new(2014, 4, 8, 16, 40, 33, "+02:00"),
|
53
|
+
author: "Author",
|
54
|
+
url: "http://feedproxy.google.com/~r/Rubyflow/~3/2ynPljVok9U/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project",
|
55
|
+
id: "http://www.rubyflow.com/items/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project"
|
56
|
+
}]
|
57
|
+
})
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe FeedDuck::RSSEntry do
|
63
|
+
let(:rss_feed) do
|
64
|
+
File.open('spec/fixtures/feed_fixture.rss', 'r') do |rss|
|
65
|
+
RSS::Parser.parse(rss)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
let(:feed) { FeedDuck::RSSFeed.new(rss_feed) }
|
70
|
+
|
71
|
+
subject { feed.entries.first }
|
72
|
+
|
73
|
+
it "has a FeedDuck::Entry type" do
|
74
|
+
expect(subject).to be_a FeedDuck::RSSEntry
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#title" do
|
78
|
+
it "returns the entry's title" do
|
79
|
+
expect(subject.title).to eq "A Guide to Choosing the Best Gems for Your Ruby Project"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "#content" do
|
84
|
+
it "returns the entry's content" do
|
85
|
+
expect(subject.content).to include "If you need something done in Ruby, a gem for it probably exists."
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#published_at" do
|
90
|
+
it "returns the entry's published date" do
|
91
|
+
expect(subject.published_at).to eq Time.new(2014, 4, 8, 16, 40, 33, "+02:00")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#author" do
|
96
|
+
it "returns the entry's author name" do
|
97
|
+
expect(subject.author).to eq "Author"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe "#url" do
|
102
|
+
it "returns a URL to the entry" do
|
103
|
+
expect(subject.url).to eq "http://feedproxy.google.com/~r/Rubyflow/~3/2ynPljVok9U/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
describe "#id" do
|
108
|
+
it "returns the entry id" do
|
109
|
+
expect(subject.id).to eq "http://www.rubyflow.com/items/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe "#to_h" do
|
114
|
+
it "returns a hash representation of the entry" do
|
115
|
+
expect(subject.to_h).to eq({
|
116
|
+
title: "A Guide to Choosing the Best Gems for Your Ruby Project",
|
117
|
+
content: "If you need something done in Ruby, a gem for it probably exists.",
|
118
|
+
published_at: Time.new(2014, 4, 8, 16, 40, 33, "+02:00"),
|
119
|
+
author: "Author",
|
120
|
+
url: "http://feedproxy.google.com/~r/Rubyflow/~3/2ynPljVok9U/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project",
|
121
|
+
id: "http://www.rubyflow.com/items/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project"
|
122
|
+
})
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'feed_duck'
|
2
|
+
|
3
|
+
describe FeedDuck::Parser do
|
4
|
+
describe "#parse" do
|
5
|
+
it "parses and returns a RSS feed" do
|
6
|
+
feed = File.open('spec/fixtures/feed_fixture.rss', 'r') do |rss|
|
7
|
+
FeedDuck::Parser.new(rss).parse
|
8
|
+
end
|
9
|
+
|
10
|
+
expect(feed.title).to eq "RubyFlow"
|
11
|
+
end
|
12
|
+
|
13
|
+
it "parses and returns an Atom feed" do
|
14
|
+
feed = File.open('spec/fixtures/feed_fixture.atom', 'r') do |rss|
|
15
|
+
FeedDuck::Parser.new(rss).parse
|
16
|
+
end
|
17
|
+
|
18
|
+
expect(feed.title).to eq "Example Feed"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe ".parse" do
|
23
|
+
it "provides a shortcut for FeedDuck::Parser.new(feed).parse" do
|
24
|
+
feed = File.open('spec/fixtures/feed_fixture.rss', 'r') do |rss|
|
25
|
+
FeedDuck::Parser.parse(rss)
|
26
|
+
end
|
27
|
+
|
28
|
+
expect(feed.title).to eq "RubyFlow"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
2
|
+
|
3
|
+
<feed xmlns="http://www.w3.org/2005/Atom">
|
4
|
+
|
5
|
+
<title>Example Feed</title>
|
6
|
+
<subtitle>A subtitle.</subtitle>
|
7
|
+
<link href="http://example.org/feed/" rel="self" />
|
8
|
+
<link href="http://example.org/" />
|
9
|
+
<id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>
|
10
|
+
<updated>2003-12-13T18:30:02Z</updated>
|
11
|
+
|
12
|
+
|
13
|
+
<entry>
|
14
|
+
<title>Atom-Powered Robots Run Amok</title>
|
15
|
+
<link href="http://example.org/2003/12/13/atom03" />
|
16
|
+
<link rel="alternate" type="text/html" href="http://example.org/2003/12/13/atom03.html"/>
|
17
|
+
<link rel="edit" href="http://example.org/2003/12/13/atom03/edit"/>
|
18
|
+
<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
|
19
|
+
<updated>2003-12-13T18:30:02Z</updated>
|
20
|
+
<content>Some interesting content.</content>
|
21
|
+
<author>
|
22
|
+
<name>John Doe</name>
|
23
|
+
<email>johndoe@example.com</email>
|
24
|
+
</author>
|
25
|
+
</entry>
|
26
|
+
|
27
|
+
</feed>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">
|
3
|
+
<channel>
|
4
|
+
<title>RubyFlow</title>
|
5
|
+
<link>http://www.rubyflow.com/</link>
|
6
|
+
<description>Ruby Links</description>
|
7
|
+
<language>en-us</language>
|
8
|
+
<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Rubyflow" /><feedburner:info uri="rubyflow" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" />
|
9
|
+
<item>
|
10
|
+
<title>A Guide to Choosing the Best Gems for Your Ruby Project</title>
|
11
|
+
<description>If you need something done in Ruby, a gem for it probably exists.</description>
|
12
|
+
<pubDate>Tue, 08 Apr 2014 16:40:33 +0200</pubDate>
|
13
|
+
<author>Author</author>
|
14
|
+
<link>http://feedproxy.google.com/~r/Rubyflow/~3/2ynPljVok9U/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project</link>
|
15
|
+
<guid isPermaLink="false">http://www.rubyflow.com/items/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project</guid>
|
16
|
+
<feedburner:origLink>http://www.rubyflow.com/items/10851-a-guide-to-choosing-the-best-gems-for-your-ruby-project</feedburner:origLink>
|
17
|
+
</item>
|
18
|
+
</channel>
|
19
|
+
</rss>
|
metadata
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: feed_duck
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- André Bernardes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
description: |-
|
56
|
+
This gem parses RSS and Atom feeds and provides an uniform ruby-object interface to access data from
|
57
|
+
both feed standards.
|
58
|
+
email:
|
59
|
+
- abernardes@gmail.com
|
60
|
+
executables: []
|
61
|
+
extensions: []
|
62
|
+
extra_rdoc_files: []
|
63
|
+
files:
|
64
|
+
- ".gitignore"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.md
|
68
|
+
- Rakefile
|
69
|
+
- feed_duck.gemspec
|
70
|
+
- lib/feed_duck.rb
|
71
|
+
- lib/feed_duck/atom_feed.rb
|
72
|
+
- lib/feed_duck/parser.rb
|
73
|
+
- lib/feed_duck/rss_feed.rb
|
74
|
+
- lib/feed_duck/version.rb
|
75
|
+
- spec/feed_duck/atom_feed_spec.rb
|
76
|
+
- spec/feed_duck/rss_feed_spec.rb
|
77
|
+
- spec/feed_duck_spec.rb
|
78
|
+
- spec/fixtures/feed_fixture.atom
|
79
|
+
- spec/fixtures/feed_fixture.rss
|
80
|
+
homepage: https://github.com/abernardes/feed_duck
|
81
|
+
licenses:
|
82
|
+
- MIT
|
83
|
+
metadata: {}
|
84
|
+
post_install_message:
|
85
|
+
rdoc_options: []
|
86
|
+
require_paths:
|
87
|
+
- lib
|
88
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
89
|
+
requirements:
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
requirements: []
|
99
|
+
rubyforge_project:
|
100
|
+
rubygems_version: 2.2.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 4
|
103
|
+
summary: This gem parses RSS and Atom feeds into Ruby objects.
|
104
|
+
test_files:
|
105
|
+
- spec/feed_duck/atom_feed_spec.rb
|
106
|
+
- spec/feed_duck/rss_feed_spec.rb
|
107
|
+
- spec/feed_duck_spec.rb
|
108
|
+
- spec/fixtures/feed_fixture.atom
|
109
|
+
- spec/fixtures/feed_fixture.rss
|