libxml-feed 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: