зеркало из https://github.com/github/ruby.git
463 строки
11 KiB
Ruby
463 строки
11 KiB
Ruby
# 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
|
|
|
|
class Rss < Element
|
|
|
|
include RSS09
|
|
include RootElementMixin
|
|
|
|
%w(channel).each do |name|
|
|
install_have_child_element(name, "", nil)
|
|
end
|
|
|
|
attr_writer :feed_version
|
|
alias_method(:rss_version, :feed_version)
|
|
alias_method(:rss_version=, :feed_version=)
|
|
|
|
def initialize(feed_version, version=nil, encoding=nil, standalone=nil)
|
|
super
|
|
@feed_type = "rss"
|
|
end
|
|
|
|
def items
|
|
if @channel
|
|
@channel.items
|
|
else
|
|
[]
|
|
end
|
|
end
|
|
|
|
def image
|
|
if @channel
|
|
@channel.image
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def textinput
|
|
if @channel
|
|
@channel.textInput
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
|
|
def setup_maker_elements(maker)
|
|
super
|
|
items.each do |item|
|
|
item.setup_maker(maker.items)
|
|
end
|
|
image.setup_maker(maker) if image
|
|
textinput.setup_maker(maker) if textinput
|
|
end
|
|
|
|
private
|
|
def _attrs
|
|
[
|
|
["version", true, "feed_version"],
|
|
]
|
|
end
|
|
|
|
class Channel < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["title", nil, :text],
|
|
["link", nil, :text],
|
|
["description", nil, :text],
|
|
["language", nil, :text],
|
|
["copyright", "?", :text],
|
|
["managingEditor", "?", :text],
|
|
["webMaster", "?", :text],
|
|
["rating", "?", :text],
|
|
["pubDate", "?", :date, :rfc822],
|
|
["lastBuildDate", "?", :date, :rfc822],
|
|
["docs", "?", :text],
|
|
["cloud", "?", :have_attribute],
|
|
["skipDays", "?", :have_child],
|
|
["skipHours", "?", :have_child],
|
|
["image", nil, :have_child],
|
|
["item", "*", :have_children],
|
|
["textInput", "?", :have_child],
|
|
].each do |name, occurs, type, *args|
|
|
__send__("install_#{type}_element", name, "", occurs, name, *args)
|
|
end
|
|
alias date pubDate
|
|
alias date= pubDate=
|
|
|
|
private
|
|
def maker_target(maker)
|
|
maker.channel
|
|
end
|
|
|
|
def setup_maker_elements(channel)
|
|
super
|
|
[
|
|
[skipDays, "day"],
|
|
[skipHours, "hour"],
|
|
].each do |skip, key|
|
|
if skip
|
|
skip.__send__("#{key}s").each do |val|
|
|
target_skips = channel.__send__("skip#{key.capitalize}s")
|
|
new_target = target_skips.__send__("new_#{key}")
|
|
new_target.content = val.content
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
def not_need_to_call_setup_maker_variables
|
|
%w(image textInput)
|
|
end
|
|
|
|
class SkipDays < Element
|
|
include RSS09
|
|
|
|
[
|
|
["day", "*"]
|
|
].each do |name, occurs|
|
|
install_have_children_element(name, "", occurs)
|
|
end
|
|
|
|
class Day < Element
|
|
include RSS09
|
|
|
|
content_setup
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.content = args[0]
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class SkipHours < Element
|
|
include RSS09
|
|
|
|
[
|
|
["hour", "*"]
|
|
].each do |name, occurs|
|
|
install_have_children_element(name, "", occurs)
|
|
end
|
|
|
|
class Hour < Element
|
|
include RSS09
|
|
|
|
content_setup(:integer)
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.content = args[0]
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
class Image < Element
|
|
|
|
include RSS09
|
|
|
|
%w(url title link).each do |name|
|
|
install_text_element(name, "", nil)
|
|
end
|
|
[
|
|
["width", :integer],
|
|
["height", :integer],
|
|
["description"],
|
|
].each do |name, type|
|
|
install_text_element(name, "", "?", name, type)
|
|
end
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.url = args[0]
|
|
self.title = args[1]
|
|
self.link = args[2]
|
|
self.width = args[3]
|
|
self.height = args[4]
|
|
self.description = args[5]
|
|
end
|
|
end
|
|
|
|
private
|
|
def maker_target(maker)
|
|
maker.image
|
|
end
|
|
end
|
|
|
|
class Cloud < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["domain", "", true],
|
|
["port", "", true, :integer],
|
|
["path", "", true],
|
|
["registerProcedure", "", true],
|
|
["protocol", "", true],
|
|
].each do |name, uri, required, type|
|
|
install_get_attribute(name, uri, required, type)
|
|
end
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.domain = args[0]
|
|
self.port = args[1]
|
|
self.path = args[2]
|
|
self.registerProcedure = args[3]
|
|
self.protocol = args[4]
|
|
end
|
|
end
|
|
end
|
|
|
|
class Item < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["title", '?', :text],
|
|
["link", '?', :text],
|
|
["description", '?', :text],
|
|
["category", '*', :have_children, "categories"],
|
|
["source", '?', :have_child],
|
|
["enclosure", '?', :have_child],
|
|
].each do |tag, occurs, type, *args|
|
|
__send__("install_#{type}_element", tag, "", occurs, tag, *args)
|
|
end
|
|
|
|
private
|
|
def maker_target(items)
|
|
if items.respond_to?("items")
|
|
# For backward compatibility
|
|
items = items.items
|
|
end
|
|
items.new_item
|
|
end
|
|
|
|
def setup_maker_element(item)
|
|
super
|
|
@enclosure.setup_maker(item) if @enclosure
|
|
@source.setup_maker(item) if @source
|
|
end
|
|
|
|
class Source < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["url", "", true]
|
|
].each do |name, uri, required|
|
|
install_get_attribute(name, uri, required)
|
|
end
|
|
|
|
content_setup
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.url = args[0]
|
|
self.content = args[1]
|
|
end
|
|
end
|
|
|
|
private
|
|
def maker_target(item)
|
|
item.source
|
|
end
|
|
|
|
def setup_maker_attributes(source)
|
|
source.url = url
|
|
source.content = content
|
|
end
|
|
end
|
|
|
|
class Enclosure < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["url", "", true],
|
|
["length", "", true, :integer],
|
|
["type", "", true],
|
|
].each do |name, uri, required, type|
|
|
install_get_attribute(name, uri, required, type)
|
|
end
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.url = args[0]
|
|
self.length = args[1]
|
|
self.type = args[2]
|
|
end
|
|
end
|
|
|
|
private
|
|
def maker_target(item)
|
|
item.enclosure
|
|
end
|
|
|
|
def setup_maker_attributes(enclosure)
|
|
enclosure.url = url
|
|
enclosure.length = length
|
|
enclosure.type = type
|
|
end
|
|
end
|
|
|
|
class Category < Element
|
|
|
|
include RSS09
|
|
|
|
[
|
|
["domain", "", false]
|
|
].each do |name, uri, required|
|
|
install_get_attribute(name, uri, required)
|
|
end
|
|
|
|
content_setup
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.domain = args[0]
|
|
self.content = args[1]
|
|
end
|
|
end
|
|
|
|
private
|
|
def maker_target(item)
|
|
item.new_category
|
|
end
|
|
|
|
def setup_maker_attributes(category)
|
|
category.domain = domain
|
|
category.content = content
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
class TextInput < Element
|
|
|
|
include RSS09
|
|
|
|
%w(title description name link).each do |name|
|
|
install_text_element(name, "", nil)
|
|
end
|
|
|
|
def initialize(*args)
|
|
if Utils.element_initialize_arguments?(args)
|
|
super
|
|
else
|
|
super()
|
|
self.title = args[0]
|
|
self.description = args[1]
|
|
self.name = args[2]
|
|
self.link = args[3]
|
|
end
|
|
end
|
|
|
|
private
|
|
def maker_target(maker)
|
|
maker.textinput
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
RSS09::ELEMENTS.each do |name|
|
|
BaseListener.install_get_text_element("", name, name)
|
|
end
|
|
|
|
module ListenerMixin
|
|
private
|
|
def initial_start_rss(tag_name, prefix, attrs, 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
|
|
@last_element = @rss
|
|
pr = Proc.new do |text, tags|
|
|
@rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate
|
|
end
|
|
@proc_stack.push(pr)
|
|
end
|
|
|
|
end
|
|
|
|
end
|