diff options
Diffstat (limited to 'lib/rss/maker/base.rb')
-rw-r--r-- | lib/rss/maker/base.rb | 710 |
1 files changed, 558 insertions, 152 deletions
diff --git a/lib/rss/maker/base.rb b/lib/rss/maker/base.rb index 6d7dd557bf..ad47ff29cc 100644 --- a/lib/rss/maker/base.rb +++ b/lib/rss/maker/base.rb @@ -4,9 +4,7 @@ require 'rss/rss' module RSS module Maker - module Base - def self.append_features(klass) super @@ -46,28 +44,60 @@ module RSS NEED_INITIALIZE_VARIABLES end - def self.def_array_element(name) + def self.def_array_element(name, plural=nil, klass=nil) include Enumerable extend Forwardable - def_delegators("@\#{name}", :<<, :[], :[]=, :first, :last) - def_delegators("@\#{name}", :push, :pop, :shift, :unshift) - def_delegators("@\#{name}", :each, :size) - - add_need_initialize_variable(name, "[]") + 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? - true + 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| @@ -75,16 +105,32 @@ module RSS end end - def setup_other_elements(rss) + def setup_other_elements(feed, current=nil) + current ||= current_element(feed) self.class.other_elements.each do |element| - __send__("setup_#{element}", rss, current_element(rss)) + __send__("setup_#{element}", feed, current) end end - def current_element(rss) - rss + 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? @@ -102,6 +148,10 @@ module RSS 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 @@ -110,10 +160,6 @@ module RSS end end - def variable_is_set? - variables.find {|var| !__send__(var).nil?} - end - def not_set_required_variables required_variable_names.find_all do |var| __send__(var).nil? @@ -126,7 +172,92 @@ module RSS 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 @@ -143,8 +274,8 @@ module RSS add_need_initialize_variable(element, "make_#{element}") module_eval(<<-EOC, __FILE__, __LINE__) private - def setup_#{element}(rss) - @#{element}.to_rss(rss) + def setup_#{element}(feed) + @#{element}.to_feed(feed) end def make_#{element} @@ -153,12 +284,15 @@ module RSS EOC end - attr_reader :rss_version + attr_reader :feed_version + alias_method(:rss_version, :feed_version) attr_accessor :version, :encoding, :standalone - - def initialize(rss_version) + + def initialize(feed_version) super(self) - @rss_version = rss_version + @feed_type = nil + @feed_subtype = nil + @feed_version = feed_version @version = "1.0" @encoding = "UTF-8" @standalone = nil @@ -167,19 +301,19 @@ EOC def make if block_given? yield(self) - to_rss + to_feed else nil end end - def to_rss - rss = make_rss - setup_xml_stylesheets(rss) - setup_elements(rss) - setup_other_elements(rss) - if rss.channel - rss + def to_feed + feed = make_feed + setup_xml_stylesheets(feed) + setup_elements(feed) + setup_other_elements(feed) + if feed.valid? + feed else nil end @@ -190,25 +324,12 @@ EOC def make_xml_stylesheets XMLStyleSheets.new(self) end - end class XMLStyleSheets include Base - def_array_element("xml_stylesheets") - - def to_rss(rss) - @xml_stylesheets.each do |xss| - xss.to_rss(rss) - end - end - - def new_xml_stylesheet - xss = XMLStyleSheet.new(@maker) - @xml_stylesheets << xss - xss - end + def_array_element("xml_stylesheet", nil, "XMLStyleSheet") class XMLStyleSheet include Base @@ -218,19 +339,15 @@ EOC add_need_initialize_variable(attribute) end - def to_rss(rss) + def to_feed(feed) xss = ::RSS::XMLStyleSheet.new guess_type_if_need(xss) set = setup_values(xss) if set - rss.xml_stylesheets << xss + feed.xml_stylesheets << xss end end - def have_required_values? - @href and @type - end - private def guess_type_if_need(xss) if @type.nil? @@ -238,20 +355,27 @@ EOC @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).each do |element| + %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}(rss, current) - @#{element}.to_rss(rss, current) + def setup_#{element}(feed, current) + @#{element}.to_feed(feed, current) end def make_#{element} @@ -260,34 +384,102 @@ EOC EOC end - %w(about title link description language copyright + %w(id about language managingEditor webMaster rating docs date - lastBuildDate generator ttl).each do |element| + lastBuildDate ttl).each do |element| attr_accessor element add_need_initialize_variable(element) end - alias_method(:pubDate, :date) - alias_method(:pubDate=, :date=) + 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 current_element(rss) - rss.channel + 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("days") - - def new_day - day = self.class::Day.new(@maker) - @days << day - day - end - - def current_element(rss) - rss.channel.skipDays - end + def_array_element("day") class DayBase include Base @@ -296,28 +488,13 @@ EOC attr_accessor element add_need_initialize_variable(element) end - - def current_element(rss) - rss.channel.skipDays.last - end - end end class SkipHoursBase include Base - def_array_element("hours") - - def new_hour - hour = self.class::Hour.new(@maker) - @hours << hour - hour - end - - def current_element(rss) - rss.channel.skipHours - end + def_array_element("hour") class HourBase include Base @@ -326,11 +503,6 @@ EOC attr_accessor element add_need_initialize_variable(element) end - - def current_element(rss) - rss.channel.skipHours.last - end - end end @@ -341,33 +513,88 @@ EOC attr_accessor element add_need_initialize_variable(element) end - - def current_element(rss) - rss.channel.cloud - end - end class CategoriesBase include Base - - def_array_element("categories") - def new_category - category = self.class::Category.new(@maker) - @categories << category - category - end + def_array_element("category", "categories") class CategoryBase include Base - %w(domain content).each do |element| + %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 @@ -377,21 +604,17 @@ EOC attr_accessor element add_need_initialize_variable(element) end - + def link @maker.channel.link end - - def current_element(rss) - rss.image - end end class ItemsBase include Base - def_array_element("items") - + def_array_element("item") + attr_accessor :do_sort, :max_size def initialize(maker) @@ -407,17 +630,7 @@ EOC sort_if_need[0..@max_size] end end - - def current_element(rss) - rss.items - end - def new_item - item = self.class::Item.new(@maker) - @items << item - item - end - private def sort_if_need if @do_sort.respond_to?(:call) @@ -435,15 +648,17 @@ EOC class ItemBase include Base - - %w(guid enclosure source categories).each do |element| + 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}(rss, current) - @#{element}.to_rss(rss, current) + def setup_#{element}(feed, current) + @#{element}.to_feed(feed, current) end def make_#{element} @@ -451,30 +666,77 @@ EOC end EOC end - - %w(title link description date author comments).each do |element| + + %w(date comments id published).each do |element| attr_accessor element add_need_initialize_variable(element) end - alias_method(:pubDate, :date) - alias_method(:pubDate=, :date=) + 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) - if date and other.date - date <=> other.date - elsif date + _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 + elsif _other_date -1 else 0 end end - - def current_element(rss) - rss.items.last - end class GuidBase include Base @@ -484,7 +746,7 @@ EOC add_need_initialize_variable(element) end end - + class EnclosureBase include Base @@ -493,18 +755,168 @@ EOC add_need_initialize_variable(element) end end - + class SourceBase include Base - %w(url content).each do |element| + %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 @@ -515,12 +927,6 @@ EOC attr_accessor element add_need_initialize_variable(element) end - - def current_element(rss) - rss.textinput - end - end - end end |