libxml-feed 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.
@@ -0,0 +1,15 @@
1
+ begin
2
+ require 'rubygems'
3
+ gem 'libxml-ruby'
4
+ rescue LoadError => e
5
+ end
6
+
7
+ require 'xml/libxml'
8
+ require 'xml/libxml/feed/parser'
9
+ require 'xml/libxml/feed/builder'
10
+
11
+ module XML
12
+ module Feed
13
+ VERSION = "0.0.1"
14
+ end
15
+ end
@@ -0,0 +1,10 @@
1
+ module XML
2
+ module Feed
3
+ module Builder
4
+ def self.method_missing(method, *args)
5
+ require "xml/libxml/feed/builders/#{method.to_s.downcase}"
6
+ return self.const_get(method.to_s.capitalize).new(*args)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,144 @@
1
+ class XML::Feed::Builder::Rss
2
+ class Channels
3
+ include Enumerable
4
+
5
+ attr_reader :doc
6
+
7
+ def initialize(doc)
8
+ @doc = doc
9
+ end
10
+
11
+ def create
12
+ node = Channel.new(@doc)
13
+ yield node
14
+ @doc.root << node.node
15
+ end
16
+
17
+ def each
18
+ @doc.root.find('/rss/channel').each do |x|
19
+ yield Channel.new(@doc, x)
20
+ end
21
+ end
22
+
23
+ def [](x)
24
+ return Channel.new(@doc, @doc.root.find('/rss/channel').to_a[x])
25
+ end
26
+ end
27
+
28
+ class Channel
29
+ attr_reader :doc
30
+ attr_reader :node
31
+
32
+ def initialize(doc, node=nil)
33
+ @doc = doc
34
+ @node = node
35
+ @node = XML::Node.new("channel") unless @node
36
+ end
37
+
38
+ def items
39
+ return Items.new(@doc, @node)
40
+ end
41
+
42
+ alias item items
43
+ end
44
+
45
+ class Items
46
+ include Enumerable
47
+
48
+ def initialize(doc, channel)
49
+ @doc = doc
50
+ @channel = channel
51
+ end
52
+
53
+ def create
54
+ node = Item.new(@channel)
55
+ yield node
56
+ @channel << node.node
57
+ end
58
+
59
+ def each
60
+ @channel.find('./item').each do |x|
61
+ yield Item.new(@channel, x)
62
+ end
63
+ end
64
+
65
+ def [](x)
66
+ return Item.new(@channel, @channel.find('./item').to_a[x])
67
+ end
68
+ end
69
+
70
+ class Item
71
+ attr_reader :channel
72
+ attr_reader :node
73
+
74
+ def initialize(channel, node=nil)
75
+ @channel = channel
76
+ @node = node
77
+
78
+ @node = XML::Node.new('item') unless @node
79
+ @params = Hash.new
80
+ end
81
+
82
+ # basic parameters that just get enclosed by a <tag>. More involved
83
+ # stuff should create it's own pair of methods.
84
+ def method_missing(method, *args)
85
+ meth = method.to_s
86
+ if meth =~ /=$/ # assignment
87
+ my_meth = meth.sub(/=$/, '')
88
+
89
+ node = XML::Node.new(my_meth)
90
+ node.content = args[0].to_s
91
+ @node << node
92
+ return node
93
+ end
94
+
95
+ # if we're reading, we want to collect each node that matches our method name.
96
+ # the problem is, XML::XPath::Object#find doesn't work on detached nodes, which ours
97
+ # is at this state. So we have to search manually.
98
+
99
+ array = []
100
+
101
+ @node.each do |x|
102
+ if x.name == meth
103
+ array.push x
104
+ end
105
+ end
106
+
107
+ return array.length > 1 ? array : array[0]
108
+ end
109
+ end
110
+ end
111
+
112
+ class XML::Feed::Builder::Rss
113
+
114
+ attr_accessor :version
115
+ attr_accessor :doc
116
+
117
+ def initialize(version, parser=nil)
118
+ @version = version
119
+ @parser = parser
120
+
121
+ build_document
122
+ end
123
+
124
+ def to_xml
125
+ @doc.to_s
126
+ end
127
+
128
+ def channel
129
+ return Channels.new(@doc)
130
+ end
131
+
132
+ protected
133
+
134
+ def build_document
135
+ if @parser
136
+ @doc = @parser.doc
137
+ else
138
+ @doc = XML::Document.new
139
+ @doc.root = XML::Node.new("rss")
140
+ end
141
+
142
+ @doc.root["version"] = @version
143
+ end
144
+ end
@@ -0,0 +1,87 @@
1
+ module XML
2
+ module Feed
3
+ module Parser
4
+ def self.method_missing(method, *args)
5
+ require "xml/libxml/feed/parsers/#{method.to_s.downcase}"
6
+ return self.const_get(method.to_s.capitalize).new(*args)
7
+ end
8
+
9
+ class InvalidHandle < Exception
10
+ end
11
+
12
+ class ValidationError < Exception
13
+ end
14
+
15
+ class Tag
16
+ attr_reader :property
17
+ attr_reader :data
18
+
19
+ def initialize(name, data, properties)
20
+ if properties
21
+ @property = properties.to_h.dup
22
+ else
23
+ @property = { }
24
+ end
25
+
26
+ if data
27
+ @data = data
28
+ else
29
+ @data = ""
30
+ end
31
+
32
+ @name = name.dup
33
+ end
34
+
35
+ def to_s
36
+ @data.to_s
37
+ end
38
+
39
+ alias to_str to_s
40
+ end
41
+
42
+ class Base
43
+ attr_reader :xml
44
+ attr_reader :version
45
+ attr_reader :validated
46
+ attr_reader :doc
47
+
48
+ def initialize(version, io, auto_validate=true)
49
+ @version = version
50
+
51
+ case io
52
+ when IO
53
+ @xml = io.read
54
+ io.close
55
+ when StringIO
56
+ @xml = io.read
57
+ io.close
58
+ when String
59
+ @xml = io.dup
60
+ else
61
+ raise XML::Feed::Parser::InvalidHandle, "Must be IO, StringIO, or String object"
62
+ end
63
+
64
+ @xml.freeze
65
+ @version.freeze
66
+ @validated = false
67
+
68
+ if @xml.length == 0
69
+ raise XML::Feed::Parser::InvalidHandle, "Resulting XML String must have a length greater than 0"
70
+ end
71
+
72
+ @doc = XML::Parser.string(@xml).parse
73
+
74
+ if auto_validate
75
+ validate!
76
+ end
77
+ end
78
+
79
+ protected
80
+
81
+ def validation_error(error_string)
82
+ raise ValidationError, error_string
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,113 @@
1
+ module XML
2
+ module Feed
3
+ module Parser
4
+ class Rss < XML::Feed::Parser::Base
5
+ require 'xml/libxml/feed/parsers/rss/channel'
6
+ require 'xml/libxml/feed/parsers/rss/item'
7
+
8
+ def initialize(version, io, auto_validate=true)
9
+ super
10
+ end
11
+
12
+ def validate!
13
+ case @version
14
+ when '2.0'
15
+ validate_20
16
+ else
17
+ validation_error "Validating RSS version #{@version} is not supported (yet!)"
18
+ end
19
+
20
+ @validated = true
21
+ end
22
+
23
+ def channel
24
+ channels = []
25
+ @doc.find('/rss/channel').each do |x|
26
+ channels.push(Channel.new(x))
27
+ end
28
+
29
+ return channels
30
+ end
31
+
32
+ protected
33
+
34
+ #
35
+ # Given a node, an xpath expression to apply to that node, the
36
+ # error_message is thrown via validation_error() if the block
37
+ # evaluates to a false value or it raises an exception itself.
38
+ #
39
+ def validate_xpath(node, xpath, error_message, &block)
40
+ node = node.find(xpath)
41
+
42
+ result = true
43
+
44
+ if node and node.first
45
+ begin
46
+ result = yield node.first.content
47
+ rescue Exception => e
48
+ validation_error error_message
49
+ end
50
+ end
51
+
52
+ validation_error error_message unless result
53
+ end
54
+
55
+ # all the validation rules for RSS 2.0 that are fit to print.
56
+ def validate_20
57
+ validation_error "Document Root is not named 'rss'" unless @doc.root.name.downcase == "rss"
58
+ validation_error "Document Version does not exist" unless @doc.root["version"]
59
+ validation_error "Document Version is not '2.0'" unless @doc.root["version"] == "2.0"
60
+ validation_error "Channel elements do not exist" if @doc.find('/rss/channel').length == 0
61
+
62
+ @doc.find('/rss/channel').each_with_index do |node, i|
63
+
64
+ validate_20_channel(node, i)
65
+
66
+ if items = node.find('./item')
67
+ items.each_with_index do |item, item_i|
68
+ validation_error "Item must contain a title or description" unless item.find('./title').first or item.find('./description').first
69
+ validate_xpath(item, './pubDate', "Channel #{i} item #{item_i} element pubDate does not parse as a rfc822 time") do |x|
70
+ Time.rfc2822(x)
71
+ end
72
+ validate_xpath(item, './link', "Channel #{i} item #{item_i} element link does not parse as a URI") do |x|
73
+ URI.parse(x)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+ def validate_20_channel(node, i)
81
+ %w(title link description).each do |x|
82
+ validation_error "Channel node #{i} does not have a #{x} element" unless node.find('./' + x).length > 0
83
+ validation_error "Channel node #{i} has more than one #{x} element" if node.find('./' + x).length > 1
84
+ end
85
+ %w(link docs).each do |uri|
86
+ validate_xpath(node, "./#{uri}", "Channel #{i} element #{uri} does not parse as a URI") do |x|
87
+ URI.parse(x)
88
+ end
89
+ end
90
+ %w(pubDate lastBuildDate).each do |t|
91
+ validate_xpath(node, "./#{t}", "Channel #{i} element #{t} does not parse as a rfc822 time") do |x|
92
+ Time.rfc2822(x)
93
+ end
94
+ end
95
+ validate_xpath(node, './ttl', 'Channel #{i} element ttl is not an integer') do |x|
96
+ x.to_i.to_s == x
97
+ end
98
+ if node.find('./cloud')
99
+ #warn "Cloud support is currently not implemented"
100
+ end
101
+ if image = node.find('./image')
102
+ %w(url link).each do |ele|
103
+ validate_xpath(node, "./image/#{ele}", "Channel #{i} element image/#{ele} does not parse as a URI") do |x|
104
+ URI.parse(x)
105
+ end
106
+ end
107
+ validation_error "Title element must exist in Channel #{i} element image" unless node.find('./title').length > 0
108
+ end
109
+ end
110
+ end
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,14 @@
1
+ require 'xml/libxml/feed/parsers/rss/common'
2
+
3
+ class XML::Feed::Parser::Rss::Channel
4
+ include XML::Feed::Parser::Rss::Common
5
+
6
+ def item
7
+ items = []
8
+ @node.find('./item').each do |x|
9
+ items.push XML::Feed::Parser::Rss::Item.new(x)
10
+ end
11
+
12
+ return items
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ module XML::Feed::Parser::Rss::Common
2
+ attr_reader :node
3
+
4
+ def initialize(node)
5
+ @node = node
6
+ end
7
+
8
+ def method_missing(methId, *args)
9
+ requested = @node.find("./#{methId.to_s}")
10
+ if requested.first
11
+ if requested.length > 1
12
+ array = []
13
+ requested.each do |x|
14
+ array.push XML::Feed::Parser::Tag.new(x.name, type_node(x), x.properties)
15
+ end
16
+
17
+ return array
18
+ else
19
+ r = requested.first
20
+ return XML::Feed::Parser::Tag.new(r.name, type_node(r), r.properties)
21
+ end
22
+ end
23
+
24
+ return nil
25
+ end
26
+
27
+ protected
28
+
29
+ def type_node(node)
30
+ case node.name
31
+ when 'pubDate'
32
+ Time.rfc2822(node.content)
33
+ when 'lastBuildDate'
34
+ Time.rfc2822(node.content)
35
+ when 'docs'
36
+ URI.parse(node.content)
37
+ when 'link'
38
+ URI.parse(node.content)
39
+ when 'url'
40
+ URI.parse(node.content)
41
+ when 'ttl'
42
+ node.content.to_i
43
+ else
44
+ node.content
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,5 @@
1
+ require 'xml/libxml/feed/parsers/rss/common'
2
+
3
+ class XML::Feed::Parser::Rss::Item
4
+ include XML::Feed::Parser::Rss::Common
5
+ end
@@ -0,0 +1,127 @@
1
+ require 'test/unit'
2
+ require 'xml/libxml/feed'
3
+ require 'stringio'
4
+
5
+ class TestBuilderInterface < Test::Unit::TestCase
6
+
7
+ def test_loader
8
+ builder = nil
9
+ assert_nothing_raised do
10
+ builder = XML::Feed::Builder.rss('2.0')
11
+ end
12
+
13
+ assert_instance_of(XML::Feed::Builder::Rss, builder)
14
+
15
+ # test with a parser
16
+ parser = nil
17
+ assert_nothing_raised do
18
+ parser = XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml'), true)
19
+ end
20
+
21
+ assert_instance_of(XML::Feed::Parser::Rss, parser)
22
+
23
+ assert_nothing_raised do
24
+ builder = XML::Feed::Builder.rss('2.0', parser)
25
+ end
26
+
27
+ assert_instance_of(XML::Feed::Builder::Rss, builder)
28
+ end
29
+
30
+ def test_output
31
+ builder = nil
32
+
33
+ assert_nothing_raised do
34
+ builder = XML::Feed::Builder.rss("2.0")
35
+ end
36
+
37
+ assert_equal("<?xml version=\"1.0\"?>\n<rss version=\"2.0\"/>\n", builder.to_xml)
38
+
39
+ parser = nil
40
+
41
+ #
42
+ # Tests that the builder and parser interoperate.
43
+ #
44
+
45
+ assert_nothing_raised do
46
+ parser = XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml'), true)
47
+ end
48
+
49
+ assert_nothing_raised do
50
+ builder = XML::Feed::Builder.rss("2.0", parser)
51
+ end
52
+
53
+ assert_equal(parser.doc.to_s, builder.to_xml)
54
+
55
+ #
56
+ # Tests that we can build a basic set of rss data.
57
+ #
58
+
59
+ assert_nothing_raised do
60
+ builder = XML::Feed::Builder.rss("2.0")
61
+ end
62
+
63
+ assert_nothing_raised do
64
+ builder.channel.create do |x|
65
+ x.items.create do |y|
66
+ y.title = "Bar"
67
+ y.description = "Foo"
68
+ y.link = URI.parse("http://funky.cold.medina.com")
69
+ end
70
+ end
71
+ end
72
+
73
+ assert_equal(
74
+ "<?xml version=\"1.0\"?>\n<rss version=\"2.0\">\n <channel>\n <item>\n <title>Bar</title>\n <description>Foo</description>\n <link>http://funky.cold.medina.com</link>\n </item>\n </channel>\n</rss>\n",
75
+ builder.to_xml
76
+ )
77
+
78
+ #
79
+ # Tests that we can create a basic set of RSS data in an item and append it to parsed data.
80
+ #
81
+
82
+ assert_nothing_raised do
83
+ builder = XML::Feed::Builder.rss("2.0", parser)
84
+ end
85
+
86
+ assert_nothing_raised do
87
+ builder.channel[0].items.create do |y|
88
+ y.title = "Bar"
89
+ y.description = "Foo"
90
+ y.link = URI.parse("http://funky.cold.medina.com")
91
+ end
92
+ end
93
+
94
+ assert_equal(File.open("test/data/valid-2.0-rss-build1.xml").read.gsub(/\r/, ''), builder.to_xml)
95
+
96
+ #
97
+ # Tests that we can create elements in an item that have properties.
98
+ #
99
+
100
+ assert_nothing_raised do
101
+ parser = XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml'), true)
102
+ builder = XML::Feed::Builder.rss("2.0", parser)
103
+ end
104
+
105
+ assert_nothing_raised do
106
+ builder.channel[0].items.create do |y|
107
+ y.title = "Bar"
108
+ y.description = "Foo"
109
+ y.link = URI.parse("http://funky.cold.medina.com")
110
+ y.category = "my_category"
111
+ y.category["domain"] = "alt.swedish.chef.bork.bork.bork"
112
+ end
113
+ end
114
+
115
+ assert_equal(File.open("test/data/valid-2.0-rss-build2.xml").read.gsub(/\r/, ''), builder.to_xml)
116
+
117
+ # tests two things:
118
+ # 1) title only returns one object, and therefore isn't boxed
119
+ # 2) tests that we get data that is parsed as well as created
120
+
121
+ assert_kind_of(XML::Node, builder.channel[0].item[0].title)
122
+ assert_equal(builder.channel[0].item[0].title.content, "Seventh Heaven! Ryan Hurls Another No Hitter")
123
+
124
+ assert_kind_of(XML::Node, builder.channel[0].item[-1].title)
125
+ assert_equal(builder.channel[0].item[-1].title.content, "Bar")
126
+ end
127
+ end
@@ -0,0 +1,71 @@
1
+ require 'test/unit'
2
+ require 'xml/libxml/feed'
3
+ require 'stringio'
4
+
5
+ class TestParserInterface < Test::Unit::TestCase
6
+ def test_loader
7
+ parser = nil
8
+ assert_nothing_raised do
9
+ parser = XML::Feed::Parser.rss('2.0', "<rss></rss>", false)
10
+ end
11
+
12
+ assert_instance_of(XML::Feed::Parser::Rss, parser)
13
+ end
14
+
15
+ # tests various forms of IO that can be passed to the constructors for the default parsers
16
+ def test_IO_acceptance
17
+ assert_nothing_raised do
18
+ XML::Feed::Parser.rss('2.0', '<rss></rss>', false)
19
+ end
20
+
21
+ assert_nothing_raised do
22
+ XML::Feed::Parser.rss('2.0', File.open('test/data/basic.xml', 'r'), false)
23
+ end
24
+
25
+ assert_nothing_raised do
26
+ XML::Feed::Parser.rss('2.0', StringIO.new("<rss></rss>"), false)
27
+ end
28
+
29
+ assert_raise(XML::Feed::Parser::InvalidHandle) do
30
+ XML::Feed::Parser.rss('2.0', Array.new, false)
31
+ end
32
+
33
+ assert_raise(XML::Feed::Parser::InvalidHandle) do
34
+ XML::Feed::Parser.rss('2.0', '', false)
35
+ end
36
+ end
37
+
38
+ def test_base_accessors
39
+ parser = nil
40
+
41
+ assert_nothing_raised do
42
+ parser = XML::Feed::Parser.rss('2.0', '<rss></rss>', false)
43
+ end
44
+
45
+ assert_equal('<rss></rss>', parser.xml)
46
+ assert_equal('2.0', parser.version)
47
+
48
+ assert_nothing_raised do
49
+ parser = XML::Feed::Parser.rss('1.0', File.open('test/data/basic.xml', 'r'), false)
50
+ end
51
+
52
+ assert_equal(File.open('test/data/basic.xml').read, parser.xml)
53
+ assert_equal('1.0', parser.version)
54
+
55
+ assert_nothing_raised do
56
+ parser = XML::Feed::Parser.rss('2.0', StringIO.new('<rss></rss>'), false)
57
+ end
58
+
59
+ assert_equal('<rss></rss>', parser.xml)
60
+ assert_equal('2.0', parser.version)
61
+ assert(!parser.validated)
62
+
63
+ assert_nothing_raised do
64
+ parser = XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml', 'r'), true)
65
+ end
66
+
67
+ assert_equal(File.open('test/data/valid-2.0-rss.xml').read, parser.xml)
68
+ assert_equal('2.0', parser.version)
69
+ assert(parser.validated)
70
+ end
71
+ end
@@ -0,0 +1,165 @@
1
+ require 'test/unit'
2
+ require 'xml/libxml/feed'
3
+
4
+ class TestRssParser < Test::Unit::TestCase
5
+
6
+ def test_rss_interface
7
+ parser = nil
8
+
9
+ assert_nothing_raised do
10
+ parser = XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml'), true)
11
+ end
12
+
13
+ assert(parser.channel)
14
+ assert_kind_of(Array, parser.channel)
15
+ assert_kind_of(XML::Feed::Parser::Rss::Channel, parser.channel[0])
16
+
17
+ assert(parser.channel[0].pubDate)
18
+ assert_kind_of(XML::Feed::Parser::Tag, parser.channel[0].pubDate)
19
+ assert_kind_of(Time, parser.channel[0].pubDate.data)
20
+ assert_kind_of(Hash, parser.channel[0].pubDate.property)
21
+
22
+ assert(parser.channel[0].lastBuildDate)
23
+ assert_kind_of(XML::Feed::Parser::Tag, parser.channel[0].lastBuildDate)
24
+ assert_kind_of(Time, parser.channel[0].lastBuildDate.data)
25
+ assert_kind_of(Hash, parser.channel[0].lastBuildDate.property)
26
+
27
+ assert(parser.channel[0].link)
28
+ assert_kind_of(XML::Feed::Parser::Tag, parser.channel[0].link)
29
+ assert_kind_of(URI, parser.channel[0].link.data)
30
+ assert_kind_of(Hash, parser.channel[0].link.property)
31
+
32
+ assert(parser.channel[0].docs)
33
+ assert_kind_of(XML::Feed::Parser::Tag, parser.channel[0].docs)
34
+ assert_kind_of(URI, parser.channel[0].docs.data)
35
+ assert_kind_of(Hash, parser.channel[0].docs.property)
36
+
37
+ assert(parser.channel[0].ttl)
38
+ assert_kind_of(XML::Feed::Parser::Tag, parser.channel[0].ttl)
39
+ assert_kind_of(Numeric, parser.channel[0].ttl.data)
40
+ assert_kind_of(Hash, parser.channel[0].ttl.property)
41
+
42
+ assert(parser.channel[0].item)
43
+ assert_kind_of(Array, parser.channel[0].item)
44
+
45
+ parser.channel[0].item.each do |item|
46
+ assert_kind_of(XML::Feed::Parser::Rss::Item, item)
47
+ if item.link
48
+ assert_kind_of(XML::Feed::Parser::Tag, item.link)
49
+ assert_nothing_raised do
50
+ "string" + item.link
51
+ end
52
+ assert_kind_of(URI, item.link.data)
53
+ assert_kind_of(Hash, item.link.property)
54
+ end
55
+ if item.description
56
+ assert_kind_of(XML::Feed::Parser::Tag, item.description)
57
+ assert_nothing_raised do
58
+ "string" + item.description
59
+ end
60
+ assert_kind_of(String, item.description.data)
61
+ assert_kind_of(Hash, item.description.property)
62
+ end
63
+ if item.title
64
+ assert_kind_of(XML::Feed::Parser::Tag, item.title)
65
+ assert_nothing_raised do
66
+ "string" + item.title
67
+ end
68
+ assert_kind_of(String, item.title.data)
69
+ assert_kind_of(Hash, item.title.property)
70
+ end
71
+ end
72
+ end
73
+
74
+ def test_validate_rss
75
+ assert_raise(XML::Feed::Parser::ValidationError) do
76
+ XML::Feed::Parser.rss('1.0', File.open('test/data/valid-2.0-rss.xml'), true)
77
+ end
78
+ end
79
+
80
+ def test_validate_rss_20
81
+ assert_raise(XML::Feed::Parser::ValidationError) do
82
+ XML::Feed::Parser.rss('2.0', File.open('test/data/basic.xml'), true)
83
+ end
84
+
85
+ # test a valid one first
86
+ assert_nothing_raised do
87
+ XML::Feed::Parser.rss('2.0', File.open('test/data/valid-2.0-rss.xml'), true)
88
+ end
89
+
90
+ # test without the version
91
+ assert_raise(XML::Feed::Parser::ValidationError) do
92
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-root-2.0-rss.xml'), true)
93
+ end
94
+
95
+ # test without the version
96
+ assert_raise(XML::Feed::Parser::ValidationError) do
97
+ XML::Feed::Parser.rss('2.0', File.open('test/data/missing-version-2.0-rss.xml'), true)
98
+ end
99
+
100
+ # invalid version
101
+ assert_raise(XML::Feed::Parser::ValidationError) do
102
+ XML::Feed::Parser.rss('2.0', File.open('test/data/invalid-version-2.0-rss.xml'), true)
103
+ end
104
+
105
+ # missing channel
106
+ assert_raise(XML::Feed::Parser::ValidationError) do
107
+ XML::Feed::Parser.rss('2.0', File.open('test/data/missing-channel-2.0-rss.xml'), true)
108
+ end
109
+
110
+ # missing channel title
111
+ assert_raise(XML::Feed::Parser::ValidationError) do
112
+ XML::Feed::Parser.rss('2.0', File.open('test/data/missing-channel-title-2.0-rss.xml'), true)
113
+ end
114
+
115
+ # missing channel link
116
+ assert_raise(XML::Feed::Parser::ValidationError) do
117
+ XML::Feed::Parser.rss('2.0', File.open('test/data/missing-channel-link-2.0-rss.xml'), true)
118
+ end
119
+
120
+ # missing channel description
121
+ assert_raise(XML::Feed::Parser::ValidationError) do
122
+ XML::Feed::Parser.rss('2.0', File.open('test/data/missing-channel-description-2.0-rss.xml'), true)
123
+ end
124
+
125
+ # duplicate channel title
126
+ assert_raise(XML::Feed::Parser::ValidationError) do
127
+ XML::Feed::Parser.rss('2.0', File.open('test/data/duplicate-channel-title-2.0-rss.xml'), true)
128
+ end
129
+
130
+ # duplicate channel link
131
+ assert_raise(XML::Feed::Parser::ValidationError) do
132
+ XML::Feed::Parser.rss('2.0', File.open('test/data/duplicate-channel-link-2.0-rss.xml'), true)
133
+ end
134
+
135
+ # duplicate channel description
136
+ assert_raise(XML::Feed::Parser::ValidationError) do
137
+ XML::Feed::Parser.rss('2.0', File.open('test/data/duplicate-channel-description-2.0-rss.xml'), true)
138
+ end
139
+
140
+ # bad URI
141
+ assert_raise(XML::Feed::Parser::ValidationError) do
142
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-uri-2.0-rss.xml'), true)
143
+ end
144
+
145
+ # bad pubDate
146
+ assert_raise(XML::Feed::Parser::ValidationError) do
147
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-pubdate-2.0-rss.xml'), true)
148
+ end
149
+
150
+ # bad ttl
151
+ assert_raise(XML::Feed::Parser::ValidationError) do
152
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-ttl-2.0-rss.xml'), true)
153
+ end
154
+
155
+ # bad image
156
+ assert_raise(XML::Feed::Parser::ValidationError) do
157
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-image-2.0-rss.xml'), true)
158
+ end
159
+
160
+ # bad item
161
+ assert_raise(XML::Feed::Parser::ValidationError) do
162
+ XML::Feed::Parser.rss('2.0', File.open('test/data/bad-item-2.0-rss.xml'), true)
163
+ end
164
+ end
165
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
4
+ name: libxml-feed
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.0.1
7
+ date: 2008-01-05 00:00:00 -08:00
8
+ summary: Provides a alternative and faster feed (RSS, Atom, et al) parsing layer through libxml's parsing framework
9
+ require_paths:
10
+ - lib
11
+ email: erik@hollensbe.org
12
+ homepage:
13
+ rubyforge_project: libxml-tools
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Erik Hollensbe
31
+ files:
32
+ - lib/xml
33
+ - lib/xml/libxml
34
+ - lib/xml/libxml/feed
35
+ - lib/xml/libxml/feed/builder.rb
36
+ - lib/xml/libxml/feed/builders
37
+ - lib/xml/libxml/feed/builders/rss.rb
38
+ - lib/xml/libxml/feed/parser.rb
39
+ - lib/xml/libxml/feed/parsers
40
+ - lib/xml/libxml/feed/parsers/rss
41
+ - lib/xml/libxml/feed/parsers/rss/channel.rb
42
+ - lib/xml/libxml/feed/parsers/rss/common.rb
43
+ - lib/xml/libxml/feed/parsers/rss/item.rb
44
+ - lib/xml/libxml/feed/parsers/rss.rb
45
+ - lib/xml/libxml/feed.rb
46
+ - test/data
47
+ - test/test_builder_interface.rb
48
+ - test/test_parser_interface.rb
49
+ - test/test_rss_parser.rb
50
+ test_files: []
51
+
52
+ rdoc_options: []
53
+
54
+ extra_rdoc_files: []
55
+
56
+ executables: []
57
+
58
+ extensions: []
59
+
60
+ requirements: []
61
+
62
+ dependencies:
63
+ - !ruby/object:Gem::Dependency
64
+ name: libxml-ruby
65
+ version_requirement:
66
+ version_requirements: !ruby/object:Gem::Version::Requirement
67
+ requirements:
68
+ - - ">"
69
+ - !ruby/object:Gem::Version
70
+ version: 0.0.0
71
+ version: