diff options
author | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-10-31 14:14:21 +0000 |
---|---|---|
committer | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-10-31 14:14:21 +0000 |
commit | d58d59b0a4fa6859a3d3efd1a9d40832c3007ecf (patch) | |
tree | f9ae1db068b4fe971550f6cb2afda5a2c399f2bd /lib | |
parent | c6cf2e24fe9895b84308374017100cb77900d6db (diff) |
* lib/rss/maker/*.rb: added RSS Maker.
* test/rss/test_maker_*.rb: added tests for RSS Maker.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@7155 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rss/0.9.rb | 2 | ||||
-rw-r--r-- | lib/rss/maker/0.9.rb | 163 | ||||
-rw-r--r-- | lib/rss/maker/1.0.rb | 184 | ||||
-rw-r--r-- | lib/rss/maker/2.0.rb | 131 | ||||
-rw-r--r-- | lib/rss/maker/base.rb | 380 | ||||
-rw-r--r-- | lib/rss/maker/content.rb | 29 | ||||
-rw-r--r-- | lib/rss/maker/dublincore.rb | 47 | ||||
-rw-r--r-- | lib/rss/maker/syndication.rb | 27 | ||||
-rw-r--r-- | lib/rss/maker/trackback.rb | 30 | ||||
-rw-r--r-- | lib/rss/syndication.rb | 2 |
10 files changed, 993 insertions, 2 deletions
diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb index dd5f93b868..d5c6b3a89d 100644 --- a/lib/rss/0.9.rb +++ b/lib/rss/0.9.rb @@ -252,7 +252,7 @@ EOT install_get_attribute(name, uri, required) end - def initialize(domain, port, path, rp, protocol) + def initialize(domain=nil, port=nil, path=nil, rp=nil, protocol=nil) super() @domain = domain @port = port diff --git a/lib/rss/maker/0.9.rb b/lib/rss/maker/0.9.rb new file mode 100644 index 0000000000..7223246647 --- /dev/null +++ b/lib/rss/maker/0.9.rb @@ -0,0 +1,163 @@ +require "rss/0.9" + +require "rss/maker/base" + +module RSS + module Maker + + class RSS09 < RSSBase + + def initialize(rss_version="0.91") + super + end + + def to_rss + rss = Rss.new(@rss_version, @version, @encoding, @standalone) + setup_xml_stylesheets(rss) + setup_channel(rss) + setup_other_elements(rss) + if rss.channel + rss + else + nil + end + end + + private + def setup_channel(rss) + @channel.to_rss(rss) + end + + class Channel < ChannelBase + + alias_method(:pubDate, :date) + alias_method(:pubDate=, :date=) + + def to_rss(rss) + channel = Rss::Channel.new + set = setup_values(channel) + if set + rss.channel = channel + setup_items(rss) + setup_image(rss) + setup_textinput(rss) + setup_other_elements(rss) + if rss.channel.image + rss + else + nil + end + end + end + + def have_required_values? + @title and @link and @description and @language and + @maker.image.have_required_values? + end + + private + def setup_items(rss) + @maker.items.to_rss(rss) + end + + def setup_image(rss) + @maker.image.to_rss(rss) + end + + def setup_textinput(rss) + @maker.textinput.to_rss(rss) + end + + def variables + super + ["pubDate"] + end + + class Cloud < CloudBase + end + + end + + class Image < ImageBase + def to_rss(rss) + image = Rss::Channel::Image.new + set = setup_values(image) + if set + image.link = link + rss.channel.image = image + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @title and link + end + end + + class Items < ItemsBase + def to_rss(rss) + if rss.channel + normalize.each do |item| + item.to_rss(rss) + end + setup_other_elements(rss) + end + end + + class Item < ItemBase + def to_rss(rss) + item = Rss::Channel::Item.new + set = setup_values(item) + if set + rss.items << item + setup_other_elements(rss) + end + end + + private + def have_required_values? + @title and @link + end + + class Guid < GuidBase + def to_rss(*args) + end + end + + class Enclosure < EnclosureBase + def to_rss(*args) + end + end + + class Source < SourceBase + def to_rss(*args) + end + end + + class Category < CategoryBase + def to_rss(*args) + end + end + + end + end + + class Textinput < TextinputBase + def to_rss(rss) + textInput = Rss::Channel::TextInput.new + set = setup_values(textInput) + if set + rss.channel.textInput = textInput + setup_other_elements(rss) + end + end + + private + def have_required_values? + @title and @description and @name and @link + end + end + end + + add_maker(filename_to_version(__FILE__), RSS09) + end +end diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb new file mode 100644 index 0000000000..894bcc0a24 --- /dev/null +++ b/lib/rss/maker/1.0.rb @@ -0,0 +1,184 @@ +require "rss/1.0" + +require "rss/maker/base" + +module RSS + module Maker + + class RSS10 < RSSBase + + def initialize + super("1.0") + end + + def to_rss + rss = RDF.new(@version, @encoding, @standalone) + setup_xml_stylesheets(rss) + setup_channel(rss) + setup_image(rss) + setup_items(rss) + setup_textinput(rss) + setup_other_elements(rss) + if rss.channel + rss + else + nil + end + end + + private + def setup_channel(rss) + @channel.to_rss(rss) + end + + def setup_image(rss) + @image.to_rss(rss) + end + + def setup_items(rss) + @items.to_rss(rss) + end + + def setup_textinput(rss) + @textinput.to_rss(rss) + end + + class Channel < ChannelBase + + def to_rss(rss) + if @about + channel = RDF::Channel.new(@about) + set = setup_values(channel) + if set + rss.channel = channel + setup_items(rss) + setup_image(rss) + setup_textinput(rss) + setup_other_elements(rss) + end + end + end + + def have_required_values? + @about and @title and @link and @description + end + + private + def setup_items(rss) + items = RDF::Channel::Items.new + seq = items.Seq + @maker.items.normalize.each do |item| + seq.lis << RDF::Channel::Items::Seq::Li.new(item.link) + end + rss.channel.items = items + end + + def setup_image(rss) + if @maker.image.have_required_values? + rss.channel.image = RDF::Channel::Image.new(@maker.image.url) + end + end + + def setup_textinput(rss) + if @maker.textinput.have_required_values? + textinput = RDF::Channel::Textinput.new(@maker.textinput.link) + rss.channel.textinput = textinput + end + end + + class Cloud < CloudBase + end + end + + class Image < ImageBase + def to_rss(rss) + if @url + image = RDF::Image.new(@url) + set = setup_values(image) + if set + rss.image = image + setup_other_elements(rss) + end + end + end + + def have_required_values? + @url and @title and link and @maker.channel.have_required_values? + end + + private + def variables + super + ["link"] + end + end + + class Items < ItemsBase + def to_rss(rss) + if rss.channel + normalize.each do |item| + item.to_rss(rss) + end + setup_other_elements(rss) + end + end + + class Item < ItemBase + def to_rss(rss) + if @link + item = RDF::Item.new(@link) + set = setup_values(item) + if set + rss.items << item + setup_other_elements(rss) + end + end + end + + def have_required_values? + @title and @link + end + + class Guid < GuidBase + def to_rss(*args) + end + end + + class Enclosure < EnclosureBase + def to_rss(*args) + end + end + + class Source < SourceBase + def to_rss(*args) + end + end + + class Category < CategoryBase + def to_rss(*args) + end + end + end + end + + class Textinput < TextinputBase + def to_rss(rss) + if @link + textinput = RDF::Textinput.new(@link) + set = setup_values(textinput) + if set + rss.textinput = textinput + setup_other_elements(rss) + end + end + end + + def have_required_values? + @title and @description and @name and @link and + @maker.channel.have_required_values? + end + end + end + + add_maker(filename_to_version(__FILE__), RSS10) + end +end diff --git a/lib/rss/maker/2.0.rb b/lib/rss/maker/2.0.rb new file mode 100644 index 0000000000..2fa61e80e6 --- /dev/null +++ b/lib/rss/maker/2.0.rb @@ -0,0 +1,131 @@ +require "rss/2.0" + +require "rss/maker/0.9" + +module RSS + module Maker + + class RSS20 < RSS09 + + def initialize(rss_version="2.0") + super + end + + class Channel < RSS09::Channel + + add_other_element("cloud") + + def have_required_values? + @title and @link and @description + end + + private + def setup_cloud(rss, current) + @maker.channel.cloud.to_rss(rss) + end + + class Cloud < RSS09::Channel::Cloud + def to_rss(rss) + cloud = Rss::Channel::Cloud.new + set = setup_values(cloud) + if set + rss.channel.cloud = cloud + setup_other_elements(rss) + end + end + + def have_required_values? + @domain and @port and @path and + @registerProcedure and @protocol + end + end + end + + class Image < RSS09::Image + end + + class Items < RSS09::Items + + class Item < RSS09::Items::Item + + alias_method(:pubDate, :date) + + def have_required_values? + @title or @description + end + + private + def variables + super + ["pubDate"] + end + + class Guid < RSS09::Items::Item::Guid + def to_rss(rss, item) + guid = Rss::Channel::Item::Guid.new + set = setup_values(guid) + if set + item.guid = guid + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + + class Enclosure < RSS09::Items::Item::Enclosure + def to_rss(rss, item) + enclosure = Rss::Channel::Item::Enclosure.new + set = setup_values(enclosure) + if set + item.enclosure = enclosure + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @length and @type + end + end + + class Source < RSS09::Items::Item::Source + def to_rss(rss, item) + source = Rss::Channel::Item::Source.new + set = setup_values(source) + if set + item.source = source + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @content + end + end + + class Category < RSS09::Items::Item::Category + def to_rss(rss, item) + category = Rss::Channel::Item::Category.new + set = setup_values(category) + if set + item.category = category + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + + end + + class Textinput < RSS09::Textinput + end + end + + add_maker(filename_to_version(__FILE__), RSS20) + end +end diff --git a/lib/rss/maker/base.rb b/lib/rss/maker/base.rb new file mode 100644 index 0000000000..a9f1639503 --- /dev/null +++ b/lib/rss/maker/base.rb @@ -0,0 +1,380 @@ +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", + OTHER_ELEMENTS.dup) + subclass.const_set("NEED_INITIALIZE_VARIABLES", + NEED_INITIALIZE_VARIABLES.dup) + end + + def self.add_other_element(variable_name) + const_get("OTHER_ELEMENTS") << variable_name + end + + def self.other_elements + const_get("OTHER_ELEMENTS") + end + + def self.add_need_initialize_variable(variable_name) + const_get("NEED_INITIALIZE_VARIABLES") << variable_name + end + + def self.need_initialize_variables + const_get("NEED_INITIALIZE_VARIABLES") + end + EOC + end + + def initialize(maker) + @maker = maker + initialize_variables + end + + def have_required_values? + true + end + + private + def initialize_variables + self.class.need_initialize_variables.each do |variable_name| + instance_eval("@#{variable_name} = nil", __FILE__, __LINE__) + end + end + + def setup_other_elements(rss) + self.class.other_elements.each do |element| + __send__("setup_#{element}", rss, current_element(rss)) + end + end + + def setup_values(target) + set = false + if have_required_values? + variables.each do |var| + setter = "#{var}=" + if target.respond_to?(setter) + value = self.__send__(var) + if value + target.__send__(setter, value) + set = true + end + end + end + end + set + end + + def variables + self.class.need_initialize_variables + end + + end + + class RSSBase + include Base + + class << self + def make(&block) + new.make(&block) + end + end + + attr_reader :rss_version, :xml_stylesheets + attr_reader :channel, :image, :items, :textinput + + attr_accessor :version, :encoding, :standalone + + def initialize(rss_version) + super(self) + @rss_version = rss_version + @version = "1.0" + @encoding = "UTF-8" + @standalone = nil + @xml_stylesheets = make_xml_stylesheets + @channel = make_channel + @image = make_image + @items = make_items + @textinput = make_textinput + end + + def make(&block) + block.call(self) if block + to_rss + end + + def current_element(rss) + rss + end + + private + def make_xml_stylesheets + XMLStyleSheets.new(self) + end + + def make_channel + self.class::Channel.new(self) + end + + def make_image + self.class::Image.new(self) + end + + def make_items + self.class::Items.new(self) + end + + def make_textinput + self.class::Textinput.new(self) + end + + def setup_xml_stylesheets(rss) + rss.xml_stylesheets = @xml_stylesheets.normalize + end + + end + + class XMLStyleSheets + include Base + + extend Forwardable + + def_delegators(:@xml_stylesheets, :<<, :[], :[]=) + + def initialize(maker) + super + @xml_stylesheets = [] + end + + def normalize + @xml_stylesheets.collect do |info| + make_xml_stylesheet(info) + end + end + + private + def make_xml_stylesheet(info) + RSS::XMLStyleSheet.new(*info) + end + end + + class ChannelBase + include Base + + attr_reader :cloud + + %w(about title link description language copyright + managingEditor webMaster rating docs skipDays + skipHours date lastBuildDate category generator ttl + ).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def initialize(maker) + super + @cloud = make_cloud + end + + def current_element(rss) + rss.channel + end + + private + def make_cloud + self.class::Cloud.new(@maker) + end + + class CloudBase + include Base + + %w(domain port path registerProcedure protocol).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def current_element(rss) + rss.channel.cloud + end + + 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 + + def current_element(rss) + rss.image + end + end + + class ItemsBase + include Base + + extend Forwardable + + def_delegators(:@items, :<<, :[], :[]=, :first, :last) + def_delegators(:@items, :push, :pop, :shift, :unshift) + + attr_accessor :sort + + def initialize(maker) + super + @items = [] + @sort = false + end + + def normalize + sort_if_need + 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 @sort.respond_to?(:call) + @items.sort do |x, y| + @sort.call(x, y) + end + elsif @sort + @items.sort do |x, y| + y <=> x + end + else + @items + end + end + + class ItemBase + include Base + + %w(guid enclosure source category).each do |element| + attr_reader element + add_other_element(element) + module_eval(<<-EOC, __FILE__, __LINE__) + private + def setup_#{element}(rss, current) + @#{element}.to_rss(rss, current) + end + + def make_#{element} + self.class::#{element[0,1].upcase}#{element[1..-1]}.new(@maker) + end +EOC + end + + %w(title link description date author comments).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def initialize(maker) + super + @guid = make_guid + @enclosure = make_enclosure + @source = make_source + @category = make_category + end + + def <=>(other) + if @date and other.date + @date <=> other.date + elsif @date + 1 + elsif other.date + -1 + else + 0 + end + end + + def current_element(rss) + rss.items.last + 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(url content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + + class CategoryBase + include Base + + %w(domain content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + + end + end + + class TextinputBase + include Base + + %w(title description name link).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def current_element(rss) + rss.textinput + end + + end + + end +end diff --git a/lib/rss/maker/content.rb b/lib/rss/maker/content.rb new file mode 100644 index 0000000000..67b237f4ef --- /dev/null +++ b/lib/rss/maker/content.rb @@ -0,0 +1,29 @@ +require 'rss/content' +require 'rss/maker/1.0' + +module RSS + module Maker + module ContentModel + def self.append_features(klass) + super + + ::RSS::ContentModel::ELEMENTS.each do |element| + klass.add_need_initialize_variable(element) + klass.add_other_element(element) + klass.__send__(:attr_accessor, element) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + def setup_#{element}(rss, current) + current.#{element} = @#{element} if @#{element} + end +EOC + end + end + end + + class RSS10 + class Items + class Item; include ContentModel; end + end + end + end +end diff --git a/lib/rss/maker/dublincore.rb b/lib/rss/maker/dublincore.rb new file mode 100644 index 0000000000..6a4c64a464 --- /dev/null +++ b/lib/rss/maker/dublincore.rb @@ -0,0 +1,47 @@ +require 'rss/dublincore' +require 'rss/maker/1.0' + +module RSS + module Maker + module DublinCoreModel + def self.append_features(klass) + super + + ::RSS::DublinCoreModel::ELEMENTS.each do |element| + klass.add_need_initialize_variable(element) + klass.add_other_element(element) + klass.__send__(:attr_accessor, element) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + def setup_#{element}(rss, current) + current.#{element} = #{element} if #{element} + end +EOC + end + end + end + + class RSS10 + class Channel + include DublinCoreModel + + alias_method(:_dc_date, :dc_date) + alias_method(:_dc_date=, :dc_date=) + alias_method(:dc_date, :date) + alias_method(:dc_date=, :date=) + end + + class Image; include DublinCoreModel; end + class Items + class Item + include DublinCoreModel + + alias_method(:_dc_date, :dc_date) + alias_method(:_dc_date=, :dc_date=) + alias_method(:dc_date, :date) + alias_method(:dc_date=, :date=) + end + end + class Textinput; include DublinCoreModel; end + end + end +end diff --git a/lib/rss/maker/syndication.rb b/lib/rss/maker/syndication.rb new file mode 100644 index 0000000000..ad846413ae --- /dev/null +++ b/lib/rss/maker/syndication.rb @@ -0,0 +1,27 @@ +require 'rss/syndication' +require 'rss/maker/1.0' + +module RSS + module Maker + module SyndicationModel + def self.append_features(klass) + super + + ::RSS::SyndicationModel::ELEMENTS.each do |element| + klass.add_need_initialize_variable(element) + klass.add_other_element(element) + klass.__send__(:attr_accessor, element) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + def setup_#{element}(rss, current) + current.#{element} = @#{element} if @#{element} + end +EOC + end + end + end + + class RSS10 + class Channel; include SyndicationModel; end + end + end +end diff --git a/lib/rss/maker/trackback.rb b/lib/rss/maker/trackback.rb new file mode 100644 index 0000000000..ff0e1abe44 --- /dev/null +++ b/lib/rss/maker/trackback.rb @@ -0,0 +1,30 @@ +require 'rss/trackback' +require 'rss/maker/1.0' + +module RSS + module Maker + module TrackBackModel + def self.append_features(klass) + super + + %w(ping about).each do |element| + name = "#{RSS::TRACKBACK_PREFIX}_#{element}" + klass.add_need_initialize_variable(name) + klass.add_other_element(name) + klass.__send__(:attr_accessor, name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + def setup_#{name}(rss, current) + current.#{name} = @#{name} if @#{name} + end +EOC + end + end + end + + class RSS10 + class Items + class Item; include TrackBackModel; end + end + end + end +end diff --git a/lib/rss/syndication.rb b/lib/rss/syndication.rb index 75f612864d..b8200ad70d 100644 --- a/lib/rss/syndication.rb +++ b/lib/rss/syndication.rb @@ -34,7 +34,6 @@ module RSS alias_method(:_sy_updateFrequency=, :sy_updateFrequency=) def sy_updateFrequency=(new_value) - new_value = new_value.strip validate_sy_updateFrequency(new_value) if @do_validate self._sy_updateFrequency = new_value.to_i end @@ -65,6 +64,7 @@ module RSS SY_UPDATEFREQUENCY_AVAILABLE_RE = /\A\s*\+?\d+\s*\z/ def validate_sy_updateFrequency(value) + value = value.to_s.strip if SY_UPDATEFREQUENCY_AVAILABLE_RE !~ value raise NotAvailableValueError.new("updateFrequency", value) end |