diff --git a/ChangeLog b/ChangeLog index 0eb3bf4a0b..986045d9dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,37 @@ +Fri Nov 19 17:18:17 2004 Kouhei Sutou + + * lib/rss/rss.rb (RSS::VERSION): 0.1.0 -> 0.1.1. + + * lib/rss: #to_s used #tag. + + * test/rss/test_to_s.rb: added. + + * lib/rss/maker.rb (RSS::Maker.make): changed API. It's not + received modules which is used as the second argument. + + * lib/rss/xml-stylesheet.rb (RSS::XMLStyleSheet#alternate): + changed return value type which is not String but Boolean. + + * lib/rss/2.0.rb (RSS::Rss::Channel#ttl): changed return value + type which is not String but Integer. + + * lib/rss/0.9.rb (RSS::Rss::Channel): has s and + has s. + + * lib/rss/maker/0.9.rb (RSS::Maker::RSS09::Channel): ditto. + + * lib/rss/0.9.rb (RSS::Rss::Channel::Item): has s. + + * lib/rss/maker/2.0.rb (RSS::Maker::Rss20::Channel::Item): ditto. + + * lib/rss/2.0.rb (RSS::Rss::Channel): has s. + + * lib/rss/maker/2.0.rb (RSS::Maker::RSS20::Channel): ditto. + + * lib/rss/trackback.rb: parent element has s. + + * lib/rss/maker/trackback.rb: ditto. + Fri Nov 19 11:10:16 2004 WATANABE Hirofumi * lib/test/unit/collector/dir.rb: add support for directory name diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb index c772e80870..20a229b926 100644 --- a/lib/rss/0.9.rb +++ b/lib/rss/0.9.rb @@ -60,17 +60,14 @@ module RSS end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOR -#{xmldecl} -#{xml_stylesheet_pi} -#{indent} -#{channel_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOR + rv = tag(indent, ns_declarations) do |next_indent| + [ + channel_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter - remove_empty_newline(rv) + rv end private @@ -86,7 +83,7 @@ EOR def _attrs [ - ["version", true], + ["version", true, "rss_version"], ] end @@ -104,8 +101,6 @@ EOR ["webMaster", "?"], ["rating", "?"], ["docs", "?"], - ["skipDays", "?"], - ["skipHours", "?"], ].each do |x, occurs| install_text_element(x) install_model(x, occurs) @@ -120,6 +115,8 @@ EOR end [ + ["skipDays", "?"], + ["skipHours", "?"], ["image", nil], ["textInput", "?"], ].each do |x, occurs| @@ -146,35 +143,35 @@ EOR end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{description_element(false, next_indent)} -#{language_element(false, next_indent)} -#{copyright_element(false, next_indent)} -#{managingEditor_element(false, next_indent)} -#{webMaster_element(false, next_indent)} -#{rating_element(false, next_indent)} -#{pubDate_element(false, next_indent)} -#{lastBuildDate_element(false, next_indent)} -#{docs_element(false, next_indent)} -#{skipDays_element(false, next_indent)} -#{skipHours_element(false, next_indent)} -#{image_element(false, next_indent)} -#{item_elements(false, next_indent)} -#{textInput_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + link_element(false, next_indent), + description_element(false, next_indent), + language_element(false, next_indent), + copyright_element(false, next_indent), + managingEditor_element(false, next_indent), + webMaster_element(false, next_indent), + rating_element(false, next_indent), + pubDate_element(false, next_indent), + lastBuildDate_element(false, next_indent), + docs_element(false, next_indent), + cloud_element(false, next_indent), + skipDays_element(false, next_indent), + skipHours_element(false, next_indent), + image_element(false, next_indent), + item_elements(false, next_indent), + textInput_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end private def children - [@image, @textInput, @cloud, *@item] + [@skipDays, @skipHours, @image, @textInput, @cloud, *@item] end def _tags @@ -206,6 +203,101 @@ EOT rv end + class SkipDays < Element + include RSS09 + + [ + ["day", "*"] + ].each do |x, occurs| + install_have_children_element(x) + install_model(x, occurs) + end + + def to_s(convert=true, indent=calc_indent) + rv = tag(indent) do |next_indent| + [ + day_elements(false, next_indent) + ] + end + rv = @converter.convert(rv) if convert and @converter + rv + end + + private + def children + @day + end + + def _tags + @day.compact.collect do + [nil, "day"] + end + end + + class Day < Element + include RSS09 + + content_setup + + def initialize(content=nil) + super() + @content = content + end + + end + + end + + class SkipHours < Element + include RSS09 + + [ + ["hour", "*"] + ].each do |x, occurs| + install_have_children_element(x) + install_model(x, occurs) + end + + def to_s(convert=true, indent=calc_indent) + rv = tag(indent) do |next_indent| + [ + hour_elements(false, next_indent) + ] + end + rv = @converter.convert(rv) if convert and @converter + rv + end + + private + def children + @hour + end + + def _tags + @hour.compact.collect do + [nil, "hour"] + end + end + + class Hour < Element + include RSS09 + + content_setup + + def initialize(content=nil) + super() + @content = content + end + + undef :content= + def content=(value) + @content = value.to_i + end + + end + + end + class Image < Element include RSS09 @@ -220,18 +312,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent} -#{url_element(false, next_indent)} -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{width_element(false, next_indent)} -#{height_element(false, next_indent)} -#{description_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + url_element(false, next_indent), + title_element(false, next_indent), + link_element(false, next_indent), + width_element(false, next_indent), + height_element(false, next_indent), + description_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end @@ -245,7 +336,7 @@ EOT end end end - + class Cloud < Element include RSS09 @@ -270,16 +361,8 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent} -EOT - rv = @converter.convert(rv) if convert and @converter + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter rv end @@ -300,15 +383,21 @@ EOT install_text_element(x) end - %w(category source enclosure).each do |x| + %w(source enclosure).each do |x| install_have_child_element(x) end + [ + %w(category categories), + ].each do |name, plural_name| + install_have_children_element(name, plural_name) + end + [ ["title", '?'], ["link", '?'], ["description", '?'], - ["category", '?'], + ["category", '*'], ["source", '?'], ["enclosure", '?'], ].each do |tag, occurs| @@ -316,34 +405,39 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{description_element(false, next_indent)} -#{category_element(false, next_indent)} -#{source_element(false, next_indent)} -#{enclosure_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT - rv = @converter.convert(rv) if convert and @converter + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + link_element(false, next_indent), + description_element(false, next_indent), + category_elements(false, next_indent), + source_element(false, next_indent), + enclosure_element(false, next_indent), + other_element(false, next_indent), + ] + end + rv = @converter.convert(rv) if convert and @converter rv end private def children - [@category, @source, @enclosure,].compact + [@source, @enclosure, *@category].compact end def _tags - %w(title link description author comments category + rv = %w(title link description author comments source enclosure).delete_if do |x| send(x).nil? end.collect do |x| [nil, x] end + + @category.each do + rv << [nil, "category"] + end + + rv end class Source < Element @@ -364,17 +458,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @url - rv = %Q! ! - rv << %Q!#{@content}! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _tags [] @@ -408,14 +491,9 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @url and @length and @type - rv = %Q!! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private @@ -447,17 +525,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @domain - rv = %Q!! - rv << %Q!#{h @content}! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _attrs [ @@ -470,7 +537,7 @@ EOT end class TextInput < Element - + include RSS09 %w(title description name link).each do |x| @@ -479,17 +546,16 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{description_element(false, next_indent)} -#{name_element(false, next_indent)} -#{link_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT - rv = @converter.convert(rv) if convert and @converter + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + description_element(false, next_indent), + name_element(false, next_indent), + link_element(false, next_indent), + other_element(false, next_indent), + ] + end + rv = @converter.convert(rv) if convert and @converter rv end diff --git a/lib/rss/1.0.rb b/lib/rss/1.0.rb index 563ed66426..9a61e456ba 100644 --- a/lib/rss/1.0.rb +++ b/lib/rss/1.0.rb @@ -18,7 +18,6 @@ module RSS include RSS10 include RootElementMixin - include XMLStyleSheetMixin class << self @@ -57,21 +56,22 @@ module RSS super('1.0', version, encoding, standalone) end + def full_name + tag_name_with_prefix(PREFIX) + end + def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EORDF -#{xmldecl} -#{xml_stylesheet_pi} -#{indent}<#{PREFIX}:RDF#{ns_declaration(next_indent)}> -#{channel_element(false, next_indent)} -#{image_element(false, next_indent)} -#{item_elements(false, next_indent)} -#{textinput_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EORDF + rv = tag(indent, ns_declarations) do |next_indent| + [ + channel_element(false, next_indent), + image_element(false, next_indent), + item_elements(false, next_indent), + textinput_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter - remove_empty_newline(rv) + rv end private @@ -119,16 +119,19 @@ EORDF end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - <<-EOT -#{indent}<#{PREFIX}:Seq> -#{li_elements(convert, next_indent)} -#{other_element(convert, next_indent)} -#{indent} -EOT + tag(indent) do |next_indent| + [ + li_elements(convert, next_indent), + other_element(convert, next_indent), + ] + end end - private + def full_name + tag_name_with_prefix(PREFIX) + end + + private def children @li end @@ -169,15 +172,15 @@ EOT super() @resource = resource end + + def full_name + tag_name_with_prefix(PREFIX) + end def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q!#{indent}<#{PREFIX}:li resource="#{h @resource}" />\n! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private @@ -232,20 +235,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - about = '' - about << %Q!#{PREFIX}:about="#{h @about}"! if @about - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{description_element(false, next_indent)} -#{image_element(false, next_indent)} -#{items_element(false, next_indent)} -#{textinput_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + link_element(false, next_indent), + description_element(false, next_indent), + image_element(false, next_indent), + items_element(false, next_indent), + textinput_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end @@ -270,7 +270,7 @@ EOT def _attrs [ - ["about", true] + ["#{PREFIX}:about", true, "about"] ] end @@ -298,22 +298,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q!#{indent}! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private def _attrs [ - ["resource", true] + ["#{PREFIX}:resource", true, "resource"] ] end - end class Textinput < Element @@ -340,22 +335,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q|#{indent}| - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private def _attrs [ - ["resource", true], + ["#{PREFIX}:resource", true, "resource"] ] end - end class Items < Element @@ -387,13 +377,12 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - <<-EOT -#{indent} -#{Seq_element(convert, next_indent)} -#{other_element(convert, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + Seq_element(convert, next_indent), + other_element(convert, next_indent), + ] + end end private @@ -452,17 +441,14 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - about = '' - about << %Q!#{PREFIX}:about="#{h @about}"! if @about - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{url_element(false, next_indent)} -#{link_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + url_element(false, next_indent), + link_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end @@ -480,10 +466,9 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end - end class Item < Element @@ -522,17 +507,14 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - about = '' - about << %Q!#{PREFIX}:about="#{h @about}"! if @about - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{description_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + link_element(false, next_indent), + description_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end @@ -550,10 +532,9 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end - end class Textinput < Element @@ -593,18 +574,15 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - about = '' - about << %Q!#{PREFIX}:about="#{h @about}"! if @about - rv = <<-EOT -#{indent} -#{title_element(false, next_indent)} -#{description_element(false, next_indent)} -#{name_element(false, next_indent)} -#{link_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent} -EOT + rv = tag(indent) do |next_indent| + [ + title_element(false, next_indent), + description_element(false, next_indent), + name_element(false, next_indent), + link_element(false, next_indent), + other_element(false, next_indent), + ] + end rv = @converter.convert(rv) if convert and @converter rv end @@ -623,10 +601,9 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end - end end diff --git a/lib/rss/2.0.rb b/lib/rss/2.0.rb index 7fafb23ba9..0a2d86860d 100644 --- a/lib/rss/2.0.rb +++ b/lib/rss/2.0.rb @@ -11,11 +11,18 @@ module RSS install_model(x, '?') end - %w(category).each do |x| - install_have_child_element(x) - install_model(x, '?') + undef :ttl= + def ttl=(value) + @ttl = value.to_i end - + + [ + %w(category categories), + ].each do |name, plural_name| + install_have_children_element(name, plural_name) + install_model(name, '*') + end + [ ["image", "?"], ["language", "?"], @@ -25,7 +32,7 @@ module RSS def other_element(convert, indent) rv = <<-EOT -#{category_element(convert, indent)} +#{category_elements(convert, indent)} #{generator_element(convert, indent)} #{ttl_element(convert, indent)} EOT @@ -35,16 +42,22 @@ EOT private alias children09 children def children - children09 + [@category].compact + children09 + @category.compact end alias _tags09 _tags def _tags - %w(generator ttl category).delete_if do |x| + rv = %w(generator ttl).delete_if do |x| send(x).nil? end.collect do |elem| [nil, elem] end + _tags09 + + @category.each do + rv << [nil, "category"] + end + + rv end Category = Item::Category @@ -74,13 +87,15 @@ EOT end def other_element(convert, indent) - rv = <<-EOT -#{author_element(false, indent)} -#{comments_element(false, indent)} -#{pubDate_element(false, indent)} -#{guid_element(false, indent)} -EOT - rv << super + rv = [ + super, + *%w(author comments pubDate guid).collect do |name| + __send__("#{name}_element", false, indent) + end + ].reject do |value| + /\A\s*\z/.match(value) + end + rv.join("\n") end private @@ -116,18 +131,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @content - rv = %Q!#{h @content}! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _attrs [ diff --git a/lib/rss/maker.rb b/lib/rss/maker.rb index c158c726c3..66c3bc2928 100644 --- a/lib/rss/maker.rb +++ b/lib/rss/maker.rb @@ -7,12 +7,7 @@ module RSS MAKERS = {} class << self - def make(version, modules=[], &block) - prefix = "rss/maker" - require "#{prefix}/#{version}" - modules.each do |mod| - require "#{prefix}/#{mod}" - end + def make(version, &block) maker(version).make(&block) end @@ -31,3 +26,10 @@ module RSS end end + +require "rss/maker/1.0" +require "rss/maker/2.0" +require "rss/maker/content" +require "rss/maker/dublincore" +require "rss/maker/syndication" +require "rss/maker/trackback" diff --git a/lib/rss/maker/0.9.rb b/lib/rss/maker/0.9.rb index 05578082b0..6f26e20f4f 100644 --- a/lib/rss/maker/0.9.rb +++ b/lib/rss/maker/0.9.rb @@ -69,9 +69,72 @@ module RSS super + ["pubDate"] end + class SkipDays < SkipDaysBase + def to_rss(rss, channel) + unless @days.empty? + skipDays = Rss::Channel::SkipDays.new + channel.skipDays = skipDays + @days.each do |day| + day.to_rss(rss, skipDays.days) + end + end + end + + class Day < DayBase + def to_rss(rss, days) + day = Rss::Channel::SkipDays::Day.new + set = setup_values(day) + if set + days << day + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + + class SkipHours < SkipHoursBase + def to_rss(rss, channel) + unless @hours.empty? + skipHours = Rss::Channel::SkipHours.new + channel.skipHours = skipHours + @hours.each do |hour| + hour.to_rss(rss, skipHours.hours) + end + end + end + + class Hour < HourBase + def to_rss(rss, hours) + hour = Rss::Channel::SkipHours::Hour.new + set = setup_values(hour) + if set + hours << hour + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + class Cloud < CloudBase + def to_rss(*args) + end end + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end + end end class Image < ImageBase @@ -130,9 +193,12 @@ module RSS end end - class Category < CategoryBase + class Categories < CategoriesBase def to_rss(*args) end + + class Category < CategoryBase + end end end diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb index 894bcc0a24..ae22eb4fc4 100644 --- a/lib/rss/maker/1.0.rb +++ b/lib/rss/maker/1.0.rb @@ -86,7 +86,33 @@ module RSS end end + class SkipDays < SkipDaysBase + def to_rss(*args) + end + + class Day < DayBase + end + end + + class SkipHours < SkipHoursBase + def to_rss(*args) + end + + class Hour < HourBase + end + end + class Cloud < CloudBase + def to_rss(*args) + end + end + + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end end end @@ -153,9 +179,12 @@ module RSS end end - class Category < CategoryBase + class Categories < CategoriesBase def to_rss(*args) end + + class Category < CategoryBase + end end end end diff --git a/lib/rss/maker/2.0.rb b/lib/rss/maker/2.0.rb index 05fc46480a..8ac5e7bbb3 100644 --- a/lib/rss/maker/2.0.rb +++ b/lib/rss/maker/2.0.rb @@ -13,23 +13,26 @@ module RSS 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) + 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_rss(rss) + def to_rss(rss, channel) cloud = Rss::Channel::Cloud.new set = setup_values(cloud) if set - rss.channel.cloud = cloud + channel.cloud = cloud setup_other_elements(rss) end end @@ -39,6 +42,30 @@ module RSS @registerProcedure and @protocol end end + + class Categories < RSS09::Channel::Categories + def to_rss(rss, channel) + @categories.each do |category| + category.to_rss(rss, channel) + end + end + + class Category < RSS09::Channel::Categories::Category + def to_rss(rss, channel) + category = Rss::Channel::Category.new + set = setup_values(category) + if set + channel.category = category + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + end class Image < RSS09::Image @@ -102,18 +129,26 @@ module RSS end end - class Category < RSS09::Items::Item::Category + class Categories < RSS09::Items::Item::Categories def to_rss(rss, item) - category = Rss::Channel::Item::Category.new - set = setup_values(category) - if set - item.category = category - setup_other_elements(rss) + @categories.each do |category| + category.to_rss(rss, item) end end - - def have_required_values? - @content + + class Category < RSS09::Items::Item::Categories::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 diff --git a/lib/rss/maker/base.rb b/lib/rss/maker/base.rb index 21222351f2..91eb072ec7 100644 --- a/lib/rss/maker/base.rb +++ b/lib/rss/maker/base.rb @@ -38,13 +38,24 @@ module RSS OTHER_ELEMENTS end - def self.add_need_initialize_variable(variable_name) - const_get("NEED_INITIALIZE_VARIABLES") << variable_name + def self.add_need_initialize_variable(variable_name, init_value="nil") + const_get("NEED_INITIALIZE_VARIABLES") << [variable_name, init_value] end def self.need_initialize_variables NEED_INITIALIZE_VARIABLES end + + def self.def_array_element(name) + include Enumerable + extend Forwardable + + def_delegators("@\#{name}", :<<, :[], :[]=, :first, :last) + def_delegators("@\#{name}", :push, :pop, :shift, :unshift) + def_delegators("@\#{name}", :each) + + add_need_initialize_variable(name, "[]") + end EOC end @@ -59,8 +70,8 @@ module RSS private def initialize_variables - self.class.need_initialize_variables.each do |variable_name| - instance_eval("@#{variable_name} = nil", __FILE__, __LINE__) + self.class.need_initialize_variables.each do |variable_name, init_value| + instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__) end end @@ -88,7 +99,11 @@ module RSS end def variables - self.class.need_initialize_variables + self.class.need_initialize_variables.find_all do |name, init| + "nil" == init + end.collect do |name, init| + name + end end end @@ -159,17 +174,7 @@ module RSS class XMLStyleSheets include Base - include Enumerable - extend Forwardable - - def_delegators(:@xml_stylesheets, :<<, :[], :[]=, :first, :last) - def_delegators(:@xml_stylesheets, :push, :pop, :shift, :unshift) - def_delegators(:@xml_stylesheets, :each) - - def initialize(maker) - super - @xml_stylesheets = [] - end + def_array_element("xml_stylesheets") def to_rss(rss) @xml_stylesheets.each do |xss| @@ -217,12 +222,25 @@ module RSS class ChannelBase include Base - attr_reader :cloud + %w(cloud categories skipDays skipHours).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) + end + + def make_#{element} + self.class::#{element[0,1].upcase}#{element[1..-1]}.new(@maker) + end +EOC + end %w(about title link description language copyright - managingEditor webMaster rating docs skipDays - skipHours date lastBuildDate category generator ttl - ).each do |element| + managingEditor webMaster rating docs date + lastBuildDate generator ttl).each do |element| attr_accessor element add_need_initialize_variable(element) end @@ -230,18 +248,68 @@ module RSS alias_method(:pubDate, :date) alias_method(:pubDate=, :date=) - def initialize(maker) - super - @cloud = make_cloud - end - def current_element(rss) rss.channel end - private - def make_cloud - self.class::Cloud.new(@maker) + 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 + + class DayBase + include Base + + %w(content).each do |element| + 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 + + class HourBase + include Base + + %w(content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def current_element(rss) + rss.channel.skipHours.last + end + + end end class CloudBase @@ -257,6 +325,27 @@ module RSS end end + + class CategoriesBase + include Base + + def_array_element("categories") + + def new_category + category = self.class::Category.new(@maker) + @categories << category + category + end + + class CategoryBase + include Base + + %w(domain content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + end end class ImageBase @@ -279,18 +368,12 @@ module RSS class ItemsBase include Base - include Enumerable - extend Forwardable - - def_delegators(:@items, :<<, :[], :[]=, :first, :last) - def_delegators(:@items, :push, :pop, :shift, :unshift) - def_delegators(:@items, :each) + def_array_element("items") attr_accessor :do_sort def initialize(maker) super - @items = [] @do_sort = false end @@ -326,9 +409,10 @@ module RSS class ItemBase include Base - %w(guid enclosure source category).each do |element| + %w(guid enclosure source categories).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) @@ -349,14 +433,6 @@ EOC alias_method(:pubDate, :date) alias_method(:pubDate=, :date=) - 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 @@ -400,14 +476,7 @@ EOC end end - class CategoryBase - include Base - - %w(domain content).each do |element| - attr_accessor element - add_need_initialize_variable(element) - end - end + CategoriesBase = ChannelBase::CategoriesBase end end diff --git a/lib/rss/maker/trackback.rb b/lib/rss/maker/trackback.rb index 1ec59ab0b0..ef78bf2f20 100644 --- a/lib/rss/maker/trackback.rb +++ b/lib/rss/maker/trackback.rb @@ -1,5 +1,6 @@ require 'rss/trackback' require 'rss/maker/1.0' +require 'rss/maker/2.0' module RSS module Maker @@ -7,18 +8,65 @@ module RSS 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) - if #{name} and current.respond_to?(:#{name}=) - current.#{name} = @#{name} if @#{name} - end + name = "#{RSS::TRACKBACK_PREFIX}_ping" + 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) + if #{name} and current.respond_to?(:#{name}=) + current.#{name} = #{name} end - EOC + end + EOC + + name = "#{RSS::TRACKBACK_PREFIX}_abouts" + klass.add_need_initialize_variable(name, "make_#{name}") + klass.add_other_element(name) + klass.__send__(:attr_accessor, name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + def make_#{name} + self.class::TrackBackAbouts.new(self) + end + + def setup_#{name}(rss, current) + @#{name}.to_rss(rss, current) + end + EOC + end + + class TrackBackAboutsBase + include Base + + def_array_element("abouts") + + def new_about + about = self.class::About.new(@maker) + @abouts << about + about + end + + def to_rss(rss, current) + @abouts.each do |about| + about.to_rss(rss, current) + end + end + + class AboutBase + include Base + + attr_accessor :value + add_need_initialize_variable(:value) + + alias_method(:resource, :value) + alias_method(:resource=, :value=) + alias_method(:content, :value) + alias_method(:content=, :value=) + + def have_required_values? + @value + end + end end end @@ -26,5 +74,53 @@ module RSS class ItemsBase class ItemBase; include TrackBackModel; end end + + class RSS10 + class Items + class Item + class TrackBackAbouts < TrackBackAboutsBase + class About < AboutBase + def to_rss(rss, current) + if resource + about = ::RSS::TrackBackModel10::About.new(resource) + current.trackback_abouts << about + end + end + end + end + end + end + end + + class RSS09 + class Items + class Item + class TrackBackAbouts < TrackBackAboutsBase + def to_rss(*args) + end + class About < AboutBase + end + end + end + end + end + + class RSS20 + class Items + class Item + class TrackBackAbouts < TrackBackAboutsBase + class About < AboutBase + def to_rss(rss, current) + if content + about = ::RSS::TrackBackModel20::About.new(content) + current.trackback_abouts << about + end + end + end + end + end + end + end + end end diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb index 09b3213372..e1da24418a 100644 --- a/lib/rss/parser.rb +++ b/lib/rss/parser.rb @@ -348,6 +348,13 @@ module RSS end if @do_validate and required and val.nil? + unless a_uri.include?(nil) + for prefix, uri in ns + if a_uri.include?(uri) + a_name = "#{prefix}:#{a_name}" + end + end + end raise MissingAttributeError.new(tag_name, a_name) end diff --git a/lib/rss/rexmlparser.rb b/lib/rss/rexmlparser.rb index 375b7794fb..73e352a731 100644 --- a/lib/rss/rexmlparser.rb +++ b/lib/rss/rexmlparser.rb @@ -36,7 +36,7 @@ module RSS include ListenerMixin def xmldecl(version, encoding, standalone) - super + super(version, encoding, standalone == "yes") # Encoding is converted to UTF-8 when REXML parse XML. @encoding = 'UTF-8' end diff --git a/lib/rss/rss.rb b/lib/rss/rss.rb index b6afa24b93..a63bee8a69 100644 --- a/lib/rss/rss.rb +++ b/lib/rss/rss.rb @@ -58,7 +58,7 @@ require "rss/xml-stylesheet" module RSS - VERSION = "0.1.0" + VERSION = "0.1.1" URI = "http://purl.org/rss/1.0/" @@ -164,17 +164,17 @@ EOC end alias_method(:install_have_attribute_element, :install_have_child_element) - def install_have_children_element(name, postfix="s") + def install_have_children_element(name, plural_name=nil) add_have_children_element(name) - def_children_accessor(name, postfix) - install_element(name, postfix) do |n, elem_name| + def_children_accessor(name, plural_name) + install_element(name, "s") do |n, elem_name| <<-EOC - rv = '' + rv = [] @#{n}.each do |x| rv << "\#{x.to_s(convert, indent)}" end - rv + rv.join("\n") EOC end end @@ -289,9 +289,10 @@ EOC end end - def def_children_accessor(accessor_name, postfix="s") + def def_children_accessor(accessor_name, plural_name=nil) + plural_name ||= "#{accessor_name}s" module_eval(<<-EOC, *get_file_and_line_from_caller(2)) - def #{accessor_name}#{postfix} + def #{plural_name} @#{accessor_name} end @@ -314,6 +315,22 @@ EOC EOC end + def def_content_only_to_s + module_eval(<<-EOC, *get_file_and_line_from_caller(2)) + def to_s(convert=true, indent=calc_indent) + if @content + rv = tag(indent) do |next_indent| + h(@content) + end + rv = @converter.convert(rv) if convert and @converter + rv + else + "" + end + end +EOC + end + end class Element @@ -329,7 +346,8 @@ EOC klass.module_eval(<<-EOC) public - @tag_name = name.split(/::/).last.downcase + @tag_name = name.split(/::/).last + @tag_name[0,1] = @tag_name[0,1].downcase @indent_size = name.split(/::/).size - 2 @@must_call_validators = {} @@ -373,6 +391,7 @@ EOC def self.content_setup attr_writer :content convert_attr_reader :content + def_content_only_to_s @@have_content = true end @@ -440,6 +459,14 @@ EOC self.class.tag_name end + def full_name + tag_name + end + + def indent_size + self.class.indent_size + end + def converter=(converter) @converter = converter children.each do |child| @@ -472,6 +499,66 @@ EOC end end + def tag(indent, additional_attrs=[]) + next_indent = indent + INDENT + + attrs = collect_attrs + return "" if attrs.nil? + + attrs += additional_attrs + start_tag = make_start_tag(indent, next_indent, attrs) + + if block_given? + content = yield(next_indent) + else + content = [] + end + + if content.is_a?(String) + content = [content] + start_tag << ">" + end_tag = "" + else + content = content.reject{|x| x.empty?} + if content.empty? + end_tag = "/>" + else + start_tag << ">\n" + end_tag = "\n#{indent}" + end + end + + start_tag + content.join("\n") + end_tag + end + + def make_start_tag(indent, next_indent, attrs) + start_tag = ["#{indent}<#{full_name}"] + unless attrs.empty? + start_tag << attrs.collect do |key, value| + %Q[#{h key}="#{h value}"] + end.join("\n#{next_indent}") + end + start_tag.join(" ") + end + + def collect_attrs + _attrs.collect do |name, required, alias_name| + value = __send__(alias_name || name) + return nil if required and value.nil? + [name, value] + end.reject do |name, value| + value.nil? + end + end + + def tag_name_with_prefix(prefix) + "#{prefix}:#{tag_name}" + end + + def calc_indent + INDENT * (self.class.indent_size) + end + # not String class children. def children [] @@ -507,23 +594,23 @@ EOC end def validate_attribute - _attrs.each do |a_name, required| - if required and send(a_name).nil? - raise MissingAttributeError.new(self.class.tag_name, a_name) + _attrs.each do |a_name, required, alias_name| + if required and __send__(alias_name || a_name).nil? + raise MissingAttributeError.new(tag_name, a_name) end end end def other_element(convert, indent='') - rv = '' + rv = [] private_methods.each do |meth| if /\A([^_]+)_[^_]+_elements?\z/ =~ meth and self.class::NSPOOL.has_key?($1) - res = send(meth, convert) - rv << "#{indent}#{res}\n" if /\A\s*\z/ !~ res + res = __send__(meth, convert) + rv << "#{indent}#{res}" if /\A\s*\z/ !~ res end end - rv + rv.join("\n") end def _validate(tags, model=self.class.model) @@ -626,19 +713,12 @@ EOC rv end - private - def calc_indent - INDENT * (self.class.indent_size) - end - - def remove_empty_newline(string) - string.gsub(/^\s*$(?:\r?\n?)/, '') - end - end module RootElementMixin + include XMLStyleSheetMixin + attr_reader :output_encoding def initialize(rss_version, version=nil, encoding=nil, standalone=nil) @@ -656,23 +736,27 @@ EOC end private + def tag(indent, attrs) + rv = xmldecl + xml_stylesheet_pi + rv << super + rv + end + def xmldecl rv = %Q[' + rv << %Q[ standalone="yes"] if @standalone + rv << "?>\n" rv end - def ns_declaration(indent) - rv = '' - self.class::NSPOOL.each do |prefix, uri| + def ns_declarations + self.class::NSPOOL.collect do |prefix, uri| prefix = ":#{prefix}" unless prefix.empty? - rv << %Q|\n#{indent}xmlns#{prefix}="#{html_escape(uri)}"| + ["xmlns#{prefix}", uri] end - rv end end diff --git a/lib/rss/trackback.rb b/lib/rss/trackback.rb index e276305ec1..5cbf652406 100644 --- a/lib/rss/trackback.rb +++ b/lib/rss/trackback.rb @@ -9,7 +9,16 @@ module RSS RDF.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) Rss.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) - module BaseTrackBackModel + module TrackBackUtils + private + def new_with_value_if_need(klass, value) + if value.is_a?(klass) + value + else + klass.new(value) + end + end + def trackback_validate(tags) counter = {} %w(ping about).each do |x| @@ -31,179 +40,64 @@ module RSS end end end - - module TrackBackModel10 - extend BaseModel - include BaseTrackBackModel - - def self.append_features(klass) + + module BaseTrackBackModel + def append_features(klass) super unless klass.class == Module - %w(ping).each do |x| - klass.install_have_child_element("#{TRACKBACK_PREFIX}_#{x}") - end - - %w(about).each do |x| - klass.install_have_children_element("#{TRACKBACK_PREFIX}_#{x}") - end - end - end + klass.__send__(:include, TrackBackUtils) - class Ping < Element - include RSS10 - - class << self - - def required_prefix - TRACKBACK_PREFIX - end - - def required_uri - TRACKBACK_URI - end - - end - - [ - ["resource", ::RSS::RDF::URI, true] - ].each do |name, uri, required| - install_get_attribute(name, uri, required) - end - - def initialize(resource=nil) - super() - @resource = resource - end - - def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q[#{indent}<#{TRACKBACK_PREFIX}:ping ] - rv << %Q[#{::RSS::RDF::PREFIX}:resource="#{h @resource}"/>] - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - - private - def _attrs - [ - ["resource", true], - ] - end - - end - - class About < Element - include RSS10 - - class << self - - def required_prefix - TRACKBACK_PREFIX - end - - def required_uri - TRACKBACK_URI - end - - end - - [ - ["resource", ::RSS::RDF::URI, true] - ].each do |name, uri, required| - install_get_attribute(name, uri, required) - end - - def initialize(resource=nil) - super() - @resource = resource - end - - def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q[#{indent}<#{TRACKBACK_PREFIX}:about ] - rv << %Q[#{::RSS::RDF::PREFIX}:resource="#{h @resource}"/>] - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - - private - def _attrs - [ - ["resource", true], - ] - end - - end - end - - module TrackBackModel20 - include BaseTrackBackModel - extend BaseModel - - def self.append_features(klass) - super - - unless klass.class == Module %w(ping).each do |x| var_name = "#{TRACKBACK_PREFIX}_#{x}" + klass_name = x.capitalize klass.install_have_child_element(var_name) - klass.module_eval(<<-EOC) - alias _#{var_name} #{var_name} + klass.module_eval(<<-EOC, __FILE__, __LINE__) + undef #{var_name} def #{var_name} - @#{var_name} and @#{var_name}.content + @#{var_name} and @#{var_name}.value end - alias _#{var_name}= #{var_name}= - def #{var_name}=(content) - @#{var_name} = new_with_content_if_need(#{x.capitalize}, content) + undef #{var_name}= + def #{var_name}=(value) + @#{var_name} = new_with_value_if_need(#{klass_name}, value) end EOC end [%w(about s)].each do |x, postfix| var_name = "#{TRACKBACK_PREFIX}_#{x}" + klass_name = x.capitalize klass.install_have_children_element(var_name) - klass.module_eval(<<-EOC) - alias _#{var_name}#{postfix} #{var_name}#{postfix} - def #{var_name}#{postfix} - @#{var_name}.collect {|x| x.content} - end - - alias _#{var_name} #{var_name} + klass.module_eval(<<-EOC, __FILE__, __LINE__) + undef #{var_name} def #{var_name}(*args) if args.empty? - @#{var_name}.first and @#{var_name}.first.content + @#{var_name}.first and @#{var_name}.first.value else ret = @#{var_name}.send("[]", *args) if ret.is_a?(Array) - ret.collect {|x| x.content} + ret.collect {|x| x.value} else - ret.content + ret.value end end end - alias _#{var_name}= #{var_name}= - alias _set_#{var_name} set_#{var_name} + undef #{var_name}= + undef set_#{var_name} def #{var_name}=(*args) if args.size == 1 - item = new_with_content_if_need(#{x.capitalize}, args[0]) + item = new_with_value_if_need(#{klass_name}, args[0]) @#{var_name}.push(item) else new_val = args.last if new_val.is_a?(Array) new_val = new_value.collect do |val| - new_with_content_if_need(#{x.capitalize}, val) + new_with_value_if_need(#{klass_name}, val) end else - new_val = new_with_content_if_need(#{x.capitalize}, new_val) + new_val = new_with_value_if_need(#{klass_name}, new_val) end @#{var_name}.send("[]=", *(args[0..-2] + [new_val])) end @@ -213,22 +107,112 @@ module RSS end end end + end - private - def new_with_content(klass, content) - obj = klass.new - obj.content = content - obj - end + module TrackBackModel10 + extend BaseModel + extend BaseTrackBackModel + + class Ping < Element + include RSS10 + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end - def new_with_content_if_need(klass, content) - if content.is_a?(klass) - content - else - new_with_content(klass, content) end + + [ + ["resource", ::RSS::RDF::URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required) + end + + alias_method(:value, :resource) + alias_method(:value=, :resource=) + + def initialize(resource=nil) + super() + @resource = resource + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + + def to_s(convert=true, indent=calc_indent) + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv + end + + private + def _attrs + [ + ["#{::RSS::RDF::PREFIX}:resource", true, "resource"], + ] + end + end + class About < Element + include RSS10 + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end + + end + + [ + ["resource", ::RSS::RDF::URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required) + end + + alias_method(:value, :resource) + alias_method(:value=, :resource=) + + def initialize(resource=nil) + super() + @resource = resource + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + + def to_s(convert=true, indent=calc_indent) + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv + end + + private + def _attrs + [ + ["#{::RSS::RDF::PREFIX}:resource", true, "resource"], + ] + end + + end + end + + module TrackBackModel20 + extend BaseModel + extend BaseTrackBackModel class Ping < Element include RSS09 @@ -247,18 +231,18 @@ module RSS end - def to_s(convert=true, indent=calc_indent) - if @content - rv = %Q[#{indent}<#{TRACKBACK_PREFIX}:ping>] - rv << h(@content) - rv << %Q[] - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end + alias_method(:value, :content) + alias_method(:value=, :content=) + def initialize(content=nil) + super() + @content = content + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + end class About < Element @@ -277,19 +261,19 @@ module RSS end end - - def to_s(convert=true, indent=calc_indent) - if @content - rv = %Q[#{indent}<#{TRACKBACK_PREFIX}:about>] - rv << h(@content) - rv << %Q[] - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end + alias_method(:value, :content) + alias_method(:value=, :content=) + + def initialize(content=nil) + super() + @content = content + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + end end diff --git a/lib/rss/xmlscanner.rb b/lib/rss/xmlscanner.rb index 472ca93523..c5a11bad18 100644 --- a/lib/rss/xmlscanner.rb +++ b/lib/rss/xmlscanner.rb @@ -45,7 +45,7 @@ module RSS end def on_xmldecl_end - xmldecl(@version, @encoding, @standalone) + xmldecl(@version, @encoding, @standalone == "yes") end alias_method(:on_pi, :instruction) diff --git a/test/rss/rss-assertions.rb b/test/rss/rss-assertions.rb index 6b83cbe093..a51fc1fd60 100644 --- a/test/rss/rss-assertions.rb +++ b/test/rss/rss-assertions.rb @@ -94,27 +94,32 @@ module RSS end end end - - def assert_xml_stylesheet_attrs(xsl, attrs) + + def assert_xml_declaration(version, encoding, standalone, rss) _wrap_assertion do - normalized_attrs = {} - attrs.each do |name, value| - normalized_attrs[name.to_s] = value - end + assert_equal(version, rss.version) + assert_equal(encoding, rss.encoding) + assert_equal(standalone, rss.standalone) + end + end + + def assert_xml_stylesheet_attrs(attrs, xsl) + _wrap_assertion do + n_attrs = normalized_attrs(attrs) ::RSS::XMLStyleSheet::ATTRIBUTES.each do |name| - assert_equal(normalized_attrs[name], xsl.send(name)) + assert_equal(n_attrs[name], xsl.send(name)) end end end - def assert_xml_stylesheet(target, xsl, attrs) + def assert_xml_stylesheet(target, attrs, xsl) _wrap_assertion do if attrs.has_key?(:href) if !attrs.has_key?(:type) and attrs.has_key?(:guess_type) attrs[:type] = attrs[:guess_type] end assert_equal("xml-stylesheet", target) - assert_xml_stylesheet_attrs(xsl, attrs) + assert_xml_stylesheet_attrs(attrs, xsl) else assert_nil(target) assert_equal("", xsl.to_s) @@ -123,40 +128,314 @@ module RSS end def assert_xml_stylesheet_pis(attrs_ary) - rdf = ::RSS::RDF.new() - xss_strs = [] - attrs_ary.each do |attrs| - xss = ::RSS::XMLStyleSheet.new(*attrs) - xss_strs.push(xss.to_s) - rdf.xml_stylesheets.push(xss) + _wrap_assertion do + rdf = ::RSS::RDF.new() + xss_strs = [] + attrs_ary.each do |attrs| + xss = ::RSS::XMLStyleSheet.new(*attrs) + xss_strs.push(xss.to_s) + rdf.xml_stylesheets.push(xss) + end + pi_str = rdf.to_s.gsub(/<\?xml .*\n/, "").gsub(/\s* "http://bar.com/tb.cgi?tb_id=rssplustrackback", - :about => "http://foo.com/trackback/tb.cgi?tb_id=20020923", + :abouts => [ + "http://foo.com/trackback/tb.cgi?tb_id=20020923", + "http://bar.com/trackback/tb.cgi?tb_id=20041114", + ], } end def test_rss10 - rss = RSS::Maker.make("1.0", ["trackback"]) do |maker| + rss = RSS::Maker.make("1.0") do |maker| setup_dummy_channel(maker) setup_dummy_item(maker) item = maker.items.last - @elements.each do |name, value| - item.__send__("#{accessor_name(name)}=", value) + item.trackback_ping = @elements[:ping] + @elements[:abouts].each do |about| + new_about = item.trackback_abouts.new_about + new_about.value = about end end assert_trackback(@elements, rss.items.last) diff --git a/test/rss/test_parser.rb b/test/rss/test_parser.rb index de4894997f..019030bcce 100644 --- a/test/rss/test_parser.rb +++ b/test/rss/test_parser.rb @@ -116,7 +116,7 @@ EOR def test_channel - assert_parse(make_RDF(<<-EOR), :missing_attribute, "channel", "about") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "channel", "rdf:about") EOR @@ -145,7 +145,7 @@ EOR EOR - assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "resource") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "rdf:resource") hoge http://example.com/ @@ -194,7 +194,7 @@ EOR EOR - assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "resource") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "rdf:resource") hoge http://example.com/ @@ -257,7 +257,7 @@ EOR def test_image - assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "about") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "image", "rdf:about") #{make_channel} @@ -314,7 +314,7 @@ EOR def test_item - assert_parse(make_RDF(<<-EOR), :missing_attribute, "item", "about") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "item", "rdf:about") #{make_channel} #{make_image} @@ -371,7 +371,7 @@ EOR def test_textinput - assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "about") + assert_parse(make_RDF(<<-EOR), :missing_attribute, "textinput", "rdf:about") #{make_channel} #{make_image} #{make_item} diff --git a/test/rss/test_to_s.rb b/test/rss/test_to_s.rb new file mode 100644 index 0000000000..e2263ca17c --- /dev/null +++ b/test/rss/test_to_s.rb @@ -0,0 +1,440 @@ +require "rexml/document" + +require "rss-testcase" + +require "rss/maker" +require "rss/1.0" +require "rss/2.0" +require "rss/content" +require "rss/dublincore" +require "rss/syndication" +require "rss/trackback" + +module RSS + class TestToS < TestCase + + def setup + @image_url = "http://example.com/foo.png" + @textinput_link = "http://example.com/search.cgi" + @item_links = [ + "http://example.com/1", + "http://example.com/2", + ] + + setup_xml_declaration_info + setup_xml_stylesheet_infos + setup_channel_info + setup_item_infos + setup_image_info + setup_textinput_info + + setup_dublin_core_info + setup_syndication_info + setup_content_info + setup_trackback_info + end + + def test_to_s_10 + rss = RSS::Maker.make("1.0") do |maker| + setup_full(maker) + end + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel10(@channel_info, rss.channel) + assert_items10(@item_infos, rss.items) + rss.items.each do |item| + assert_trackback(@trackback_info, item) + end + assert_image10(@image_info, rss.image) + assert_textinput10(@textinput_info, rss.textinput) + + rss = RSS::Parser.parse(rss.to_s) + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel10(@channel_info, rss.channel) + assert_items10(@item_infos, rss.items) + assert_image10(@image_info, rss.image) + assert_textinput10(@textinput_info, rss.textinput) + end + + def test_to_s_09 + rss = RSS::Maker.make("0.9") do |maker| + setup_full(maker) + end + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel09(@channel_info, rss.channel) + assert_items09(@item_infos, rss.items) + assert_image09(@image_info, rss.image) + assert_textinput09(@textinput_info, rss.textinput) + + rss = RSS::Parser.parse(rss.to_s) + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel09(@channel_info, rss.channel) + assert_items09(@item_infos, rss.items) + assert_image09(@image_info, rss.image) + assert_textinput09(@textinput_info, rss.textinput) + end + + def test_to_s_20 + rss = RSS::Maker.make("2.0") do |maker| + setup_full(maker) + end + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel20(@channel_info, rss.channel) + assert_items20(@item_infos, rss.items) + assert_image20(@image_info, rss.image) + assert_textinput20(@textinput_info, rss.textinput) + + rss = RSS::Parser.parse(rss.to_s) + + assert_xml_declaration(@version, @encoding, @standalone, rss) + assert_xml_stylesheets(@xs_infos, rss.xml_stylesheets) + assert_channel20(@channel_info, rss.channel) + assert_items20(@item_infos, rss.items) + assert_image20(@image_info, rss.image) + assert_textinput20(@textinput_info, rss.textinput) + end + + private + def setup_xml_declaration_info + @version = "1.0" + @encoding = "UTF-8" + @standalone = false + end + + def setup_xml_stylesheet_infos + @xs_infos = [ + { + "href" => "XXX.xsl", + "type" => "text/xsl", + "title" => "XXX", + "media" => "print", + "alternate" => "no", + }, + { + "href" => "YYY.css", + "type" => "text/css", + "title" => "YYY", + "media" => "all", + "alternate" => "no", + }, + ] + end + + def setup_channel_info + @channel_info = { + "about" => "http://example.com/index.rdf", + "title" => "Sample RSS", + "link" => "http://example.com/", + "description" => "Sample\n\n\n\n\nSite", + "language" => "en", + "copyright" => "FDL", + "managingEditor" => "foo@example.com", + "webMaster" => "webmaster@example.com", + "rating" => '(PICS-1.1 "http://www.rsac.org/ratingsv01.html" l gen true comment "RSACi North America Server" for "http://www.rsac.org" on "1996.04.16T08:15-0500" r (n 0 s 0 v 0 l 0))', + "docs" => "http://backend.userland.com/rss091", + "skipDays" => [ + "Monday", + "Friday", + ], + "skipHours" => [ + 12, + 23, + ], + "date" => Time.now, + "lastBuildDate" => Time.now - 3600, + "generator" => "RSS Maker", + "ttl" => 60, + "cloud" => { + "domain" => "rpc.sys.com", + "port" => "80", + "path" => "/RPC2", + "registerProcedure" => "myCloud.rssPleaseNotify", + "protocol" => "xml-rpc", + }, + "category" => { + "domain" => "http://example.com/misc/", + "content" => "misc", + }, + + "image" => { + "resource" => @image_url, + }, + + "textinput" => { + "resource" => @textinput_link, + }, + + "items" => @item_links.collect{|link| {"resource" => link}}, + } + end + + def setup_item_infos + @item_infos = [ + { + "title" => "Sample item1", + "link" => @item_links[0], + "description" => "Sample description1", + "date" => Time.now - 3600, + "author" => "foo@example.com", + "comments" => "http://example.com/1/comments", + "guid" => { + "isPermaLink" => "ture", + "content" => "http://example.com/1", + }, + "enclosure" => { + "url" => "http://example.com/1.mp3", + "length" => "100", + "type" => "audio/mpeg", + }, + "source" => { + "url" => "http:/example.com/", + "content" => "Sample site", + }, + "category" => { + "domain" => "http://example.com/misc/", + "content" => "misc", + }, + }, + + { + "title" => "Sample item2", + "link" => @item_links[1], + "description" => "Sample description2", + "date" => Time.now - 7200, + "author" => "foo@example.com", + "comments" => "http://example.com/2/comments", + "guid" => { + "isPermaLink" => "false", + "content" => "http://example.com/2", + }, + "enclosure" => { + "url" => "http://example.com/2.mp3", + "length" => "200", + "type" => "audio/mpeg", + }, + "source" => { + "url" => "http:/example.com/", + "content" => "Sample site", + }, + "category" => { + "domain" => "http://example.com/misc/", + "content" => "misc", + }, + }, + ] + end + + def setup_image_info + @image_info = { + "title" => "Sample image", + "url" => @image_url, + "width" => "88", + "height" => "31", + "description" => "Sample", + } + end + + def setup_textinput_info + @textinput_info = { + "title" => "Sample textinput", + "description" => "Search", + "name" => "key", + "link" => @textinput_link, + } + end + + def setup_dublin_core_info + @dc_info = { + "title" => "DC title", + "description" => "DC desc", + "creator" => "DC creator", + "subject" => "DC subject", + "publisher" => "DC publisher", + "contributor" => "DC contributor", + "type" => "DC type", + "format" => "DC format", + "identifier" => "DC identifier", + "source" => "DC source", + "language" => "ja", + "relation" => "DC relation", + "coverage" => "DC coverage", + "rights" => "DC rights", + "date" => Time.now - 60, + } + end + + def setup_syndication_info + @sy_info = { + "updatePeriod" => "hourly", + "updateFrequency" => 2, + "updateBase" => Time.now - 3600, + } + end + + def setup_content_info + @content_info = { + "encoded" => "

p

", + } + end + + def setup_trackback_info + @trackback_info = { + "ping" => "http://example.com/tb.cgi?tb_id=XXX", + "abouts" => [ + "http://example.net/tb.cgi?tb_id=YYY", + "http://example.org/tb.cgi?tb_id=ZZZ", + ] + } + end + + + def setup_full(maker) + setup_xml_declaration(maker) + setup_xml_stylesheets(maker) + setup_channel(maker) + setup_image(maker) + setup_items(maker) + setup_textinput(maker) + end + + def setup_xml_declaration(maker) + %w(version encoding standalone).each do |name| + maker.__send__("#{name}=", instance_eval("@#{name}")) + end + end + + def setup_xml_stylesheets(maker) + @xs_infos.each do |info| + xs = maker.xml_stylesheets.new_xml_stylesheet + info.each do |name, value| + xs.__send__("#{name}=", value) + end + end + end + + def setup_channel(maker) + channel = maker.channel + info = @channel_info + + %w(about title link description language copyright + managingEditor webMaster rating docs date + lastBuildDate generator ttl).each do |name| + channel.__send__("#{name}=", info[name]) + end + + skipDays = channel.skipDays + info["skipDays"].each do |day| + new_day = skipDays.new_day + new_day.content = day + end + + skipHours = channel.skipHours + info["skipHours"].each do |hour| + new_hour = skipHours.new_hour + new_hour.content = hour + end + + cloud = channel.cloud + %w(domain port path registerProcedure protocol).each do |name| + cloud.__send__("#{name}=", info["cloud"][name]) + end + + category = channel.categories.new_category + %w(domain content).each do |name| + category.__send__("#{name}=", info["category"][name]) + end + end + + def setup_image(maker) + image = maker.image + info = @image_info + + %w(title url width height description).each do |name| + image.__send__("#{name}=", info[name]) + end + end + + def setup_items(maker) + items = maker.items + + @item_infos.each do |info| + item = items.new_item + %w(title link description date author comments).each do |name| + item.__send__("#{name}=", info[name]) + end + + guid = item.guid + %w(isPermaLink content).each do |name| + guid.__send__("#{name}=", info["guid"][name]) + end + + enclosure = item.enclosure + %w(url length type).each do |name| + enclosure.__send__("#{name}=", info["enclosure"][name]) + end + + source = item.source + %w(url content).each do |name| + source.__send__("#{name}=", info["source"][name]) + end + + category = item.categories.new_category + %w(domain content).each do |name| + category.__send__("#{name}=", info["category"][name]) + end + + setup_trackback(item) + end + end + + def setup_textinput(maker) + textinput = maker.textinput + info = @textinput_info + + %w(title description name link).each do |name| + textinput.__send__("#{name}=", info[name]) + end + end + + def setup_content(target) + prefix = "content" + %w(encoded).each do |name| + target.__send__("#{prefix}_#{name}=", @content_info[name]) + end + end + + def setup_dublin_core(target) + prefix = "dc" + %w(title description creator subject publisher + contributor type format identifier source language + relation coverage rights).each do |name| + target.__send__("#{prefix}_#{name}=", @dc_info[name]) + end + end + + def setup_syndicate(target) + prefix = "sy" + %w(updatePeriod updateFrequency updateBase).each do |name| + target.__send__("#{prefix}_#{name}=", @sy_info[name]) + end + end + + def setup_trackback(target) + target.trackback_ping = @trackback_info["ping"] + @trackback_info["abouts"].each do |about| + new_about = target.trackback_abouts.new_about + new_about.value = about + end + end + + end +end diff --git a/test/rss/test_trackback.rb b/test/rss/test_trackback.rb index bfe39d005b..a3f023e887 100644 --- a/test/rss/test_trackback.rb +++ b/test/rss/test_trackback.rb @@ -88,19 +88,19 @@ EOR @elems.each do |name, value| @parents.each do |parent| accessor = "#{RSS::TRACKBACK_PREFIX}_#{name}" - target_accessor = "resource" - target = @rss.send(parent).send(accessor) + target = @rss.send(parent) target20 = @rss20.channel.send(parent, -1) - assert_equal(value, target.send(target_accessor)) + assert_equal(value, target.send(accessor)) assert_equal(value, target20.send(accessor)) - target.send("#{target_accessor}=", new_value[name].to_s) if name == :about # abount is zero or more + target.send("#{accessor}=", 0, new_value[name].to_s) target20.send("#{accessor}=", 0, new_value[name].to_s) else + target.send("#{accessor}=", new_value[name].to_s) target20.send("#{accessor}=", new_value[name].to_s) end - assert_equal(new_value[name], target.send(target_accessor)) + assert_equal(new_value[name], target.send(accessor)) assert_equal(new_value[name], target20.send(accessor)) end end diff --git a/test/rss/test_xml-stylesheet.rb b/test/rss/test_xml-stylesheet.rb index ab16d6e2ff..c88a858f56 100644 --- a/test/rss/test_xml-stylesheet.rb +++ b/test/rss/test_xml-stylesheet.rb @@ -14,7 +14,7 @@ module RSS {:media => "print", :title => "FOO"}, {:charset => "UTF-8", :alternate => "yes"}, ].each do |attrs| - assert_xml_stylesheet_attrs(XMLStyleSheet.new(*attrs), attrs) + assert_xml_stylesheet_attrs(attrs, XMLStyleSheet.new(*attrs)) end end @@ -36,7 +36,7 @@ module RSS :alternate => "yes"}, ].each do |attrs| target, contents = parse_pi(XMLStyleSheet.new(*attrs).to_s) - assert_xml_stylesheet(target, XMLStyleSheet.new(*contents), attrs) + assert_xml_stylesheet(target, attrs, XMLStyleSheet.new(*contents)) end end @@ -88,7 +88,7 @@ module RSS assert_equal(have_href_xsss.size, rss.xml_stylesheets.size) rss.xml_stylesheets.each_with_index do |stylesheet, i| target, = parse_pi(stylesheet.to_s) - assert_xml_stylesheet(target, stylesheet, have_href_xsss[i]) + assert_xml_stylesheet(target, have_href_xsss[i], stylesheet) end end end