simple-rss 1.3.3 → 2.1.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.
- checksums.yaml +4 -4
- data/LICENSE +79 -7
- data/README.md +321 -0
- data/Rakefile +134 -136
- data/lib/simple-rss.rb +541 -154
- data/simple-rss.gemspec +5 -6
- data/test/base/array_tags_test.rb +37 -0
- data/test/base/base_test.rb +76 -77
- data/test/base/empty_tag_test.rb +56 -0
- data/test/base/encoding_test.rb +87 -0
- data/test/base/enumerable_test.rb +101 -0
- data/test/base/feed_attributes_test.rb +26 -0
- data/test/base/fetch_test.rb +117 -0
- data/test/base/hash_xml_serialization_test.rb +142 -0
- data/test/base/item_attributes_test.rb +26 -0
- data/test/base/json_serialization_test.rb +81 -0
- data/test/data/atom_with_entry_attrs.xml +13 -0
- data/test/data/atom_with_feed_attrs.xml +13 -0
- data/test/data/media_rss.xml +465 -0
- data/test/data/rss20_utf8.xml +61 -0
- data/test/data/rss20_with_channel_attrs.xml +13 -0
- data/test/data/rss20_with_item_attrs.xml +13 -0
- data/test/test_helper.rb +10 -3
- metadata +21 -11
- data/README.markdown +0 -47
- data/install.rb +0 -40
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
class HashXmlSerializationTest < Test::Unit::TestCase
|
|
4
|
+
def setup
|
|
5
|
+
@rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20.xml")
|
|
6
|
+
@atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom.xml")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# to_hash tests
|
|
10
|
+
|
|
11
|
+
def test_to_hash_returns_hash
|
|
12
|
+
result = @rss20.to_hash
|
|
13
|
+
assert_kind_of Hash, result
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_to_hash_includes_feed_title
|
|
17
|
+
result = @rss20.to_hash
|
|
18
|
+
assert_equal "Technoblog", result[:title]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_to_hash_includes_items
|
|
22
|
+
result = @rss20.to_hash
|
|
23
|
+
assert_kind_of Array, result[:items]
|
|
24
|
+
assert_equal 10, result[:items].size
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_to_hash_is_alias_for_as_json
|
|
28
|
+
assert_equal @rss20.as_json, @rss20.to_hash
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# to_xml RSS 2.0 tests
|
|
32
|
+
|
|
33
|
+
def test_to_xml_returns_string
|
|
34
|
+
result = @rss20.to_xml
|
|
35
|
+
assert_kind_of String, result
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_to_xml_default_format_is_rss2
|
|
39
|
+
result = @rss20.to_xml
|
|
40
|
+
assert_match(/<rss version="2.0">/, result)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_to_xml_rss2_has_xml_declaration
|
|
44
|
+
result = @rss20.to_xml(format: :rss2)
|
|
45
|
+
assert_match(/^<\?xml version="1.0" encoding="UTF-8"\?>/, result)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_to_xml_rss2_has_channel
|
|
49
|
+
result = @rss20.to_xml(format: :rss2)
|
|
50
|
+
assert_match(/<channel>/, result)
|
|
51
|
+
assert_match(%r{</channel>}, result)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_to_xml_rss2_has_title
|
|
55
|
+
result = @rss20.to_xml(format: :rss2)
|
|
56
|
+
assert_match(%r{<title>Technoblog</title>}, result)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def test_to_xml_rss2_has_link
|
|
60
|
+
result = @rss20.to_xml(format: :rss2)
|
|
61
|
+
assert_match(%r{<link>http://tech.rufy.com</link>}, result)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def test_to_xml_rss2_has_items
|
|
65
|
+
result = @rss20.to_xml(format: :rss2)
|
|
66
|
+
assert_match(/<item>/, result)
|
|
67
|
+
assert_match(%r{</item>}, result)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_to_xml_rss2_item_has_title
|
|
71
|
+
result = @rss20.to_xml(format: :rss2)
|
|
72
|
+
assert_match(/<item>\n<title>/, result)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def test_to_xml_rss2_item_has_guid
|
|
76
|
+
result = @rss20.to_xml(format: :rss2)
|
|
77
|
+
assert_match(%r{<guid>http://tech.rufy.com/entry/\d+</guid>}, result)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def test_to_xml_rss2_escapes_special_characters
|
|
81
|
+
rss = SimpleRSS.parse('<rss version="2.0"><channel><title>Test & Title</title><item><title>Item <1></title></item></channel></rss>')
|
|
82
|
+
result = rss.to_xml(format: :rss2)
|
|
83
|
+
assert_match(/&/, result)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# to_xml Atom tests
|
|
87
|
+
|
|
88
|
+
def test_to_xml_atom_format
|
|
89
|
+
result = @atom.to_xml(format: :atom)
|
|
90
|
+
assert_match(%r{<feed xmlns="http://www.w3.org/2005/Atom">}, result)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_to_xml_atom_has_title
|
|
94
|
+
result = @atom.to_xml(format: :atom)
|
|
95
|
+
assert_match(%r{<title>dive into mark</title>}, result)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def test_to_xml_atom_has_link
|
|
99
|
+
result = @atom.to_xml(format: :atom)
|
|
100
|
+
assert_match(%r{<link href="http://example.org/" rel="alternate"/>}, result)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_to_xml_atom_has_entries
|
|
104
|
+
result = @atom.to_xml(format: :atom)
|
|
105
|
+
assert_match(/<entry>/, result)
|
|
106
|
+
assert_match(%r{</entry>}, result)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_to_xml_atom_entry_has_title
|
|
110
|
+
result = @atom.to_xml(format: :atom)
|
|
111
|
+
assert_match(%r{<entry>\n<title>Atom draft-07 snapshot</title>}, result)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
# Error handling
|
|
115
|
+
|
|
116
|
+
def test_to_xml_raises_on_unknown_format
|
|
117
|
+
assert_raise(ArgumentError) { @rss20.to_xml(format: :unknown) }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_to_xml_error_message_includes_supported_formats
|
|
121
|
+
error = assert_raise(ArgumentError) { @rss20.to_xml(format: :foo) }
|
|
122
|
+
assert_match(/Supported: :rss2, :atom/, error.message)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Round-trip tests
|
|
126
|
+
|
|
127
|
+
def test_to_xml_rss2_can_be_reparsed
|
|
128
|
+
xml = @rss20.to_xml(format: :rss2)
|
|
129
|
+
reparsed = SimpleRSS.parse(xml)
|
|
130
|
+
|
|
131
|
+
assert_equal "Technoblog", reparsed.title
|
|
132
|
+
assert_equal 10, reparsed.items.size
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def test_to_xml_atom_can_be_reparsed
|
|
136
|
+
xml = @atom.to_xml(format: :atom)
|
|
137
|
+
reparsed = SimpleRSS.parse(xml)
|
|
138
|
+
|
|
139
|
+
assert_equal "dive into mark", reparsed.title
|
|
140
|
+
assert_equal 1, reparsed.items.size
|
|
141
|
+
end
|
|
142
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
|
|
3
|
+
class ItemAttributesTest < Test::Unit::TestCase
|
|
4
|
+
def setup
|
|
5
|
+
# Add item/entry attribute tags before parsing
|
|
6
|
+
SimpleRSS.item_tags << :"entry#custom:id"
|
|
7
|
+
SimpleRSS.item_tags << :"item#data-id"
|
|
8
|
+
|
|
9
|
+
@atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom_with_entry_attrs.xml")
|
|
10
|
+
@rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20_with_item_attrs.xml")
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def teardown
|
|
14
|
+
# Clean up added tags
|
|
15
|
+
SimpleRSS.item_tags.delete(:"entry#custom:id")
|
|
16
|
+
SimpleRSS.item_tags.delete(:"item#data-id")
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_atom_entry_attribute
|
|
20
|
+
assert_equal "12345", @atom.entries.first[:entry_custom_id]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_rss20_item_attribute
|
|
24
|
+
assert_equal "67890", @rss20.items.first[:"item_data-id"]
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
require "test_helper"
|
|
2
|
+
require "json"
|
|
3
|
+
|
|
4
|
+
class JsonSerializationTest < Test::Unit::TestCase
|
|
5
|
+
def setup
|
|
6
|
+
@rss20 = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/rss20.xml")
|
|
7
|
+
@atom = SimpleRSS.parse open(File.dirname(__FILE__) + "/../data/atom.xml")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def test_as_json_returns_hash
|
|
11
|
+
result = @rss20.as_json
|
|
12
|
+
assert_kind_of Hash, result
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def test_as_json_includes_feed_title
|
|
16
|
+
result = @rss20.as_json
|
|
17
|
+
assert_equal "Technoblog", result[:title]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def test_as_json_includes_feed_link
|
|
21
|
+
result = @rss20.as_json
|
|
22
|
+
assert_equal "http://tech.rufy.com", result[:link]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_as_json_includes_items
|
|
26
|
+
result = @rss20.as_json
|
|
27
|
+
assert_kind_of Array, result[:items]
|
|
28
|
+
assert_equal 10, result[:items].size
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_as_json_items_have_title
|
|
32
|
+
result = @rss20.as_json
|
|
33
|
+
assert result[:items].first[:title].include?("some_string.starts_with?")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_as_json_converts_time_to_iso8601
|
|
37
|
+
result = @rss20.as_json
|
|
38
|
+
pub_date = result[:items].first[:pubDate]
|
|
39
|
+
assert_kind_of String, pub_date
|
|
40
|
+
assert_match(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/, pub_date)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_as_json_works_with_atom
|
|
44
|
+
result = @atom.as_json
|
|
45
|
+
assert_equal "dive into mark", result[:title]
|
|
46
|
+
assert_equal 1, result[:items].size
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_to_json_returns_string
|
|
50
|
+
result = @rss20.to_json
|
|
51
|
+
assert_kind_of String, result
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_to_json_is_valid_json
|
|
55
|
+
result = @rss20.to_json
|
|
56
|
+
parsed = JSON.parse(result)
|
|
57
|
+
assert_kind_of Hash, parsed
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_to_json_roundtrip
|
|
61
|
+
json_string = @rss20.to_json
|
|
62
|
+
parsed = JSON.parse(json_string, symbolize_names: true)
|
|
63
|
+
|
|
64
|
+
assert_equal "Technoblog", parsed[:title]
|
|
65
|
+
assert_equal 10, parsed[:items].size
|
|
66
|
+
assert parsed[:items].first[:title].include?("some_string.starts_with?")
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def test_as_json_excludes_nil_feed_tags
|
|
70
|
+
result = @rss20.as_json
|
|
71
|
+
# Feed tags that weren't in the source shouldn't appear
|
|
72
|
+
refute result.key?(:subtitle)
|
|
73
|
+
refute result.key?(:id)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_as_json_accepts_options_parameter
|
|
77
|
+
# Should not raise, even if options aren't used yet
|
|
78
|
+
result = @rss20.as_json(only: [:title])
|
|
79
|
+
assert_kind_of Hash, result
|
|
80
|
+
end
|
|
81
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:custom="http://example.org/custom">
|
|
3
|
+
<title type="text">Test Feed</title>
|
|
4
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
5
|
+
<id>tag:example.org,2003:3</id>
|
|
6
|
+
<link rel="alternate" type="text/html" href="http://example.org/"/>
|
|
7
|
+
<entry custom:id="12345">
|
|
8
|
+
<title>Test Entry</title>
|
|
9
|
+
<link rel="alternate" type="text/html" href="http://example.org/entry/1"/>
|
|
10
|
+
<id>tag:example.org,2003:3.2397</id>
|
|
11
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
12
|
+
</entry>
|
|
13
|
+
</feed>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
2
|
+
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:app="http://example.org/app" app:id="12345">
|
|
3
|
+
<title type="text">Test Feed</title>
|
|
4
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
5
|
+
<id>tag:example.org,2003:3</id>
|
|
6
|
+
<link rel="alternate" type="text/html" href="http://example.org/"/>
|
|
7
|
+
<entry>
|
|
8
|
+
<title>Test Entry</title>
|
|
9
|
+
<link rel="alternate" type="text/html" href="http://example.org/entry/1"/>
|
|
10
|
+
<id>tag:example.org,2003:3.2397</id>
|
|
11
|
+
<updated>2005-07-31T12:29:29Z</updated>
|
|
12
|
+
</entry>
|
|
13
|
+
</feed>
|