1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/lib/rss/maker/base.rb

933 lines
22 KiB
Ruby
Raw Normal View History

require 'forwardable'
require 'rss/rss'
module RSS
module Maker
module Base
def self.append_features(klass)
super
klass.module_eval(<<-EOC, __FILE__, __LINE__)
OTHER_ELEMENTS = []
NEED_INITIALIZE_VARIABLES = []
def self.inherited(subclass)
subclass.const_set("OTHER_ELEMENTS", [])
subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
subclass.module_eval(<<-EOEOC, __FILE__, __LINE__)
def self.other_elements
OTHER_ELEMENTS + super
end
def self.need_initialize_variables
NEED_INITIALIZE_VARIABLES + super
end
EOEOC
end
def self.add_other_element(variable_name)
OTHER_ELEMENTS << variable_name
end
def self.other_elements
OTHER_ELEMENTS
end
def self.add_need_initialize_variable(variable_name, init_value="nil")
NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
end
def self.need_initialize_variables
NEED_INITIALIZE_VARIABLES
end
def self.def_array_element(name, plural=nil, klass=nil)
include Enumerable
extend Forwardable
plural ||= "\#{name}s"
klass ||= "self.class::\#{Utils.to_class_name(name)}"
def_delegators("@\#{plural}", :<<, :[], :[]=, :first, :last)
def_delegators("@\#{plural}", :push, :pop, :shift, :unshift)
def_delegators("@\#{plural}", :each, :size, :empty?, :clear)
add_need_initialize_variable(plural, "[]")
module_eval(<<-EOM, __FILE__, __LINE__ + 1)
def new_\#{name}
\#{name} = \#{klass}.new(@maker)
@\#{plural} << \#{name}
if block_given?
yield \#{name}
else
\#{name}
end
end
alias new_child new_\#{name}
def to_feed(*args)
@\#{plural}.each do |\#{name}|
\#{name}.to_feed(*args)
end
end
def replace(elements)
@\#{plural}.replace(elements.to_a)
end
EOM
end
EOC
end
attr_reader :maker
def initialize(maker)
@maker = maker
@default_values_are_set = false
initialize_variables
end
def have_required_values?
not_set_required_variables.empty?
end
def variable_is_set?
variables.any? {|var| not __send__(var).nil?}
end
private
def initialize_variables
self.class.need_initialize_variables.each do |variable_name, init_value|
instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__)
end
end
def setup_other_elements(feed, current=nil)
current ||= current_element(feed)
self.class.other_elements.each do |element|
__send__("setup_#{element}", feed, current)
end
end
def current_element(feed)
feed
end
def set_default_values(&block)
return yield if @default_values_are_set
begin
@default_values_are_set = true
_set_default_values(&block)
ensure
@default_values_are_set = false
end
end
def _set_default_values(&block)
yield
end
def setup_values(target)
set = false
if have_required_values?
variables.each do |var|
setter = "#{var}="
if target.respond_to?(setter)
value = __send__(var)
if value
target.__send__(setter, value)
set = true
end
end
end
end
set
end
def set_parent(target, parent)
target.parent = parent if target.class.need_parent?
end
def variables
self.class.need_initialize_variables.find_all do |name, init|
"nil" == init
end.collect do |name, init|
name
end
end
def not_set_required_variables
required_variable_names.find_all do |var|
__send__(var).nil?
end
end
def required_variables_are_set?
required_variable_names.each do |var|
return false if __send__(var).nil?
end
true
end
end
module AtomPersonConstructBase
def self.append_features(klass)
super
klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
%w(name uri email).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
EOC
end
end
module AtomTextConstructBase
module EnsureXMLContent
def ensure_xml_content(content)
xhtml_uri = ::RSS::Atom::XHTML_URI
unless content.is_a?(RSS::XML::Element) and
["div", xhtml_uri] == [content.name, content.uri]
children = content
children = [children] unless content.is_a?(Array)
children = set_xhtml_uri_as_default_uri(children)
content = RSS::XML::Element.new("div", nil, xhtml_uri,
{"xmlns" => xhtml_uri},
children)
end
content
end
private
def set_xhtml_uri_as_default_uri(children)
children.collect do |child|
if child.is_a?(RSS::XML::Element) and
child.prefix.nil? and child.uri.nil?
RSS::XML::Element.new(child.name, nil, ::RSS::Atom::XHTML_URI,
child.attributes.dup,
set_xhtml_uri_as_default_uri(child.children))
else
child
end
end
end
end
def self.append_features(klass)
super
klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
include EnsureXMLContent
%w(type content xml_content).each do |element|
attr element, element != "xml_content"
add_need_initialize_variable(element)
end
def xml_content=(content)
@xml_content = ensure_xml_content(content)
end
alias_method(:xhtml, :xml_content)
alias_method(:xhtml=, :xml_content=)
EOC
end
end
module SetupDefaultDate
private
def _set_default_values(&block)
keep = {
:date => date,
:dc_dates => dc_dates.to_a.dup,
}
_date = date
if _date and !dc_dates.any? {|dc_date| dc_date.value == _date}
dc_date = self.class::DublinCoreDates::Date.new(self)
dc_date.value = _date.dup
dc_dates.unshift(dc_date)
end
self.date ||= self.dc_date
super(&block)
ensure
date = keep[:date]
dc_dates.replace(keep[:dc_dates])
end
end
class RSSBase
include Base
class << self
def make(&block)
new.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__)
private
def setup_#{element}(feed)
@#{element}.to_feed(feed)
end
def make_#{element}
self.class::#{Utils.to_class_name(element)}.new(self)
end
EOC
end
attr_reader :feed_version
alias_method(:rss_version, :feed_version)
attr_accessor :version, :encoding, :standalone
def initialize(feed_version)
super(self)
@feed_type = nil
@feed_subtype = nil
@feed_version = feed_version
@version = "1.0"
@encoding = "UTF-8"
@standalone = nil
end
def make
if block_given?
yield(self)
to_feed
else
nil
end
end
def to_feed
feed = make_feed
setup_xml_stylesheets(feed)
setup_elements(feed)
setup_other_elements(feed)
if feed.valid?
feed
else
nil
end
end
private
remove_method :make_xml_stylesheets
def make_xml_stylesheets
XMLStyleSheets.new(self)
end
end
class XMLStyleSheets
include Base
def_array_element("xml_stylesheet", nil, "XMLStyleSheet")
class XMLStyleSheet
include Base
::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute|
attr_accessor attribute
add_need_initialize_variable(attribute)
end
def to_feed(feed)
xss = ::RSS::XMLStyleSheet.new
guess_type_if_need(xss)
set = setup_values(xss)
if set
feed.xml_stylesheets << xss
end
end
private
def guess_type_if_need(xss)
if @type.nil?
xss.href = @href
@type = xss.type
end
end
def required_variable_names
%w(href type)
end
end
end
class ChannelBase
include Base
include SetupDefaultDate
%w(cloud categories skipDays skipHours links authors
contributors generator copyright description
title).each do |element|
attr_reader element
add_other_element(element)
add_need_initialize_variable(element, "make_#{element}")
module_eval(<<-EOC, __FILE__, __LINE__)
private
def setup_#{element}(feed, current)
@#{element}.to_feed(feed, current)
end
def make_#{element}
self.class::#{Utils.to_class_name(element)}.new(@maker)
end
EOC
end
%w(id about language
managingEditor webMaster rating docs date
lastBuildDate ttl).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
def pubDate
date
end
def pubDate=(date)
self.date = date
end
def updated
date
end
def updated=(date)
self.date = date
end
def link
_link = links.first
_link ? _link.href : nil
end
def link=(href)
_link = links.first || links.new_link
_link.rel = "self"
_link.href = href
end
def author
_author = authors.first
_author ? _author.name : nil
end
def author=(name)
_author = authors.first || authors.new_author
_author.name = name
end
def contributor
_contributor = contributors.first
_contributor ? _contributor.name : nil
end
def contributor=(name)
_contributor = contributors.first || contributors.new_contributor
_contributor.name = name
end
def generator=(content)
@generator.content = content
end
def copyright=(content)
@copyright.content = content
end
alias_method(:rights, :copyright)
alias_method(:rights=, :copyright=)
def description=(content)
@description.content = content
end
alias_method(:subtitle, :description)
alias_method(:subtitle=, :description=)
def title=(content)
@title.content = content
end
def icon
image_favicon.about
end
def icon=(url)
image_favicon.about = url
end
def logo
maker.image.url
end
def logo=(url)
maker.image.url = url
end
class SkipDaysBase
include Base
def_array_element("day")
class DayBase
include Base
%w(content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
end
class SkipHoursBase
include Base
def_array_element("hour")
class HourBase
include Base
%w(content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
end
class CloudBase
include Base
%w(domain port path registerProcedure protocol).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
class CategoriesBase
include Base
def_array_element("category", "categories")
class CategoryBase
include Base
%w(domain content label).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
alias_method(:term, :domain)
alias_method(:term=, :domain=)
alias_method(:scheme, :content)
alias_method(:scheme=, :content=)
end
end
class LinksBase
include Base
def_array_element("link")
class LinkBase
include Base
%w(href rel type hreflang title length).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
end
class AuthorsBase
include Base
def_array_element("author")
class AuthorBase
include Base
include AtomPersonConstructBase
end
end
class ContributorsBase
include Base
def_array_element("contributor")
class ContributorBase
include Base
include AtomPersonConstructBase
end
end
class GeneratorBase
include Base
%w(uri version content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
class CopyrightBase
include Base
include AtomTextConstructBase
end
class DescriptionBase
include Base
include AtomTextConstructBase
end
class TitleBase
include Base
include AtomTextConstructBase
end
end
class ImageBase
include Base
%w(title url width height description).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
def link
@maker.channel.link
end
end
class ItemsBase
include 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]
else
sort_if_need[0..@max_size]
end
end
private
def sort_if_need
if @do_sort.respond_to?(:call)
@items.sort do |x, y|
@do_sort.call(x, y)
end
elsif @do_sort
@items.sort do |x, y|
y <=> x
end
else
@items
end
end
class ItemBase
include Base
include SetupDefaultDate
%w(guid enclosure source categories authors links
contributors rights description content title).each do |element|
attr_reader element
add_other_element(element)
add_need_initialize_variable(element, "make_#{element}")
module_eval(<<-EOC, __FILE__, __LINE__)
private
def setup_#{element}(feed, current)
@#{element}.to_feed(feed, current)
end
def make_#{element}
self.class::#{Utils.to_class_name(element)}.new(@maker)
end
EOC
end
%w(date comments id published).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
def pubDate
date
end
def pubDate=(date)
self.date = date
end
def updated
date
end
def updated=(date)
self.date = date
end
def author
_link = authors.first
_link ? _author.name : nil
end
def author=(name)
_author = authors.first || authors.new_author
_author.name = name
end
def link
_link = links.first
_link ? _link.href : nil
end
def link=(href)
_link = links.first || links.new_link
_link.rel = "alternate"
_link.href = href
end
def rights=(content)
@rights.content = content
end
def description=(content)
@description.content = content
end
alias_method(:summary, :description)
alias_method(:summary=, :description=)
def title=(content)
@title.content = content
end
def <=>(other)
_date = date || dc_date
_other_date = other.date || other.dc_date
if _date and _other_date
_date <=> _other_date
elsif _date
1
elsif _other_date
-1
else
0
end
end
class GuidBase
include Base
%w(isPermaLink content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
class EnclosureBase
include Base
%w(url length type).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
class SourceBase
include Base
%w(authors categories contributors generator icon
links logo rights subtitle title).each do |element|
attr_reader element
add_other_element(element)
add_need_initialize_variable(element, "make_#{element}")
module_eval(<<-EOC, __FILE__, __LINE__)
private
def setup_#{element}(feed, current)
@#{element}.to_feed(feed, current)
end
def make_#{element}
self.class::#{Utils.to_class_name(element)}.new(@maker)
end
EOC
end
%w(id content date).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
def url
link = links.first
link ? link.href : nil
end
def url=(value)
link = links.first || links.new_link
link.href = value
end
def updated
date
end
def updated=(date)
self.date = date
end
private
AuthorsBase = ChannelBase::AuthorsBase
CategoriesBase = ChannelBase::CategoriesBase
ContributorsBase = ChannelBase::ContributorsBase
GeneratorBase = ChannelBase::GeneratorBase
class IconBase
include Base
%w(url).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
LinksBase = ChannelBase::LinksBase
class LogoBase
include Base
%w(uri).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
class RightsBase
include Base
include AtomTextConstructBase
end
class SubtitleBase
include Base
include AtomTextConstructBase
end
class TitleBase
include Base
include AtomTextConstructBase
end
end
CategoriesBase = ChannelBase::CategoriesBase
AuthorsBase = ChannelBase::AuthorsBase
LinksBase = ChannelBase::LinksBase
ContributorsBase = ChannelBase::ContributorsBase
class RightsBase
include Base
include AtomTextConstructBase
end
class DescriptionBase
include Base
include AtomTextConstructBase
end
class ContentBase
include Base
include AtomTextConstructBase::EnsureXMLContent
%w(type src content xml_content).each do |element|
attr element, element != "xml_content"
add_need_initialize_variable(element)
end
def xml_content=(content)
content = ensure_xml_content(content) if inline_xhtml?
@xml_content = content
end
alias_method(:xhtml, :xml_content)
alias_method(:xhtml=, :xml_content=)
alias_method(:xml, :xml_content)
alias_method(:xml=, :xml_content=)
private
def inline_text?
[nil, "text", "html"].include?(@type)
end
def inline_html?
@type == "html"
end
def inline_xhtml?
@type == "xhtml"
end
def inline_other?
!out_of_line? and ![nil, "text", "html", "xhtml"].include?(@type)
end
def inline_other_text?
return false if @type.nil? or out_of_line?
/\Atext\//i.match(@type) ? true : false
end
def inline_other_xml?
return false if @type.nil? or out_of_line?
/[\+\/]xml\z/i.match(@type) ? true : false
end
def inline_other_base64?
return false if @type.nil? or out_of_line?
@type.include?("/") and !inline_other_text? and !inline_other_xml?
end
def out_of_line?
not @src.nil? and @content.nil?
end
end
class TitleBase
include Base
include AtomTextConstructBase
end
end
end
class TextinputBase
include Base
%w(title description name link).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
end
end