rss 0.2.7

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.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.travis.yml +6 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +88 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/lib/rss.rb +92 -0
  11. data/lib/rss/0.9.rb +462 -0
  12. data/lib/rss/1.0.rb +485 -0
  13. data/lib/rss/2.0.rb +143 -0
  14. data/lib/rss/atom.rb +1025 -0
  15. data/lib/rss/content.rb +34 -0
  16. data/lib/rss/content/1.0.rb +10 -0
  17. data/lib/rss/content/2.0.rb +12 -0
  18. data/lib/rss/converter.rb +171 -0
  19. data/lib/rss/dublincore.rb +164 -0
  20. data/lib/rss/dublincore/1.0.rb +13 -0
  21. data/lib/rss/dublincore/2.0.rb +13 -0
  22. data/lib/rss/dublincore/atom.rb +17 -0
  23. data/lib/rss/image.rb +198 -0
  24. data/lib/rss/itunes.rb +413 -0
  25. data/lib/rss/maker.rb +79 -0
  26. data/lib/rss/maker/0.9.rb +509 -0
  27. data/lib/rss/maker/1.0.rb +436 -0
  28. data/lib/rss/maker/2.0.rb +224 -0
  29. data/lib/rss/maker/atom.rb +173 -0
  30. data/lib/rss/maker/base.rb +945 -0
  31. data/lib/rss/maker/content.rb +22 -0
  32. data/lib/rss/maker/dublincore.rb +122 -0
  33. data/lib/rss/maker/entry.rb +164 -0
  34. data/lib/rss/maker/feed.rb +427 -0
  35. data/lib/rss/maker/image.rb +112 -0
  36. data/lib/rss/maker/itunes.rb +243 -0
  37. data/lib/rss/maker/slash.rb +34 -0
  38. data/lib/rss/maker/syndication.rb +19 -0
  39. data/lib/rss/maker/taxonomy.rb +119 -0
  40. data/lib/rss/maker/trackback.rb +62 -0
  41. data/lib/rss/parser.rb +589 -0
  42. data/lib/rss/rexmlparser.rb +50 -0
  43. data/lib/rss/rss.rb +1346 -0
  44. data/lib/rss/slash.rb +52 -0
  45. data/lib/rss/syndication.rb +69 -0
  46. data/lib/rss/taxonomy.rb +148 -0
  47. data/lib/rss/trackback.rb +291 -0
  48. data/lib/rss/utils.rb +200 -0
  49. data/lib/rss/xml-stylesheet.rb +106 -0
  50. data/lib/rss/xml.rb +72 -0
  51. data/lib/rss/xmlparser.rb +95 -0
  52. data/lib/rss/xmlscanner.rb +122 -0
  53. data/rss.gemspec +38 -0
  54. metadata +138 -0
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: false
2
+ module RSS
3
+
4
+ ##
5
+ # RSS::Utils is a module that holds various utility functions that are used
6
+ # across many parts of the rest of the RSS library. Like most modules named
7
+ # some variant of 'util', its methods are probably not particularly useful
8
+ # to those who aren't developing the library itself.
9
+ module Utils
10
+ module_function
11
+
12
+ # Given a +name+ in a name_with_underscores or a name-with-dashes format,
13
+ # returns the CamelCase version of +name+.
14
+ #
15
+ # If the +name+ is already CamelCased, nothing happens.
16
+ #
17
+ # Examples:
18
+ #
19
+ # require 'rss/utils'
20
+ #
21
+ # RSS::Utils.to_class_name("sample_name")
22
+ # # => "SampleName"
23
+ # RSS::Utils.to_class_name("with-dashes")
24
+ # # => "WithDashes"
25
+ # RSS::Utils.to_class_name("CamelCase")
26
+ # # => "CamelCase"
27
+ def to_class_name(name)
28
+ name.split(/[_\-]/).collect do |part|
29
+ "#{part[0, 1].upcase}#{part[1..-1]}"
30
+ end.join("")
31
+ end
32
+
33
+ # Returns an array of two elements: the filename where the calling method
34
+ # is located, and the line number where it is defined.
35
+ #
36
+ # Takes an optional argument +i+, which specifies how many callers up the
37
+ # stack to look.
38
+ #
39
+ # Examples:
40
+ #
41
+ # require 'rss/utils'
42
+ #
43
+ # def foo
44
+ # p RSS::Utils.get_file_and_line_from_caller
45
+ # p RSS::Utils.get_file_and_line_from_caller(1)
46
+ # end
47
+ #
48
+ # def bar
49
+ # foo
50
+ # end
51
+ #
52
+ # def baz
53
+ # bar
54
+ # end
55
+ #
56
+ # baz
57
+ # # => ["test.rb", 5]
58
+ # # => ["test.rb", 9]
59
+ #
60
+ # If +i+ is not given, or is the default value of 0, it attempts to figure
61
+ # out the correct value. This is useful when in combination with
62
+ # instance_eval. For example:
63
+ #
64
+ # require 'rss/utils'
65
+ #
66
+ # def foo
67
+ # p RSS::Utils.get_file_and_line_from_caller(1)
68
+ # end
69
+ #
70
+ # def bar
71
+ # foo
72
+ # end
73
+ #
74
+ # instance_eval <<-RUBY, *RSS::Utils.get_file_and_line_from_caller
75
+ # def baz
76
+ # bar
77
+ # end
78
+ # RUBY
79
+ #
80
+ # baz
81
+ #
82
+ # # => ["test.rb", 8]
83
+ def get_file_and_line_from_caller(i=0)
84
+ file, line, = caller[i].split(':')
85
+ line = line.to_i
86
+ line += 1 if i.zero?
87
+ [file, line]
88
+ end
89
+
90
+ # Takes a string +s+ with some HTML in it, and escapes '&', '"', '<' and '>', by
91
+ # replacing them with the appropriate entities.
92
+ #
93
+ # This method is also aliased to h, for convenience.
94
+ #
95
+ # Examples:
96
+ #
97
+ # require 'rss/utils'
98
+ #
99
+ # RSS::Utils.html_escape("Dungeons & Dragons")
100
+ # # => "Dungeons &amp; Dragons"
101
+ # RSS::Utils.h(">_>")
102
+ # # => "&gt;_&gt;"
103
+ def html_escape(s)
104
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
105
+ end
106
+ alias h html_escape
107
+
108
+ # If +value+ is an instance of class +klass+, return it, else
109
+ # create a new instance of +klass+ with value +value+.
110
+ def new_with_value_if_need(klass, value)
111
+ if value.is_a?(klass)
112
+ value
113
+ else
114
+ klass.new(value)
115
+ end
116
+ end
117
+
118
+ # This method is used inside of several different objects to determine
119
+ # if special behavior is needed in the constructor.
120
+ #
121
+ # Special behavior is needed if the array passed in as +args+ has
122
+ # +true+ or +false+ as its value, and if the second element of +args+
123
+ # is a hash.
124
+ def element_initialize_arguments?(args)
125
+ [true, false].include?(args[0]) and args[1].is_a?(Hash)
126
+ end
127
+
128
+ module ExplicitCleanOther
129
+ module_function
130
+ def parse(value)
131
+ if [true, false, nil].include?(value)
132
+ value
133
+ else
134
+ case value.to_s
135
+ when /\Aexplicit|yes|true\z/i
136
+ true
137
+ when /\Aclean|no|false\z/i
138
+ false
139
+ else
140
+ nil
141
+ end
142
+ end
143
+ end
144
+ end
145
+
146
+ module YesOther
147
+ module_function
148
+ def parse(value)
149
+ if [true, false].include?(value)
150
+ value
151
+ else
152
+ /\Ayes\z/i.match(value.to_s) ? true : false
153
+ end
154
+ end
155
+ end
156
+
157
+ module CSV
158
+ module_function
159
+ def parse(value, &block)
160
+ if value.is_a?(String)
161
+ value = value.strip.split(/\s*,\s*/)
162
+ value = value.collect(&block) if block_given?
163
+ value
164
+ else
165
+ value
166
+ end
167
+ end
168
+ end
169
+
170
+ module InheritedReader
171
+ def inherited_reader(constant_name)
172
+ base_class = inherited_base
173
+ result = base_class.const_get(constant_name)
174
+ found_base_class = false
175
+ ancestors.reverse_each do |klass|
176
+ if found_base_class
177
+ if klass.const_defined?(constant_name)
178
+ result = yield(result, klass.const_get(constant_name))
179
+ end
180
+ else
181
+ found_base_class = klass == base_class
182
+ end
183
+ end
184
+ result
185
+ end
186
+
187
+ def inherited_array_reader(constant_name)
188
+ inherited_reader(constant_name) do |result, current|
189
+ current + result
190
+ end
191
+ end
192
+
193
+ def inherited_hash_reader(constant_name)
194
+ inherited_reader(constant_name) do |result, current|
195
+ result.merge(current)
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: false
2
+ require_relative "utils"
3
+
4
+ module RSS
5
+
6
+ module XMLStyleSheetMixin
7
+ attr_accessor :xml_stylesheets
8
+ def initialize(*args)
9
+ super
10
+ @xml_stylesheets = []
11
+ end
12
+
13
+ private
14
+ def xml_stylesheet_pi
15
+ xsss = @xml_stylesheets.collect do |xss|
16
+ pi = xss.to_s
17
+ pi = nil if /\A\s*\z/ =~ pi
18
+ pi
19
+ end.compact
20
+ xsss.push("") unless xsss.empty?
21
+ xsss.join("\n")
22
+ end
23
+ end
24
+
25
+ class XMLStyleSheet
26
+
27
+ include Utils
28
+
29
+ ATTRIBUTES = %w(href type title media charset alternate)
30
+
31
+ GUESS_TABLE = {
32
+ "xsl" => "text/xsl",
33
+ "css" => "text/css",
34
+ }
35
+
36
+ attr_accessor(*ATTRIBUTES)
37
+ attr_accessor(:do_validate)
38
+ def initialize(*attrs)
39
+ if attrs.size == 1 and
40
+ (attrs.first.is_a?(Hash) or attrs.first.is_a?(Array))
41
+ attrs = attrs.first
42
+ end
43
+ @do_validate = true
44
+ ATTRIBUTES.each do |attr|
45
+ __send__("#{attr}=", nil)
46
+ end
47
+ vars = ATTRIBUTES.dup
48
+ vars.unshift(:do_validate)
49
+ attrs.each do |name, value|
50
+ if vars.include?(name.to_s)
51
+ __send__("#{name}=", value)
52
+ end
53
+ end
54
+ end
55
+
56
+ def to_s
57
+ rv = ""
58
+ if @href
59
+ rv << %Q[<?xml-stylesheet]
60
+ ATTRIBUTES.each do |name|
61
+ if __send__(name)
62
+ rv << %Q[ #{name}="#{h __send__(name)}"]
63
+ end
64
+ end
65
+ rv << %Q[?>]
66
+ end
67
+ rv
68
+ end
69
+
70
+ remove_method(:href=)
71
+ def href=(value)
72
+ @href = value
73
+ if @href and @type.nil?
74
+ @type = guess_type(@href)
75
+ end
76
+ @href
77
+ end
78
+
79
+ remove_method(:alternate=)
80
+ def alternate=(value)
81
+ if value.nil? or /\A(?:yes|no)\z/ =~ value
82
+ @alternate = value
83
+ else
84
+ if @do_validate
85
+ args = ["?xml-stylesheet?", %Q[alternate="#{value}"]]
86
+ raise NotAvailableValueError.new(*args)
87
+ end
88
+ end
89
+ @alternate
90
+ end
91
+
92
+ def setup_maker(maker)
93
+ xss = maker.xml_stylesheets.new_xml_stylesheet
94
+ ATTRIBUTES.each do |attr|
95
+ xss.__send__("#{attr}=", __send__(attr))
96
+ end
97
+ end
98
+
99
+ private
100
+ def guess_type(filename)
101
+ /\.([^.]+)$/ =~ filename
102
+ GUESS_TABLE[$1]
103
+ end
104
+
105
+ end
106
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: false
2
+ require_relative "utils"
3
+
4
+ module RSS
5
+ module XML
6
+ class Element
7
+ include Enumerable
8
+
9
+ attr_reader :name, :prefix, :uri, :attributes, :children
10
+ def initialize(name, prefix=nil, uri=nil, attributes={}, children=[])
11
+ @name = name
12
+ @prefix = prefix
13
+ @uri = uri
14
+ @attributes = attributes
15
+ if children.is_a?(String) or !children.respond_to?(:each)
16
+ @children = [children]
17
+ else
18
+ @children = children
19
+ end
20
+ end
21
+
22
+ def [](name)
23
+ @attributes[name]
24
+ end
25
+
26
+ def []=(name, value)
27
+ @attributes[name] = value
28
+ end
29
+
30
+ def <<(child)
31
+ @children << child
32
+ end
33
+
34
+ def each(&block)
35
+ @children.each(&block)
36
+ end
37
+
38
+ def ==(other)
39
+ other.kind_of?(self.class) and
40
+ @name == other.name and
41
+ @uri == other.uri and
42
+ @attributes == other.attributes and
43
+ @children == other.children
44
+ end
45
+
46
+ def to_s
47
+ rv = "<#{full_name}"
48
+ attributes.each do |key, value|
49
+ rv << " #{Utils.html_escape(key)}=\"#{Utils.html_escape(value)}\""
50
+ end
51
+ if children.empty?
52
+ rv << "/>"
53
+ else
54
+ rv << ">"
55
+ children.each do |child|
56
+ rv << child.to_s
57
+ end
58
+ rv << "</#{full_name}>"
59
+ end
60
+ rv
61
+ end
62
+
63
+ def full_name
64
+ if @prefix
65
+ "#{@prefix}:#{@name}"
66
+ else
67
+ @name
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: false
2
+ begin
3
+ require "xml/parser"
4
+ rescue LoadError
5
+ require "xmlparser"
6
+ end
7
+
8
+ begin
9
+ require "xml/encoding-ja"
10
+ rescue LoadError
11
+ require "xmlencoding-ja"
12
+ if defined?(Kconv)
13
+ module XMLEncoding_ja
14
+ class SJISHandler
15
+ include Kconv
16
+ end
17
+ end
18
+ end
19
+ end
20
+
21
+ module XML
22
+ class Parser
23
+ unless defined?(Error)
24
+ # This error is legacy, so we just set it to the new one
25
+ Error = ::XMLParserError # :nodoc:
26
+ end
27
+ end
28
+ end
29
+
30
+ module RSS
31
+
32
+ class REXMLLikeXMLParser < ::XML::Parser
33
+
34
+ include ::XML::Encoding_ja
35
+
36
+ def listener=(listener)
37
+ @listener = listener
38
+ end
39
+
40
+ def startElement(name, attrs)
41
+ @listener.tag_start(name, attrs)
42
+ end
43
+
44
+ def endElement(name)
45
+ @listener.tag_end(name)
46
+ end
47
+
48
+ def character(data)
49
+ @listener.text(data)
50
+ end
51
+
52
+ def xmlDecl(version, encoding, standalone)
53
+ @listener.xmldecl(version, encoding, standalone == 1)
54
+ end
55
+
56
+ def processingInstruction(target, content)
57
+ @listener.instruction(target, content)
58
+ end
59
+
60
+ end
61
+
62
+ class XMLParserParser < BaseParser
63
+
64
+ class << self
65
+ def listener
66
+ XMLParserListener
67
+ end
68
+ end
69
+
70
+ private
71
+ def _parse
72
+ begin
73
+ parser = REXMLLikeXMLParser.new
74
+ parser.listener = @listener
75
+ parser.parse(@rss)
76
+ rescue ::XML::Parser::Error => e
77
+ raise NotWellFormedError.new(parser.line){e.message}
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ class XMLParserListener < BaseListener
84
+
85
+ include ListenerMixin
86
+
87
+ def xmldecl(version, encoding, standalone)
88
+ super
89
+ # Encoding is converted to UTF-8 when XMLParser parses XML.
90
+ @encoding = 'UTF-8'
91
+ end
92
+
93
+ end
94
+
95
+ end