diff options
author | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-12-08 12:58:36 +0000 |
---|---|---|
committer | kou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2004-12-08 12:58:36 +0000 |
commit | bcf72db844b54492aca33b068711992bd73caccf (patch) | |
tree | a54da3329420c04614c460c3b45388951a790aa2 /lib | |
parent | 67c5b057e692b39c801aea811c6b75b40c4b8c22 (diff) | |
download | ruby-bcf72db844b54492aca33b068711992bd73caccf.tar.gz |
* lib/rss, test/rss, sample/rss: backported from CVS HEAD.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7509 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r-- | lib/rss/0.9.rb | 367 | ||||
-rw-r--r-- | lib/rss/1.0.rb | 209 | ||||
-rw-r--r-- | lib/rss/2.0.rb | 69 | ||||
-rw-r--r-- | lib/rss/maker.rb | 14 | ||||
-rw-r--r-- | lib/rss/maker/0.9.rb | 100 | ||||
-rw-r--r-- | lib/rss/maker/1.0.rb | 74 | ||||
-rw-r--r-- | lib/rss/maker/2.0.rb | 73 | ||||
-rw-r--r-- | lib/rss/maker/base.rb | 260 | ||||
-rw-r--r-- | lib/rss/maker/trackback.rb | 118 | ||||
-rw-r--r-- | lib/rss/parser.rb | 14 | ||||
-rw-r--r-- | lib/rss/rexmlparser.rb | 2 | ||||
-rw-r--r-- | lib/rss/rss.rb | 256 | ||||
-rw-r--r-- | lib/rss/trackback.rb | 260 | ||||
-rw-r--r-- | lib/rss/xml-stylesheet.rb | 7 | ||||
-rw-r--r-- | lib/rss/xmlscanner.rb | 2 |
15 files changed, 1232 insertions, 593 deletions
diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb index c772e80870..797a46ca3b 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}<rss version="#{@rss_version}"#{ns_declaration(next_indent)}> -#{channel_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent}</rss> -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}<channel> -#{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}</channel> -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,121 @@ EOT rv end + def maker_target(maker) + maker.channel + end + + def setup_maker_elements(channel) + super + [ + [skipDays, "day"], + [skipHours, "hour"], + ].each do |skip, key| + if skip + skip.__send__("#{key}s").each do |val| + target_skips = channel.__send__("skip#{key.capitalize}s") + new_target = target_skips.__send__("new_#{key}") + new_target.content = val.content + end + end + end + end + + 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 + + remove_method :content= + def content=(value) + @content = value.to_i + end + + end + + end + class Image < Element include RSS09 @@ -220,19 +332,18 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent}<image> -#{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}</image> -EOT - rv = @converter.convert(rv) if convert and @converter + 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 @@ -244,8 +355,12 @@ EOT [nil, elem] end end + + def maker_target(maker) + maker.image + end end - + class Cloud < Element include RSS09 @@ -270,16 +385,8 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent}<cloud -#{next_indent}domain="#{h @domain}" -#{next_indent}port="#{h @port}" -#{next_indent}path="#{h @path}" -#{next_indent}registerProcedure="#{h @registerProcedure}" -#{next_indent}protocol="#{h @protocol}"/> -EOT - rv = @converter.convert(rv) if convert and @converter + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter rv end @@ -300,15 +407,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,36 +429,51 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent}<item> -#{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}</item> -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 + + def maker_target(maker) + maker.items.new_item end + def setup_maker_element(item) + super + @enclosure.setup_maker(item) if @enclosure + @source.setup_maker(item) if @source + end + class Source < Element include RSS09 @@ -364,17 +492,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @url - rv = %Q! <source url="#{@url}">! - rv << %Q!#{@content}</source>! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _tags [] @@ -386,6 +503,15 @@ EOT ] end + + def maker_target(item) + item.source + end + + def setup_maker_attributes(source) + source.url = url + source.content = content + end end class Enclosure < Element @@ -408,14 +534,9 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @url and @length and @type - rv = %Q!<enclosure url="#{h @url}" ! - rv << %Q!length="#{h @length}" type="#{h @type}"/>! - 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 @@ -427,6 +548,15 @@ EOT ] end + def maker_target(item) + item.enclosure + end + + def setup_maker_attributes(enclosure) + enclosure.url = url + enclosure.length = length + enclosure.type = type + end end class Category < Element @@ -447,17 +577,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @domain - rv = %Q!<category domain="#{h @domain}">! - rv << %Q!#{h @content}</category>! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _attrs [ @@ -465,12 +584,21 @@ EOT ] end + def maker_target(item) + item.new_category + end + + def setup_maker_attributes(category) + category.domain = domain + category.content = content + end + end end class TextInput < Element - + include RSS09 %w(title description name link).each do |x| @@ -479,16 +607,15 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - rv = <<-EOT -#{indent}<textInput> -#{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}</textInput> -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 @@ -501,6 +628,10 @@ EOT [nil, elem] end end + + def maker_target(maker) + maker.textinput + end end end diff --git a/lib/rss/1.0.rb b/lib/rss/1.0.rb index 563ed66426..0e3e66ea95 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}</#{PREFIX}:RDF> -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}</#{PREFIX}:Seq> -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}<channel #{about}> -#{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}</channel> -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,10 +270,18 @@ EOT def _attrs [ - ["about", true] + ["#{PREFIX}:about", true, "about"] ] end + def maker_target(maker) + maker.channel + end + + def setup_maker_attributes(channel) + channel.about = self.about + end + class Image < Element include RSS10 @@ -298,22 +306,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q!#{indent}<image #{PREFIX}:resource="#{h @resource}" />! - 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 +343,17 @@ EOT end def to_s(convert=true, indent=calc_indent) - if @resource - rv = %Q|#{indent}<textinput #{PREFIX}:resource="#{h @resource}" />| - 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 +385,12 @@ EOT end def to_s(convert=true, indent=calc_indent) - next_indent = indent + INDENT - <<-EOT -#{indent}<items> -#{Seq_element(convert, next_indent)} -#{other_element(convert, next_indent)} -#{indent}</items> -EOT + rv = tag(indent) do |next_indent| + [ + Seq_element(convert, next_indent), + other_element(convert, next_indent), + ] + end end private @@ -452,17 +449,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}<image #{about}> -#{title_element(false, next_indent)} -#{url_element(false, next_indent)} -#{link_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent}</image> -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 +474,13 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end + def maker_target(maker) + maker.image + end end class Item < Element @@ -522,17 +519,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}<item #{about}> -#{title_element(false, next_indent)} -#{link_element(false, next_indent)} -#{description_element(false, next_indent)} -#{other_element(false, next_indent)} -#{indent}</item> -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 +544,13 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end + def maker_target(maker) + maker.items.new_item + end end class Textinput < Element @@ -593,18 +590,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}<textinput #{about}> -#{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}</textinput> -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 +617,13 @@ EOT def _attrs [ - ["about", true], + ["#{PREFIX}:about", true, "about"] ] end + def maker_target(maker) + maker.textinput + end end end diff --git a/lib/rss/2.0.rb b/lib/rss/2.0.rb index 7fafb23ba9..19cb487d79 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, '?') + remove_method :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 @@ -98,6 +113,12 @@ EOT end + _tags09 end + alias _setup_maker_element setup_maker_element + def setup_maker_element(item) + _setup_maker_element(item) + @guid.setup_maker(item) if @guid + end + class Guid < Element include RSS09 @@ -116,18 +137,6 @@ EOT @content = content end - def to_s(convert=true, indent=calc_indent) - if @content - rv = %Q!<guid! - rv << %Q! isPermaLink="#{h @isPermaLink}"! if @isPermaLink - rv << %Q!>#{h @content}</guid>! - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end - end - private def _attrs [ @@ -135,6 +144,14 @@ EOT ] end + def maker_target(item) + item.guid + end + + def setup_maker_attributes(guid) + guid.isPermaLink = isPermaLink + guid.content = content + end end end 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..b82585fb96 100644 --- a/lib/rss/maker/0.9.rb +++ b/lib/rss/maker/0.9.rb @@ -11,23 +11,15 @@ module RSS 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) + def make_rss + Rss.new(@rss_version, @version, @encoding, @standalone) end - + + def setup_elements(rss) + setup_channel(rss) + end + class Channel < ChannelBase def to_rss(rss) @@ -44,12 +36,13 @@ module RSS else nil end + elsif variable_is_set? + raise NotSetError.new("maker.channel", not_set_required_variables) end end def have_required_values? - @title and @link and @description and @language and - @maker.image.have_required_values? + @title and @link and @description and @language end private @@ -69,9 +62,76 @@ module RSS super + ["pubDate"] end + def required_variable_names + %w(title link description language) + 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 +190,12 @@ module RSS end end - class Category < CategoryBase + class Categories < CategoriesBase def to_rss(*args) end + + class Category < CategoryBase + end end end @@ -156,5 +219,6 @@ module RSS end add_maker(filename_to_version(__FILE__), RSS09) + add_maker(filename_to_version(__FILE__) + "1", RSS09) end end diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb index 894bcc0a24..e38a2f89e0 100644 --- a/lib/rss/maker/1.0.rb +++ b/lib/rss/maker/1.0.rb @@ -11,41 +11,22 @@ module RSS super("1.0") end - def to_rss - rss = RDF.new(@version, @encoding, @standalone) - setup_xml_stylesheets(rss) + private + def make_rss + RDF.new(@version, @encoding, @standalone) + end + + def setup_elements(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) + set = false if @about channel = RDF::Channel.new(@about) set = setup_values(channel) @@ -57,12 +38,16 @@ module RSS setup_other_elements(rss) end end + + if (!@about or !set) and variable_is_set? + raise NotSetError.new("maker.channel", not_set_required_variables) + end end def have_required_values? @about and @title and @link and @description end - + private def setup_items(rss) items = RDF::Channel::Items.new @@ -86,7 +71,37 @@ module RSS end end + def required_variable_names + %w(about title link description) + 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 +168,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..a958661614 100644 --- a/lib/rss/maker/2.0.rb +++ b/lib/rss/maker/2.0.rb @@ -13,23 +13,30 @@ 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) + def required_variable_names + %w(title link description) end - + + 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 +46,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.categories << category + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + end class Image < RSS09::Image @@ -102,18 +133,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.categories << 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..93f668beff 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,28 @@ 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 + + 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? + end + end + + def required_variables_are_set? + required_variable_names.each do |var| + return false if __send__(var).nil? + end + true end end @@ -102,9 +134,22 @@ module RSS end end - attr_reader :rss_version, :xml_stylesheets - attr_reader :channel, :image, :items, :textinput + %w(xml_stylesheets channel image items textinput).each do |element| + attr_reader element + add_need_initialize_variable(element, "make_#{element}") + module_eval(<<-EOC, __FILE__, __LINE__) + private + def setup_#{element}(rss) + @#{element}.to_rss(rss) + end + + def make_#{element} + self.class::#{element[0,1].upcase}#{element[1..-1]}.new(self) + end +EOC + end + attr_reader :rss_version attr_accessor :version, :encoding, :standalone def initialize(rss_version) @@ -113,63 +158,45 @@ module RSS @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 + def make + if block_given? + yield(self) + to_rss + 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 + else + nil + end + end + def current_element(rss) rss end private + remove_method :make_xml_stylesheets 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) - @xml_stylesheets.to_rss(rss) - end - end 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 +244,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 +270,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 +347,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,23 +390,18 @@ 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 + attr_accessor :do_sort, :max_size def initialize(maker) super - @items = [] @do_sort = false + @max_size = -1 end def normalize - sort_if_need + sort_if_need[0..@max_size] end def current_element(rss) @@ -326,9 +432,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 +456,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 +499,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..1030c8f5d4 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 @@ -357,10 +364,9 @@ module RSS previous = @last_element next_element = klass.send(:new, *args) next_element.do_validate = @do_validate - setter = "" - setter << "#{klass.required_prefix}_" if klass.required_prefix - setter << "#{tag_name}=" - @last_element.send(setter, next_element) + prefix = "" + prefix << "#{klass.required_prefix}_" if klass.required_prefix + previous.__send__(:set_next_element, prefix, tag_name, next_element) @last_element = next_element @proc_stack.push Proc.new { |text, tags| p(@last_element.class) if DEBUG 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..11fe6d6dd1 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.2" URI = "http://purl.org/rss/1.0/" @@ -144,6 +144,15 @@ module RSS end end + class NotSetError < Error + attr_reader :name, :variables + def initialize(name, variables) + @name = name + @variables = variables + super("required variables of #{@name} are not set: #{@variables.join(', ')}") + end + end + module BaseModel include Utils @@ -164,17 +173,20 @@ EOC end alias_method(:install_have_attribute_element, :install_have_child_element) - def install_have_children_element(name, postfix="s") - add_have_children_element(name) - - def_children_accessor(name, postfix) - install_element(name, postfix) do |n, elem_name| + def install_have_children_element(name, plural_name=nil) + plural_name ||= "#{name}s" + add_have_children_element(name, plural_name) + add_plural_form(name, plural_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)}" + value = "\#{x.to_s(convert, indent)}" + rv << value if /\\A\\s*\\z/ !~ value end - rv + rv.join("\n") EOC end end @@ -289,9 +301,9 @@ EOC end end - def def_children_accessor(accessor_name, postfix="s") + def def_children_accessor(accessor_name, plural_name) module_eval(<<-EOC, *get_file_and_line_from_caller(2)) - def #{accessor_name}#{postfix} + def #{plural_name} @#{accessor_name} end @@ -302,8 +314,12 @@ EOC @#{accessor_name}.send("[]", *args) end end - + def #{accessor_name}=(*args) + warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \ + "Don't use `#{accessor_name} = XXX'/`set_#{accessor_name}(XXX)'. " \ + "Those APIs are not sense of Ruby. " \ + "Use `#{plural_name} << XXX' instead of them.") if args.size == 1 @#{accessor_name}.push(args[0]) else @@ -314,6 +330,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 +361,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 +406,7 @@ EOC def self.content_setup attr_writer :content convert_attr_reader :content + def_content_only_to_s @@have_content = true end @@ -386,8 +420,8 @@ EOC @@have_children_elements end - def self.add_have_children_element(variable_name) - @@have_children_elements << variable_name + def self.add_have_children_element(variable_name, plural_name) + @@have_children_elements << [variable_name, plural_name] end @@need_initialize_variables = [] @@ -400,6 +434,16 @@ EOC @@need_initialize_variables end + @@plural_forms = {} + + def self.add_plural_form(singular, plural) + @@plural_forms[singular] = plural + end + + def self.plural_forms + @@plural_forms + end + EOC end @@ -440,6 +484,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| @@ -457,6 +509,15 @@ EOC __validate(tags, false) end + def setup_maker(maker) + target = maker_target(maker) + unless target.nil? + setup_maker_attributes(target) + setup_maker_element(target) + setup_maker_elements(target) + end + end + private def initialize_variables self.class.need_initialize_variables.each do |variable_name| @@ -467,11 +528,111 @@ EOC end def initialize_have_children_elements - self.class.have_children_elements.each do |variable_name| + self.class.have_children_elements.each do |variable_name, plural_name| instance_eval("@#{variable_name} = []") end end + def tag(indent, additional_attrs=[], &block) + 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 + content = block.call(next_indent) + else + content = [] + end + + if content.is_a?(String) + content = [content] + start_tag << ">" + end_tag = "</#{full_name}>" + else + content = content.reject{|x| x.empty?} + if content.empty? + end_tag = "/>" + else + start_tag << ">\n" + end_tag = "\n#{indent}</#{full_name}>" + 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 + + def maker_target(maker) + nil + end + + def setup_maker_attributes(target) + end + + def setup_maker_element(target) + self.class.need_initialize_variables.each do |var| + setter = "#{var}=" + if target.respond_to?(setter) + target.__send__(setter, __send__(var)) + end + end + end + + def setup_maker_elements(parent) + self.class.have_children_elements.each do |name, plural_name| + real_name = name.sub(/^[^_]+_/, '') + if parent.respond_to?(plural_name) + target = parent.__send__(plural_name) + __send__(plural_name).each do |elem| + elem.__send__("setup_maker", target) + end + end + end + end + + def set_next_element(prefix, tag_name, next_element) + klass = next_element.class + prefix = "" + prefix << "#{klass.required_prefix}_" if klass.required_prefix + if self.class.plural_forms.has_key?(tag_name) + ary = __send__("#{prefix}#{self.class.plural_forms[tag_name]}") + ary << next_element + else + __send__("#{prefix}#{tag_name}=", next_element) + end + end + # not String class children. def children [] @@ -507,23 +668,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 +787,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) @@ -655,26 +809,50 @@ EOC self.converter = Converter.new(@output_encoding, @encoding) end + def setup_maker(maker) + maker.version = version + maker.encoding = encoding + maker.standalone = standalone + + xml_stylesheets.each do |xss| + xss.setup_maker(maker) + end + + setup_maker_elements(maker) + end + private + def tag(indent, attrs, &block) + rv = xmldecl + xml_stylesheet_pi + rv << super(indent, attrs, &block) + rv + end + def xmldecl rv = %Q[<?xml version="#{@version}"] if @output_encoding or @encoding rv << %Q[ encoding="#{@output_encoding or @encoding}"] end - rv << %Q[ standalone="#{@standalone}"] if @standalone - rv << '?>' + 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 + def setup_maker_elements(maker) + channel.setup_maker(maker) if channel + image.setup_maker(maker) if image + textinput.setup_maker(maker) if textinput + items.each do |item| + item.setup_maker(maker) + end + end end end diff --git a/lib/rss/trackback.rb b/lib/rss/trackback.rb index e276305ec1..8bc1ee5ad5 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,24 +40,78 @@ 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 + klass.__send__(:include, TrackBackUtils) + %w(ping).each do |x| - klass.install_have_child_element("#{TRACKBACK_PREFIX}_#{x}") + var_name = "#{TRACKBACK_PREFIX}_#{x}" + klass_name = x.capitalize + klass.install_have_child_element(var_name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + remove_method :#{var_name} + def #{var_name} + @#{var_name} and @#{var_name}.value + end + + remove_method :#{var_name}= + def #{var_name}=(value) + @#{var_name} = new_with_value_if_need(#{klass_name}, value) + end + EOC end - %w(about).each do |x| - klass.install_have_children_element("#{TRACKBACK_PREFIX}_#{x}") + [%w(about s)].each do |name, postfix| + var_name = "#{TRACKBACK_PREFIX}_#{name}" + klass_name = name.capitalize + klass.install_have_children_element(var_name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + remove_method :#{var_name} + def #{var_name}(*args) + if args.empty? + @#{var_name}.first and @#{var_name}.first.value + else + ret = @#{var_name}.send("[]", *args) + if ret.is_a?(Array) + ret.collect {|x| x.value} + else + ret.value + end + end + end + + remove_method :#{var_name}= + remove_method :set_#{var_name} + def #{var_name}=(*args) + if args.size == 1 + 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_value_if_need(#{klass_name}, val) + end + else + new_val = new_with_value_if_need(#{klass_name}, new_val) + end + @#{var_name}.send("[]=", *(args[0..-2] + [new_val])) + end + end + alias set_#{var_name} #{var_name}= + EOC end end end + end + + module TrackBackModel10 + extend BaseModel + extend BaseTrackBackModel class Ping < Element include RSS10 @@ -71,26 +134,28 @@ module RSS 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) - 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 + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private def _attrs [ - ["resource", true], + ["#{::RSS::RDF::PREFIX}:resource", true, "resource"], ] end @@ -117,118 +182,45 @@ module RSS 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) - 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 + rv = tag(indent) + rv = @converter.convert(rv) if convert and @converter + rv end private def _attrs [ - ["resource", true], + ["#{::RSS::RDF::PREFIX}:resource", true, "resource"], ] 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.install_have_child_element(var_name) - klass.module_eval(<<-EOC) - alias _#{var_name} #{var_name} - def #{var_name} - @#{var_name} and @#{var_name}.content - end - - alias _#{var_name}= #{var_name}= - def #{var_name}=(content) - @#{var_name} = new_with_content_if_need(#{x.capitalize}, content) - end - EOC - end - - [%w(about s)].each do |x, postfix| - var_name = "#{TRACKBACK_PREFIX}_#{x}" - 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} - def #{var_name}(*args) - if args.empty? - @#{var_name}.first and @#{var_name}.first.content - else - ret = @#{var_name}.send("[]", *args) - if ret.is_a?(Array) - ret.collect {|x| x.content} - else - ret.content - end - end - end - - alias _#{var_name}= #{var_name}= - alias _set_#{var_name} set_#{var_name} - def #{var_name}=(*args) - if args.size == 1 - item = new_with_content_if_need(#{x.capitalize}, 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) - end - else - new_val = new_with_content_if_need(#{x.capitalize}, new_val) - end - @#{var_name}.send("[]=", *(args[0..-2] + [new_val])) - end - end - alias set_#{var_name} #{var_name}= - EOC - end + def maker_target(abouts) + abouts.new_about end - end - private - def new_with_content(klass, content) - obj = klass.new - obj.content = content - obj - end - - def new_with_content_if_need(klass, content) - if content.is_a?(klass) - content - else - new_with_content(klass, content) + def setup_maker_attributes(about) + about.resource = self.resource end + end + end + module TrackBackModel20 + extend BaseModel + extend BaseTrackBackModel class Ping < Element include RSS09 @@ -247,18 +239,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[</#{TRACKBACK_PREFIX}:ping>] - 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 +269,19 @@ module RSS end end + + alias_method(:value, :content) + alias_method(:value=, :content=) + + def initialize(content=nil) + super() + @content = content + end - def to_s(convert=true, indent=calc_indent) - if @content - rv = %Q[#{indent}<#{TRACKBACK_PREFIX}:about>] - rv << h(@content) - rv << %Q[</#{TRACKBACK_PREFIX}:about>] - rv = @converter.convert(rv) if convert and @converter - rv - else - '' - end + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) end - + end end diff --git a/lib/rss/xml-stylesheet.rb b/lib/rss/xml-stylesheet.rb index c51c0dc71a..05602eee9b 100644 --- a/lib/rss/xml-stylesheet.rb +++ b/lib/rss/xml-stylesheet.rb @@ -84,6 +84,13 @@ module RSS @alternate end + def setup_maker(maker) + xss = maker.xml_stylesheets.new_xml_stylesheet + ATTRIBUTES.each do |attr| + xss.__send__("#{attr}=", __send__(attr)) + end + end + private def guess_type(filename) /\.([^.]+)$/ =~ filename 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) |