rubysl-rss 1.0.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 +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rss.rb +1 -0
- data/lib/rss/0.9.rb +428 -0
- data/lib/rss/1.0.rb +452 -0
- data/lib/rss/2.0.rb +111 -0
- data/lib/rss/atom.rb +749 -0
- data/lib/rss/content.rb +31 -0
- data/lib/rss/content/1.0.rb +10 -0
- data/lib/rss/content/2.0.rb +12 -0
- data/lib/rss/converter.rb +162 -0
- data/lib/rss/dublincore.rb +161 -0
- data/lib/rss/dublincore/1.0.rb +13 -0
- data/lib/rss/dublincore/2.0.rb +13 -0
- data/lib/rss/dublincore/atom.rb +17 -0
- data/lib/rss/image.rb +193 -0
- data/lib/rss/itunes.rb +410 -0
- data/lib/rss/maker.rb +44 -0
- data/lib/rss/maker/0.9.rb +467 -0
- data/lib/rss/maker/1.0.rb +434 -0
- data/lib/rss/maker/2.0.rb +223 -0
- data/lib/rss/maker/atom.rb +172 -0
- data/lib/rss/maker/base.rb +868 -0
- data/lib/rss/maker/content.rb +21 -0
- data/lib/rss/maker/dublincore.rb +124 -0
- data/lib/rss/maker/entry.rb +163 -0
- data/lib/rss/maker/feed.rb +429 -0
- data/lib/rss/maker/image.rb +111 -0
- data/lib/rss/maker/itunes.rb +242 -0
- data/lib/rss/maker/slash.rb +33 -0
- data/lib/rss/maker/syndication.rb +18 -0
- data/lib/rss/maker/taxonomy.rb +118 -0
- data/lib/rss/maker/trackback.rb +61 -0
- data/lib/rss/parser.rb +541 -0
- data/lib/rss/rexmlparser.rb +54 -0
- data/lib/rss/rss.rb +1312 -0
- data/lib/rss/slash.rb +49 -0
- data/lib/rss/syndication.rb +67 -0
- data/lib/rss/taxonomy.rb +145 -0
- data/lib/rss/trackback.rb +288 -0
- data/lib/rss/utils.rb +111 -0
- data/lib/rss/xml-stylesheet.rb +105 -0
- data/lib/rss/xml.rb +71 -0
- data/lib/rss/xmlparser.rb +93 -0
- data/lib/rss/xmlscanner.rb +121 -0
- data/lib/rubysl/rss.rb +2 -0
- data/lib/rubysl/rss/rss.rb +19 -0
- data/lib/rubysl/rss/version.rb +5 -0
- data/rubysl-rss.gemspec +23 -0
- metadata +153 -0
data/lib/rss/utils.rb
ADDED
@@ -0,0 +1,111 @@
|
|
1
|
+
module RSS
|
2
|
+
module Utils
|
3
|
+
module_function
|
4
|
+
|
5
|
+
# Convert a name_with_underscores to CamelCase.
|
6
|
+
def to_class_name(name)
|
7
|
+
name.split(/[_\-]/).collect do |part|
|
8
|
+
"#{part[0, 1].upcase}#{part[1..-1]}"
|
9
|
+
end.join("")
|
10
|
+
end
|
11
|
+
|
12
|
+
def get_file_and_line_from_caller(i=0)
|
13
|
+
file, line, = caller[i].split(':')
|
14
|
+
line = line.to_i
|
15
|
+
line += 1 if i.zero?
|
16
|
+
[file, line]
|
17
|
+
end
|
18
|
+
|
19
|
+
# escape '&', '"', '<' and '>' for use in HTML.
|
20
|
+
def html_escape(s)
|
21
|
+
s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
22
|
+
end
|
23
|
+
alias h html_escape
|
24
|
+
|
25
|
+
# If +value+ is an instance of class +klass+, return it, else
|
26
|
+
# create a new instance of +klass+ with value +value+.
|
27
|
+
def new_with_value_if_need(klass, value)
|
28
|
+
if value.is_a?(klass)
|
29
|
+
value
|
30
|
+
else
|
31
|
+
klass.new(value)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def element_initialize_arguments?(args)
|
36
|
+
[true, false].include?(args[0]) and args[1].is_a?(Hash)
|
37
|
+
end
|
38
|
+
|
39
|
+
module YesCleanOther
|
40
|
+
module_function
|
41
|
+
def parse(value)
|
42
|
+
if [true, false, nil].include?(value)
|
43
|
+
value
|
44
|
+
else
|
45
|
+
case value.to_s
|
46
|
+
when /\Ayes\z/i
|
47
|
+
true
|
48
|
+
when /\Aclean\z/i
|
49
|
+
false
|
50
|
+
else
|
51
|
+
nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
module YesOther
|
58
|
+
module_function
|
59
|
+
def parse(value)
|
60
|
+
if [true, false].include?(value)
|
61
|
+
value
|
62
|
+
else
|
63
|
+
/\Ayes\z/i.match(value.to_s) ? true : false
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module CSV
|
69
|
+
module_function
|
70
|
+
def parse(value, &block)
|
71
|
+
if value.is_a?(String)
|
72
|
+
value = value.strip.split(/\s*,\s*/)
|
73
|
+
value = value.collect(&block) if block_given?
|
74
|
+
value
|
75
|
+
else
|
76
|
+
value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
module InheritedReader
|
82
|
+
def inherited_reader(constant_name)
|
83
|
+
base_class = inherited_base
|
84
|
+
result = base_class.const_get(constant_name)
|
85
|
+
found_base_class = false
|
86
|
+
ancestors.reverse_each do |klass|
|
87
|
+
if found_base_class
|
88
|
+
if klass.const_defined?(constant_name)
|
89
|
+
result = yield(result, klass.const_get(constant_name))
|
90
|
+
end
|
91
|
+
else
|
92
|
+
found_base_class = klass == base_class
|
93
|
+
end
|
94
|
+
end
|
95
|
+
result
|
96
|
+
end
|
97
|
+
|
98
|
+
def inherited_array_reader(constant_name)
|
99
|
+
inherited_reader(constant_name) do |result, current|
|
100
|
+
current + result
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def inherited_hash_reader(constant_name)
|
105
|
+
inherited_reader(constant_name) do |result, current|
|
106
|
+
result.merge(current)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "rss/utils"
|
2
|
+
|
3
|
+
module RSS
|
4
|
+
|
5
|
+
module XMLStyleSheetMixin
|
6
|
+
attr_accessor :xml_stylesheets
|
7
|
+
def initialize(*args)
|
8
|
+
super
|
9
|
+
@xml_stylesheets = []
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
def xml_stylesheet_pi
|
14
|
+
xsss = @xml_stylesheets.collect do |xss|
|
15
|
+
pi = xss.to_s
|
16
|
+
pi = nil if /\A\s*\z/ =~ pi
|
17
|
+
pi
|
18
|
+
end.compact
|
19
|
+
xsss.push("") unless xsss.empty?
|
20
|
+
xsss.join("\n")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class XMLStyleSheet
|
25
|
+
|
26
|
+
include Utils
|
27
|
+
|
28
|
+
ATTRIBUTES = %w(href type title media charset alternate)
|
29
|
+
|
30
|
+
GUESS_TABLE = {
|
31
|
+
"xsl" => "text/xsl",
|
32
|
+
"css" => "text/css",
|
33
|
+
}
|
34
|
+
|
35
|
+
attr_accessor(*ATTRIBUTES)
|
36
|
+
attr_accessor(:do_validate)
|
37
|
+
def initialize(*attrs)
|
38
|
+
if attrs.size == 1 and
|
39
|
+
(attrs.first.is_a?(Hash) or attrs.first.is_a?(Array))
|
40
|
+
attrs = attrs.first
|
41
|
+
end
|
42
|
+
@do_validate = true
|
43
|
+
ATTRIBUTES.each do |attr|
|
44
|
+
__send__("#{attr}=", nil)
|
45
|
+
end
|
46
|
+
vars = ATTRIBUTES.dup
|
47
|
+
vars.unshift(:do_validate)
|
48
|
+
attrs.each do |name, value|
|
49
|
+
if vars.include?(name.to_s)
|
50
|
+
__send__("#{name}=", value)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_s
|
56
|
+
rv = ""
|
57
|
+
if @href
|
58
|
+
rv << %Q[<?xml-stylesheet]
|
59
|
+
ATTRIBUTES.each do |name|
|
60
|
+
if __send__(name)
|
61
|
+
rv << %Q[ #{name}="#{h __send__(name)}"]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
rv << %Q[?>]
|
65
|
+
end
|
66
|
+
rv
|
67
|
+
end
|
68
|
+
|
69
|
+
remove_method(:href=)
|
70
|
+
def href=(value)
|
71
|
+
@href = value
|
72
|
+
if @href and @type.nil?
|
73
|
+
@type = guess_type(@href)
|
74
|
+
end
|
75
|
+
@href
|
76
|
+
end
|
77
|
+
|
78
|
+
remove_method(:alternate=)
|
79
|
+
def alternate=(value)
|
80
|
+
if value.nil? or /\A(?:yes|no)\z/ =~ value
|
81
|
+
@alternate = value
|
82
|
+
else
|
83
|
+
if @do_validate
|
84
|
+
args = ["?xml-stylesheet?", %Q[alternate="#{value}"]]
|
85
|
+
raise NotAvailableValueError.new(*args)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
@alternate
|
89
|
+
end
|
90
|
+
|
91
|
+
def setup_maker(maker)
|
92
|
+
xss = maker.xml_stylesheets.new_xml_stylesheet
|
93
|
+
ATTRIBUTES.each do |attr|
|
94
|
+
xss.__send__("#{attr}=", __send__(attr))
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
def guess_type(filename)
|
100
|
+
/\.([^.]+)$/ =~ filename
|
101
|
+
GUESS_TABLE[$1]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
data/lib/rss/xml.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require "rss/utils"
|
2
|
+
|
3
|
+
module RSS
|
4
|
+
module XML
|
5
|
+
class Element
|
6
|
+
include Enumerable
|
7
|
+
|
8
|
+
attr_reader :name, :prefix, :uri, :attributes, :children
|
9
|
+
def initialize(name, prefix=nil, uri=nil, attributes={}, children=[])
|
10
|
+
@name = name
|
11
|
+
@prefix = prefix
|
12
|
+
@uri = uri
|
13
|
+
@attributes = attributes
|
14
|
+
if children.is_a?(String) or !children.respond_to?(:each)
|
15
|
+
@children = [children]
|
16
|
+
else
|
17
|
+
@children = children
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def [](name)
|
22
|
+
@attributes[name]
|
23
|
+
end
|
24
|
+
|
25
|
+
def []=(name, value)
|
26
|
+
@attributes[name] = value
|
27
|
+
end
|
28
|
+
|
29
|
+
def <<(child)
|
30
|
+
@children << child
|
31
|
+
end
|
32
|
+
|
33
|
+
def each(&block)
|
34
|
+
@children.each(&block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(other)
|
38
|
+
other.kind_of?(self.class) and
|
39
|
+
@name == other.name and
|
40
|
+
@uri == other.uri and
|
41
|
+
@attributes == other.attributes and
|
42
|
+
@children == other.children
|
43
|
+
end
|
44
|
+
|
45
|
+
def to_s
|
46
|
+
rv = "<#{full_name}"
|
47
|
+
attributes.each do |key, value|
|
48
|
+
rv << " #{Utils.html_escape(key)}=\"#{Utils.html_escape(value)}\""
|
49
|
+
end
|
50
|
+
if children.empty?
|
51
|
+
rv << "/>"
|
52
|
+
else
|
53
|
+
rv << ">"
|
54
|
+
children.each do |child|
|
55
|
+
rv << child.to_s
|
56
|
+
end
|
57
|
+
rv << "</#{full_name}>"
|
58
|
+
end
|
59
|
+
rv
|
60
|
+
end
|
61
|
+
|
62
|
+
def full_name
|
63
|
+
if @prefix
|
64
|
+
"#{@prefix}:#{@name}"
|
65
|
+
else
|
66
|
+
@name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
begin
|
2
|
+
require "xml/parser"
|
3
|
+
rescue LoadError
|
4
|
+
require "xmlparser"
|
5
|
+
end
|
6
|
+
|
7
|
+
begin
|
8
|
+
require "xml/encoding-ja"
|
9
|
+
rescue LoadError
|
10
|
+
require "xmlencoding-ja"
|
11
|
+
if defined?(Kconv)
|
12
|
+
module XMLEncoding_ja
|
13
|
+
class SJISHandler
|
14
|
+
include Kconv
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
module XML
|
21
|
+
class Parser
|
22
|
+
unless defined?(Error)
|
23
|
+
Error = ::XMLParserError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module RSS
|
29
|
+
|
30
|
+
class REXMLLikeXMLParser < ::XML::Parser
|
31
|
+
|
32
|
+
include ::XML::Encoding_ja
|
33
|
+
|
34
|
+
def listener=(listener)
|
35
|
+
@listener = listener
|
36
|
+
end
|
37
|
+
|
38
|
+
def startElement(name, attrs)
|
39
|
+
@listener.tag_start(name, attrs)
|
40
|
+
end
|
41
|
+
|
42
|
+
def endElement(name)
|
43
|
+
@listener.tag_end(name)
|
44
|
+
end
|
45
|
+
|
46
|
+
def character(data)
|
47
|
+
@listener.text(data)
|
48
|
+
end
|
49
|
+
|
50
|
+
def xmlDecl(version, encoding, standalone)
|
51
|
+
@listener.xmldecl(version, encoding, standalone == 1)
|
52
|
+
end
|
53
|
+
|
54
|
+
def processingInstruction(target, content)
|
55
|
+
@listener.instruction(target, content)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
class XMLParserParser < BaseParser
|
61
|
+
|
62
|
+
class << self
|
63
|
+
def listener
|
64
|
+
XMLParserListener
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
private
|
69
|
+
def _parse
|
70
|
+
begin
|
71
|
+
parser = REXMLLikeXMLParser.new
|
72
|
+
parser.listener = @listener
|
73
|
+
parser.parse(@rss)
|
74
|
+
rescue ::XML::Parser::Error => e
|
75
|
+
raise NotWellFormedError.new(parser.line){e.message}
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
class XMLParserListener < BaseListener
|
82
|
+
|
83
|
+
include ListenerMixin
|
84
|
+
|
85
|
+
def xmldecl(version, encoding, standalone)
|
86
|
+
super
|
87
|
+
# Encoding is converted to UTF-8 when XMLParser parses XML.
|
88
|
+
@encoding = 'UTF-8'
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'xmlscan/scanner'
|
2
|
+
require 'stringio'
|
3
|
+
|
4
|
+
module RSS
|
5
|
+
|
6
|
+
class XMLScanParser < BaseParser
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def listener
|
10
|
+
XMLScanListener
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
def _parse
|
16
|
+
begin
|
17
|
+
if @rss.is_a?(String)
|
18
|
+
input = StringIO.new(@rss)
|
19
|
+
else
|
20
|
+
input = @rss
|
21
|
+
end
|
22
|
+
scanner = XMLScan::XMLScanner.new(@listener)
|
23
|
+
scanner.parse(input)
|
24
|
+
rescue XMLScan::Error => e
|
25
|
+
lineno = e.lineno || scanner.lineno || input.lineno
|
26
|
+
raise NotWellFormedError.new(lineno){e.message}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class XMLScanListener < BaseListener
|
33
|
+
|
34
|
+
include XMLScan::Visitor
|
35
|
+
include ListenerMixin
|
36
|
+
|
37
|
+
ENTITIES = {
|
38
|
+
'lt' => '<',
|
39
|
+
'gt' => '>',
|
40
|
+
'amp' => '&',
|
41
|
+
'quot' => '"',
|
42
|
+
'apos' => '\''
|
43
|
+
}
|
44
|
+
|
45
|
+
def on_xmldecl_version(str)
|
46
|
+
@version = str
|
47
|
+
end
|
48
|
+
|
49
|
+
def on_xmldecl_encoding(str)
|
50
|
+
@encoding = str
|
51
|
+
end
|
52
|
+
|
53
|
+
def on_xmldecl_standalone(str)
|
54
|
+
@standalone = str
|
55
|
+
end
|
56
|
+
|
57
|
+
def on_xmldecl_end
|
58
|
+
xmldecl(@version, @encoding, @standalone == "yes")
|
59
|
+
end
|
60
|
+
|
61
|
+
alias_method(:on_pi, :instruction)
|
62
|
+
alias_method(:on_chardata, :text)
|
63
|
+
alias_method(:on_cdata, :text)
|
64
|
+
|
65
|
+
def on_etag(name)
|
66
|
+
tag_end(name)
|
67
|
+
end
|
68
|
+
|
69
|
+
def on_entityref(ref)
|
70
|
+
text(entity(ref))
|
71
|
+
end
|
72
|
+
|
73
|
+
def on_charref(code)
|
74
|
+
text([code].pack('U'))
|
75
|
+
end
|
76
|
+
|
77
|
+
alias_method(:on_charref_hex, :on_charref)
|
78
|
+
|
79
|
+
def on_stag(name)
|
80
|
+
@attrs = {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def on_attribute(name)
|
84
|
+
@attrs[name] = @current_attr = ''
|
85
|
+
end
|
86
|
+
|
87
|
+
def on_attr_value(str)
|
88
|
+
@current_attr << str
|
89
|
+
end
|
90
|
+
|
91
|
+
def on_attr_entityref(ref)
|
92
|
+
@current_attr << entity(ref)
|
93
|
+
end
|
94
|
+
|
95
|
+
def on_attr_charref(code)
|
96
|
+
@current_attr << [code].pack('U')
|
97
|
+
end
|
98
|
+
|
99
|
+
alias_method(:on_attr_charref_hex, :on_attr_charref)
|
100
|
+
|
101
|
+
def on_stag_end(name)
|
102
|
+
tag_start(name, @attrs)
|
103
|
+
end
|
104
|
+
|
105
|
+
def on_stag_end_empty(name)
|
106
|
+
tag_start(name, @attrs)
|
107
|
+
tag_end(name)
|
108
|
+
end
|
109
|
+
|
110
|
+
private
|
111
|
+
def entity(ref)
|
112
|
+
ent = ENTITIES[ref]
|
113
|
+
if ent
|
114
|
+
ent
|
115
|
+
else
|
116
|
+
wellformed_error("undefined entity: #{ref}")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|