summaryrefslogtreecommitdiff
path: root/lib/rss
diff options
context:
space:
mode:
Diffstat (limited to 'lib/rss')
-rw-r--r--lib/rss/0.9.rb74
-rw-r--r--lib/rss/1.0.rb81
-rw-r--r--lib/rss/2.0.rb38
-rw-r--r--lib/rss/atom.rb284
-rw-r--r--lib/rss/content.rb3
-rw-r--r--lib/rss/content/1.0.rb2
-rw-r--r--lib/rss/content/2.0.rb2
-rw-r--r--lib/rss/converter.rb37
-rw-r--r--lib/rss/dublincore.rb19
-rw-r--r--lib/rss/dublincore/1.0.rb2
-rw-r--r--lib/rss/dublincore/2.0.rb2
-rw-r--r--lib/rss/dublincore/atom.rb2
-rw-r--r--lib/rss/image.rb23
-rw-r--r--lib/rss/itunes.rb5
-rw-r--r--lib/rss/maker.rb47
-rw-r--r--lib/rss/maker/0.9.rb88
-rw-r--r--lib/rss/maker/1.0.rb14
-rw-r--r--lib/rss/maker/2.0.rb23
-rw-r--r--lib/rss/maker/atom.rb1
-rw-r--r--lib/rss/maker/base.rb163
-rw-r--r--lib/rss/maker/content.rb1
-rw-r--r--lib/rss/maker/dublincore.rb6
-rw-r--r--lib/rss/maker/entry.rb7
-rw-r--r--lib/rss/maker/feed.rb10
-rw-r--r--lib/rss/maker/image.rb7
-rw-r--r--lib/rss/maker/itunes.rb11
-rw-r--r--lib/rss/maker/slash.rb1
-rw-r--r--lib/rss/maker/syndication.rb1
-rw-r--r--lib/rss/maker/taxonomy.rb9
-rw-r--r--lib/rss/maker/trackback.rb3
-rw-r--r--lib/rss/parser.rb82
-rw-r--r--lib/rss/rexmlparser.rb16
-rw-r--r--lib/rss/rss.rb124
-rw-r--r--lib/rss/slash.rb3
-rw-r--r--lib/rss/syndication.rb12
-rw-r--r--lib/rss/taxonomy.rb23
-rw-r--r--lib/rss/trackback.rb41
-rw-r--r--lib/rss/utils.rb103
-rw-r--r--lib/rss/xml-stylesheet.rb5
-rw-r--r--lib/rss/xml.rb1
-rw-r--r--lib/rss/xmlparser.rb18
-rw-r--r--lib/rss/xmlscanner.rb11
42 files changed, 1065 insertions, 340 deletions
diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb
index 7b24e7596d..d852a6a85e 100644
--- a/lib/rss/0.9.rb
+++ b/lib/rss/0.9.rb
@@ -1,14 +1,48 @@
+# frozen_string_literal: false
require "rss/parser"
module RSS
+ ##
+ # = RSS 0.9 support
+ #
+ # RSS has three different versions. This module contains support for version
+ # 0.9.1[http://www.rssboard.org/rss-0-9-1-netscape].
+ #
+ # == Producing RSS 0.9
+ #
+ # Producing our own RSS feeds is easy as well. Let's make a very basic feed:
+ #
+ # require "rss"
+ #
+ # rss = RSS::Maker.make("0.91") do |maker|
+ # maker.channel.language = "en"
+ # maker.channel.author = "matz"
+ # maker.channel.updated = Time.now.to_s
+ # maker.channel.link = "http://www.ruby-lang.org/en/feeds/news.rss"
+ # maker.channel.title = "Example Feed"
+ # maker.channel.description = "A longer description of my feed."
+ # maker.image.url = "http://www.ruby-lang.org/images/logo.gif"
+ # maker.image.title = "An image"
+ # maker.items.new_item do |item|
+ # item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
+ # item.title = "Ruby 1.9.2-p136 is released"
+ # item.updated = Time.now.to_s
+ # end
+ # end
+ #
+ # puts rss
+ #
+ # As you can see, this is a very Builder-like DSL. This code will spit out an
+ # RSS 0.9 feed with one item. If we needed a second item, we'd make another
+ # block with maker.items.new_item and build a second one.
module RSS09
NSPOOL = {}
ELEMENTS = []
def self.append_features(klass)
super
-
+
klass.install_must_call_validator('', "")
end
end
@@ -123,7 +157,7 @@ module RSS
def not_need_to_call_setup_maker_variables
%w(image textInput)
end
-
+
class SkipDays < Element
include RSS09
@@ -146,11 +180,11 @@ module RSS
self.content = args[0]
end
end
-
+
end
-
+
end
-
+
class SkipHours < Element
include RSS09
@@ -174,13 +208,13 @@ module RSS
end
end
end
-
+
end
-
+
class Image < Element
include RSS09
-
+
%w(url title link).each do |name|
install_text_element(name, "", nil)
end
@@ -239,9 +273,9 @@ module RSS
end
end
end
-
+
class Item < Element
-
+
include RSS09
[
@@ -269,7 +303,7 @@ module RSS
@enclosure.setup_maker(item) if @enclosure
@source.setup_maker(item) if @source
end
-
+
class Source < Element
include RSS09
@@ -279,7 +313,7 @@ module RSS
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
-
+
content_setup
def initialize(*args)
@@ -341,7 +375,7 @@ module RSS
class Category < Element
include RSS09
-
+
[
["domain", "", false]
].each do |name, uri, required|
@@ -369,11 +403,11 @@ module RSS
category.domain = domain
category.content = content
end
-
+
end
end
-
+
class TextInput < Element
include RSS09
@@ -399,9 +433,9 @@ module RSS
maker.textinput
end
end
-
+
end
-
+
end
RSS09::ELEMENTS.each do |name|
@@ -411,8 +445,8 @@ module RSS
module ListenerMixin
private
def initial_start_rss(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, "")
-
+ check_ns(tag_name, prefix, ns, "", false)
+
@rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
@rss.do_validate = @do_validate
@rss.xml_stylesheets = @xml_stylesheets
@@ -422,7 +456,7 @@ module RSS
end
@proc_stack.push(pr)
end
-
+
end
end
diff --git a/lib/rss/1.0.rb b/lib/rss/1.0.rb
index f04e61c5eb..fb63937c5e 100644
--- a/lib/rss/1.0.rb
+++ b/lib/rss/1.0.rb
@@ -1,14 +1,47 @@
+# frozen_string_literal: false
require "rss/parser"
module RSS
+ ##
+ # = RSS 1.0 support
+ #
+ # RSS has three different versions. This module contains support for version
+ # 1.0[http://web.resource.org/rss/1.0/]
+ #
+ # == Producing RSS 1.0
+ #
+ # Producing our own RSS feeds is easy as well. Let's make a very basic feed:
+ #
+ # require "rss"
+ #
+ # rss = RSS::Maker.make("1.0") do |maker|
+ # maker.channel.language = "en"
+ # maker.channel.author = "matz"
+ # maker.channel.about = "About my feed."
+ # maker.channel.updated = Time.now.to_s
+ # maker.channel.link = "http://www.ruby-lang.org/en/feeds/news.rss"
+ # maker.channel.title = "Example Feed"
+ # maker.channel.description = "A longer description of my feed."
+ # maker.items.new_item do |item|
+ # item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
+ # item.title = "Ruby 1.9.2-p136 is released"
+ # item.updated = Time.now.to_s
+ # end
+ # end
+ #
+ # puts rss
+ #
+ # As you can see, this is a very Builder-like DSL. This code will spit out an
+ # RSS 1.0 feed with one item. If we needed a second item, we'd make another
+ # block with maker.items.new_item and build a second one.
module RSS10
NSPOOL = {}
ELEMENTS = []
def self.append_features(klass)
super
-
+
klass.install_must_call_validator('', ::RSS::URI)
end
@@ -64,13 +97,13 @@ module RSS
URI
end
end
-
+
[
["resource", [URI, ""], true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -98,10 +131,10 @@ module RSS
end
@tag_name = 'Seq'
-
+
install_have_children_element("li", URI, "*")
install_must_call_validator('rdf', ::RSS::RDF::URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -114,7 +147,7 @@ module RSS
def full_name
tag_name_with_prefix(PREFIX)
end
-
+
def setup_maker(target)
lis.each do |li|
target << li.resource
@@ -135,10 +168,10 @@ module RSS
end
@tag_name = 'Bag'
-
+
install_have_children_element("li", URI, "*")
install_must_call_validator('rdf', URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -151,7 +184,7 @@ module RSS
def full_name
tag_name_with_prefix(PREFIX)
end
-
+
def setup_maker(target)
lis.each do |li|
target << li.resource
@@ -162,7 +195,7 @@ module RSS
class Channel < Element
include RSS10
-
+
class << self
def required_uri
@@ -202,17 +235,17 @@ module RSS
def maker_target(maker)
maker.channel
end
-
+
def setup_maker_attributes(channel)
channel.about = about
end
class Image < Element
-
+
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -225,7 +258,7 @@ module RSS
install_get_attribute(name, uri, required, nil, nil,
"#{PREFIX}:#{name}")
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -237,11 +270,11 @@ module RSS
end
class Textinput < Element
-
+
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -254,7 +287,7 @@ module RSS
install_get_attribute(name, uri, required, nil, nil,
"#{PREFIX}:#{name}")
end
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -264,7 +297,7 @@ module RSS
end
end
end
-
+
class Items < Element
include RSS10
@@ -272,16 +305,16 @@ module RSS
Seq = ::RSS::RDF::Seq
class << self
-
+
def required_uri
::RSS::URI
end
-
+
end
install_have_child_element("Seq", URI, nil)
install_must_call_validator('rdf', URI)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -309,7 +342,7 @@ module RSS
include RSS10
class << self
-
+
def required_uri
::RSS::URI
end
@@ -351,7 +384,7 @@ module RSS
def required_uri
::RSS::URI
end
-
+
end
@@ -436,7 +469,7 @@ module RSS
module ListenerMixin
private
def initial_start_RDF(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, RDF::URI)
+ check_ns(tag_name, prefix, ns, RDF::URI, false)
@rss = RDF.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
diff --git a/lib/rss/2.0.rb b/lib/rss/2.0.rb
index 3798da4eb7..13f9ade918 100644
--- a/lib/rss/2.0.rb
+++ b/lib/rss/2.0.rb
@@ -1,7 +1,39 @@
+# frozen_string_literal: false
require "rss/0.9"
module RSS
+ ##
+ # = RSS 2.0 support
+ #
+ # RSS has three different versions. This module contains support for version
+ # 2.0[http://www.rssboard.org/rss-specification]
+ #
+ # == Producing RSS 2.0
+ #
+ # Producing our own RSS feeds is easy as well. Let's make a very basic feed:
+ #
+ # require "rss"
+ #
+ # rss = RSS::Maker.make("2.0") do |maker|
+ # maker.channel.language = "en"
+ # maker.channel.author = "matz"
+ # maker.channel.updated = Time.now.to_s
+ # maker.channel.link = "http://www.ruby-lang.org/en/feeds/news.rss"
+ # maker.channel.title = "Example Feed"
+ # maker.channel.description = "A longer description of my feed."
+ # maker.items.new_item do |item|
+ # item.link = "http://www.ruby-lang.org/en/news/2010/12/25/ruby-1-9-2-p136-is-released/"
+ # item.title = "Ruby 1.9.2-p136 is released"
+ # item.updated = Time.now.to_s
+ # end
+ # end
+ #
+ # puts rss
+ #
+ # As you can see, this is a very Builder-like DSL. This code will spit out an
+ # RSS 2.0 feed with one item. If we needed a second item, we'd make another
+ # block with maker.items.new_item and build a second one.
class Rss
class Channel
@@ -29,7 +61,7 @@ module RSS
Category = Item::Category
class Item
-
+
[
["comments", "?"],
["author", "?"],
@@ -57,9 +89,9 @@ module RSS
_setup_maker_element(item)
@guid.setup_maker(item) if @guid
end
-
+
class Guid < Element
-
+
include RSS09
[
diff --git a/lib/rss/atom.rb b/lib/rss/atom.rb
index 7cba934feb..38e927478c 100644
--- a/lib/rss/atom.rb
+++ b/lib/rss/atom.rb
@@ -1,9 +1,25 @@
-require 'base64'
+# frozen_string_literal: false
require 'rss/parser'
module RSS
+ ##
+ # Atom is an XML-based document format that is used to describe 'feeds' of related information.
+ # A typical use is in a news feed where the information is periodically updated and which users
+ # can subscribe to. The Atom format is described in http://tools.ietf.org/html/rfc4287
+ #
+ # The Atom module provides support in reading and creating feeds.
+ #
+ # See the RSS module for examples consuming and creating feeds.
module Atom
+
+ ##
+ # The Atom URI W3C Namespace
+
URI = "http://www.w3.org/2005/Atom"
+
+ ##
+ # The XHTML URI W3C Namespace
+
XHTML_URI = "http://www.w3.org/1999/xhtml"
module CommonModel
@@ -21,10 +37,12 @@ module RSS
end
klass.class_eval do
class << self
+ # Returns the Atom URI W3C Namespace
def required_uri
URI
end
+ # Returns true
def need_parent?
true
end
@@ -75,6 +93,12 @@ module RSS
end
end
+ # The TextConstruct module is used to define a Text construct Atom element,
+ # which is used to store small quantities of human-readable text.
+ #
+ # The TextConstruct has a type attribute, e.g. text, html, xhtml
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#text.constructs
module TextConstruct
def self.append_features(klass)
super
@@ -101,6 +125,8 @@ module RSS
end
attr_writer :xhtml
+
+ # Returns or builds the XHTML content.
def xhtml
return @xhtml if @xhtml.nil?
if @xhtml.is_a?(XML::Element) and
@@ -114,10 +140,13 @@ module RSS
{"xmlns" => XHTML_URI}, children)
end
+ # Returns true if type is "xhtml".
def have_xml_content?
@type == "xhtml"
end
+ # Raises a MissingTagError or NotExpectedTagError
+ # if the element is not properly formatted.
def atom_validate(ignore_unknown_element, tags, uri)
if have_xml_content?
if @xhtml.nil?
@@ -141,7 +170,15 @@ module RSS
end
end
+ # The PersonConstruct module is used to define a person Atom element that can be
+ # used to describe a person, corporation or similar entity.
+ #
+ # The PersonConstruct has a Name, Uri and Email child elements.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#atomPersonConstruct
module PersonConstruct
+
+ # Adds attributes for name, uri, and email to the +klass+
def self.append_features(klass)
super
klass.class_eval do
@@ -159,22 +196,36 @@ module RSS
target.__send__("new_#{self.class.name.split(/::/).last.downcase}")
end
+ # The name of the person or entity.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.name
class Name < RSS::Element
include CommonModel
include ContentModel
end
+ # The URI of the person or entity.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.uri
class Uri < RSS::Element
include CommonModel
include URIContentModel
end
+ # The email of the person or entity.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.email
class Email < RSS::Element
include CommonModel
include ContentModel
end
end
+ # Element used to describe an Atom date and time in the ISO 8601 format
+ #
+ # Examples:
+ # * 2013-03-04T15:30:02Z
+ # * 2013-03-04T10:30:02-05:00
module DateConstruct
def self.append_features(klass)
super
@@ -184,12 +235,17 @@ module RSS
end
end
+ # Raises NotAvailableValueError if element content is nil
def atom_validate(ignore_unknown_element, tags, uri)
raise NotAvailableValueError.new(tag_name, "") if content.nil?
end
end
module DuplicateLinkChecker
+ # Checks if there are duplicate links with the same type and hreflang attributes
+ # that have an alternate (or empty) rel attribute
+ #
+ # Raises a TooMuchTagError if there are duplicates found
def validate_duplicate_links(links)
link_infos = {}
links.each do |link|
@@ -204,6 +260,28 @@ module RSS
end
end
+ # Defines the top-level element of an Atom Feed Document.
+ # It consists of a number of children Entry elements,
+ # and has the following attributes:
+ #
+ # * author
+ # * categories
+ # * category
+ # * content
+ # * contributor
+ # * entries (aliased as items)
+ # * entry
+ # * generator
+ # * icon
+ # * id
+ # * link
+ # * logo
+ # * rights
+ # * subtitle
+ # * title
+ # * updated
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.feed
class Feed < RSS::Element
include RootElementMixin
include CommonModel
@@ -231,6 +309,7 @@ module RSS
tag, URI, occurs, tag, *args)
end
+ # Creates a new Atom feed
def initialize(version=nil, encoding=nil, standalone=nil)
super("1.0", version, encoding, standalone)
@feed_type = "atom"
@@ -239,6 +318,8 @@ module RSS
alias_method :items, :entries
+ # Returns true if there are any authors for the feed or any of the Entry
+ # child elements have an author
def have_author?
authors.any? {|author| !author.to_s.empty?} or
entries.any? {|entry| entry.have_author?(false)}
@@ -275,11 +356,23 @@ module RSS
end
end
+ # PersonConstruct that contains information regarding the author
+ # of a Feed or Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.author
class Author < RSS::Element
include CommonModel
include PersonConstruct
end
+ # Contains information about a category associated with a Feed or Entry.
+ # It has the following attributes:
+ #
+ # * term
+ # * scheme
+ # * label
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.category
class Category < RSS::Element
include CommonModel
@@ -297,11 +390,18 @@ module RSS
end
end
+ # PersonConstruct that contains information regarding the
+ # contributors of a Feed or Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.contributor
class Contributor < RSS::Element
include CommonModel
include PersonConstruct
end
+ # Contains information on the agent used to generate the feed.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.generator
class Generator < RSS::Element
include CommonModel
include ContentModel
@@ -322,16 +422,34 @@ module RSS
end
end
+ # Defines an image that provides a visual identification for a eed.
+ # The image should have an aspect ratio of 1:1.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.icon
class Icon < RSS::Element
include CommonModel
include URIContentModel
end
+ # Defines the Universally Unique Identifier (UUID) for a Feed or Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.id
class Id < RSS::Element
include CommonModel
include URIContentModel
end
+ # Defines a reference to a Web resource. It has the following
+ # attributes:
+ #
+ # * href
+ # * rel
+ # * type
+ # * hreflang
+ # * title
+ # * length
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.link
class Link < RSS::Element
include CommonModel
@@ -352,6 +470,10 @@ module RSS
end
end
+ # Defines an image that provides a visual identification for the Feed.
+ # The image should have an aspect ratio of 2:1 (horizontal:vertical).
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.logo
class Logo < RSS::Element
include CommonModel
include URIContentModel
@@ -366,26 +488,60 @@ module RSS
end
end
+ # TextConstruct that contains copyright information regarding
+ # the content in an Entry or Feed. It should not be used to
+ # convey machine readable licensing information.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.rights
class Rights < RSS::Element
include CommonModel
include TextConstruct
end
+ # TextConstruct that conveys a description or subtitle for a Feed.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.subtitle
class Subtitle < RSS::Element
include CommonModel
include TextConstruct
end
+ # TextConstruct that conveys a description or title for a Feed or Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.title
class Title < RSS::Element
include CommonModel
include TextConstruct
end
+ # DateConstruct indicating the most recent time when a Feed or
+ # Entry was modified in a way the publisher considers
+ # significant.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.updated
class Updated < RSS::Element
include CommonModel
include DateConstruct
end
+ # Defines a child Atom Entry element of an Atom Feed element.
+ # It has the following attributes:
+ #
+ # * author
+ # * category
+ # * categories
+ # * content
+ # * contributor
+ # * id
+ # * link
+ # * published
+ # * rights
+ # * source
+ # * summary
+ # * title
+ # * updated
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.entry
class Entry < RSS::Element
include CommonModel
include DuplicateLinkChecker
@@ -409,6 +565,12 @@ module RSS
tag, URI, occurs, tag, *args)
end
+ # Returns whether any of the following are true:
+ #
+ # * There are any authors in the feed
+ # * If the parent element has an author and the +check_parent+
+ # parameter was given.
+ # * There is a source element that has an author
def have_author?(check_parent=true)
authors.any? {|author| !author.to_s.empty?} or
(check_parent and @parent and @parent.have_author?) or
@@ -435,9 +597,18 @@ module RSS
items.new_item
end
+ # Feed::Author
Author = Feed::Author
+ # Feed::Category
Category = Feed::Category
+ # Contains or links to the content of the Entry.
+ # It has the following attributes:
+ #
+ # * type
+ # * src
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.content
class Content < RSS::Element
include CommonModel
@@ -461,11 +632,15 @@ module RSS
content_setup
add_need_initialize_variable("xml")
+ # Returns the element content in XML.
attr_writer :xml
+
+ # Returns true if the element has inline XML content.
def have_xml_content?
inline_xhtml? or inline_other_xml?
end
+ # Returns or builds the element content in XML.
def xml
return @xml unless inline_xhtml?
return @xml if @xml.nil?
@@ -480,6 +655,7 @@ module RSS
{"xmlns" => XHTML_URI}, children)
end
+ # Returns the element content in XHTML.
def xhtml
if inline_xhtml?
xml
@@ -488,6 +664,9 @@ module RSS
end
end
+ # Raises a MissingAttributeError, NotAvailableValueError,
+ # MissingTagError or NotExpectedTagError if the element is
+ # not properly formatted.
def atom_validate(ignore_unknown_element, tags, uri)
if out_of_line?
raise MissingAttributeError.new(tag_name, "type") if @type.nil?
@@ -504,19 +683,27 @@ module RSS
end
end
+ # Returns true if the element contains inline content
+ # that has a text or HTML media type, or no media type at all.
def inline_text?
!out_of_line? and [nil, "text", "html"].include?(@type)
end
+ # Returns true if the element contains inline content that
+ # has a HTML media type.
def inline_html?
return false if out_of_line?
@type == "html" or mime_split == ["text", "html"]
end
+ # Returns true if the element contains inline content that
+ # has a XHTML media type.
def inline_xhtml?
!out_of_line? and @type == "xhtml"
end
+ # Returns true if the element contains inline content that
+ # has a MIME media type.
def inline_other?
return false if out_of_line?
media_type, subtype = mime_split
@@ -524,15 +711,19 @@ module RSS
true
end
+ # Returns true if the element contains inline content that
+ # has a text media type.
def inline_other_text?
return false unless inline_other?
return false if inline_other_xml?
- media_type, subtype = mime_split
+ media_type, = mime_split
return true if "text" == media_type.downcase
false
end
+ # Returns true if the element contains inline content that
+ # has a XML media type.
def inline_other_xml?
return false unless inline_other?
@@ -547,14 +738,18 @@ module RSS
false
end
+ # Returns true if the element contains inline content
+ # encoded in base64.
def inline_other_base64?
inline_other? and !inline_other_text? and !inline_other_xml?
end
+ # Returns true if the element contains linked content.
def out_of_line?
not @src.nil?
end
+ # Splits the type attribute into an array, e.g. ["text", "xml"]
def mime_split
media_type = subtype = nil
if /\A\s*([a-z]+)\/([a-z\+]+)\s*(?:;.*)?\z/i =~ @type.to_s
@@ -564,6 +759,7 @@ module RSS
[media_type, subtype]
end
+ # Returns true if the content needs to be encoded in base64.
def need_base64_encode?
inline_other_base64?
end
@@ -574,17 +770,43 @@ module RSS
end
end
+ # Feed::Contributor
Contributor = Feed::Contributor
+ # Feed::Id
Id = Feed::Id
+ # Feed::Link
Link = Feed::Link
+ # DateConstruct that usually indicates the time of the initial
+ # creation of an Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.published
class Published < RSS::Element
include CommonModel
include DateConstruct
end
+ # Feed::Rights
Rights = Feed::Rights
+ # Defines a Atom Source element. It has the following attributes:
+ #
+ # * author
+ # * category
+ # * categories
+ # * content
+ # * contributor
+ # * generator
+ # * icon
+ # * id
+ # * link
+ # * logo
+ # * rights
+ # * subtitle
+ # * title
+ # * updated
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.source
class Source < RSS::Element
include CommonModel
@@ -607,34 +829,71 @@ module RSS
tag, URI, occurs, tag, *args)
end
+ # Returns true if the Source element has an author.
def have_author?
!author.to_s.empty?
end
+ # Feed::Author
Author = Feed::Author
+ # Feed::Category
Category = Feed::Category
+ # Feed::Contributor
Contributor = Feed::Contributor
+ # Feed::Generator
Generator = Feed::Generator
+ # Feed::Icon
Icon = Feed::Icon
+ # Feed::Id
Id = Feed::Id
+ # Feed::Link
Link = Feed::Link
+ # Feed::Logo
Logo = Feed::Logo
+ # Feed::Rights
Rights = Feed::Rights
+ # Feed::Subtitle
Subtitle = Feed::Subtitle
+ # Feed::Title
Title = Feed::Title
+ # Feed::Updated
Updated = Feed::Updated
end
+ # TextConstruct that describes a summary of the Entry.
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.summary
class Summary < RSS::Element
include CommonModel
include TextConstruct
end
+ # Feed::Title
Title = Feed::Title
+ # Feed::Updated
Updated = Feed::Updated
end
end
+ # Defines a top-level Atom Entry element,
+ # used as the document element of a stand-alone Atom Entry Document.
+ # It has the following attributes:
+ #
+ # * author
+ # * category
+ # * categories
+ # * content
+ # * contributor
+ # * id
+ # * link
+ # * published
+ # * rights
+ # * source
+ # * summary
+ # * title
+ # * updated
+ #
+ # Reference: https://validator.w3.org/feed/docs/rfc4287.html#element.entry]
class Entry < RSS::Element
include RootElementMixin
include CommonModel
@@ -659,21 +918,26 @@ module RSS
tag, URI, occurs, tag, *args)
end
+ # Creates a new Atom Entry element.
def initialize(version=nil, encoding=nil, standalone=nil)
super("1.0", version, encoding, standalone)
@feed_type = "atom"
@feed_subtype = "entry"
end
+ # Returns the Entry in an array.
def items
[self]
end
+ # Sets up the +maker+ for constructing Entry elements.
def setup_maker(maker)
maker = maker.maker if maker.respond_to?("maker")
super(maker)
end
+ # Returns where there are any authors present or there is a
+ # source with an author.
def have_author?
authors.any? {|author| !author.to_s.empty?} or
(source and source.have_author?)
@@ -695,17 +959,29 @@ module RSS
maker.items.new_item
end
+ # Feed::Entry::Author
Author = Feed::Entry::Author
+ # Feed::Entry::Category
Category = Feed::Entry::Category
+ # Feed::Entry::Content
Content = Feed::Entry::Content
+ # Feed::Entry::Contributor
Contributor = Feed::Entry::Contributor
+ # Feed::Entry::Id
Id = Feed::Entry::Id
+ # Feed::Entry::Link
Link = Feed::Entry::Link
+ # Feed::Entry::Published
Published = Feed::Entry::Published
+ # Feed::Entry::Rights
Rights = Feed::Entry::Rights
+ # Feed::Entry::Source
Source = Feed::Entry::Source
+ # Feed::Entry::Summary
Summary = Feed::Entry::Summary
+ # Feed::Entry::Title
Title = Feed::Entry::Title
+ # Feed::Entry::Updated
Updated = Feed::Entry::Updated
end
end
@@ -717,7 +993,7 @@ module RSS
module ListenerMixin
private
def initial_start_feed(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, Atom::URI)
+ check_ns(tag_name, prefix, ns, Atom::URI, false)
@rss = Atom::Feed.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
@@ -732,7 +1008,7 @@ module RSS
end
def initial_start_entry(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, Atom::URI)
+ check_ns(tag_name, prefix, ns, Atom::URI, false)
@rss = Atom::Entry.new(@version, @encoding, @standalone)
@rss.do_validate = @do_validate
diff --git a/lib/rss/content.rb b/lib/rss/content.rb
index b12ee918aa..d35311075a 100644
--- a/lib/rss/content.rb
+++ b/lib/rss/content.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: false
require "rss/rss"
module RSS
+ # The prefix for the Content XML namespace.
CONTENT_PREFIX = 'content'
+ # The URI of the Content specification.
CONTENT_URI = "http://purl.org/rss/1.0/modules/content/"
module ContentModel
diff --git a/lib/rss/content/1.0.rb b/lib/rss/content/1.0.rb
index e7c0c19685..1367dfe092 100644
--- a/lib/rss/content/1.0.rb
+++ b/lib/rss/content/1.0.rb
@@ -1,5 +1,5 @@
+# frozen_string_literal: false
require 'rss/1.0'
-require 'rss/content'
module RSS
RDF.install_ns(CONTENT_PREFIX, CONTENT_URI)
diff --git a/lib/rss/content/2.0.rb b/lib/rss/content/2.0.rb
index 8671b5b1a6..3b468248ac 100644
--- a/lib/rss/content/2.0.rb
+++ b/lib/rss/content/2.0.rb
@@ -1,5 +1,5 @@
+# frozen_string_literal: false
require "rss/2.0"
-require "rss/content"
module RSS
Rss.install_ns(CONTENT_PREFIX, CONTENT_URI)
diff --git a/lib/rss/converter.rb b/lib/rss/converter.rb
index 415a319188..b92e35a051 100644
--- a/lib/rss/converter.rb
+++ b/lib/rss/converter.rb
@@ -1,12 +1,17 @@
+# frozen_string_literal: false
require "rss/utils"
module RSS
class Converter
-
+
include Utils
def initialize(to_enc, from_enc=nil)
+ if "".respond_to?(:encode)
+ @to_encoding = to_enc
+ return
+ end
normalized_to_enc = to_enc.downcase.gsub(/-/, '_')
from_enc ||= 'utf-8'
normalized_from_enc = from_enc.downcase.gsub(/-/, '_')
@@ -23,7 +28,11 @@ module RSS
end
def convert(value)
- value
+ if value.is_a?(String) and value.respond_to?(:encode)
+ value.encode(@to_encoding)
+ else
+ value
+ end
end
def def_convert(depth=0)
@@ -55,11 +64,11 @@ module RSS
raise UnknownConversionMethodError.new(to_enc, from_enc)
end
end
-
+
def def_else_enc(to_enc, from_enc)
def_iconv_convert(to_enc, from_enc, 0)
end
-
+
def def_same_enc()
def_convert do |value|
value
@@ -93,40 +102,40 @@ module RSS
def def_to_euc_jp_from_utf_8
def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We')
end
-
+
def def_to_utf_8_from_euc_jp
def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew')
end
-
+
def def_to_shift_jis_from_utf_8
def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws')
end
-
+
def def_to_utf_8_from_shift_jis
def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw')
end
-
+
def def_to_euc_jp_from_shift_jis
require "nkf"
def_convert do |value|
"NKF.nkf('-Se', #{value})"
end
end
-
+
def def_to_shift_jis_from_euc_jp
require "nkf"
def_convert do |value|
"NKF.nkf('-Es', #{value})"
end
end
-
+
def def_to_euc_jp_from_iso_2022_jp
require "nkf"
def_convert do |value|
"NKF.nkf('-Je', #{value})"
end
end
-
+
def def_to_iso_2022_jp_from_euc_jp
require "nkf"
def_convert do |value|
@@ -139,7 +148,7 @@ module RSS
"#{value}.unpack('C*').pack('U*')"
end
end
-
+
def def_to_iso_8859_1_from_utf_8
def_convert do |value|
<<-EOC
@@ -156,7 +165,7 @@ module RSS
EOC
end
end
-
+
end
-
+
end
diff --git a/lib/rss/dublincore.rb b/lib/rss/dublincore.rb
index 7ba239f8f1..8d1a551947 100644
--- a/lib/rss/dublincore.rb
+++ b/lib/rss/dublincore.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: false
require "rss/rss"
module RSS
+ # The prefix for the Dublin Core XML namespace.
DC_PREFIX = 'dc'
+ # The URI of the Dublin Core specification.
DC_URI = "http://purl.org/dc/elements/1.1/"
module BaseDublinCoreModel
@@ -25,7 +28,7 @@ module RSS
def #{full_name}
@#{full_name}.first and @#{full_name}.first.value
end
-
+
def #{full_name}=(new_value)
@#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value)
end
@@ -50,7 +53,7 @@ module RSS
EOC
end
end
-
+
module DublinCoreModel
extend BaseModel
@@ -76,26 +79,26 @@ module RSS
DATE_ELEMENTS = {
"date" => "w3cdtf",
}
-
+
ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a
DublinCoreModel::DATE_ELEMENTS.each do |name, |
ELEMENT_NAME_INFOS << [name, nil]
end
-
+
ELEMENTS = TEXT_ELEMENTS.keys + DATE_ELEMENTS.keys
ELEMENTS.each do |name, plural_name|
module_eval(<<-EOC, *get_file_and_line_from_caller(0))
class DublinCore#{Utils.to_class_name(name)} < Element
include RSS10
-
+
content_setup
class << self
def required_prefix
DC_PREFIX
end
-
+
def required_uri
DC_URI
end
@@ -105,7 +108,7 @@ module RSS
alias_method(:value, :content)
alias_method(:value=, :content=)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -114,7 +117,7 @@ module RSS
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(DC_PREFIX)
end
diff --git a/lib/rss/dublincore/1.0.rb b/lib/rss/dublincore/1.0.rb
index e193c6d2c2..1d96fab9b9 100644
--- a/lib/rss/dublincore/1.0.rb
+++ b/lib/rss/dublincore/1.0.rb
@@ -1,5 +1,5 @@
+# frozen_string_literal: false
require "rss/1.0"
-require "rss/dublincore"
module RSS
RDF.install_ns(DC_PREFIX, DC_URI)
diff --git a/lib/rss/dublincore/2.0.rb b/lib/rss/dublincore/2.0.rb
index 82ed1888c5..e3011fef6a 100644
--- a/lib/rss/dublincore/2.0.rb
+++ b/lib/rss/dublincore/2.0.rb
@@ -1,5 +1,5 @@
+# frozen_string_literal: false
require "rss/2.0"
-require "rss/dublincore"
module RSS
Rss.install_ns(DC_PREFIX, DC_URI)
diff --git a/lib/rss/dublincore/atom.rb b/lib/rss/dublincore/atom.rb
index e78df4821b..0b8b11e440 100644
--- a/lib/rss/dublincore/atom.rb
+++ b/lib/rss/dublincore/atom.rb
@@ -1,5 +1,5 @@
+# frozen_string_literal: false
require "rss/atom"
-require "rss/dublincore"
module RSS
module Atom
diff --git a/lib/rss/image.rb b/lib/rss/image.rb
index c4714aea12..6b86ec0e5b 100644
--- a/lib/rss/image.rb
+++ b/lib/rss/image.rb
@@ -1,13 +1,18 @@
+# frozen_string_literal: false
require 'rss/1.0'
require 'rss/dublincore'
module RSS
+ # The prefix for the Image XML namespace.
IMAGE_PREFIX = 'image'
+ # The URI for the Image specification.
IMAGE_URI = 'http://purl.org/rss/1.0/modules/image/'
RDF.install_ns(IMAGE_PREFIX, IMAGE_URI)
+ # This constant holds strings which contain the names of
+ # image elements, with the appropriate prefix.
IMAGE_ELEMENTS = []
%w(item favicon).each do |name|
@@ -15,7 +20,7 @@ module RSS
BaseListener.install_class_name(IMAGE_URI, name, "Image#{class_name}")
IMAGE_ELEMENTS << "#{IMAGE_PREFIX}_#{name}"
end
-
+
module ImageModelUtils
def validate_one_tag_name(ignore_unknown_element, name, tags)
if !ignore_unknown_element
@@ -25,7 +30,7 @@ module RSS
raise TooMuchTagError.new(name, tag_name) if tags.size > 1
end
end
-
+
module ImageItemModel
include ImageModelUtils
extend BaseModel
@@ -43,12 +48,12 @@ module RSS
include DublinCoreModel
@tag_name = "item"
-
+
class << self
def required_prefix
IMAGE_PREFIX
end
-
+
def required_uri
IMAGE_URI
end
@@ -102,11 +107,11 @@ module RSS
end
end
end
-
+
module ImageFaviconModel
include ImageModelUtils
extend BaseModel
-
+
def self.append_features(klass)
super
@@ -122,12 +127,12 @@ module RSS
include DublinCoreModel
@tag_name = "favicon"
-
+
class << self
def required_prefix
IMAGE_PREFIX
end
-
+
def required_uri
IMAGE_URI
end
@@ -154,7 +159,7 @@ module RSS
end
set_size(new_value)
end
-
+
alias image_size= size=
alias image_size size
diff --git a/lib/rss/itunes.rb b/lib/rss/itunes.rb
index f95ca7aa2e..987b090f21 100644
--- a/lib/rss/itunes.rb
+++ b/lib/rss/itunes.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: false
require 'rss/2.0'
module RSS
+ # The prefix for the iTunes XML namespace.
ITUNES_PREFIX = 'itunes'
+ # The URI of the iTunes specification.
ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
@@ -48,7 +51,7 @@ module RSS
ELEMENT_INFOS = [["author"],
["block", :yes_other],
- ["explicit", :yes_clean_other],
+ ["explicit", :explicit_clean_other],
["keywords", :csv],
["subtitle"],
["summary"]]
diff --git a/lib/rss/maker.rb b/lib/rss/maker.rb
index bcba1aaff3..33d285f6af 100644
--- a/lib/rss/maker.rb
+++ b/lib/rss/maker.rb
@@ -1,30 +1,65 @@
+# frozen_string_literal: false
require "rss/rss"
module RSS
+ ##
+ #
+ # Provides a set of builders for various RSS objects
+ #
+ # * Feeds
+ # * RSS 0.91
+ # * RSS 1.0
+ # * RSS 2.0
+ # * Atom 1.0
+ #
+ # * Elements
+ # * Atom::Entry
+
module Maker
+
+ # Collection of supported makers
MAKERS = {}
class << self
+ # Builder for an RSS object
+ # Creates an object of the type passed in +args+
+ #
+ # Executes the +block+ to populate elements of the created RSS object
def make(version, &block)
- m = maker(version)
- raise UnsupportedMakerVersionError.new(version) if m.nil?
- m[:maker].make(m[:version], &block)
+ self[version].make(&block)
end
- def maker(version)
- MAKERS[version]
+ # Returns the maker for the +version+
+ def [](version)
+ maker_info = maker(version)
+ raise UnsupportedMakerVersionError.new(version) if maker_info.nil?
+ maker_info[:maker]
end
+ # Adds a maker to the set of supported makers
def add_maker(version, normalized_version, maker)
MAKERS[version] = {:maker => maker, :version => normalized_version}
end
+ # Returns collection of supported maker versions
def versions
MAKERS.keys.uniq.sort
end
+ # Returns collection of supported makers
def makers
- MAKERS.values.collect {|info| info[:maker]}.uniq
+ MAKERS.values.collect { |info| info[:maker] }.uniq
+ end
+
+ # Returns true if the version is supported
+ def supported?(version)
+ versions.include?(version)
+ end
+
+ private
+ # Can I remove this method?
+ def maker(version)
+ MAKERS[version]
end
end
end
diff --git a/lib/rss/maker/0.9.rb b/lib/rss/maker/0.9.rb
index 72b14dc977..622a4c30b4 100644
--- a/lib/rss/maker/0.9.rb
+++ b/lib/rss/maker/0.9.rb
@@ -1,17 +1,18 @@
+# frozen_string_literal: false
require "rss/0.9"
require "rss/maker/base"
module RSS
module Maker
-
+
class RSS09 < RSSBase
-
- def initialize(feed_version="0.92")
+
+ def initialize(feed_version)
super
@feed_type = "rss"
end
-
+
private
def make_feed
Rss.new(@feed_version, @version, @encoding, @standalone)
@@ -24,7 +25,7 @@ module RSS
class Channel < ChannelBase
def to_feed(rss)
channel = Rss::Channel.new
- set = setup_values(channel)
+ setup_values(channel)
_not_set_required_variables = not_set_required_variables
if _not_set_required_variables.empty?
rss.channel = channel
@@ -38,20 +39,20 @@ module RSS
raise NotSetError.new("maker.channel", _not_set_required_variables)
end
end
-
+
private
def setup_items(rss)
@maker.items.to_feed(rss)
end
-
+
def setup_image(rss)
@maker.image.to_feed(rss)
end
-
+
def setup_textinput(rss)
@maker.textinput.to_feed(rss)
end
-
+
def variables
super + ["pubDate"]
end
@@ -78,7 +79,7 @@ module RSS
end
end
end
-
+
class Day < DayBase
def to_feed(rss, days)
day = Rss::Channel::SkipDays::Day.new
@@ -96,7 +97,7 @@ module RSS
end
end
end
-
+
class SkipHours < SkipHoursBase
def to_feed(rss, channel)
unless @hours.empty?
@@ -108,7 +109,7 @@ module RSS
end
end
end
-
+
class Hour < HourBase
def to_feed(rss, hours)
hour = Rss::Channel::SkipHours::Hour.new
@@ -126,7 +127,7 @@ module RSS
end
end
end
-
+
class Cloud < CloudBase
def to_feed(*args)
end
@@ -243,7 +244,7 @@ module RSS
true
end
end
-
+
class Items < ItemsBase
def to_feed(rss)
if rss.channel
@@ -253,11 +254,11 @@ module RSS
setup_other_elements(rss, rss.items)
end
end
-
+
class Item < ItemBase
def to_feed(rss)
item = Rss::Channel::Item.new
- set = setup_values(item)
+ setup_values(item)
_not_set_required_variables = not_set_required_variables
if _not_set_required_variables.empty?
rss.items << item
@@ -439,7 +440,7 @@ module RSS
end
end
end
-
+
class Textinput < TextinputBase
def to_feed(rss)
textInput = Rss::Channel::TextInput.new
@@ -457,11 +458,52 @@ module RSS
end
end
end
-
- add_maker("0.9", "0.92", RSS09)
- add_maker("0.91", "0.91", RSS09)
- add_maker("0.92", "0.92", RSS09)
- add_maker("rss0.91", "0.91", RSS09)
- add_maker("rss0.92", "0.92", RSS09)
+
+ class RSS091 < RSS09
+ def initialize(feed_version="0.91")
+ super
+ end
+
+ class Channel < RSS09::Channel
+ end
+
+ class Items < RSS09::Items
+ class Item < RSS09::Items::Item
+ end
+ end
+
+ class Image < RSS09::Image
+ end
+
+ class Textinput < RSS09::Textinput
+ end
+ end
+
+ class RSS092 < RSS09
+ def initialize(feed_version="0.92")
+ super
+ end
+
+ class Channel < RSS09::Channel
+ end
+
+ class Items < RSS09::Items
+ class Item < RSS09::Items::Item
+ end
+ end
+
+ class Image < RSS09::Image
+ end
+
+ class Textinput < RSS09::Textinput
+ end
+ end
+
+ add_maker("0.9", "0.92", RSS092)
+ add_maker("0.91", "0.91", RSS091)
+ add_maker("0.92", "0.92", RSS092)
+ add_maker("rss0.9", "0.92", RSS092)
+ add_maker("rss0.91", "0.91", RSS091)
+ add_maker("rss0.92", "0.92", RSS092)
end
end
diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb
index a1e2594f70..3aee77e913 100644
--- a/lib/rss/maker/1.0.rb
+++ b/lib/rss/maker/1.0.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/1.0"
require "rss/maker/base"
@@ -25,13 +26,14 @@ module RSS
end
class Channel < ChannelBase
+ include SetupDefaultLanguage
def to_feed(rss)
set_default_values do
_not_set_required_variables = not_set_required_variables
if _not_set_required_variables.empty?
channel = RDF::Channel.new(@about)
- set = setup_values(channel)
+ setup_values(channel)
channel.dc_dates.clear
rss.channel = channel
set_parent(channel, rss)
@@ -60,7 +62,7 @@ module RSS
rss.channel.items = items
set_parent(rss.channel, items)
end
-
+
def setup_image(rss)
if @maker.image.have_required_values?
image = RDF::Channel::Image.new(@maker.image.url)
@@ -91,11 +93,11 @@ module RSS
class SkipDays < SkipDaysBase
def to_feed(*args)
end
-
+
class Day < DayBase
end
end
-
+
class SkipHours < SkipHoursBase
def to_feed(*args)
end
@@ -103,7 +105,7 @@ module RSS
class Hour < HourBase
end
end
-
+
class Cloud < CloudBase
def to_feed(*args)
end
@@ -403,7 +405,7 @@ module RSS
end
end
end
-
+
class Textinput < TextinputBase
def to_feed(rss)
if @link
diff --git a/lib/rss/maker/2.0.rb b/lib/rss/maker/2.0.rb
index 67d68126ac..1f77a014d1 100644
--- a/lib/rss/maker/2.0.rb
+++ b/lib/rss/maker/2.0.rb
@@ -1,12 +1,13 @@
+# frozen_string_literal: false
require "rss/2.0"
require "rss/maker/0.9"
module RSS
module Maker
-
+
class RSS20 < RSS09
-
+
def initialize(feed_version="2.0")
super
end
@@ -17,17 +18,17 @@ module RSS
def required_variable_names
%w(link)
end
-
+
class SkipDays < RSS09::Channel::SkipDays
class Day < RSS09::Channel::SkipDays::Day
end
end
-
+
class SkipHours < RSS09::Channel::SkipHours
class Hour < RSS09::Channel::SkipHours::Hour
end
end
-
+
class Cloud < RSS09::Channel::Cloud
def to_feed(rss, channel)
cloud = Rss::Channel::Cloud.new
@@ -51,7 +52,7 @@ module RSS
category.to_feed(rss, channel)
end
end
-
+
class Category < RSS09::Channel::Categories::Category
def to_feed(rss, channel)
category = Rss::Channel::Category.new
@@ -81,14 +82,14 @@ module RSS
end
end
end
-
+
class Image < RSS09::Image
private
def required_element?
false
end
end
-
+
class Items < RSS09::Items
class Item < RSS09::Items::Item
private
@@ -179,7 +180,7 @@ module RSS
category.to_feed(rss, item)
end
end
-
+
class Category < RSS09::Items::Item::Categories::Category
def to_feed(rss, item)
category = Rss::Channel::Item::Category.new
@@ -212,11 +213,11 @@ module RSS
end
end
end
-
+
class Textinput < RSS09::Textinput
end
end
-
+
add_maker("2.0", "2.0", RSS20)
add_maker("rss2.0", "2.0", RSS20)
end
diff --git a/lib/rss/maker/atom.rb b/lib/rss/maker/atom.rb
index fd3198cd9e..e0cd7623c8 100644
--- a/lib/rss/maker/atom.rb
+++ b/lib/rss/maker/atom.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/atom"
require "rss/maker/base"
diff --git a/lib/rss/maker/base.rb b/lib/rss/maker/base.rb
index 56bf04657e..bc4ca84141 100644
--- a/lib/rss/maker/base.rb
+++ b/lib/rss/maker/base.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'forwardable'
require 'rss/rss'
@@ -23,15 +24,17 @@ module RSS
end
def inherited(subclass)
- subclass.const_set("OTHER_ELEMENTS", [])
- subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
+ subclass.const_set(:OTHER_ELEMENTS, [])
+ subclass.const_set(:NEED_INITIALIZE_VARIABLES, [])
end
def add_other_element(variable_name)
self::OTHER_ELEMENTS << variable_name
end
- def add_need_initialize_variable(variable_name, init_value="nil")
+ def add_need_initialize_variable(variable_name, init_value=nil,
+ &init_block)
+ init_value ||= init_block
self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
end
@@ -45,7 +48,7 @@ module RSS
def_delegators("@#{plural}", :push, :pop, :shift, :unshift)
def_delegators("@#{plural}", :each, :size, :empty?, :clear)
- add_need_initialize_variable(plural, "[]")
+ add_need_initialize_variable(plural) {[]}
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
def new_#{name}
@@ -74,7 +77,9 @@ module RSS
def def_classed_element_without_accessor(name, class_name=nil)
class_name ||= Utils.to_class_name(name)
add_other_element(name)
- add_need_initialize_variable(name, "make_#{name}")
+ add_need_initialize_variable(name) do |object|
+ object.send("make_#{name}")
+ end
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
private
def setup_#{name}(feed, current)
@@ -185,7 +190,19 @@ module RSS
private
def initialize_variables
self.class.need_initialize_variables.each do |variable_name, init_value|
- instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__)
+ if init_value.nil?
+ value = nil
+ else
+ if init_value.respond_to?(:call)
+ value = init_value.call(self)
+ elsif init_value.is_a?(String)
+ # just for backward compatibility
+ value = instance_eval(init_value, __FILE__, __LINE__)
+ else
+ value = init_value
+ end
+ end
+ instance_variable_set("@#{variable_name}", value)
end
end
@@ -222,7 +239,7 @@ module RSS
setter = "#{var}="
if target.respond_to?(setter)
value = __send__(var)
- if value
+ unless value.nil?
target.__send__(setter, value)
set = true
end
@@ -238,7 +255,8 @@ module RSS
def variables
self.class.need_initialize_variables.find_all do |name, init|
- "nil" == init
+ # init == "nil" is just for backward compatibility
+ init.nil? or init == "nil"
end.collect do |name, init|
name
end
@@ -336,36 +354,62 @@ module RSS
module SetupDefaultDate
private
- def _set_default_values(&block)
+ def _set_default_values
keep = {
:date => date,
:dc_dates => dc_dates.to_a.dup,
}
- _date = date
+ _date = _parse_date_if_needed(date)
if _date and !dc_dates.any? {|dc_date| dc_date.value == _date}
dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self)
dc_date.value = _date.dup
dc_dates.unshift(dc_date)
end
self.date ||= self.dc_date
- super(&block)
+ super
ensure
- date = keep[:date]
+ self.date = keep[:date]
dc_dates.replace(keep[:dc_dates])
end
+
+ def _parse_date_if_needed(date_value)
+ date_value = Time.parse(date_value) if date_value.is_a?(String)
+ date_value
+ end
+ end
+
+ module SetupDefaultLanguage
+ private
+ def _set_default_values
+ keep = {
+ :dc_languages => dc_languages.to_a.dup,
+ }
+ _language = language
+ if _language and
+ !dc_languages.any? {|dc_language| dc_language.value == _language}
+ dc_language = self.class::DublinCoreLanguages::DublinCoreLanguage.new(self)
+ dc_language.value = _language.dup
+ dc_languages.unshift(dc_language)
+ end
+ super
+ ensure
+ dc_languages.replace(keep[:dc_languages])
+ end
end
class RSSBase < Base
class << self
- def make(version, &block)
- new(version).make(&block)
+ def make(*args, &block)
+ new(*args).make(&block)
end
end
%w(xml_stylesheets channel image items textinput).each do |element|
attr_reader element
- add_need_initialize_variable(element, "make_#{element}")
- module_eval(<<-EOC, __FILE__, __LINE__)
+ add_need_initialize_variable(element) do |object|
+ object.send("make_#{element}")
+ end
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
private
def setup_#{element}(feed)
@#{element}.to_feed(feed)
@@ -376,7 +420,7 @@ module RSS
end
EOC
end
-
+
attr_reader :feed_version
alias_method(:rss_version, :feed_version)
attr_accessor :version, :encoding, :standalone
@@ -390,14 +434,10 @@ module RSS
@encoding = "UTF-8"
@standalone = nil
end
-
+
def make
- if block_given?
- yield(self)
- to_feed
- else
- nil
- end
+ yield(self)
+ to_feed
end
def to_feed
@@ -405,13 +445,10 @@ module RSS
setup_xml_stylesheets(feed)
setup_elements(feed)
setup_other_elements(feed)
- if feed.valid?
- feed
- else
- nil
- end
+ feed.validate
+ feed
end
-
+
private
remove_method :make_xml_stylesheets
def make_xml_stylesheets
@@ -428,7 +465,7 @@ module RSS
attr_accessor attribute
add_need_initialize_variable(attribute)
end
-
+
def to_feed(feed)
xss = ::RSS::XMLStyleSheet.new
guess_type_if_need(xss)
@@ -451,7 +488,7 @@ module RSS
end
end
end
-
+
class ChannelBase < Base
include SetupDefaultDate
@@ -472,12 +509,24 @@ module RSS
end
%w(id about language
- managingEditor webMaster rating docs date
- lastBuildDate ttl).each do |element|
+ managingEditor webMaster rating docs ttl).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
+ %w(date lastBuildDate).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
+ def lastBuildDate=(_date)
+ @lastBuildDate = _parse_date_if_needed(_date)
+ end
+
def pubDate
date
end
@@ -526,7 +575,7 @@ module RSS
end
end
end
-
+
class SkipHoursBase < Base
def_array_element("hour")
@@ -537,7 +586,7 @@ module RSS
end
end
end
-
+
class CloudBase < Base
%w(domain port path registerProcedure protocol).each do |element|
attr_accessor element
@@ -607,7 +656,7 @@ module RSS
include AtomTextConstructBase
end
end
-
+
class ImageBase < Base
%w(title url width height description).each do |element|
attr_accessor element
@@ -618,18 +667,18 @@ module RSS
@maker.channel.link
end
end
-
+
class ItemsBase < Base
def_array_element("item")
attr_accessor :do_sort, :max_size
-
+
def initialize(maker)
super
@do_sort = false
@max_size = -1
end
-
+
def normalize
if @max_size >= 0
sort_if_need[0...@max_size]
@@ -670,13 +719,22 @@ module RSS
["contributor", "name"],
].each do |name, attribute|
def_classed_elements(name, attribute)
- end
+ end
- %w(date comments id published).each do |element|
+ %w(comments id published).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
+ %w(date).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
def pubDate
date
end
@@ -715,6 +773,14 @@ module RSS
attr_accessor element
add_need_initialize_variable(element)
end
+
+ def permanent_link?
+ isPermaLink
+ end
+
+ def permanent_link=(bool)
+ self.isPermaLink = bool
+ end
end
class EnclosureBase < Base
@@ -725,6 +791,8 @@ module RSS
end
class SourceBase < Base
+ include SetupDefaultDate
+
%w(authors categories contributors generator icon
logo rights subtitle title).each do |name|
def_classed_element(name)
@@ -736,7 +804,7 @@ module RSS
def_classed_elements(name, attribute)
end
- %w(id content date).each do |element|
+ %w(id content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
@@ -744,6 +812,15 @@ module RSS
alias_method(:url, :link)
alias_method(:url=, :link=)
+ %w(date).each do |date_element|
+ attr_reader date_element
+ add_need_initialize_variable(date_element)
+ end
+
+ def date=(_date)
+ @date = _parse_date_if_needed(_date)
+ end
+
def updated
date
end
diff --git a/lib/rss/maker/content.rb b/lib/rss/maker/content.rb
index 46c4911f73..3559a45ad0 100644
--- a/lib/rss/maker/content.rb
+++ b/lib/rss/maker/content.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/content'
require 'rss/maker/1.0'
require 'rss/maker/2.0'
diff --git a/lib/rss/maker/dublincore.rb b/lib/rss/maker/dublincore.rb
index ff4813fe19..988209c045 100644
--- a/lib/rss/maker/dublincore.rb
+++ b/lib/rss/maker/dublincore.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/dublincore'
require 'rss/maker/1.0'
@@ -11,10 +12,7 @@ module RSS
plural_name ||= "#{name}s"
full_name = "#{RSS::DC_PREFIX}_#{name}"
full_plural_name = "#{RSS::DC_PREFIX}_#{plural_name}"
- klass_name = Utils.to_class_name(name)
plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
- full_plural_klass_name = "self.class::#{plural_klass_name}"
- full_klass_name = "#{full_plural_klass_name}::#{klass_name}"
klass.def_classed_elements(full_name, "value", plural_klass_name,
full_plural_name, name)
klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
@@ -90,7 +88,7 @@ EOC
class ChannelBase
include DublinCoreModel
end
-
+
class ImageBase; include DublinCoreModel; end
class ItemsBase
class ItemBase
diff --git a/lib/rss/maker/entry.rb b/lib/rss/maker/entry.rb
index edaa31ec06..f806cbcaae 100644
--- a/lib/rss/maker/entry.rb
+++ b/lib/rss/maker/entry.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/maker/atom"
require "rss/maker/feed"
@@ -99,7 +100,7 @@ module RSS
end
end
- def _set_default_values(&block)
+ def _set_default_values
keep = {
:authors => authors.to_a.dup,
:contributors => contributors.to_a.dup,
@@ -126,7 +127,7 @@ module RSS
@maker.channel.title {|t| @title = t}
end
self.updated ||= @maker.channel.updated
- super(&block)
+ super
ensure
authors.replace(keep[:authors])
contributors.replace(keep[:contributors])
@@ -135,7 +136,7 @@ module RSS
self.id = keep[:id]
@rights = keep[:rights]
@title = keep[:title]
- self.updated = keep[:prev_updated]
+ self.updated = keep[:updated]
end
Guid = Feed::Items::Item::Guid
diff --git a/lib/rss/maker/feed.rb b/lib/rss/maker/feed.rb
index 3a30ad4287..fdef7ad643 100644
--- a/lib/rss/maker/feed.rb
+++ b/lib/rss/maker/feed.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/maker/atom"
module RSS
@@ -22,6 +23,8 @@ module RSS
end
class Channel < ChannelBase
+ include SetupDefaultLanguage
+
def to_feed(feed)
set_default_values do
setup_values(feed)
@@ -71,14 +74,11 @@ module RSS
def _set_default_values(&block)
keep = {
:id => id,
- :updated => updated,
}
self.id ||= about
- self.updated ||= dc_date
super(&block)
ensure
self.id = keep[:id]
- self.updated = keep[:updated]
end
class SkipDays < SkipDaysBase
@@ -182,6 +182,7 @@ module RSS
set_default_values do
entry = feed.class::Entry.new
set = setup_values(entry)
+ entry.dc_dates.clear
setup_other_elements(feed, entry)
if set
feed.entries << entry
@@ -216,14 +217,11 @@ module RSS
def _set_default_values(&block)
keep = {
:id => id,
- :updated => updated,
}
self.id ||= link
- self.updated ||= dc_date
super(&block)
ensure
self.id = keep[:id]
- self.updated = keep[:updated]
end
class Guid < GuidBase
diff --git a/lib/rss/maker/image.rb b/lib/rss/maker/image.rb
index b95cf4c714..1957ba8689 100644
--- a/lib/rss/maker/image.rb
+++ b/lib/rss/maker/image.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/image'
require 'rss/maker/1.0'
require 'rss/maker/dublincore'
@@ -13,7 +14,7 @@ module RSS
end
def self.install_image_item(klass)
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
class ImageItem < ImageItemBase
DublinCoreModel.install_dublin_core(self)
end
@@ -57,7 +58,7 @@ EOC
end
def self.install_image_favicon(klass)
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
class ImageFavicon < ImageFaviconBase
DublinCoreModel.install_dublin_core(self)
end
@@ -89,7 +90,7 @@ EOC
end
class ChannelBase; include Maker::ImageFaviconModel; end
-
+
class ItemsBase
class ItemBase; include Maker::ImageItemModel; end
end
diff --git a/lib/rss/maker/itunes.rb b/lib/rss/maker/itunes.rb
index 7c5049129d..d964a4d942 100644
--- a/lib/rss/maker/itunes.rb
+++ b/lib/rss/maker/itunes.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/itunes'
require 'rss/maker/2.0'
@@ -12,8 +13,8 @@ module RSS
klass.def_other_element(full_name)
when :yes_other
def_yes_other_accessor(klass, full_name)
- when :yes_clean_other
- def_yes_clean_other_accessor(klass, full_name)
+ when :explicit_clean_other
+ def_explicit_clean_other_accessor(klass, full_name)
when :csv
def_csv_accessor(klass, full_name)
when :element, :attribute
@@ -42,11 +43,11 @@ module RSS
EOC
end
- def def_yes_clean_other_accessor(klass, full_name)
+ def def_explicit_clean_other_accessor(klass, full_name)
klass.def_other_element(full_name)
klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
def #{full_name}?
- Utils::YesCleanOther.parse(#{full_name})
+ Utils::ExplicitCleanOther.parse(#{full_name})
end
EOC
end
@@ -176,7 +177,7 @@ module RSS
%w(hour minute second).each do |name|
attr_reader(name)
- add_need_initialize_variable(name, '0')
+ add_need_initialize_variable(name, 0)
end
def content=(content)
diff --git a/lib/rss/maker/slash.rb b/lib/rss/maker/slash.rb
index 27adef3832..3bd82d3057 100644
--- a/lib/rss/maker/slash.rb
+++ b/lib/rss/maker/slash.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/slash'
require 'rss/maker/1.0'
diff --git a/lib/rss/maker/syndication.rb b/lib/rss/maker/syndication.rb
index b81230457c..840b70229a 100644
--- a/lib/rss/maker/syndication.rb
+++ b/lib/rss/maker/syndication.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/syndication'
require 'rss/maker/1.0'
diff --git a/lib/rss/maker/taxonomy.rb b/lib/rss/maker/taxonomy.rb
index 211603840f..76a2d1600d 100644
--- a/lib/rss/maker/taxonomy.rb
+++ b/lib/rss/maker/taxonomy.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/taxonomy'
require 'rss/maker/1.0'
require 'rss/maker/dublincore'
@@ -72,12 +73,12 @@ EOC
class TaxonomyTopicBase < Base
include DublinCoreModel
include TaxonomyTopicsModel
-
+
attr_accessor :value
add_need_initialize_variable("value")
alias_method(:taxo_link, :value)
alias_method(:taxo_link=, :value=)
-
+
def have_required_values?
@value
end
@@ -88,11 +89,11 @@ EOC
class RSSBase
include TaxonomyTopicModel
end
-
+
class ChannelBase
include TaxonomyTopicsModel
end
-
+
class ItemsBase
class ItemBase
include TaxonomyTopicsModel
diff --git a/lib/rss/maker/trackback.rb b/lib/rss/maker/trackback.rb
index 278fe53ebe..f97691c608 100644
--- a/lib/rss/maker/trackback.rb
+++ b/lib/rss/maker/trackback.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require 'rss/trackback'
require 'rss/maker/1.0'
require 'rss/maker/2.0'
@@ -19,7 +20,7 @@ module RSS
class TrackBackAboutBase < Base
attr_accessor :value
add_need_initialize_variable("value")
-
+
alias_method(:resource, :value)
alias_method(:resource=, :value=)
alias_method(:content, :value)
diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb
index 9e4919223c..a9842e6d40 100644
--- a/lib/rss/parser.rb
+++ b/lib/rss/parser.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "forwardable"
require "open-uri"
@@ -34,8 +35,8 @@ module RSS
class NotValidXMLParser < Error
def initialize(parser)
super("#{parser} is not an available XML parser. " <<
- "Available XML parser"<<
- (AVAILABLE_PARSERS.size > 1 ? "s are ": " is ") <<
+ "Available XML parser" <<
+ (AVAILABLE_PARSERS.size > 1 ? "s are " : " is ") <<
"#{AVAILABLE_PARSERS.inspect}.")
end
end
@@ -98,7 +99,7 @@ module RSS
return rss if maybe_xml?(rss)
uri = to_uri(rss)
-
+
if uri.respond_to?(:read)
uri.read
elsif !rss.tainted? and File.readable?(rss)
@@ -113,7 +114,7 @@ module RSS
source.is_a?(String) and /</ =~ source
end
- # Attempt to convert rss to a URI, but just return it if
+ # Attempt to convert rss to a URI, but just return it if
# there's a ::URI::Error
def to_uri(rss)
return rss if rss.is_a?(::URI::Generic)
@@ -133,7 +134,7 @@ module RSS
listener.raise_for_undefined_entity?
end
end
-
+
def initialize(rss)
@listener = self.class.listener.new
@rss = rss
@@ -196,13 +197,13 @@ module RSS
def available_tags(uri)
(@@accessor_bases[uri] || {}).keys
end
-
+
# register uri against this name.
def register_uri(uri, name)
@@registered_uris[name] ||= {}
@@registered_uris[name][uri] = nil
end
-
+
# test if this uri is registered against this name
def uri_registered?(uri, name)
@@registered_uris[name].has_key?(uri)
@@ -220,9 +221,7 @@ module RSS
name = (@@class_names[uri] || {})[tag_name]
return name if name
- tag_name = tag_name.gsub(/[_\-]([a-z]?)/) do
- $1.upcase
- end
+ tag_name = tag_name.gsub(/[_\-]([a-z]?)/) {$1.upcase}
tag_name[0, 1].upcase + tag_name[1..-1]
end
@@ -230,11 +229,11 @@ module RSS
install_accessor_base(uri, name, accessor_base)
def_get_text_element(uri, name, *get_file_and_line_from_caller(1))
end
-
+
def raise_for_undefined_entity?
true
end
-
+
private
# set the accessor for the uri, tag_name pair
def install_accessor_base(uri, tag_name, accessor_base)
@@ -281,7 +280,7 @@ module RSS
@xml_element = nil
@last_xml_element = nil
end
-
+
# set instance vars for version, encoding, standalone
def xmldecl(version, encoding, standalone)
@version, @encoding, @standalone = version, encoding, standalone
@@ -389,14 +388,12 @@ module RSS
def start_else_element(local, prefix, attrs, ns)
class_name = self.class.class_name(_ns(ns, prefix), local)
current_class = @last_element.class
- if class_name and
- (current_class.const_defined?(class_name) or
- current_class.constants.include?(class_name))
+ if known_class?(current_class, class_name)
next_class = current_class.const_get(class_name)
start_have_something_element(local, prefix, attrs, ns, next_class)
else
if !@do_validate or @ignore_unknown_element
- @proc_stack.push(nil)
+ @proc_stack.push(setup_next_element_in_unknown_element)
else
parent = "ROOT ELEMENT???"
if current_class.tag_name
@@ -407,19 +404,42 @@ module RSS
end
end
- NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/
+ if Module.method(:const_defined?).arity == -1
+ def known_class?(target_class, class_name)
+ class_name and
+ (target_class.const_defined?(class_name, false) or
+ target_class.constants.include?(class_name.to_sym))
+ end
+ else
+ def known_class?(target_class, class_name)
+ class_name and
+ (target_class.const_defined?(class_name) or
+ target_class.constants.include?(class_name))
+ end
+ end
+
+ NAMESPLIT = /^(?:([\w:][-\w.]*):)?([\w:][-\w.]*)/
def split_name(name)
name =~ NAMESPLIT
[$1 || '', $2]
end
- def check_ns(tag_name, prefix, ns, require_uri)
- unless _ns(ns, prefix) == require_uri
- if @do_validate
+ def check_ns(tag_name, prefix, ns, require_uri, ignore_unknown_element=nil)
+ if _ns(ns, prefix) == require_uri
+ true
+ else
+ if ignore_unknown_element.nil?
+ ignore_unknown_element = @ignore_unknown_element
+ end
+
+ if ignore_unknown_element
+ false
+ elsif @do_validate
raise NSError.new(tag_name, prefix, require_uri)
else
# Force bind required URI with prefix
@ns_stack.last[prefix] = require_uri
+ true
end
end
end
@@ -427,7 +447,7 @@ module RSS
def start_get_text_element(tag_name, prefix, ns, required_uri)
pr = Proc.new do |text, tags|
setter = self.class.setter(required_uri, tag_name)
- if @last_element.respond_to?(setter)
+ if setter and @last_element.respond_to?(setter)
if @do_validate
getter = self.class.getter(required_uri, tag_name)
if @last_element.__send__(getter)
@@ -446,9 +466,12 @@ module RSS
end
def start_have_something_element(tag_name, prefix, attrs, ns, klass)
- check_ns(tag_name, prefix, ns, klass.required_uri)
- attributes = collect_attributes(tag_name, prefix, attrs, ns, klass)
- @proc_stack.push(setup_next_element(tag_name, klass, attributes))
+ if check_ns(tag_name, prefix, ns, klass.required_uri)
+ attributes = collect_attributes(tag_name, prefix, attrs, ns, klass)
+ @proc_stack.push(setup_next_element(tag_name, klass, attributes))
+ else
+ @proc_stack.push(setup_next_element_in_unknown_element)
+ end
end
def collect_attributes(tag_name, prefix, attrs, ns, klass)
@@ -504,7 +527,7 @@ module RSS
else
if klass.have_content?
if @last_element.need_base64_encode?
- text = Base64.decode64(text.lstrip)
+ text = text.lstrip.unpack("m").first
end
@last_element.content = text
end
@@ -515,9 +538,15 @@ module RSS
@last_element = previous
end
end
+
+ def setup_next_element_in_unknown_element
+ current_element, @last_element = @last_element, nil
+ Proc.new {@last_element = current_element}
+ end
end
unless const_defined? :AVAILABLE_PARSER_LIBRARIES
+ # The list of all available libraries for parsing.
AVAILABLE_PARSER_LIBRARIES = [
["rss/xmlparser", :XMLParserParser],
["rss/xmlscanner", :XMLScanParser],
@@ -525,6 +554,7 @@ module RSS
]
end
+ # The list of all available parsers, in constant form.
AVAILABLE_PARSERS = []
AVAILABLE_PARSER_LIBRARIES.each do |lib, parser|
diff --git a/lib/rss/rexmlparser.rb b/lib/rss/rexmlparser.rb
index 4dabf59199..ef0595e447 100644
--- a/lib/rss/rexmlparser.rb
+++ b/lib/rss/rexmlparser.rb
@@ -1,13 +1,9 @@
+# frozen_string_literal: false
require "rexml/document"
require "rexml/streamlistener"
-/\A(\d+)\.(\d+)(?:\.\d+)+\z/ =~ REXML::Version
-if ([$1.to_i, $2.to_i] <=> [2, 5]) < 0
- raise LoadError, "needs REXML 2.5 or later (#{REXML::Version})"
-end
-
module RSS
-
+
class REXMLParser < BaseParser
class << self
@@ -15,7 +11,7 @@ module RSS
REXMLListener
end
end
-
+
private
def _parse
begin
@@ -28,9 +24,9 @@ module RSS
raise NotWellFormedError.new(line){e.message}
end
end
-
+
end
-
+
class REXMLListener < BaseListener
include REXML::StreamListener
@@ -41,7 +37,7 @@ module RSS
false
end
end
-
+
def xmldecl(version, encoding, standalone)
super(version, encoding, standalone == "yes")
# Encoding is converted to UTF-8 when REXML parse XML.
diff --git a/lib/rss/rss.rb b/lib/rss/rss.rb
index 5aa4a2cedd..db87e11ad5 100644
--- a/lib/rss/rss.rb
+++ b/lib/rss/rss.rb
@@ -1,8 +1,17 @@
+# frozen_string_literal: false
require "time"
class Time
class << self
unless respond_to?(:w3cdtf)
+ # This method converts a W3CDTF string date/time format to Time object.
+ #
+ # The W3CDTF format is defined here: http://www.w3.org/TR/NOTE-datetime
+ #
+ # Time.w3cdtf('2003-02-15T13:50:05-05:00')
+ # # => 2003-02-15 10:50:05 -0800
+ # Time.w3cdtf('2003-02-15T13:50:05-05:00').class
+ # # => Time
def w3cdtf(date)
if /\A\s*
(-?\d+)-(\d\d)-(\d\d)
@@ -20,7 +29,7 @@ class Time
datetime = apply_offset(*(datetime + [off]))
datetime << usec
time = Time.utc(*datetime)
- time.localtime unless zone_utc?(zone)
+ force_zone!(time, zone, off)
time
else
datetime << usec
@@ -34,17 +43,25 @@ class Time
end
unless method_defined?(:w3cdtf)
+ # This method converts a Time object to a String. The String contains the
+ # time in W3CDTF date/time format.
+ #
+ # The W3CDTF format is defined here: http://www.w3.org/TR/NOTE-datetime
+ #
+ # Time.now.w3cdtf
+ # # => "2013-08-26T14:12:10.817124-07:00"
def w3cdtf
if usec.zero?
fraction_digits = 0
else
- fraction_digits = Math.log10(usec.to_s.sub(/0*$/, '').to_i).floor + 1
+ fraction_digits = strftime('%6N').index(/0*\z/)
end
xmlschema(fraction_digits)
end
end
end
+
require "English"
require "rss/utils"
require "rss/converter"
@@ -52,14 +69,20 @@ require "rss/xml-stylesheet"
module RSS
- VERSION = "0.2.4"
+ # The current version of RSS
+ VERSION = "0.2.7"
+ # The URI of the RSS 1.0 specification
URI = "http://purl.org/rss/1.0/"
- DEBUG = false
+ DEBUG = false # :nodoc:
+ # The basic error all other RSS errors stem from. Rescue this error if you
+ # want to handle any given RSS error and you don't care about the details.
class Error < StandardError; end
+ # RSS, being an XML-based format, has namespace support. If two namespaces are
+ # declared with the same name, an OverlappedPrefixError will be raised.
class OverlappedPrefixError < Error
attr_reader :prefix
def initialize(prefix)
@@ -67,8 +90,13 @@ module RSS
end
end
+ # The InvalidRSSError error is the base class for a variety of errors
+ # related to a poorly-formed RSS feed. Rescue this error if you only
+ # care that a file could be invalid, but don't care how it is invalid.
class InvalidRSSError < Error; end
+ # Since RSS is based on XML, it must have opening and closing tags that
+ # match. If they don't, a MissingTagError will be raised.
class MissingTagError < InvalidRSSError
attr_reader :tag, :parent
def initialize(tag, parent)
@@ -77,6 +105,9 @@ module RSS
end
end
+ # Some tags must only exist a specific number of times in a given RSS feed.
+ # If a feed has too many occurrences of one of these tags, a TooMuchTagError
+ # will be raised.
class TooMuchTagError < InvalidRSSError
attr_reader :tag, :parent
def initialize(tag, parent)
@@ -85,6 +116,8 @@ module RSS
end
end
+ # Certain attributes are required on specific tags in an RSS feed. If a feed
+ # is missing one of these attributes, a MissingAttributeError is raised.
class MissingAttributeError < InvalidRSSError
attr_reader :tag, :attribute
def initialize(tag, attribute)
@@ -93,6 +126,8 @@ module RSS
end
end
+ # RSS does not allow for free-form tag names, so if an RSS feed contains a
+ # tag that we don't know about, an UnknownTagError is raised.
class UnknownTagError < InvalidRSSError
attr_reader :tag, :uri
def initialize(tag, uri)
@@ -101,6 +136,7 @@ module RSS
end
end
+ # Raised when an unexpected tag is encountered.
class NotExpectedTagError < InvalidRSSError
attr_reader :tag, :uri, :parent
def initialize(tag, uri, parent)
@@ -109,8 +145,10 @@ module RSS
end
end
# For backward compatibility :X
- NotExceptedTagError = NotExpectedTagError
+ NotExceptedTagError = NotExpectedTagError # :nodoc:
+ # Attributes are in key-value form, and if there's no value provided for an
+ # attribute, a NotAvailableValueError will be raised.
class NotAvailableValueError < InvalidRSSError
attr_reader :tag, :value, :attribute
def initialize(tag, value, attribute=nil)
@@ -122,6 +160,7 @@ module RSS
end
end
+ # Raised when an unknown conversion error occurs.
class UnknownConversionMethodError < Error
attr_reader :to, :from
def initialize(to, from)
@@ -131,8 +170,9 @@ module RSS
end
end
# for backward compatibility
- UnknownConvertMethod = UnknownConversionMethodError
+ UnknownConvertMethod = UnknownConversionMethodError # :nodoc:
+ # Raised when a conversion failure occurs.
class ConversionError < Error
attr_reader :string, :to, :from
def initialize(string, to, from)
@@ -143,6 +183,7 @@ module RSS
end
end
+ # Raised when a required variable is not set.
class NotSetError < Error
attr_reader :name, :variables
def initialize(name, variables)
@@ -152,6 +193,7 @@ module RSS
end
end
+ # Raised when a RSS::Maker attempts to use an unknown maker.
class UnsupportedMakerVersionError < Error
attr_reader :version
def initialize(version)
@@ -228,7 +270,7 @@ EOC
else
rv << value
end
- rv << "</#{elem_name}>"
+ rv << "</#{elem_name}>"
rv
else
''
@@ -248,7 +290,7 @@ EOC
# accessor
convert_attr_reader name
date_writer(name, type, disp_name)
-
+
install_element(name) do |n, elem_name|
<<-EOC
if @#{n}
@@ -259,7 +301,7 @@ EOC
else
rv << value
end
- rv << "</#{elem_name}>"
+ rv << "</#{elem_name}>"
rv
else
''
@@ -284,7 +326,6 @@ EOC
def inherit_convert_attr_reader(*attrs)
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{attr}_without_inherit
convert(@#{attr})
@@ -305,7 +346,6 @@ EOC
def uri_convert_attr_reader(*attrs)
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{attr}_without_base
convert(@#{attr})
@@ -326,7 +366,6 @@ EOC
def convert_attr_reader(*attrs)
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{attr}
convert(@#{attr})
@@ -335,13 +374,12 @@ EOC
end
end
- def yes_clean_other_attr_reader(*attrs)
+ def explicit_clean_other_attr_reader(*attrs)
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
attr_reader(:#{attr})
def #{attr}?
- YesCleanOther.parse(@#{attr})
+ ExplicitCleanOther.parse(@#{attr})
end
EOC
end
@@ -349,7 +387,6 @@ EOC
def yes_other_attr_reader(*attrs)
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
attr_reader(:#{attr})
def #{attr}?
@@ -367,7 +404,6 @@ EOC
end
separator ||= ", "
attrs.each do |attr|
- attr = attr.id2name if attr.kind_of?(Integer)
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
attr_reader(:#{attr})
def #{attr}_content
@@ -508,7 +544,7 @@ EOC
EOC
end
- def yes_clean_other_writer(name, disp_name=name)
+ def explicit_clean_other_writer(name, disp_name=name)
module_eval(<<-EOC, __FILE__, __LINE__ + 1)
def #{name}=(value)
value = (value ? "yes" : "no") if [true, false].include?(value)
@@ -560,11 +596,10 @@ EOC
def #{accessor_name}=(*args)
receiver = self.class.name
- warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \
- "Don't use `\#{receiver}\##{accessor_name} = XXX'/" \
+ warn("Don't use `\#{receiver}\##{accessor_name} = XXX'/" \
"`\#{receiver}\#set_#{accessor_name}(XXX)'. " \
"Those APIs are not sense of Ruby. " \
- "Use `\#{receiver}\##{plural_name} << XXX' instead of them.")
+ "Use `\#{receiver}\##{plural_name} << XXX' instead of them.", uplevel: 1)
if args.size == 1
@#{accessor_name}.push(args[0])
else
@@ -633,7 +668,7 @@ EOC
include SetupMaker
INDENT = " "
-
+
MUST_CALL_VALIDATORS = {}
MODELS = []
GET_ATTRIBUTES = []
@@ -670,18 +705,18 @@ EOC
end
def inherited(klass)
- klass.const_set("MUST_CALL_VALIDATORS", {})
- klass.const_set("MODELS", [])
- klass.const_set("GET_ATTRIBUTES", [])
- klass.const_set("HAVE_CHILDREN_ELEMENTS", [])
- klass.const_set("TO_ELEMENT_METHODS", [])
- klass.const_set("NEED_INITIALIZE_VARIABLES", [])
- klass.const_set("PLURAL_FORMS", {})
+ klass.const_set(:MUST_CALL_VALIDATORS, {})
+ klass.const_set(:MODELS, [])
+ klass.const_set(:GET_ATTRIBUTES, [])
+ klass.const_set(:HAVE_CHILDREN_ELEMENTS, [])
+ klass.const_set(:TO_ELEMENT_METHODS, [])
+ klass.const_set(:NEED_INITIALIZE_VARIABLES, [])
+ klass.const_set(:PLURAL_FORMS, {})
tag_name = klass.name.split(/::/).last
tag_name[0, 1] = tag_name[0, 1].downcase
- klass.instance_variable_set("@tag_name", tag_name)
- klass.instance_variable_set("@have_content", false)
+ klass.instance_variable_set(:@tag_name, tag_name)
+ klass.instance_variable_set(:@have_content, false)
end
def install_must_call_validator(prefix, uri)
@@ -727,8 +762,8 @@ EOC
text_type_writer name, disp_name
when :content
content_writer name, disp_name
- when :yes_clean_other
- yes_clean_other_writer name, disp_name
+ when :explicit_clean_other
+ explicit_clean_other_writer name, disp_name
when :yes_other
yes_other_writer name, disp_name
when :csv
@@ -746,8 +781,8 @@ EOC
inherit_convert_attr_reader name
when :uri
uri_convert_attr_reader name
- when :yes_clean_other
- yes_clean_other_attr_reader name
+ when :explicit_clean_other
+ explicit_clean_other_attr_reader name
when :yes_other
yes_other_attr_reader name
when :csv
@@ -829,7 +864,7 @@ EOC
def full_name
tag_name
end
-
+
def converter=(converter)
@converter = converter
targets = children.dup
@@ -864,7 +899,7 @@ EOC
ensure
@do_validate = do_validate
end
-
+
def validate_for_stream(tags, ignore_unknown_element=true)
validate_attribute
__validate(ignore_unknown_element, tags, false)
@@ -921,7 +956,7 @@ EOC
children = child
children.any? {|c| c.have_required_elements?}
else
- !child.to_s.empty?
+ not child.nil?
end
else
true
@@ -984,7 +1019,7 @@ EOC
end_tag = "\n#{indent}</#{full_name}>"
end
end
-
+
start_tag + content.join("\n") + end_tag
end
@@ -1009,7 +1044,7 @@ EOC
end
attrs
end
-
+
def tag_name_with_prefix(prefix)
"#{prefix}:#{tag_name}"
end
@@ -1092,9 +1127,8 @@ EOC
tags = tags.sort_by {|x| element_names.index(x) || tags_size}
end
- _tags = tags.dup if tags
models.each_with_index do |model, i|
- name, model_uri, occurs, getter = model
+ name, _, occurs, = model
if DEBUG
p "before"
@@ -1200,7 +1234,7 @@ EOC
__send__(self.class.xml_getter).to_s
else
_content = content
- _content = Base64.encode64(_content) if need_base64_encode?
+ _content = [_content].pack("m0") if need_base64_encode?
h(_content)
end
end
@@ -1209,7 +1243,7 @@ EOC
module RootElementMixin
include XMLStyleSheetMixin
-
+
attr_reader :output_encoding
attr_reader :feed_type, :feed_subtype, :feed_version
attr_accessor :version, :encoding, :standalone
@@ -1295,7 +1329,7 @@ EOC
rv << "?>\n"
rv
end
-
+
def ns_declarations
decls = {}
self.class::NSPOOL.collect do |prefix, uri|
diff --git a/lib/rss/slash.rb b/lib/rss/slash.rb
index f102413b46..0055fc9f88 100644
--- a/lib/rss/slash.rb
+++ b/lib/rss/slash.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: false
require 'rss/1.0'
module RSS
+ # The prefix for the Slash XML namespace.
SLASH_PREFIX = 'slash'
+ # The URI of the Slash specification.
SLASH_URI = "http://purl.org/rss/1.0/modules/slash/"
RDF.install_ns(SLASH_PREFIX, SLASH_URI)
diff --git a/lib/rss/syndication.rb b/lib/rss/syndication.rb
index 3eb15429f6..8f9620f9f3 100644
--- a/lib/rss/syndication.rb
+++ b/lib/rss/syndication.rb
@@ -1,18 +1,20 @@
+# frozen_string_literal: false
require "rss/1.0"
module RSS
-
+ # The prefix for the Syndication XML namespace.
SY_PREFIX = 'sy'
+ # The URI of the Syndication specification.
SY_URI = "http://purl.org/rss/1.0/modules/syndication/"
RDF.install_ns(SY_PREFIX, SY_URI)
module SyndicationModel
-
+
extend BaseModel
-
+
ELEMENTS = []
-
+
def self.append_features(klass)
super
@@ -46,7 +48,7 @@ module RSS
private
SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly)
- def validate_sy_updatePeriod(value)
+ def validate_sy_updatePeriod(value) # :nodoc:
unless SY_UPDATEPERIOD_AVAILABLE_VALUES.include?(value)
raise NotAvailableValueError.new("updatePeriod", value)
end
diff --git a/lib/rss/taxonomy.rb b/lib/rss/taxonomy.rb
index 276f63b05d..b7ea219e8c 100644
--- a/lib/rss/taxonomy.rb
+++ b/lib/rss/taxonomy.rb
@@ -1,13 +1,16 @@
+# frozen_string_literal: false
require "rss/1.0"
require "rss/dublincore"
module RSS
-
+ # The prefix for the Taxonomy XML namespace.
TAXO_PREFIX = "taxo"
+ # The URI for the specification of the Taxonomy XML namespace.
TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/"
RDF.install_ns(TAXO_PREFIX, TAXO_URI)
+ # The listing of all the taxonomy elements, with the appropriate namespace.
TAXO_ELEMENTS = []
%w(link).each do |name|
@@ -24,7 +27,7 @@ module RSS
module TaxonomyTopicsModel
extend BaseModel
-
+
def self.append_features(klass)
super
@@ -37,21 +40,21 @@ module RSS
class TaxonomyTopics < Element
include RSS10
-
+
Bag = ::RSS::RDF::Bag
class << self
def required_prefix
TAXO_PREFIX
end
-
+
def required_uri
TAXO_URI
end
end
@tag_name = "topics"
-
+
install_have_child_element("Bag", RDF::URI, nil)
install_must_call_validator('rdf', RDF::URI)
@@ -84,10 +87,10 @@ module RSS
end
end
end
-
+
module TaxonomyTopicModel
extend BaseModel
-
+
def self.append_features(klass)
super
var_name = "#{TAXO_PREFIX}_topic"
@@ -99,12 +102,12 @@ module RSS
include DublinCoreModel
include TaxonomyTopicsModel
-
+
class << self
def required_prefix
TAXO_PREFIX
end
-
+
def required_uri
TAXO_URI
end
@@ -115,7 +118,7 @@ module RSS
install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil,
"#{RDF::PREFIX}:about")
install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link")
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
diff --git a/lib/rss/trackback.rb b/lib/rss/trackback.rb
index ee2491f332..1a3c3849b5 100644
--- a/lib/rss/trackback.rb
+++ b/lib/rss/trackback.rb
@@ -1,7 +1,10 @@
+# frozen_string_literal: false
+# This file contains the implementation of trackbacks. It is entirely internal
+# and not useful to outside developers.
require 'rss/1.0'
require 'rss/2.0'
-module RSS
+module RSS # :nodoc: all
TRACKBACK_PREFIX = 'trackback'
TRACKBACK_URI = 'http://madskills.com/public/xml/rss/module/trackback/'
@@ -23,7 +26,7 @@ module RSS
module BaseTrackBackModel
ELEMENTS = %w(ping about)
-
+
def append_features(klass)
super
@@ -47,7 +50,7 @@ module RSS
end
EOC
end
-
+
[%w(about s)].each do |name, postfix|
var_name = "#{TRACKBACK_PREFIX}_#{name}"
klass_name = "TrackBack#{Utils.to_class_name(name)}"
@@ -105,7 +108,7 @@ module RSS
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
@@ -141,17 +144,17 @@ module RSS
include RSS10
class << self
-
+
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
end
-
+
@tag_name = "about"
[
@@ -163,7 +166,7 @@ module RSS
alias_method(:value, :resource)
alias_method(:value=, :resource=)
-
+
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
@@ -185,7 +188,7 @@ module RSS
def setup_maker_attributes(about)
about.resource = self.resource
end
-
+
end
end
@@ -197,7 +200,7 @@ module RSS
include RSS09
@tag_name = "ping"
-
+
content_setup
class << self
@@ -205,13 +208,13 @@ module RSS
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
end
-
+
alias_method(:value, :content)
alias_method(:value=, :content=)
@@ -223,26 +226,26 @@ module RSS
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
+
end
class TrackBackAbout < Element
include RSS09
@tag_name = "about"
-
+
content_setup
class << self
-
+
def required_prefix
TRACKBACK_PREFIX
end
-
+
def required_uri
TRACKBACK_URI
end
@@ -260,11 +263,11 @@ module RSS
self.content = args[0]
end
end
-
+
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
+
end
end
diff --git a/lib/rss/utils.rb b/lib/rss/utils.rb
index 0e4001e1f3..9203df9a9b 100644
--- a/lib/rss/utils.rb
+++ b/lib/rss/utils.rb
@@ -1,14 +1,85 @@
+# frozen_string_literal: false
module RSS
+
+ ##
+ # RSS::Utils is a module that holds various utility functions that are used
+ # across many parts of the rest of the RSS library. Like most modules named
+ # some variant of 'util', its methods are probably not particularly useful
+ # to those who aren't developing the library itself.
module Utils
module_function
- # Convert a name_with_underscores to CamelCase.
+ # Given a +name+ in a name_with_underscores or a name-with-dashes format,
+ # returns the CamelCase version of +name+.
+ #
+ # If the +name+ is already CamelCased, nothing happens.
+ #
+ # Examples:
+ #
+ # require 'rss/utils'
+ #
+ # RSS::Utils.to_class_name("sample_name")
+ # # => "SampleName"
+ # RSS::Utils.to_class_name("with-dashes")
+ # # => "WithDashes"
+ # RSS::Utils.to_class_name("CamelCase")
+ # # => "CamelCase"
def to_class_name(name)
name.split(/[_\-]/).collect do |part|
"#{part[0, 1].upcase}#{part[1..-1]}"
end.join("")
end
-
+
+ # Returns an array of two elements: the filename where the calling method
+ # is located, and the line number where it is defined.
+ #
+ # Takes an optional argument +i+, which specifies how many callers up the
+ # stack to look.
+ #
+ # Examples:
+ #
+ # require 'rss/utils'
+ #
+ # def foo
+ # p RSS::Utils.get_file_and_line_from_caller
+ # p RSS::Utils.get_file_and_line_from_caller(1)
+ # end
+ #
+ # def bar
+ # foo
+ # end
+ #
+ # def baz
+ # bar
+ # end
+ #
+ # baz
+ # # => ["test.rb", 5]
+ # # => ["test.rb", 9]
+ #
+ # If +i+ is not given, or is the default value of 0, it attempts to figure
+ # out the correct value. This is useful when in combination with
+ # instance_eval. For example:
+ #
+ # require 'rss/utils'
+ #
+ # def foo
+ # p RSS::Utils.get_file_and_line_from_caller(1)
+ # end
+ #
+ # def bar
+ # foo
+ # end
+ #
+ # instance_eval <<-RUBY, *RSS::Utils.get_file_and_line_from_caller
+ # def baz
+ # bar
+ # end
+ # RUBY
+ #
+ # baz
+ #
+ # # => ["test.rb", 8]
def get_file_and_line_from_caller(i=0)
file, line, = caller[i].split(':')
line = line.to_i
@@ -16,12 +87,24 @@ module RSS
[file, line]
end
- # escape '&', '"', '<' and '>' for use in HTML.
+ # Takes a string +s+ with some HTML in it, and escapes '&', '"', '<' and '>', by
+ # replacing them with the appropriate entities.
+ #
+ # This method is also aliased to h, for convenience.
+ #
+ # Examples:
+ #
+ # require 'rss/utils'
+ #
+ # RSS::Utils.html_escape("Dungeons & Dragons")
+ # # => "Dungeons &amp; Dragons"
+ # RSS::Utils.h(">_>")
+ # # => "&gt;_&gt;"
def html_escape(s)
s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
end
alias h html_escape
-
+
# If +value+ is an instance of class +klass+, return it, else
# create a new instance of +klass+ with value +value+.
def new_with_value_if_need(klass, value)
@@ -32,20 +115,26 @@ module RSS
end
end
+ # This method is used inside of several different objects to determine
+ # if special behavior is needed in the constructor.
+ #
+ # Special behavior is needed if the array passed in as +args+ has
+ # +true+ or +false+ as its value, and if the second element of +args+
+ # is a hash.
def element_initialize_arguments?(args)
[true, false].include?(args[0]) and args[1].is_a?(Hash)
end
- module YesCleanOther
+ module ExplicitCleanOther
module_function
def parse(value)
if [true, false, nil].include?(value)
value
else
case value.to_s
- when /\Ayes\z/i
+ when /\Aexplicit|yes|true\z/i
true
- when /\Aclean\z/i
+ when /\Aclean|no|false\z/i
false
else
nil
diff --git a/lib/rss/xml-stylesheet.rb b/lib/rss/xml-stylesheet.rb
index 559d6bcd56..be9cfaaf64 100644
--- a/lib/rss/xml-stylesheet.rb
+++ b/lib/rss/xml-stylesheet.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/utils"
module RSS
@@ -8,7 +9,7 @@ module RSS
super
@xml_stylesheets = []
end
-
+
private
def xml_stylesheet_pi
xsss = @xml_stylesheets.collect do |xss|
@@ -94,7 +95,7 @@ module RSS
xss.__send__("#{attr}=", __send__(attr))
end
end
-
+
private
def guess_type(filename)
/\.([^.]+)$/ =~ filename
diff --git a/lib/rss/xml.rb b/lib/rss/xml.rb
index 1ae878b772..cda8668044 100644
--- a/lib/rss/xml.rb
+++ b/lib/rss/xml.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require "rss/utils"
module RSS
diff --git a/lib/rss/xmlparser.rb b/lib/rss/xmlparser.rb
index 3dfe7d461a..cb2dd2afdd 100644
--- a/lib/rss/xmlparser.rb
+++ b/lib/rss/xmlparser.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
begin
require "xml/parser"
rescue LoadError
@@ -20,15 +21,16 @@ end
module XML
class Parser
unless defined?(Error)
- Error = ::XMLParserError
+ # This error is legacy, so we just set it to the new one
+ Error = ::XMLParserError # :nodoc:
end
end
end
module RSS
-
+
class REXMLLikeXMLParser < ::XML::Parser
-
+
include ::XML::Encoding_ja
def listener=(listener)
@@ -38,7 +40,7 @@ module RSS
def startElement(name, attrs)
@listener.tag_start(name, attrs)
end
-
+
def endElement(name)
@listener.tag_end(name)
end
@@ -64,7 +66,7 @@ module RSS
XMLParserListener
end
end
-
+
private
def _parse
begin
@@ -75,13 +77,13 @@ module RSS
raise NotWellFormedError.new(parser.line){e.message}
end
end
-
+
end
-
+
class XMLParserListener < BaseListener
include ListenerMixin
-
+
def xmldecl(version, encoding, standalone)
super
# Encoding is converted to UTF-8 when XMLParser parses XML.
diff --git a/lib/rss/xmlscanner.rb b/lib/rss/xmlscanner.rb
index 61b9fa6bf4..6e3b13d2f5 100644
--- a/lib/rss/xmlscanner.rb
+++ b/lib/rss/xmlscanner.rb
@@ -1,16 +1,17 @@
+# frozen_string_literal: false
require 'xmlscan/scanner'
require 'stringio'
module RSS
-
+
class XMLScanParser < BaseParser
-
+
class << self
def listener
XMLScanListener
end
end
-
+
private
def _parse
begin
@@ -26,11 +27,11 @@ module RSS
raise NotWellFormedError.new(lineno){e.message}
end
end
-
+
end
class XMLScanListener < BaseListener
-
+
include XMLScan::Visitor
include ListenerMixin