[前][次][番号順一覧][スレッド一覧]

ruby-changes:2256

From: ko1@a...
Date: 21 Oct 2007 21:20:18 +0900
Subject: [ruby-changes:2256] kou - Ruby:r13747 (ruby_1_8): * lib/rss.rb, lib/rss/, test/rss/, sample/rss/: merged from trunk.

kou	2007-10-21 21:19:43 +0900 (Sun, 21 Oct 2007)

  New Revision: 13747

  Added directories:
    branches/ruby_1_8/lib/rss/dublincore/
  Added files:
    branches/ruby_1_8/lib/rss/.gdbinit
    branches/ruby_1_8/lib/rss/atom.rb
    branches/ruby_1_8/lib/rss/itunes.rb
    branches/ruby_1_8/lib/rss/maker/atom.rb
    branches/ruby_1_8/lib/rss/maker/entry.rb
    branches/ruby_1_8/lib/rss/maker/feed.rb
    branches/ruby_1_8/lib/rss/maker/itunes.rb
    branches/ruby_1_8/lib/rss/maker/slash.rb
    branches/ruby_1_8/lib/rss/prelude.rb
    branches/ruby_1_8/lib/rss/slash.rb
    branches/ruby_1_8/lib/rss/xml.rb
    branches/ruby_1_8/test/rss/test_atom.rb
    branches/ruby_1_8/test/rss/test_itunes.rb
    branches/ruby_1_8/test/rss/test_maker_atom_entry.rb
    branches/ruby_1_8/test/rss/test_maker_atom_feed.rb
    branches/ruby_1_8/test/rss/test_maker_itunes.rb
    branches/ruby_1_8/test/rss/test_maker_slash.rb
    branches/ruby_1_8/test/rss/test_parser_atom_entry.rb
    branches/ruby_1_8/test/rss/test_parser_atom_feed.rb
    branches/ruby_1_8/test/rss/test_setup_maker_atom_entry.rb
    branches/ruby_1_8/test/rss/test_setup_maker_atom_feed.rb
    branches/ruby_1_8/test/rss/test_setup_maker_itunes.rb
    branches/ruby_1_8/test/rss/test_setup_maker_slash.rb
    branches/ruby_1_8/test/rss/test_slash.rb
  Modified files:
    branches/ruby_1_8/ChangeLog
    branches/ruby_1_8/lib/rss/0.9.rb
    branches/ruby_1_8/lib/rss/1.0.rb
    branches/ruby_1_8/lib/rss/2.0.rb
    branches/ruby_1_8/lib/rss/content.rb
    branches/ruby_1_8/lib/rss/converter.rb
    branches/ruby_1_8/lib/rss/dublincore.rb
    branches/ruby_1_8/lib/rss/image.rb
    branches/ruby_1_8/lib/rss/maker/0.9.rb
    branches/ruby_1_8/lib/rss/maker/1.0.rb
    branches/ruby_1_8/lib/rss/maker/2.0.rb
    branches/ruby_1_8/lib/rss/maker/base.rb
    branches/ruby_1_8/lib/rss/maker/content.rb
    branches/ruby_1_8/lib/rss/maker/dublincore.rb
    branches/ruby_1_8/lib/rss/maker/image.rb
    branches/ruby_1_8/lib/rss/maker/syndication.rb
    branches/ruby_1_8/lib/rss/maker/taxonomy.rb
    branches/ruby_1_8/lib/rss/maker/trackback.rb
    branches/ruby_1_8/lib/rss/maker.rb
    branches/ruby_1_8/lib/rss/parser.rb
    branches/ruby_1_8/lib/rss/rss.rb
    branches/ruby_1_8/lib/rss/syndication.rb
    branches/ruby_1_8/lib/rss/taxonomy.rb
    branches/ruby_1_8/lib/rss/utils.rb
    branches/ruby_1_8/lib/rss/xml-stylesheet.rb
    branches/ruby_1_8/lib/rss.rb
    branches/ruby_1_8/sample/rss/blend.rb
    branches/ruby_1_8/sample/rss/convert.rb
    branches/ruby_1_8/sample/rss/list_description.rb
    branches/ruby_1_8/sample/rss/re_read.rb
    branches/ruby_1_8/sample/rss/rss_recent.rb
    branches/ruby_1_8/test/rss/rss-assertions.rb
    branches/ruby_1_8/test/rss/rss-testcase.rb
    branches/ruby_1_8/test/rss/test_1.0.rb
    branches/ruby_1_8/test/rss/test_2.0.rb
    branches/ruby_1_8/test/rss/test_dublincore.rb
    branches/ruby_1_8/test/rss/test_image.rb
    branches/ruby_1_8/test/rss/test_inherit.rb
    branches/ruby_1_8/test/rss/test_maker_0.9.rb
    branches/ruby_1_8/test/rss/test_maker_1.0.rb
    branches/ruby_1_8/test/rss/test_maker_2.0.rb
    branches/ruby_1_8/test/rss/test_maker_dc.rb
    branches/ruby_1_8/test/rss/test_maker_sy.rb
    branches/ruby_1_8/test/rss/test_maker_xml-stylesheet.rb
    branches/ruby_1_8/test/rss/test_parser.rb
    branches/ruby_1_8/test/rss/test_parser_1.0.rb
    branches/ruby_1_8/test/rss/test_setup_maker_0.9.rb
    branches/ruby_1_8/test/rss/test_setup_maker_1.0.rb
    branches/ruby_1_8/test/rss/test_syndication.rb
    branches/ruby_1_8/test/rss/test_taxonomy.rb
    branches/ruby_1_8/test/rss/test_to_s.rb
    branches/ruby_1_8/test/rss/test_version.rb
    branches/ruby_1_8/test/rss/test_xml-stylesheet.rb
    branches/ruby_1_8/version.h

  Log:
    * lib/rss.rb, lib/rss/, test/rss/, sample/rss/: merged from trunk.
      - 0.1.6 -> 2.0.0.
      - fixed image module URI. Thanks to Dmitry Borodaenko.
      - supported Atom.
      - supported ITunes module.
      - supported Slash module.
    
    * NEWS: added an entry for RSS Parser.

  Added: branches/ruby_1_8/lib/rss/dublincore/

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/dublincore.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/itunes.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/blend.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/.gdbinit
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_version.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_atom_entry.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/content.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/parser.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_2.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/dublincore
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/itunes.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/2.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/rss.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/0.9.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_sy.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/slash.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/version.h?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_dc.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/atom.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_atom_feed.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/base.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/slash.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_atom_entry.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_slash.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_atom.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/image.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/syndication.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_0.9.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/dublincore.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/utils.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/2.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/ChangeLog?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_taxonomy.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/syndication.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_image.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/content.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/feed.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_itunes.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_parser_atom_feed.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/trackback.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_2.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_syndication.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/taxonomy.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/rss-testcase.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_xml-stylesheet.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_0.9.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_slash.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_itunes.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/atom.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/list_description.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/list_description.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_dublincore.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_parser_1.0.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_maker_xml-stylesheet.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/taxonomy.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_inherit.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/xml.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/xml-stylesheet.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/rss-assertions.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/prelude.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/convert.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_parser_atom_entry.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/re_read.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/entry.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_to_s.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_slash.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_setup_maker_atom_feed.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_itunes.rb
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/converter.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/test/rss/test_parser.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/0.9.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/rss_recent.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/sample/rss/rss_recent.rb?r1=13747&r2=13746
  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8/lib/rss/maker/image.rb?r1=13747&r2=13746

Index: ruby_1_8/ChangeLog
===================================================================
--- ruby_1_8/ChangeLog	(revision 13746)
+++ ruby_1_8/ChangeLog	(revision 13747)
@@ -1,3 +1,14 @@
+Sun Oct 21 21:16:43 2007  Kouhei Sutou  <kou@c...>
+
+	* lib/rss.rb, lib/rss/, test/rss/, sample/rss/: merged from trunk.
+	- 0.1.6 -> 2.0.0.
+	- fixed image module URI. Thanks to Dmitry Borodaenko.
+	- supported Atom.
+	- supported ITunes module.
+	- supported Slash module.
+
+	* NEWS: added an entry for RSS Parser.
+
 Thu Oct 18 10:57:06 2007  Tanaka Akira  <akr@f...>
 
 	* ruby.h (RCLASS_IV_TBL): defined.
Index: ruby_1_8/version.h
===================================================================
--- ruby_1_8/version.h	(revision 13746)
+++ ruby_1_8/version.h	(revision 13747)
@@ -1,7 +1,7 @@
 #define RUBY_VERSION "1.8.6"
-#define RUBY_RELEASE_DATE "2007-10-15"
+#define RUBY_RELEASE_DATE "2007-10-21"
 #define RUBY_VERSION_CODE 186
-#define RUBY_RELEASE_CODE 20071015
+#define RUBY_RELEASE_CODE 20071021
 #define RUBY_PATCHLEVEL 5000
 
 #define RUBY_VERSION_MAJOR 1
@@ -9,7 +9,7 @@
 #define RUBY_VERSION_TEENY 6
 #define RUBY_RELEASE_YEAR 2007
 #define RUBY_RELEASE_MONTH 10
-#define RUBY_RELEASE_DAY 15
+#define RUBY_RELEASE_DAY 21
 
 #ifdef RUBY_EXTERN
 RUBY_EXTERN const char ruby_version[];
Index: ruby_1_8/sample/rss/list_description.rb
===================================================================
--- ruby_1_8/sample/rss/list_description.rb	(revision 13746)
+++ ruby_1_8/sample/rss/list_description.rb	(revision 13747)
@@ -56,9 +56,18 @@
     rescue RSS::UnknownConversionMethodError
       error($!) if verbose
     end
-    rss.channel.title ||= "Unknown"
+
+    rss = rss.to_rss("1.0") do |maker|
+      maker.channel.about ||= maker.channel.link
+      maker.channel.description ||= "No description"
+      maker.items.each do |item|
+        item.title ||= "No title"
+        item.link ||= "UNKNOWN"
+      end
+    end
+    next if rss.nil?
+
     rss.items.each do |item|
-      item.title ||= "Unknown"
       channels[rss.channel.title] ||= []
       channels[rss.channel.title] << item if item.description
     end

Property changes on: ruby_1_8/sample/rss/list_description.rb
___________________________________________________________________
Name: svn:executable
   + *

Index: ruby_1_8/sample/rss/convert.rb
===================================================================
--- ruby_1_8/sample/rss/convert.rb	(revision 13746)
+++ ruby_1_8/sample/rss/convert.rb	(revision 13747)
@@ -23,7 +23,7 @@
   when '-v'
     verbose = true
     next
-  when /^-t(0\.91|1\.0|2\.0)$/
+  when /^-t(0\.91|1\.0|2\.0|atom)$/
     to_version = $1
     next
   end
Index: ruby_1_8/sample/rss/re_read.rb
===================================================================
--- ruby_1_8/sample/rss/re_read.rb	(revision 13746)
+++ ruby_1_8/sample/rss/re_read.rb	(revision 13747)
@@ -29,16 +29,16 @@
   read = false
   begin
     rss = RSS::Parser.parse(source)
-    puts "Re-read valid RSS: #{fname}"
+    puts "Re-read valid feed: #{fname}"
     RSS::Parser.parse(rss.to_s)
     read = true
   rescue RSS::InvalidRSSError
     error($!) if verbose
-    ## do non validate parse for invalid RSS 1.0
+    ## do non validate parse for invalid feed
     begin
       rss = RSS::Parser.parse(source, false)
     rescue RSS::Error
-      ## invalid RSS.
+      ## invalid feed
       error($!) if verbose
     end
   rescue RSS::Error
@@ -46,9 +46,9 @@
   end
   
   if rss.nil?
-    puts "Invalid RSS: #{fname}"
+    puts "Invalid feed: #{fname}"
   elsif !read
-    puts "Re-read invalid RSS: #{fname}"
+    puts "Re-read invalid feed: #{fname}"
     begin
       RSS::Parser.parse(rss.to_s)
     rescue RSS::Error
Index: ruby_1_8/sample/rss/blend.rb
===================================================================
--- ruby_1_8/sample/rss/blend.rb	(revision 13746)
+++ ruby_1_8/sample/rss/blend.rb	(revision 13747)
@@ -64,6 +64,12 @@
       item.setup_maker(maker.items)
     end
   end
+
+  maker.items.each do |item|
+    item.title ||= "UNKNOWN"
+    item.link ||= "UNKNOWN"
+  end
+
   maker.items.do_sort = true
   maker.items.max_size = 15
 end
Index: ruby_1_8/sample/rss/rss_recent.rb
===================================================================
--- ruby_1_8/sample/rss/rss_recent.rb	(revision 13746)
+++ ruby_1_8/sample/rss/rss_recent.rb	(revision 13747)
@@ -55,16 +55,20 @@
     rescue RSS::UnknownConversionMethodError
       error($!) if verbose
     end
-    rss.items.each do |item|
-      if item.respond_to?(:pubDate) and item.pubDate
-        class << item
-          alias_method(:dc_date, :pubDate)
-        end
+
+    rss = rss.to_rss("1.0") do |maker|
+      maker.channel.about ||= maker.channel.link
+      maker.channel.description ||= "No description"
+      maker.items.each do |item|
+        item.title ||= "UNKNOWN"
+        item.link ||= "UNKNOWN"
       end
-      if item.respond_to?(:dc_date) and item.dc_date
-        items << [rss.channel, item]
-      end
     end
+    next if rss.nil?
+
+    rss.items.each do |item|
+      items << [rss.channel, item] if item.dc_date
+    end
   end
 end
 processing_time = Time.now - before_time

Property changes on: ruby_1_8/sample/rss/rss_recent.rb
___________________________________________________________________
Name: svn:executable
   + *

Index: ruby_1_8/lib/rss/taxonomy.rb
===================================================================
--- ruby_1_8/lib/rss/taxonomy.rb	(revision 13746)
+++ ruby_1_8/lib/rss/taxonomy.rb	(revision 13747)
@@ -12,7 +12,7 @@
 
   %w(link).each do |name|
     full_name = "#{TAXO_PREFIX}_#{name}"
-    BaseListener.install_get_text_element(TAXO_URI, name, "#{full_name}=")
+    BaseListener.install_get_text_element(TAXO_URI, name, full_name)
     TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}"
   end
 
Index: ruby_1_8/lib/rss/image.rb
===================================================================
--- ruby_1_8/lib/rss/image.rb	(revision 13746)
+++ ruby_1_8/lib/rss/image.rb	(revision 13747)
@@ -4,7 +4,7 @@
 module RSS
 
   IMAGE_PREFIX = 'image'
-  IMAGE_URI = 'http://web.resource.org/rss/1.0/modules/image/'
+  IMAGE_URI = 'http://purl.org/rss/1.0/modules/image/'
 
   RDF.install_ns(IMAGE_PREFIX, IMAGE_URI)
 
@@ -69,7 +69,7 @@
         disp_name = "#{IMAGE_PREFIX}:#{tag}"
         install_text_element(tag, IMAGE_URI, "?",
                              full_name, :integer, disp_name)
-        BaseListener.install_get_text_element(IMAGE_URI, tag, "#{full_name}=")
+        BaseListener.install_get_text_element(IMAGE_URI, tag, full_name)
       end
 
       alias width= image_width=
@@ -142,8 +142,8 @@
       end
 
       AVAILABLE_SIZES = %w(small medium large)
-      alias_method :_size=, :size=
-      private :_size=
+      alias_method :set_size, :size=
+      private :set_size
       def size=(new_value)
         if @do_validate and !new_value.nil?
           new_value = new_value.strip
@@ -152,7 +152,7 @@
             raise NotAvailableValueError.new(full_name, new_value, attr_name)
           end
         end
-        __send__(:_size=, new_value)
+        set_size(new_value)
       end
       
       alias image_size= size=
Index: ruby_1_8/lib/rss/dublincore/1.0.rb
===================================================================
--- ruby_1_8/lib/rss/dublincore/1.0.rb	(revision 0)
+++ ruby_1_8/lib/rss/dublincore/1.0.rb	(revision 13747)
@@ -0,0 +1,13 @@
+require "rss/1.0"
+require "rss/dublincore"
+
+module RSS
+  RDF.install_ns(DC_PREFIX, DC_URI)
+
+  class RDF
+    class Channel; include DublinCoreModel; end
+    class Image; include DublinCoreModel; end
+    class Item; include DublinCoreModel; end
+    class Textinput; include DublinCoreModel; end
+  end
+end
Index: ruby_1_8/lib/rss/dublincore/2.0.rb
===================================================================
--- ruby_1_8/lib/rss/dublincore/2.0.rb	(revision 0)
+++ ruby_1_8/lib/rss/dublincore/2.0.rb	(revision 13747)
@@ -0,0 +1,13 @@
+require "rss/2.0"
+require "rss/dublincore"
+
+module RSS
+  Rss.install_ns(DC_PREFIX, DC_URI)
+
+  class Rss
+    class Channel
+      include DublinCoreModel
+      class Item; include DublinCoreModel; end
+    end
+  end
+end
Index: ruby_1_8/lib/rss/dublincore/atom.rb
===================================================================
--- ruby_1_8/lib/rss/dublincore/atom.rb	(revision 0)
+++ ruby_1_8/lib/rss/dublincore/atom.rb	(revision 13747)
@@ -0,0 +1,17 @@
+require "rss/atom"
+require "rss/dublincore"
+
+module RSS
+  module Atom
+    Feed.install_ns(DC_PREFIX, DC_URI)
+
+    class Feed
+      include DublinCoreModel
+      class Entry; include DublinCoreModel; end
+    end
+
+    class Entry
+      include DublinCoreModel
+    end
+  end
+end
Index: ruby_1_8/lib/rss/syndication.rb
===================================================================
--- ruby_1_8/lib/rss/syndication.rb	(revision 13746)
+++ ruby_1_8/lib/rss/syndication.rb	(revision 13747)
@@ -29,16 +29,19 @@
 
         %w(updateBase).each do |name|
           install_date_element(name, SY_URI, "?",
-                               "#{SY_PREFIX}_#{name}", 'w3cdtf', name)
+                               "#{SY_PREFIX}_#{name}", 'w3cdtf',
+                               "#{SY_PREFIX}:#{name}")
         end
+      end
 
+      klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
         alias_method(:_sy_updatePeriod=, :sy_updatePeriod=)
         def sy_updatePeriod=(new_value)
           new_value = new_value.strip
           validate_sy_updatePeriod(new_value) if @do_validate
           self._sy_updatePeriod = new_value
         end
-      end
+      EOC
     end
 
     private
@@ -58,7 +61,7 @@
   SyndicationModel::ELEMENTS.uniq!
   SyndicationModel::ELEMENTS.each do |full_name|
     name = full_name[prefix_size..-1]
-    BaseListener.install_get_text_element(SY_URI, name, "#{full_name}=")
+    BaseListener.install_get_text_element(SY_URI, name, full_name)
   end
 
 end
Index: ruby_1_8/lib/rss/dublincore.rb
===================================================================
--- ruby_1_8/lib/rss/dublincore.rb	(revision 13746)
+++ ruby_1_8/lib/rss/dublincore.rb	(revision 13747)
@@ -1,11 +1,8 @@
-require "rss/1.0"
+require "rss/rss"
 
 module RSS
-
   DC_PREFIX = 'dc'
   DC_URI = "http://purl.org/dc/elements/1.1/"
-  
-  RDF.install_ns(DC_PREFIX, DC_URI)
 
   module BaseDublinCoreModel
     def append_features(klass)
@@ -36,8 +33,20 @@
         EOC
       end
       klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0))
-        alias date #{DC_PREFIX}_date
-        alias date= #{DC_PREFIX}_date=
+        if method_defined?(:date)
+          alias date_without_#{DC_PREFIX}_date= date=
+
+          def date=(value)
+            self.date_without_#{DC_PREFIX}_date = value
+            self.#{DC_PREFIX}_date = value
+          end
+        else
+          alias date #{DC_PREFIX}_date
+          alias date= #{DC_PREFIX}_date=
+        end
+
+        # For backward compatibility
+        alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list
       EOC
     end
   end
@@ -61,7 +70,7 @@
       "language" => nil,
       "relation" => nil,
       "coverage" => nil,
-      "rights" => "rightses" # FIXME
+      "rights" => "rights_list"
     }
 
     DATE_ELEMENTS = {
@@ -122,13 +131,14 @@
     end
 
     DATE_ELEMENTS.each do |name, type|
+      tag_name = "#{DC_PREFIX}:#{name}"
       module_eval(<<-EOC, *get_file_and_line_from_caller(0))
         class DublinCore#{Utils.to_class_name(name)} < Element
           remove_method(:content=)
           remove_method(:value=)
 
-          date_writer("content", #{type.dump}, #{name.dump})
-          
+          date_writer("content", #{type.dump}, #{tag_name.dump})
+
           alias_method(:value=, :content=)
         end
       EOC
@@ -138,13 +148,6 @@
   # For backward compatibility
   DublincoreModel = DublinCoreModel
 
-  class RDF
-    class Channel; include DublinCoreModel; end
-    class Image; include DublinCoreModel; end
-    class Item; include DublinCoreModel; end
-    class Textinput; include DublinCoreModel; end
-  end
-
   DublinCoreModel::ELEMENTS.each do |name|
     class_name = Utils.to_class_name(name)
     BaseListener.install_class_name(DC_URI, name, "DublinCore#{class_name}")
@@ -152,3 +155,7 @@
 
   DublinCoreModel::ELEMENTS.collect! {|name| "#{DC_PREFIX}_#{name}"}
 end
+
+require 'rss/dublincore/1.0'
+require 'rss/dublincore/2.0'
+require 'rss/dublincore/atom'
Index: ruby_1_8/lib/rss/xml-stylesheet.rb
===================================================================
--- ruby_1_8/lib/rss/xml-stylesheet.rb	(revision 13746)
+++ ruby_1_8/lib/rss/xml-stylesheet.rb	(revision 13747)
@@ -35,6 +35,10 @@
     attr_accessor(*ATTRIBUTES)
     attr_accessor(:do_validate)
     def initialize(*attrs)
+      if attrs.size == 1 and
+          (attrs.first.is_a?(Hash) or attrs.first.is_a?(Array))
+        attrs = attrs.first
+      end
       @do_validate = true
       ATTRIBUTES.each do |attr|
         __send__("#{attr}=", nil)
Index: ruby_1_8/lib/rss/parser.rb
===================================================================
--- ruby_1_8/lib/rss/parser.rb	(revision 13746)
+++ ruby_1_8/lib/rss/parser.rb	(revision 13747)
@@ -2,6 +2,7 @@
 require "open-uri"
 
 require "rss/rss"
+require "rss/xml"
 
 module RSS
 
@@ -118,7 +119,7 @@
       return rss if rss.is_a?(::URI::Generic)
 
       begin
-        URI(rss)
+        ::URI.parse(rss)
       rescue ::URI::Error
         rss
       end
@@ -173,24 +174,28 @@
 
     class << self
 
-      @@setters = {}
+      @@accessor_bases = {}
       @@registered_uris = {}
       @@class_names = {}
 
       # return the setter for the uri, tag_name pair, or nil.
       def setter(uri, tag_name)
-        begin
-          @@setters[uri][tag_name]
-        rescue NameError
+        _getter = getter(uri, tag_name)
+        if _getter
+          "#{_getter}="
+        else
           nil
         end
       end
 
+      def getter(uri, tag_name)
+        (@@accessor_bases[uri] || {})[tag_name]
+      end
 
       # return the tag_names for setters associated with uri
       def available_tags(uri)
         begin
-          @@setters[uri].keys
+          @@accessor_bases[uri].keys
         rescue NameError
           []
         end
@@ -223,8 +228,8 @@
         end
       end
 
-      def install_get_text_element(uri, name, setter)
-        install_setter(uri, name, setter)
+      def install_get_text_element(uri, name, accessor_base)
+        install_accessor_base(uri, name, accessor_base)
         def_get_text_element(uri, name, *get_file_and_line_from_caller(1))
       end
       
@@ -233,35 +238,31 @@
       end
     
       private
-      # set the setter for the uri, tag_name pair
-      def install_setter(uri, tag_name, setter)
-        @@setters[uri] ||= {}
-        @@setters[uri][tag_name] = setter
+      # set the accessor for the uri, tag_name pair
+      def install_accessor_base(uri, tag_name, accessor_base)
+        @@accessor_bases[uri] ||= {}
+        @@accessor_bases[uri][tag_name] = accessor_base.chomp("=")
       end
 
-      def def_get_text_element(uri, name, file, line)
-        register_uri(uri, name)
-        unless private_instance_methods(false).include?("start_#{name}")
-          module_eval(<<-EOT, file, line)
-          def start_#{name}(name, prefix, attrs, ns)
+      def def_get_text_element(uri, element_name, file, line)
+        register_uri(uri, element_name)
+        method_name = "start_#{element_name}"
+        unless private_method_defined?(method_name)
+          define_method(method_name) do |name, prefix, attrs, ns|
             uri = _ns(ns, prefix)
-            if self.class.uri_registered?(uri, #{name.inspect})
+            if self.class.uri_registered?(uri, element_name)
               start_get_text_element(name, prefix, ns, uri)
             else
               start_else_element(name, prefix, attrs, ns)
             end
           end
-          EOT
-          __send__("private", "start_#{name}")
+          private(method_name)
         end
       end
-
     end
-
   end
 
   module ListenerMixin
-
     attr_reader :rss
 
     attr_accessor :ignore_unknown_element
@@ -271,13 +272,16 @@
       @rss = nil
       @ignore_unknown_element = true
       @do_validate = true
-      @ns_stack = [{}]
+      @ns_stack = [{"xml" => :xml}]
       @tag_stack = [[]]
       @text_stack = ['']
       @proc_stack = []
       @last_element = nil
       @version = @encoding = @standalone = nil
       @xml_stylesheets = []
+      @xml_child_mode = false
+      @xml_element = nil
+      @last_xml_element = nil
     end
     
     # set instance vars for version, encoding, standalone
@@ -289,7 +293,7 @@
       if name == "xml-stylesheet"
         params = parse_pi_content(content)
         if params.has_key?("href")
-          @xml_stylesheets << XMLStyleSheet.new(*params)
+          @xml_stylesheets << XMLStyleSheet.new(params)
         end
       end
     end
@@ -311,10 +315,39 @@
       prefix, local = split_name(name)
       @tag_stack.last.push([_ns(ns, prefix), local])
       @tag_stack.push([])
-      if respond_to?("start_#{local}", true)
-        __send__("start_#{local}", local, prefix, attrs, ns.dup)
+      if @xml_child_mode
+        previous = @last_xml_element
+        element_attrs = attributes.dup
+        unless previous
+          ns.each do |ns_prefix, value|
+            next if ns_prefix == "xml"
+            key = ns_prefix.empty? ? "xmlns" : "xmlns:#{ns_prefix}"
+            element_attrs[key] ||= value
+          end
+        end
+        next_element = XML::Element.new(local,
+                                        prefix.empty? ? nil : prefix,
+                                        _ns(ns, prefix),
+                                        element_attrs)
+        previous << next_element if previous
+        @last_xml_element = next_element
+        pr = Proc.new do |text, tags|
+          if previous
+            @last_xml_element = previous
+          else
+            @xml_element = @last_xml_element
+            @last_xml_element = nil
+          end
+        end
+        @proc_stack.push(pr)
       else
-        start_else_element(local, prefix, attrs, ns.dup)
+        if @rss.nil? and respond_to?("initial_start_#{local}", true)
+          __send__("initial_start_#{local}", local, prefix, attrs, ns.dup)
+        elsif respond_to?("start_#{local}", true)
+          __send__("start_#{local}", local, prefix, attrs, ns.dup)
+        else
+          start_else_element(local, prefix, attrs, ns.dup)
+        end
       end
     end
 
@@ -331,7 +364,11 @@
     end
 
     def text(data)
-      @text_stack.last << data
+      if @xml_child_mode
+        @last_xml_element << data if @last_xml_element
+      else
+        @text_stack.last << data
+      end
     end
 
     private
@@ -354,7 +391,8 @@
     def start_else_element(local, prefix, attrs, ns)
       class_name = self.class.class_name(_ns(ns, prefix), local)
       current_class = @last_element.class
-      if current_class.constants.include?(class_name)
+      if current_class.const_defined?(class_name) or
+          current_class.constants.include?(class_name)
         next_class = current_class.const_get(class_name)
         start_have_something_element(local, prefix, attrs, ns, next_class)
       else
@@ -377,19 +415,26 @@
     end
 
     def check_ns(tag_name, prefix, ns, require_uri)
-      if @do_validate
-        if _ns(ns, prefix) == require_uri
-          #ns.delete(prefix)
+      unless _ns(ns, prefix) == require_uri
+        if @do_validate
+          raise NSError.new(tag_name, prefix, require_uri)
         else
-          raise NSError.new(tag_name, prefix, require_uri)
+          # Force bind required URI with prefix
+          @ns_stack.last[prefix] = require_uri
         end
       end
     end
 
     def start_get_text_element(tag_name, prefix, ns, required_uri)
-      @proc_stack.push Proc.new {|text, tags|
+      pr = Proc.new do |text, tags|
         setter = self.class.setter(required_uri, tag_name)
         if @last_element.respond_to?(setter)
+          if @do_validate
+            getter = self.class.getter(required_uri, tag_name)
+            if @last_element.__send__(getter)
+              raise TooMuchTagError.new(tag_name, @last_element.tag_name)
+            end
+          end
           @last_element.__send__(setter, text.to_s)
         else
           if @do_validate and !@ignore_unknown_element
@@ -397,7 +442,8 @@
                                           @last_element.tag_name)
           end
         end
-      }
+      end
+      @proc_stack.push(pr)
     end
 
     def start_have_something_element(tag_name, prefix, attrs, ns, klass)
@@ -438,16 +484,32 @@
 
       previous = @last_element
       next_element = klass.new(@do_validate, attributes)
-      previous.instance_eval {set_next_element(tag_name, next_element)}
+      previous.set_next_element(tag_name, next_element)
       @last_element = next_element
-      @proc_stack.push Proc.new { |text, tags|
+      @last_element.parent = previous if klass.need_parent?
+      @xml_child_mode = @last_element.have_xml_content?
+      pr = Proc.new do |text, tags|
         p(@last_element.class) if DEBUG
-        @last_element.content = text if klass.have_content?
+        if @xml_child_mode
+          @last_element.content = @xml_element.to_s
+          xml_setter = @last_element.class.xml_setter
+          @last_element.__send__(xml_setter, @xml_element)
+          @xml_element = nil
+          @xml_child_mode = false
+        else
+          if klass.have_content?
+            if @last_element.need_base64_encode?
+              text = Base64.decode64(text.lstrip)
+            end
+            @last_element.content = text
+          end
+        end
         if @do_validate
           @last_element.validate_for_stream(tags, @ignore_unknown_element)
         end
         @last_element = previous
-      }
+      end
+      @proc_stack.push(pr)
     end
 
   end
Index: ruby_1_8/lib/rss/.gdbinit
===================================================================
--- ruby_1_8/lib/rss/.gdbinit	(revision 0)
+++ ruby_1_8/lib/rss/.gdbinit	(revision 13747)
@@ -0,0 +1,499 @@
+define rp
+  if (VALUE)$arg0 & RUBY_FIXNUM_FLAG
+    printf "FIXNUM: %d\n", $arg0 >> 1
+  else
+  if ((VALUE)$arg0 & ~(~(VALUE)0<<RUBY_SPECIAL_SHIFT)) == RUBY_SYMBOL_FLAG
+    printf "SYMBOL(%d)\n", $arg0 >> RUBY_SPECIAL_SHIFT
+  else
+  if $arg0 == RUBY_Qfalse
+    echo false\n
+  else
+  if $arg0 == RUBY_Qtrue
+    echo true\n
+  else
+  if $arg0 == RUBY_Qnil
+    echo nil\n
+  else
+  if $arg0 == RUBY_Qundef
+    echo undef\n
+  else
+  if (VALUE)$arg0 & RUBY_IMMEDIATE_MASK
+    echo immediate\n
+  else
+  set $flags = ((struct RBasic*)$arg0)->flags
+  if ($flags & RUBY_T_MASK) == RUBY_T_NONE
+    printf "T_NONE: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_NIL
+    printf "T_NIL: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_OBJECT
+    printf "T_OBJECT: "
+    print (struct RObject *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_CLASS
+    printf "T_CLASS: "
+    print (struct RClass *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_ICLASS
+    printf "T_ICLASS: "
+    print (struct RClass *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_MODULE
+    printf "T_MODULE: "
+    print (struct RClass *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_FLOAT
+    printf "T_FLOAT: %.16g ", (((struct RFloat*)$arg0)->value)
+    print (struct RFloat *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_STRING
+    printf "T_STRING: "
+    set print address off
+    output (char *)(($flags & RUBY_FL_USER1) ? \
+	    ((struct RString*)$arg0)->as.heap.ptr : \
+	    ((struct RString*)$arg0)->as.ary)
+    set print address on
+    printf " encoding:%d ", ($flags & (RUBY_FL_USER8|RUBY_FL_USER9|RUBY_FL_USER10|RUBY_FL_USER11)) >> RUBY_ENCODING_SHIFT
+    if ($flags & (RUBY_FL_USER12|RUBY_FL_USER13)) == 0
+      printf "coderange:unknown "
+    else
+    if ($flags & (RUBY_FL_USER12|RUBY_FL_USER13)) == RUBY_FL_USER12
+      printf "coderange:single "
+    else
+    if ($flags & (RUBY_FL_USER12|RUBY_FL_USER13)) == RUBY_FL_USER13
+      printf "coderange:single "
+    else
+      printf "coderange:broken "
+    end
+    end
+    end
+    print (struct RString *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_REGEXP
+    printf "T_REGEXP: "
+    set print address off
+    output ((struct RRegexp*)$arg0)->str
+    set print address on
+    printf " "
+    print (struct RRegexp *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_ARRAY
+    printf "T_ARRAY: len=%d ", ((struct RArray*)$arg0)->len
+    print (struct RArray *)$arg0
+    x/xw ((struct RArray*)$arg0)->ptr
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_FIXNUM
+    printf "T_FIXNUM: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_HASH
+    printf "T_HASH: ",
+    if ((struct RHash *)$arg0)->ntbl
+      printf "len=%d ", ((struct RHash *)$arg0)->ntbl->num_entries
+    end
+    print (struct RHash *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_STRUCT
+    printf "T_STRUCT: len=%d ", \
+      (($flags & (RUBY_FL_USER1|RUBY_FL_USER2)) ? \
+       ($flags & (RUBY_FL_USER1|RUBY_FL_USER2)) >> (RUBY_FL_USHIFT+1) : \
+       ((struct RStruct *)$arg0)->as.heap.len)
+    print (struct RStruct *)$arg0
+    x/xw (($flags & (RUBY_FL_USER1|RUBY_FL_USER2)) ? \
+          ((struct RStruct *)$arg0)->as.ary : \
+          ((struct RStruct *)$arg0)->as.heap.len)
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_BIGNUM
+    printf "T_BIGNUM: sign=%d len=%d ", \
+      (($flags & RUBY_FL_USER1) != 0), \
+      (($flags & RUBY_FL_USER2) ? \
+       ($flags & (RUBY_FL_USER5|RUBY_FL_USER4|RUBY_FL_USER3)) >> (RUBY_FL_USHIFT+3) : \
+       ((struct RBignum*)$arg0)->as.heap.len)
+    if $flags & RUBY_FL_USER2
+      printf "(embed) "
+    end
+    print (struct RBignum *)$arg0
+    x/xw (($flags & RUBY_FL_USER2) ? \
+          ((struct RBignum*)$arg0)->as.ary : \
+          ((struct RBignum*)$arg0)->as.heap.digits)
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_FILE
+    printf "T_FILE: "
+    print (struct RFile *)$arg0
+    output *((struct RFile *)$arg0)->fptr
+    printf "\n"
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_TRUE
+    printf "T_TRUE: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_FALSE
+    printf "T_FALSE: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_DATA
+    printf "T_DATA: "
+    print (struct RData *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_MATCH
+    printf "T_MATCH: "
+    print (struct RMatch *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_SYMBOL
+    printf "T_SYMBOL: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_VALUES
+    printf "T_VALUES: "
+    print (struct RValues *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_BLOCK
+    printf "T_BLOCK: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_UNDEF
+    printf "T_UNDEF: "
+    print (struct RBasic *)$arg0
+  else
+  if ($flags & RUBY_T_MASK) == RUBY_T_NODE
+    printf "T_NODE("
+    output (enum node_type)(($flags&RUBY_NODE_TYPEMASK)>>RUBY_NODE_TYPESHIFT)
+    printf "): "
+    print *(NODE *)$arg0
+  else
+    printf "unknown: "
+    print (struct RBasic *)$arg0
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+  end
+end
+document rp
+  Print a Ruby's VALUE.
+end
+
+define nd_type
+  print (enum node_type)((((NODE*)$arg0)->flags&RUBY_NODE_TYPEMASK)>>RUBY_NODE_TYPESHIFT)
+end
+document nd_type
+  Print a Ruby' node type.
+end
+
+define nd_file
+  print ((NODE*)$arg0)->nd_file
+end
+document nd_file
+  Print the source file name of a node.
+end
+
+define nd_line
+  print ((unsigned int)((((NODE*)$arg0)->flags>>RUBY_NODE_LSHIFT)&RUBY_NODE_LMASK))
+end
+document nd_line
+  Print the source line number of a node.
+end
+
+# Print members of ruby node.
+
+define nd_head
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_alen
+  printf "u2.argc: "
+  p $arg0.u2.argc
+end
+
+define nd_next
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_cond
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_body
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+define nd_else
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_orig
+  printf "u3.value: "
+  rp $arg0.u3.value
+end
+
+
+define nd_resq
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+define nd_ensr
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_1st
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_2nd
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+
+define nd_stts
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+
+define nd_entry
+  printf "u3.entry: "
+  p $arg0.u3.entry
+end
+
+define nd_vid
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_cflag
+  printf "u2.id: "
+  p $arg0.u2.id
+end
+
+define nd_cval
+  printf "u3.value: "
+  rp $arg0.u3.value
+end
+
+
+define nd_cnt
+  printf "u3.cnt: "
+  p $arg0.u3.cnt
+end
+
+define nd_tbl
+  printf "u1.tbl: "
+  p $arg0.u1.tbl
+end
+
+
+define nd_var
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_ibdy
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+define nd_iter
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_value
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+define nd_aid
+  printf "u3.id: "
+  p $arg0.u3.id
+end
+
+
+define nd_lit
+  printf "u1.value: "
+  rp $arg0.u1.value
+end
+
+
+define nd_frml
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_rest
+  printf "u2.argc: "
+  p $arg0.u2.argc
+end
+
+define nd_opt
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+
+define nd_recv
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_mid
+  printf "u2.id: "
+  p $arg0.u2.id
+end
+
+define nd_args
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_noex
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_defn
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_old
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_new
+  printf "u2.id: "
+  p $arg0.u2.id
+end
+
+
+define nd_cfnc
+  printf "u1.cfunc: "
+  p $arg0.u1.cfunc
+end
+
+define nd_argc
+  printf "u2.argc: "
+  p $arg0.u2.argc
+end
+
+
+define nd_cname
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_super
+  printf "u3.node: "
+  rp $arg0.u3.node
+end
+
+
+define nd_modl
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_clss
+  printf "u1.value: "
+  rp $arg0.u1.value
+end
+
+
+define nd_beg
+  printf "u1.node: "
+  rp $arg0.u1.node
+end
+
+define nd_end
+  printf "u2.node: "
+  rp $arg0.u2.node
+end
+
+define nd_state
+  printf "u3.state: "
+  p $arg0.u3.state
+end
+
+define nd_rval
+  printf "u2.value: "
+  rp $arg0.u2.value
+end
+
+
+define nd_nth
+  printf "u2.argc: "
+  p $arg0.u2.argc
+end
+
+
+define nd_tag
+  printf "u1.id: "
+  p $arg0.u1.id
+end
+
+define nd_tval
+  printf "u2.value: "
+  rp $arg0.u2.value
+end
+
+define rb_p
+  call rb_p($arg0)
+end
+
+define rb_id2name
+  call rb_id2name($arg0)
+end
+
+define rb_classname
+  call classname($arg0)
+  rb_p $
+  print *(struct RClass*)$arg0
+end
+
+define rb_backtrace
+  call rb_backtrace()
+end
Index: ruby_1_8/lib/rss/maker/1.0.rb
===================================================================
--- ruby_1_8/lib/rss/maker/1.0.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/1.0.rb	(revision 13747)
@@ -9,10 +9,11 @@
 
       def initialize
         super("1.0")
+        @feed_type = "rss"
       end
 
       private
-      def make_rss
+      def make_feed
         RDF.new(@version, @encoding, @standalone)
       end
 
@@ -25,43 +26,46 @@
 
       class Channel < ChannelBase
 
-        def to_rss(rss)
-          set = false
-          if @about
-            channel = RDF::Channel.new(@about)
-            set = setup_values(channel)
-            if set
+        def to_feed(rss)
+          set_default_values do
+            _not_set_required_variables = not_set_required_variables
+            if _not_set_required_variables.empty?
+              channel = RDF::Channel.new(@about)
+              set = setup_values(channel)
               channel.dc_dates.clear
               rss.channel = channel
+              set_parent(channel, rss)
               setup_items(rss)
               setup_image(rss)
               setup_textinput(rss)
-              setup_other_elements(rss)
+              setup_other_elements(rss, channel)
+            else
+              raise NotSetError.new("maker.channel", _not_set_required_variables)
             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
           seq = items.Seq
-          @maker.items.normalize.each do |item|
-            seq.lis << RDF::Channel::Items::Seq::Li.new(item.link)
+          set_parent(items, seq)
+          target_items = @maker.items.normalize
+          raise NotSetError.new("maker", ["items"]) if target_items.empty?
+          target_items.each do |item|
+            li = RDF::Channel::Items::Seq::Li.new(item.link)
+            seq.lis << li
+            set_parent(li, seq)
           end
           rss.channel.items = items
+          set_parent(rss.channel, items)
         end
         
         def setup_image(rss)
           if @maker.image.have_required_values?
-            rss.channel.image = RDF::Channel::Image.new(@maker.image.url)
+            image = RDF::Channel::Image.new(@maker.image.url)
+            rss.channel.image = image
+            set_parent(image, rss.channel)
           end
         end
 
@@ -69,15 +73,23 @@
           if @maker.textinput.have_required_values?
             textinput = RDF::Channel::Textinput.new(@maker.textinput.link)
             rss.channel.textinput = textinput
+            set_parent(textinput, rss.channel)
           end
         end
 
         def required_variable_names
-          %w(about title link description)
+          %w(about link)
         end
-        
+
+        def not_set_required_variables
+          vars = super
+          vars << "description" unless description {|d| d.have_required_values?}
+          vars << "title" unless title {|t| t.have_required_values?}
+          vars
+        end
+
         class SkipDays < SkipDaysBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
           
           class Day < DayBase
@@ -85,7 +97,7 @@
         end
         
         class SkipHours < SkipHoursBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
 
           class Hour < HourBase
@@ -93,112 +105,330 @@
         end
         
         class Cloud < CloudBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
         end
 
         class Categories < CategoriesBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
 
           class Category < CategoryBase
           end
         end
+
+        class Links < LinksBase
+          def to_feed(rss, channel)
+            return if @links.empty?
+            @links.first.to_feed(rss, channel)
+          end
+
+          class Link < LinkBase
+            def to_feed(rss, channel)
+              if have_required_values?
+                channel.link = href
+              else
+                raise NotSetError.new("maker.channel.link",
+                                      not_set_required_variables)
+              end
+            end
+
+            private
+            def required_variable_names
+              %w(href)
+            end
+          end
+        end
+
+        class Authors < AuthorsBase
+          def to_feed(rss, channel)
+          end
+
+          class Author < AuthorBase
+            def to_feed(rss, channel)
+            end
+          end
+        end
+
+        class Contributors < ContributorsBase
+          def to_feed(rss, channel)
+          end
+
+          class Contributor < ContributorBase
+          end
+        end
+
+        class Generator < GeneratorBase
+          def to_feed(rss, channel)
+          end
+        end
+
+        class Copyright < CopyrightBase
+          def to_feed(rss, channel)
+          end
+        end
+
+        class Description < DescriptionBase
+          def to_feed(rss, channel)
+            channel.description = content if have_required_values?
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
+
+        class Title < TitleBase
+          def to_feed(rss, channel)
+            channel.title = content if have_required_values?
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
       end
 
       class Image < ImageBase
-        def to_rss(rss)
+        def to_feed(rss)
           if @url
             image = RDF::Image.new(@url)
             set = setup_values(image)
             if set
               rss.image = image
-              setup_other_elements(rss)
+              set_parent(image, rss)
+              setup_other_elements(rss, image)
             end
           end
         end
 
         def have_required_values?
-          @url and @title and link and @maker.channel.have_required_values?
+          super and @maker.channel.have_required_values?
         end
 
         private
         def variables
           super + ["link"]
         end
+
+        def required_variable_names
+          %w(url title link)
+        end
       end
 
       class Items < ItemsBase
-        def to_rss(rss)
+        def to_feed(rss)
           if rss.channel
             normalize.each do |item|
-              item.to_rss(rss)
+              item.to_feed(rss)
             end
-            setup_other_elements(rss)
+            setup_other_elements(rss, rss.items)
           end
         end
 
         class Item < ItemBase
-          def to_rss(rss)
-            if @link
-              item = RDF::Item.new(@link)
+          def to_feed(rss)
+            set_default_values do
+              item = RDF::Item.new(link)
               set = setup_values(item)
               if set
                 item.dc_dates.clear
                 rss.items << item
-                setup_other_elements(rss)
+                set_parent(item, rss)
+                setup_other_elements(rss, item)
+              elsif !have_required_values?
+                raise NotSetError.new("maker.item", not_set_required_variables)
               end
             end
           end
 
-          def have_required_values?
-            @title and @link
+          private
+          def required_variable_names
+            %w(link)
           end
 
+          def variables
+            super + %w(link)
+          end
+
+          def not_set_required_variables
+            set_default_values do
+              vars = super
+              vars << "title" unless title {|t| t.have_required_values?}
+              vars
+            end
+          end
+
           class Guid < GuidBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
           end
-        
+
           class Enclosure < EnclosureBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
           end
-        
+
           class Source < SourceBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
+
+            class Authors < AuthorsBase
+              def to_feed(*args)
+              end
+
+              class Author < AuthorBase
+              end
+            end
+
+            class Categories < CategoriesBase
+              def to_feed(*args)
+              end
+
+              class Category < CategoryBase
+              end
+            end
+
+            class Contributors < ContributorsBase
+              def to_feed(*args)
+              end
+
+              class Contributor < ContributorBase
+              end
+            end
+
+            class Generator < GeneratorBase
+              def to_feed(*args)
+              end
+            end
+
+            class Icon < IconBase
+              def to_feed(*args)
+              end
+            end
+
+            class Links < LinksBase
+              def to_feed(*args)
+              end
+
+              class Link < LinkBase
+              end
+            end
+
+            class Logo < LogoBase
+              def to_feed(*args)
+              end
+            end
+
+            class Rights < RightsBase
+              def to_feed(*args)
+              end
+            end
+
+            class Subtitle < SubtitleBase
+              def to_feed(*args)
+              end
+            end
+
+            class Title < TitleBase
+              def to_feed(*args)
+              end
+            end
           end
-        
+
           class Categories < CategoriesBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
 
             class Category < CategoryBase
             end
           end
+
+          class Authors < AuthorsBase
+            def to_feed(*args)
+            end
+
+            class Author < AuthorBase
+            end
+          end
+
+          class Links < LinksBase
+            def to_feed(*args)
+            end
+
+            class Link < LinkBase
+            end
+          end
+
+          class Contributors < ContributorsBase
+            def to_feed(rss, item)
+            end
+
+            class Contributor < ContributorBase
+            end
+          end
+
+          class Rights < RightsBase
+            def to_feed(rss, item)
+            end
+          end
+
+          class Description < DescriptionBase
+            def to_feed(rss, item)
+              item.description = content if have_required_values?
+            end
+
+            private
+            def required_variable_names
+              %w(content)
+            end
+          end
+
+          class Content < ContentBase
+            def to_feed(rss, item)
+            end
+          end
+
+          class Title < TitleBase
+            def to_feed(rss, item)
+              item.title = content if have_required_values?
+            end
+
+            private
+            def required_variable_names
+              %w(content)
+            end
+          end
         end
       end
       
       class Textinput < TextinputBase
-        def to_rss(rss)
+        def to_feed(rss)
           if @link
             textinput = RDF::Textinput.new(@link)
             set = setup_values(textinput)
             if set
               rss.textinput = textinput
-              setup_other_elements(rss)
+              set_parent(textinput, rss)
+              setup_other_elements(rss, textinput)
             end
           end
         end
 
         def have_required_values?
-          @title and @description and @name and @link and
-            @maker.channel.have_required_values?
+          super and @maker.channel.have_required_values?
         end
+
+        private
+        def required_variable_names
+          %w(title description name link)
+        end
       end
     end
 
-    add_maker(filename_to_version(__FILE__), RSS10)
+    add_maker("1.0", RSS10)
+    add_maker("rss1.0", RSS10)
   end
 end
Index: ruby_1_8/lib/rss/maker/taxonomy.rb
===================================================================
--- ruby_1_8/lib/rss/maker/taxonomy.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/taxonomy.rb	(revision 13747)
@@ -8,24 +8,14 @@
       def self.append_features(klass)
         super
 
-        klass.add_need_initialize_variable("taxo_topics", "make_taxo_topics")
-        klass.add_other_element("taxo_topics")
-        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
-          attr_reader :taxo_topics
-          def make_taxo_topics
-            self.class::TaxonomyTopics.new(@maker)
-          end
-            
-          def setup_taxo_topics(rss, current)
-            @taxo_topics.to_rss(rss, current)
-          end
-EOC
+        klass.def_classed_element("#{RSS::TAXO_PREFIX}_topics",
+                                  "TaxonomyTopics")
       end
 
       def self.install_taxo_topics(klass)
-        klass.module_eval(<<-EOC, *Utils.get_file_and_line_from_caller(1))
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
           class TaxonomyTopics < TaxonomyTopicsBase
-            def to_rss(rss, current)
+            def to_feed(feed, current)
               if current.respond_to?(:taxo_topics)
                 topics = current.class::TaxonomyTopics.new
                 bag = topics.Bag
@@ -39,11 +29,10 @@
 EOC
       end
 
-      class TaxonomyTopicsBase
-        include Base
-
+      class TaxonomyTopicsBase < Base
         attr_reader :resources
-        def_array_element("resources")
+        def_array_element("resource")
+        remove_method :new_resource
       end
     end
 
@@ -51,77 +40,35 @@
       def self.append_features(klass)
         super
 
-        klass.add_need_initialize_variable("taxo_topics", "make_taxo_topics")
-        klass.add_other_element("taxo_topics")
-        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
-          attr_reader :taxo_topics
-          def make_taxo_topics
-            self.class::TaxonomyTopics.new(@maker)
-          end
-            
-          def setup_taxo_topics(rss, current)
-            @taxo_topics.to_rss(rss, current)
-          end
-
-          def taxo_topic
-            @taxo_topics[0] and @taxo_topics[0].value
-          end
-            
-          def taxo_topic=(new_value)
-            @taxo_topic[0] = self.class::TaxonomyTopic.new(self)
-            @taxo_topic[0].value = new_value
-          end
-EOC
+        class_name = "TaxonomyTopics"
+        klass.def_classed_elements("#{TAXO_PREFIX}_topic", "value", class_name)
       end
-    
+
       def self.install_taxo_topic(klass)
-        klass.module_eval(<<-EOC, *Utils.get_file_and_line_from_caller(1))
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
           class TaxonomyTopics < TaxonomyTopicsBase
             class TaxonomyTopic < TaxonomyTopicBase
               DublinCoreModel.install_dublin_core(self)
               TaxonomyTopicsModel.install_taxo_topics(self)
 
-              def to_rss(rss, current)
+              def to_feed(feed, current)
                 if current.respond_to?(:taxo_topics)
                   topic = current.class::TaxonomyTopic.new(value)
                   topic.taxo_link = value
-                  taxo_topics.to_rss(rss, topic) if taxo_topics
+                  taxo_topics.to_feed(feed, topic) if taxo_topics
                   current.taxo_topics << topic
-                  setup_other_elements(rss)
+                  setup_other_elements(feed, topic)
                 end
               end
-
-              def current_element(rss)
-                super.taxo_topics.last
-              end
             end
           end
 EOC
       end
 
-      class TaxonomyTopicsBase
-        include Base
-        
-        def_array_element("taxo_topics")
-                            
-        def new_taxo_topic
-          taxo_topic = self.class::TaxonomyTopic.new(self)
-          @taxo_topics << taxo_topic
-          if block_given?
-            yield taxo_topic
-          else
-            taxo_topic
-          end
-        end
+      class TaxonomyTopicsBase < Base
+        def_array_element("taxo_topic", nil, "TaxonomyTopic")
 
-        def to_rss(rss, current)
-          @taxo_topics.each do |taxo_topic|
-            taxo_topic.to_rss(rss, current)
-          end
-        end
-        
-        class TaxonomyTopicBase
-          include Base
+        class TaxonomyTopicBase < Base
           include DublinCoreModel
           include TaxonomyTopicsModel
           
@@ -151,32 +98,20 @@
       end
     end
 
-    class RSS10
-      TaxonomyTopicModel.install_taxo_topic(self)
-      
-      class Channel
-        TaxonomyTopicsModel.install_taxo_topics(self)
-      end
+    makers.each do |maker|
+      maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        TaxonomyTopicModel.install_taxo_topic(self)
 
-      class Items
-        class Item
+        class Channel
           TaxonomyTopicsModel.install_taxo_topics(self)
         end
-      end
-    end
-    
-    class RSS09
-      TaxonomyTopicModel.install_taxo_topic(self)
-      
-      class Channel
-        TaxonomyTopicsModel.install_taxo_topics(self)
-      end
 
-      class Items
-        class Item
-          TaxonomyTopicsModel.install_taxo_topics(self)
+        class Items
+          class Item
+            TaxonomyTopicsModel.install_taxo_topics(self)
+          end
         end
-      end
+      EOC
     end
   end
 end
Index: ruby_1_8/lib/rss/maker/2.0.rb
===================================================================
--- ruby_1_8/lib/rss/maker/2.0.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/2.0.rb	(revision 13747)
@@ -7,18 +7,15 @@
     
     class RSS20 < RSS09
       
-      def initialize(rss_version="2.0")
+      def initialize(feed_version="2.0")
         super
       end
 
       class Channel < RSS09::Channel
 
-        def have_required_values?
-          @title and @link and @description
-        end
-
+        private
         def required_variable_names
-          %w(title link description)
+          %w(link)
         end
         
         class SkipDays < RSS09::Channel::SkipDays
@@ -32,137 +29,186 @@
         end
         
         class Cloud < RSS09::Channel::Cloud
-          def to_rss(rss, channel)
+          def to_feed(rss, channel)
             cloud = Rss::Channel::Cloud.new
             set = setup_values(cloud)
             if set
               channel.cloud = cloud
-              setup_other_elements(rss)
+              set_parent(cloud, channel)
+              setup_other_elements(rss, cloud)
             end
           end
 
-          def have_required_values?
-            @domain and @port and @path and
-              @registerProcedure and @protocol
+          private
+          def required_variable_names
+            %w(domain port path registerProcedure protocol)
           end
         end
 
         class Categories < RSS09::Channel::Categories
-          def to_rss(rss, channel)
+          def to_feed(rss, channel)
             @categories.each do |category|
-              category.to_rss(rss, channel)
+              category.to_feed(rss, channel)
             end
           end
           
           class Category < RSS09::Channel::Categories::Category
-            def to_rss(rss, channel)
+            def to_feed(rss, channel)
               category = Rss::Channel::Category.new
               set = setup_values(category)
               if set
                 channel.categories << category
-                setup_other_elements(rss)
+                set_parent(category, channel)
+                setup_other_elements(rss, category)
               end
             end
-            
-            def have_required_values?
-              @content
+
+            private
+            def required_variable_names
+              %w(content)
             end
           end
         end
-        
+
+        class Generator < GeneratorBase
+          def to_feed(rss, channel)
+            channel.generator = content
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
       end
       
       class Image < RSS09::Image
+        private
+        def required_element?
+          false
+        end
       end
       
       class Items < RSS09::Items
-        
         class Item < RSS09::Items::Item
-
-          def have_required_values?
-            @title or @description
+          private
+          def required_variable_names
+            %w(title description)
           end
 
-          private
           def variables
             super + ["pubDate"]
           end
 
           class Guid < RSS09::Items::Item::Guid
-            def to_rss(rss, item)
+            def to_feed(rss, item)
               guid = Rss::Channel::Item::Guid.new
               set = setup_values(guid)
               if set
                 item.guid = guid
-                setup_other_elements(rss)
+                set_parent(guid, item)
+                setup_other_elements(rss, guid)
               end
             end
-            
-            def have_required_values?
-              @content
+
+            private
+            def required_variable_names
+              %w(content)
             end
           end
 
           class Enclosure < RSS09::Items::Item::Enclosure
-            def to_rss(rss, item)
+            def to_feed(rss, item)
               enclosure = Rss::Channel::Item::Enclosure.new
               set = setup_values(enclosure)
               if set
                 item.enclosure = enclosure
-                setup_other_elements(rss)
+                set_parent(enclosure, item)
+                setup_other_elements(rss, enclosure)
               end
             end
-            
-            def have_required_values?
-              @url and @length and @type
+
+            private
+            def required_variable_names
+              %w(url length type)
             end
           end
 
           class Source < RSS09::Items::Item::Source
-            def to_rss(rss, item)
+            def to_feed(rss, item)
               source = Rss::Channel::Item::Source.new
               set = setup_values(source)
               if set
                 item.source = source
-                setup_other_elements(rss)
+                set_parent(source, item)
+                setup_other_elements(rss, source)
               end
             end
-            
-            def have_required_values?
-              @url and @content
+
+            private
+            def required_variable_names
+              %w(url content)
             end
+
+            class Links < RSS09::Items::Item::Source::Links
+              def to_feed(rss, source)
+                return if @links.empty?
+                @links.first.to_feed(rss, source)
+              end
+
+              class Link < RSS09::Items::Item::Source::Links::Link
+                def to_feed(rss, source)
+                  source.url = href
+                end
+              end
+            end
           end
 
           class Categories < RSS09::Items::Item::Categories
-            def to_rss(rss, item)
+            def to_feed(rss, item)
               @categories.each do |category|
-                category.to_rss(rss, item)
+                category.to_feed(rss, item)
               end
             end
           
             class Category < RSS09::Items::Item::Categories::Category
-              def to_rss(rss, item)
+              def to_feed(rss, item)
                 category = Rss::Channel::Item::Category.new
                 set = setup_values(category)
                 if set
                   item.categories << category
+                  set_parent(category, item)
                   setup_other_elements(rss)
                 end
               end
-              
-              def have_required_values?
-                @content
+
+              private
+              def required_variable_names
+                %w(content)
               end
             end
           end
+
+          class Authors < RSS09::Items::Item::Authors
+            def to_feed(rss, item)
+              return if @authors.empty?
+              @authors.first.to_feed(rss, item)
+            end
+
+            class Author < RSS09::Items::Item::Authors::Author
+              def to_feed(rss, item)
+                item.author = name
+              end
+            end
+          end
         end
-        
       end
       
       class Textinput < RSS09::Textinput
       end
     end
     
-    add_maker(filename_to_version(__FILE__), RSS20)
+    add_maker("2.0", RSS20)
+    add_maker("rss2.0", RSS20)
   end
 end
Index: ruby_1_8/lib/rss/maker/atom.rb
===================================================================
--- ruby_1_8/lib/rss/maker/atom.rb	(revision 0)
+++ ruby_1_8/lib/rss/maker/atom.rb	(revision 13747)
@@ -0,0 +1,172 @@
+require "rss/atom"
+
+require "rss/maker/base"
+
+module RSS
+  module Maker
+    module AtomPersons
+      module_function
+      def def_atom_persons(klass, name, maker_name, plural=nil)
+        plural ||= "#{name}s"
+        klass_name = Utils.to_class_name(name)
+        plural_klass_name = Utils.to_class_name(plural)
+
+        klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          class #{plural_klass_name} < #{plural_klass_name}Base
+            class #{klass_name} < #{klass_name}Base
+              def to_feed(feed, current)
+                #{name} = feed.class::#{klass_name}.new
+                set = setup_values(#{name})
+                unless set
+                  raise NotSetError.new(#{maker_name.dump},
+                                        not_set_required_variables)
+                end
+                current.#{plural} << #{name}
+                set_parent(#{name}, current)
+                setup_other_elements(#{name})
+              end
+
+              private
+              def required_variable_names
+                %w(name)
+              end
+            end
+          end
+EOC
+      end
+    end
+
+    module AtomTextConstruct
+      class << self
+        def def_atom_text_construct(klass, name, maker_name, klass_name=nil,
+                                    atom_klass_name=nil)
+          klass_name ||= Utils.to_class_name(name)
+          atom_klass_name ||= Utils.to_class_name(name)
+
+          klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            class #{klass_name} < #{klass_name}Base
+              include #{self.name}
+              def to_feed(feed, current)
+                #{name} = current.class::#{atom_klass_name}.new
+                if setup_values(#{name})
+                  current.#{name} = #{name}
+                  set_parent(#{name}, current)
+                  setup_other_elements(feed)
+                elsif variable_is_set?
+                  raise NotSetError.new(#{maker_name.dump},
+                                        not_set_required_variables)
+                end
+              end
+            end
+          EOC
+        end
+      end
+
+      private
+      def required_variable_names
+        if type == "xhtml"
+          %w(xml_content)
+        else
+          %w(content)
+        end
+      end
+
+      def variables
+        if type == "xhtml"
+          super + %w(xhtml)
+        else
+          super
+        end
+      end
+    end
+
+    module AtomCategory
+      def to_feed(feed, current)
+        category = feed.class::Category.new
+        set = setup_values(category)
+        if set
+          current.categories << category
+          set_parent(category, current)
+          setup_other_elements(feed)
+        else
+          raise NotSetError.new(self.class.not_set_name,
+                                not_set_required_variables)
+        end
+      end
+
+      private
+      def required_variable_names
+        %w(term)
+      end
+
+      def variables
+        super + ["term", "scheme"]
+      end
+    end
+
+    module AtomLink
+      def to_feed(feed, current)
+        link = feed.class::Link.new
+        set = setup_values(link)
+        if set
+          current.links << link
+          set_parent(link, current)
+          setup_other_elements(feed)
+        else
+          raise NotSetError.new(self.class.not_set_name,
+                                not_set_required_variables)
+        end
+      end
+
+      private
+      def required_variable_names
+        %w(href)
+      end
+    end
+
+    module AtomGenerator
+      def to_feed(feed, current)
+        generator = current.class::Generator.new
+        if setup_values(generator)
+          current.generator = generator
+          set_parent(generator, current)
+          setup_other_elements(feed)
+        elsif variable_is_set?
+          raise NotSetError.new(self.class.not_set_name,
+                                not_set_required_variables)
+        end
+      end
+
+      private
+      def required_variable_names
+        %w(content)
+      end
+    end
+
+    module AtomLogo
+      def to_feed(feed, current)
+        logo = current.class::Logo.new
+        class << logo
+          alias_method(:uri=, :content=)
+        end
+        set = setup_values(logo)
+        class << logo
+          remove_method(:uri=)
+        end
+        if set
+          current.logo = logo
+          set_parent(logo, current)
+          setup_other_elements(feed)
+        elsif variable_is_set?
+          raise NotSetError.new(self.class.not_set_name,
+                                not_set_required_variables)
+        end
+      end
+
+      private
+      def required_variable_names
+        %w(uri)
+      end
+    end
+  end
+end
Index: ruby_1_8/lib/rss/maker/entry.rb
===================================================================
--- ruby_1_8/lib/rss/maker/entry.rb	(revision 0)
+++ ruby_1_8/lib/rss/maker/entry.rb	(revision 13747)
@@ -0,0 +1,163 @@
+require "rss/maker/atom"
+require "rss/maker/feed"
+
+module RSS
+  module Maker
+    module Atom
+      class Entry < RSSBase
+        def initialize
+          super("1.0")
+          @feed_type = "atom"
+          @feed_subtype = "entry"
+        end
+
+        private
+        def make_feed
+          ::RSS::Atom::Entry.new(@version, @encoding, @standalone)
+        end
+
+        def setup_elements(entry)
+          setup_items(entry)
+        end
+
+        class Channel < ChannelBase
+          class SkipDays < SkipDaysBase
+            class Day < DayBase
+            end
+          end
+
+          class SkipHours < SkipHoursBase
+            class Hour < HourBase
+            end
+          end
+
+          class Cloud < CloudBase
+          end
+
+          Categories = Feed::Channel::Categories
+          Links = Feed::Channel::Links
+          Authors = Feed::Channel::Authors
+          Contributors = Feed::Channel::Contributors
+
+          class Generator < GeneratorBase
+            include AtomGenerator
+
+            def self.not_set_name
+              "maker.channel.generator"
+            end
+          end
+
+          Copyright = Feed::Channel::Copyright
+
+          class Description < DescriptionBase
+          end
+
+          Title = Feed::Channel::Title
+        end
+
+        class Image < ImageBase
+        end
+
+        class Items < ItemsBase
+          def to_feed(entry)
+            (normalize.first || Item.new(@maker)).to_feed(entry)
+          end
+
+          class Item < ItemBase
+            def to_feed(entry)
+              set_default_values do
+                setup_values(entry)
+                entry.dc_dates.clear
+                setup_other_elements(entry)
+                unless have_required_values?
+                  raise NotSetError.new("maker.item", not_set_required_variables)
+                end
+              end
+            end
+
+            private
+            def required_variable_names
+              %w(id updated)
+            end
+
+            def variables
+              super + ["updated"]
+            end
+
+            def variable_is_set?
+              super or !authors.empty?
+            end
+
+            def not_set_required_variables
+              set_default_values do
+                vars = super
+                if authors.all? {|author| !author.have_required_values?}
+                  vars << "author"
+                end
+                vars << "title" unless title {|t| t.have_required_values?}
+                vars
+              end
+            end
+
+            def _set_default_values(&block)
+              keep = {
+                :authors => authors.to_a.dup,
+                :contributors => contributors.to_a.dup,
+                :categories => categories.to_a.dup,
+                :id => id,
+                :links => links.to_a.dup,
+                :rights => @rights,
+                :title => @title,
+                :updated => updated,
+              }
+              authors.replace(@maker.channel.authors) if keep[:authors].empty?
+              if keep[:contributors].empty?
+                contributors.replace(@maker.channel.contributors)
+              end
+              if keep[:categories].empty?
+                categories.replace(@maker.channel.categories)
+              end
+              self.id ||= link || @maker.channel.id
+              links.replace(@maker.channel.links) if keep[:links].empty?
+              unless keep[:rights].variable_is_set?
+                @maker.channel.rights {|r| @rights = r}
+              end
+              unless keep[:title].variable_is_set?
+                @maker.channel.title {|t| @title = t}
+              end
+              self.updated ||= @maker.channel.updated
+              super(&block)
+            ensure
+              authors.replace(keep[:authors])
+              contributors.replace(keep[:contributors])
+              categories.replace(keep[:categories])
+              links.replace(keep[:links])
+              self.id = keep[:id]
+              @rights = keep[:rights]
+              @title = keep[:title]
+              self.updated = keep[:prev_updated]
+            end
+
+            Guid = Feed::Items::Item::Guid
+            Enclosure = Feed::Items::Item::Enclosure
+            Source = Feed::Items::Item::Source
+            Categories = Feed::Items::Item::Categories
+            Authors = Feed::Items::Item::Authors
+            Contributors = Feed::Items::Item::Contributors
+            Links = Feed::Items::Item::Links
+            Rights = Feed::Items::Item::Rights
+            Description = Feed::Items::Item::Description
+            Title = Feed::Items::Item::Title
+            Content = Feed::Items::Item::Content
+          end
+        end
+
+        class Textinput < TextinputBase
+        end
+      end
+    end
+
+    add_maker("atom:entry", Atom::Entry)
+    add_maker("atom1.0:entry", Atom::Entry)
+  end
+end
Index: ruby_1_8/lib/rss/maker/image.rb
===================================================================
--- ruby_1_8/lib/rss/maker/image.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/image.rb	(revision 13747)
@@ -9,24 +9,18 @@
         super
 
         name = "#{RSS::IMAGE_PREFIX}_item"
-        klass.add_need_initialize_variable(name, "make_#{name}")
-        klass.add_other_element(name)
-        klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-          attr_reader :#{name}
-          def setup_#{name}(rss, current)
-            if @#{name}
-              @#{name}.to_rss(rss, current)
-            end
-          end
+        klass.def_classed_element(name)
+      end
 
-          def make_#{name}
-            self.class::#{Utils.to_class_name(name)}.new(@maker)
+      def self.install_image_item(klass)
+	klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          class ImageItem < ImageItemBase
+            DublinCoreModel.install_dublin_core(self)
           end
 EOC
       end
 
-      class ImageItemBase
-        include Base
+      class ImageItemBase < Base
         include Maker::DublinCoreModel
 
         attr_accessor :about, :resource, :image_width, :image_height
@@ -42,6 +36,15 @@
         def have_required_values?
           @about
         end
+
+        def to_feed(feed, current)
+          if current.respond_to?(:image_item=) and have_required_values?
+            item = current.class::ImageItem.new
+            setup_values(item)
+            setup_other_elements(item)
+            current.image_item = item
+          end
+        end
       end
     end
 
@@ -50,24 +53,18 @@
         super
 
         name = "#{RSS::IMAGE_PREFIX}_favicon"
-        klass.add_need_initialize_variable(name, "make_#{name}")
-        klass.add_other_element(name)
-        klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-          attr_reader :#{name}
-          def setup_#{name}(rss, current)
-            if @#{name}
-              @#{name}.to_rss(rss, current)
-            end
-          end
+        klass.def_classed_element(name)
+      end
 
-          def make_#{name}
-            self.class::#{Utils.to_class_name(name)}.new(@maker)
+      def self.install_image_favicon(klass)
+	klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          class ImageFavicon < ImageFaviconBase
+            DublinCoreModel.install_dublin_core(self)
           end
-EOC
+        EOC
       end
 
-      class ImageFaviconBase
-        include Base
+      class ImageFaviconBase < Base
         include Maker::DublinCoreModel
 
         attr_accessor :about, :image_size
@@ -79,6 +76,15 @@
         def have_required_values?
           @about and @image_size
         end
+
+        def to_feed(feed, current)
+          if current.respond_to?(:image_favicon=) and have_required_values?
+            favicon = current.class::ImageFavicon.new
+            setup_values(favicon)
+            setup_other_elements(favicon)
+            current.image_favicon = favicon
+          end
+        end
       end
     end
 
@@ -88,58 +94,18 @@
       class ItemBase; include Maker::ImageItemModel; end
     end
 
-    class RSS10
-      class Items
-        class Item
-          class ImageItem < ImageItemBase
-            DublinCoreModel.install_dublin_core(self)
-            def to_rss(rss, current)
-              if @about
-                item = ::RSS::ImageItemModel::ImageItem.new(@about, @resource)
-                setup_values(item)
-                setup_other_elements(item)
-                current.image_item = item
-              end
-            end
-          end
+    makers.each do |maker|
+      maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        class Channel
+          ImageFaviconModel.install_image_favicon(self)
         end
-      end
-      
-      class Channel
-        class ImageFavicon < ImageFaviconBase
-          DublinCoreModel.install_dublin_core(self)
-          def to_rss(rss, current)
-            if @about and @image_size
-              args = [@about, @image_size]
-              favicon = ::RSS::ImageFaviconModel::ImageFavicon.new(*args)
-              setup_values(favicon)
-              setup_other_elements(favicon)
-              current.image_favicon = favicon
-            end
-          end
-        end
-      end
-    end
 
-    class RSS09
-      class Items
-        class Item
-          class ImageItem < ImageItemBase
-            DublinCoreModel.install_dublin_core(self)
-            def to_rss(*args)
-            end
+        class Items
+          class Item
+            ImageItemModel.install_image_item(self)
           end
         end
-      end
-      
-      class Channel
-        class ImageFavicon < ImageFaviconBase
-          DublinCoreModel.install_dublin_core(self)
-          def to_rss(*args)
-          end
-        end
-      end
+      EOC
     end
-
   end
 end
Index: ruby_1_8/lib/rss/maker/feed.rb
===================================================================
--- ruby_1_8/lib/rss/maker/feed.rb	(revision 0)
+++ ruby_1_8/lib/rss/maker/feed.rb	(revision 13747)
@@ -0,0 +1,429 @@
+require "rss/maker/atom"
+
+module RSS
+  module Maker
+    module Atom
+      class Feed < RSSBase
+        def initialize
+          super("1.0")
+          @feed_type = "atom"
+          @feed_subtype = "feed"
+        end
+
+        private
+        def make_feed
+          ::RSS::Atom::Feed.new(@version, @encoding, @standalone)
+        end
+
+        def setup_elements(feed)
+          setup_channel(feed)
+          setup_image(feed)
+          setup_items(feed)
+        end
+
+        class Channel < ChannelBase
+          def to_feed(feed)
+            set_default_values do
+              setup_values(feed)
+              feed.dc_dates.clear
+              setup_other_elements(feed)
+              if image_favicon.about
+                icon = feed.class::Icon.new
+                icon.content = image_favicon.about
+                feed.icon = icon
+              end
+              unless have_required_values?
+                raise NotSetError.new("maker.channel",
+                                      not_set_required_variables)
+              end
+            end
+          end
+
+          def have_required_values?
+            super and
+              (!authors.empty? or
+               @maker.items.any? {|item| !item.authors.empty?})
+          end
+
+          private
+          def required_variable_names
+            %w(id updated)
+          end
+
+          def variables
+            super + %w(id updated)
+          end
+
+          def variable_is_set?
+            super or !authors.empty?
+          end
+
+          def not_set_required_variables
+            vars = super
+            if authors.empty? and
+                @maker.items.all? {|item| item.author.to_s.empty?}
+              vars << "author"
+            end
+            vars << "title" unless title {|t| t.have_required_values?}
+            vars
+          end
+
+          def _set_default_values(&block)
+            keep = {
+              :id => id,
+              :updated => updated,
+            }
+            self.id ||= about
+            self.updated ||= dc_date
+            super(&block)
+          ensure
+            self.id = keep[:id]
+            self.updated = keep[:updated]
+          end
+
+          class SkipDays < SkipDaysBase
+            def to_feed(*args)
+            end
+
+            class Day < DayBase
+            end
+          end
+
+          class SkipHours < SkipHoursBase
+            def to_feed(*args)
+            end
+
+            class Hour < HourBase
+            end
+          end
+
+          class Cloud < CloudBase
+            def to_feed(*args)
+            end
+          end
+
+          class Categories < CategoriesBase
+            class Category < CategoryBase
+              include AtomCategory
+
+              def self.not_set_name
+                "maker.channel.category"
+              end
+            end
+          end
+
+          class Links < LinksBase
+            class Link < LinkBase
+              include AtomLink
+
+              def self.not_set_name
+                "maker.channel.link"
+              end
+            end
+          end
+
+          AtomPersons.def_atom_persons(self, "author", "maker.channel.author")
+          AtomPersons.def_atom_persons(self, "contributor",
+                                       "maker.channel.contributor")
+
+          class Generator < GeneratorBase
+            include AtomGenerator
+
+            def self.not_set_name
+              "maker.channel.generator"
+            end
+          end
+
+          AtomTextConstruct.def_atom_text_construct(self, "rights",
+                                                    "maker.channel.copyright",
+                                                    "Copyright")
+          AtomTextConstruct.def_atom_text_construct(self, "subtitle",
+                                                    "maker.channel.description",
+                                                    "Description")
+          AtomTextConstruct.def_atom_text_construct(self, "title",
+                                                    "maker.channel.title")
+        end
+
+        class Image < ImageBase
+          def to_feed(feed)
+            logo = feed.class::Logo.new
+            class << logo
+              alias_method(:url=, :content=)
+            end
+            set = setup_values(logo)
+            class << logo
+              remove_method(:url=)
+            end
+            if set
+              feed.logo = logo
+              set_parent(logo, feed)
+              setup_other_elements(feed, logo)
+            elsif variable_is_set?
+              raise NotSetError.new("maker.image", not_set_required_variables)
+            end
+          end
+
+          private
+          def required_variable_names
+            %w(url)
+          end
+        end
+
+        class Items < ItemsBase
+          def to_feed(feed)
+            normalize.each do |item|
+              item.to_feed(feed)
+            end
+            setup_other_elements(feed, feed.entries)
+          end
+
+          class Item < ItemBase
+            def to_feed(feed)
+              set_default_values do
+                entry = feed.class::Entry.new
+                set = setup_values(entry)
+                setup_other_elements(feed, entry)
+                if set
+                  feed.entries << entry
+                  set_parent(entry, feed)
+                elsif variable_is_set?
+                  raise NotSetError.new("maker.item", not_set_required_variables)
+                end
+              end
+            end
+
+            def have_required_values?
+              set_default_values do
+                super and title {|t| t.have_required_values?}
+              end
+            end
+
+            private
+            def required_variable_names
+              %w(id updated)
+            end
+
+            def variables
+              super + ["updated"]
+            end
+
+            def not_set_required_variables
+              vars = super
+              vars << "title" unless title {|t| t.have_required_values?}
+              vars
+            end
+
+            def _set_default_values(&block)
+              keep = {
+                :id => id,
+                :updated => updated,
+              }
+              self.id ||= link
+              self.updated ||= dc_date
+              super(&block)
+            ensure
+              self.id = keep[:id]
+              self.updated = keep[:updated]
+            end
+
+            class Guid < GuidBase
+              def to_feed(feed, current)
+              end
+            end
+
+            class Enclosure < EnclosureBase
+              def to_feed(feed, current)
+              end
+            end
+
+            class Source < SourceBase
+              def to_feed(feed, current)
+                source = current.class::Source.new
+                setup_values(source)
+                current.source = source
+                set_parent(source, current)
+                setup_other_elements(feed, source)
+                current.source = nil if source.to_s == "<source/>"
+              end
+
+              private
+              def required_variable_names
+                []
+              end
+
+              def variables
+                super + ["updated"]
+              end
+
+              AtomPersons.def_atom_persons(self, "author",
+                                           "maker.item.source.author")
+              AtomPersons.def_atom_persons(self, "contributor",
+                                           "maker.item.source.contributor")
+
+              class Categories < CategoriesBase
+                class Category < CategoryBase
+                  include AtomCategory
+
+                  def self.not_set_name
+                    "maker.item.source.category"
+                  end
+                end
+              end
+
+              class Generator < GeneratorBase
+                include AtomGenerator
+
+                def self.not_set_name
+                  "maker.item.source.generator"
+                end
+              end
+
+              class Icon < IconBase
+                def to_feed(feed, current)
+                  icon = current.class::Icon.new
+                  class << icon
+                    alias_method(:url=, :content=)
+                  end
+                  set = setup_values(icon)
+                  class << icon
+                    remove_method(:url=)
+                  end
+                  if set
+                    current.icon = icon
+                    set_parent(icon, current)
+                    setup_other_elements(feed, icon)
+                  elsif variable_is_set?
+                    raise NotSetError.new("maker.item.source.icon",
+                                          not_set_required_variables)
+                  end
+                end
+
+                private
+                def required_variable_names
+                  %w(url)
+                end
+              end
+
+              class Links < LinksBase
+                class Link < LinkBase
+                  include AtomLink
+
+                  def self.not_set_name
+                    "maker.item.source.link"
+                  end
+                end
+              end
+
+              class Logo < LogoBase
+                include AtomLogo
+
+                def self.not_set_name
+                  "maker.item.source.logo"
+                end
+              end
+
+              maker_name_base = "maker.item.source."
+              maker_name = "#{maker_name_base}rights"
+              AtomTextConstruct.def_atom_text_construct(self, "rights",
+                                                        maker_name)
+              maker_name = "#{maker_name_base}subtitle"
+              AtomTextConstruct.def_atom_text_construct(self, "subtitle",
+                                                        maker_name)
+              maker_name = "#{maker_name_base}title"
+              AtomTextConstruct.def_atom_text_construct(self, "title",
+                                                        maker_name)
+            end
+
+            class Categories < CategoriesBase
+              class Category < CategoryBase
+                include AtomCategory
+
+                def self.not_set_name
+                  "maker.item.category"
+                end
+              end
+            end
+
+            AtomPersons.def_atom_persons(self, "author", "maker.item.author")
+            AtomPersons.def_atom_persons(self, "contributor",
+                                         "maker.item.contributor")
+
+            class Links < LinksBase
+              class Link < LinkBase
+                include AtomLink
+
+                def self.not_set_name
+                  "maker.item.link"
+                end
+              end
+            end
+
+            AtomTextConstruct.def_atom_text_construct(self, "rights",
+                                                      "maker.item.rights")
+            AtomTextConstruct.def_atom_text_construct(self, "summary",
+                                                      "maker.item.description",
+                                                      "Description")
+            AtomTextConstruct.def_atom_text_construct(self, "title",
+                                                      "maker.item.title")
+
+            class Content < ContentBase
+              def to_feed(feed, current)
+                content = current.class::Content.new
+                if setup_values(content)
+                  content.src = nil if content.src and content.content
+                  current.content = content
+                  set_parent(content, current)
+                  setup_other_elements(feed, content)
+                elsif variable_is_set?
+                  raise NotSetError.new("maker.item.content",
+                                        not_set_required_variables)
+                end
+              end
+
+              alias_method(:xml, :xml_content)
+
+              private
+              def required_variable_names
+                if out_of_line?
+                  %w(type)
+                elsif xml_type?
+                  %w(xml_content)
+                else
+                  %w(content)
+                end
+              end
+
+              def variables
+                if out_of_line?
+                  super
+                elsif xml_type?
+                  super + %w(xml)
+                else
+                  super
+                end
+              end
+
+              def xml_type?
+                _type = type
+                return false if _type.nil?
+                _type == "xhtml" or
+                  /(?:\+xml|\/xml)$/i =~ _type or
+                  %w(text/xml-external-parsed-entity
+                     application/xml-external-parsed-entity
+                     application/xml-dtd).include?(_type.downcase)
+              end
+            end
+          end
+        end
+
+        class Textinput < TextinputBase
+        end
+      end
+    end
+
+    add_maker("atom", Atom::Feed)
+    add_maker("atom:feed", Atom::Feed)
+    add_maker("atom1.0", Atom::Feed)
+    add_maker("atom1.0:feed", Atom::Feed)
+  end
+end
Index: ruby_1_8/lib/rss/maker/syndication.rb
===================================================================
--- ruby_1_8/lib/rss/maker/syndication.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/syndication.rb	(revision 13747)
@@ -7,17 +7,8 @@
       def self.append_features(klass)
         super
 
-        ::RSS::SyndicationModel::ELEMENTS.each do |element|
-          klass.add_need_initialize_variable(element)
-          klass.add_other_element(element)
-          klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-            attr_accessor :#{element}
-            def setup_#{element}(rss, current)
-              if #{element} and current.respond_to?(:#{element}=)
-                current.#{element} = @#{element} if @#{element}
-              end
-            end
-          EOC
+        ::RSS::SyndicationModel::ELEMENTS.each do |name|
+          klass.def_other_element(name)
         end
       end
     end
Index: ruby_1_8/lib/rss/maker/trackback.rb
===================================================================
--- ruby_1_8/lib/rss/maker/trackback.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/trackback.rb	(revision 13747)
@@ -8,57 +8,15 @@
       def self.append_features(klass)
         super
 
-        name = "#{RSS::TRACKBACK_PREFIX}_ping"
-        klass.add_need_initialize_variable(name)
-        klass.add_other_element(name)
-        klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-          attr_accessor :#{name}
-          def setup_#{name}(rss, current)
-            if #{name} and current.respond_to?(:#{name}=)
-              current.#{name} = #{name}
-            end
-          end
-        EOC
-
-        name = "#{RSS::TRACKBACK_PREFIX}_abouts"
-        klass.add_need_initialize_variable(name, "make_#{name}")
-        klass.add_other_element(name)
-        klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-          attr_accessor :#{name}
-          def make_#{name}
-            self.class::TrackBackAbouts.new(self)
-          end
-
-          def setup_#{name}(rss, current)
-            @#{name}.to_rss(rss, current)
-          end
-        EOC
+        klass.def_other_element("#{RSS::TRACKBACK_PREFIX}_ping")
+        klass.def_classed_elements("#{RSS::TRACKBACK_PREFIX}_about", "value",
+                                   "TrackBackAbouts")
       end
 
-      class TrackBackAboutsBase
-        include Base
+      class TrackBackAboutsBase < Base
+        def_array_element("about", nil, "TrackBackAbout")
 
-        def_array_element("abouts")
-        
-        def new_about
-          about = self.class::TrackBackAbout.new(@maker)
-          @abouts << about
-          if block_given?
-            yield about
-          else
-            about
-          end
-        end
-
-        def to_rss(rss, current)
-          @abouts.each do |about|
-            about.to_rss(rss, current)
-          end
-        end
-        
-        class TrackBackAboutBase
-          include Base
-
+        class TrackBackAboutBase < Base
           attr_accessor :value
           add_need_initialize_variable("value")
           
@@ -66,11 +24,19 @@
           alias_method(:resource=, :value=)
           alias_method(:content, :value)
           alias_method(:content=, :value=)
-        
+
           def have_required_values?
             @value
           end
-          
+
+          def to_feed(feed, current)
+            if current.respond_to?(:trackback_abouts) and have_required_values?
+              about = current.class::TrackBackAbout.new
+              setup_values(about)
+              setup_other_elements(about)
+              current.trackback_abouts << about
+            end
+          end
         end
       end
     end
@@ -79,52 +45,17 @@
       class ItemBase; include TrackBackModel; end
     end
 
-    class RSS10
-      class Items
-        class Item
-          class TrackBackAbouts < TrackBackAboutsBase
-            class TrackBackAbout < TrackBackAboutBase
-              def to_rss(rss, current)
-                if resource
-                  about = ::RSS::TrackBackModel10::TrackBackAbout.new(resource)
-                  current.trackback_abouts << about
-                end
+    makers.each do |maker|
+      maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        class Items
+          class Item
+            class TrackBackAbouts < TrackBackAboutsBase
+              class TrackBackAbout < TrackBackAboutBase
               end
             end
           end
         end
-      end
+      EOC
     end
-
-    class RSS09
-      class Items
-        class Item
-          class TrackBackAbouts < TrackBackAboutsBase
-            def to_rss(*args)
-            end
-            class TrackBackAbout < TrackBackAboutBase
-            end
-          end
-        end
-      end
-    end
-    
-    class RSS20
-      class Items
-        class Item
-          class TrackBackAbouts < TrackBackAboutsBase
-            class TrackBackAbout < TrackBackAboutBase
-              def to_rss(rss, current)
-                if content
-                  about = ::RSS::TrackBackModel20::TrackBackAbout.new(content)
-                  current.trackback_abouts << about
-                end
-              end
-            end
-          end
-        end
-      end
-    end
-    
   end
 end
Index: ruby_1_8/lib/rss/maker/0.9.rb
===================================================================
--- ruby_1_8/lib/rss/maker/0.9.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/0.9.rb	(revision 13747)
@@ -7,13 +7,14 @@
     
     class RSS09 < RSSBase
       
-      def initialize(rss_version="0.91")
+      def initialize(feed_version="0.91")
         super
+        @feed_type = "rss"
       end
       
       private
-      def make_rss
-        Rss.new(@rss_version, @version, @encoding, @standalone)
+      def make_feed
+        Rss.new(@feed_version, @version, @encoding, @standalone)
       end
 
       def setup_elements(rss)
@@ -21,41 +22,34 @@
       end
 
       class Channel < ChannelBase
-        
-        def to_rss(rss)
+        def to_feed(rss)
           channel = Rss::Channel.new
           set = setup_values(channel)
-          if set
+          _not_set_required_variables = not_set_required_variables
+          if _not_set_required_variables.empty?
             rss.channel = channel
+            set_parent(channel, rss)
             setup_items(rss)
             setup_image(rss)
             setup_textinput(rss)
-            setup_other_elements(rss)
-            if rss.channel.image
-              rss
-            else
-              nil
-            end
-          elsif variable_is_set?
-            raise NotSetError.new("maker.channel", not_set_required_variables)
+            setup_other_elements(rss, channel)
+            rss
+          else
+            raise NotSetError.new("maker.channel", _not_set_required_variables)
           end
         end
         
-        def have_required_values?
-          @title and @link and @description and @language
-        end
-        
         private
         def setup_items(rss)
-          @maker.items.to_rss(rss)
+          @maker.items.to_feed(rss)
         end
         
         def setup_image(rss)
-          @maker.image.to_rss(rss)
+          @maker.image.to_feed(rss)
         end
         
         def setup_textinput(rss)
-          @maker.textinput.to_rss(rss)
+          @maker.textinput.to_feed(rss)
         end
         
         def variables
@@ -63,162 +57,405 @@
         end
 
         def required_variable_names
-          %w(title link description language)
+          %w(link language)
         end
-        
+
+        def not_set_required_variables
+          vars = super
+          vars << "description" unless description {|d| d.have_required_values?}
+          vars << "title" unless title {|t| t.have_required_values?}
+          vars
+        end
+
         class SkipDays < SkipDaysBase
-          def to_rss(rss, channel)
+          def to_feed(rss, channel)
             unless @days.empty?
               skipDays = Rss::Channel::SkipDays.new
               channel.skipDays = skipDays
+              set_parent(skipDays, channel)
               @days.each do |day|
-                day.to_rss(rss, skipDays.days)
+                day.to_feed(rss, skipDays.days)
               end
             end
           end
           
           class Day < DayBase
-            def to_rss(rss, days)
+            def to_feed(rss, days)
               day = Rss::Channel::SkipDays::Day.new
               set = setup_values(day)
               if set
                 days << day
-                setup_other_elements(rss)
+                set_parent(day, days)
+                setup_other_elements(rss, day)
               end
             end
 
-            def have_required_values?
-              @content
+            private
+            def required_variable_names
+              %w(content)
             end
           end
         end
         
         class SkipHours < SkipHoursBase
-          def to_rss(rss, channel)
+          def to_feed(rss, channel)
             unless @hours.empty?
               skipHours = Rss::Channel::SkipHours.new
               channel.skipHours = skipHours
+              set_parent(skipHours, channel)
               @hours.each do |hour|
-                hour.to_rss(rss, skipHours.hours)
+                hour.to_feed(rss, skipHours.hours)
               end
             end
           end
           
           class Hour < HourBase
-            def to_rss(rss, hours)
+            def to_feed(rss, hours)
               hour = Rss::Channel::SkipHours::Hour.new
               set = setup_values(hour)
               if set
                 hours << hour
-                setup_other_elements(rss)
+                set_parent(hour, hours)
+                setup_other_elements(rss, hour)
               end
             end
 
-            def have_required_values?
-              @content
+            private
+            def required_variable_names
+              %w(content)
             end
           end
         end
         
         class Cloud < CloudBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
         end
 
         class Categories < CategoriesBase
-          def to_rss(*args)
+          def to_feed(*args)
           end
 
           class Category < CategoryBase
           end
         end
+
+        class Links < LinksBase
+          def to_feed(rss, channel)
+            return if @links.empty?
+            @links.first.to_feed(rss, channel)
+          end
+
+          class Link < LinkBase
+            def to_feed(rss, channel)
+              if have_required_values?
+                channel.link = href
+              else
+                raise NotSetError.new("maker.channel.link",
+                                      not_set_required_variables)
+              end
+            end
+
+            private
+            def required_variable_names
+              %w(href)
+            end
+          end
+        end
+
+        class Authors < AuthorsBase
+          def to_feed(rss, channel)
+          end
+
+          class Author < AuthorBase
+            def to_feed(rss, channel)
+            end
+          end
+        end
+
+        class Contributors < ContributorsBase
+          def to_feed(rss, channel)
+          end
+
+          class Contributor < ContributorBase
+          end
+        end
+
+        class Generator < GeneratorBase
+          def to_feed(rss, channel)
+          end
+        end
+
+        class Copyright < CopyrightBase
+          def to_feed(rss, channel)
+            channel.copyright = content if have_required_values?
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
+
+        class Description < DescriptionBase
+          def to_feed(rss, channel)
+            channel.description = content if have_required_values?
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
+
+        class Title < TitleBase
+          def to_feed(rss, channel)
+            channel.title = content if have_required_values?
+          end
+
+          private
+          def required_variable_names
+            %w(content)
+          end
+        end
       end
-      
+
       class Image < ImageBase
-        def to_rss(rss)
+        def to_feed(rss)
           image = Rss::Channel::Image.new
           set = setup_values(image)
           if set
             image.link = link
             rss.channel.image = image
-            setup_other_elements(rss)
+            set_parent(image, rss.channel)
+            setup_other_elements(rss, image)
+          elsif required_element?
+            raise NotSetError.new("maker.image", not_set_required_variables)
           end
         end
-        
-        def have_required_values?
-          @url and @title and link
+
+        private
+        def required_variable_names
+          %w(url title link)
         end
+
+        def required_element?
+          true
+        end
       end
       
       class Items < ItemsBase
-        def to_rss(rss)
+        def to_feed(rss)
           if rss.channel
             normalize.each do |item|
-              item.to_rss(rss)
+              item.to_feed(rss)
             end
-            setup_other_elements(rss)
+            setup_other_elements(rss, rss.items)
           end
         end
         
         class Item < ItemBase
-          def to_rss(rss)
+          def to_feed(rss)
             item = Rss::Channel::Item.new
             set = setup_values(item)
-            if set
+            if set or title {|t| t.have_required_values?}
               rss.items << item
-              setup_other_elements(rss)
+              set_parent(item, rss.channel)
+              setup_other_elements(rss, item)
+            elsif variable_is_set?
+              raise NotSetError.new("maker.items", not_set_required_variables)
             end
           end
-          
+
           private
-          def have_required_values?
-            @title and @link
+          def required_variable_names
+            %w(link)
           end
 
+          def not_set_required_variables
+            vars = super
+            vars << "title" unless title {|t| t.have_required_values?}
+            vars
+          end
+
           class Guid < GuidBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
           end
-        
+
           class Enclosure < EnclosureBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
           end
-        
+
           class Source < SourceBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
+
+            class Authors < AuthorsBase
+              def to_feed(*args)
+              end
+
+              class Author < AuthorBase
+              end
+            end
+
+            class Categories < CategoriesBase
+              def to_feed(*args)
+              end
+
+              class Category < CategoryBase
+              end
+            end
+
+            class Contributors < ContributorsBase
+              def to_feed(*args)
+              end
+
+              class Contributor < ContributorBase
+              end
+            end
+
+            class Generator < GeneratorBase
+              def to_feed(*args)
+              end
+            end
+
+            class Icon < IconBase
+              def to_feed(*args)
+              end
+            end
+
+            class Links < LinksBase
+              def to_feed(*args)
+              end
+
+              class Link < LinkBase
+              end
+            end
+
+            class Logo < LogoBase
+              def to_feed(*args)
+              end
+            end
+
+            class Rights < RightsBase
+              def to_feed(*args)
+              end
+            end
+
+            class Subtitle < SubtitleBase
+              def to_feed(*args)
+              end
+            end
+
+            class Title < TitleBase
+              def to_feed(*args)
+              end
+            end
           end
-        
+
           class Categories < CategoriesBase
-            def to_rss(*args)
+            def to_feed(*args)
             end
 
             class Category < CategoryBase
             end
           end
-          
+
+          class Authors < AuthorsBase
+            def to_feed(*args)
+            end
+
+            class Author < AuthorBase
+            end
+          end
+
+          class Links < LinksBase
+            def to_feed(rss, item)
+              return if @links.empty?
+              @links.first.to_feed(rss, item)
+            end
+
+            class Link < LinkBase
+              def to_feed(rss, item)
+                if have_required_values?
+                  item.link = href
+                else
+                  raise NotSetError.new("maker.link",
+                                        not_set_required_variables)
+                end
+              end
+
+              private
+              def required_variable_names
+                %w(href)
+              end
+            end
+          end
+
+          class Contributors < ContributorsBase
+            def to_feed(rss, item)
+            end
+
+            class Contributor < ContributorBase
+            end
+          end
+
+          class Rights < RightsBase
+            def to_feed(rss, item)
+            end
+          end
+
+          class Description < DescriptionBase
+            def to_feed(rss, item)
+              item.description = content if have_required_values?
+            end
+
+            private
+            def required_variable_names
+              %w(content)
+            end
+          end
+
+          class Content < ContentBase
+            def to_feed(rss, item)
+            end
+          end
+
+          class Title < TitleBase
+            def to_feed(rss, item)
+              item.title = content if have_required_values?
+            end
+
+            private
+            def required_variable_names
+              %w(content)
+            end
+          end
         end
       end
       
       class Textinput < TextinputBase
-        def to_rss(rss)
+        def to_feed(rss)
           textInput = Rss::Channel::TextInput.new
           set = setup_values(textInput)
           if set
             rss.channel.textInput = textInput
-            setup_other_elements(rss)
+            set_parent(textInput, rss.channel)
+            setup_other_elements(rss, textInput)
           end
         end
 
         private
-        def have_required_values?
-          @title and @description and @name and @link
+        def required_variable_names
+          %w(title description name link)
         end
       end
     end
     
-    add_maker(filename_to_version(__FILE__), RSS09)
-    add_maker(filename_to_version(__FILE__) + "1", RSS09)
+    add_maker("0.9", RSS09)
+    add_maker("0.91", RSS09)
+    add_maker("rss0.91", RSS09)
   end
 end
Index: ruby_1_8/lib/rss/maker/dublincore.rb
===================================================================
--- ruby_1_8/lib/rss/maker/dublincore.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/dublincore.rb	(revision 13747)
@@ -15,60 +15,40 @@
           plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
           full_plural_klass_name = "self.class::#{plural_klass_name}"
           full_klass_name = "#{full_plural_klass_name}::#{klass_name}"
-          klass.add_need_initialize_variable(full_plural_name,
-                                             "make_#{full_plural_name}")
-          klass.add_other_element(full_plural_name)
-          klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-            attr_accessor :#{full_plural_name}
-            def make_#{full_plural_name}
-              #{full_plural_klass_name}.new(@maker)
+          klass.def_classed_elements(full_name, "value", plural_klass_name,
+                                     full_plural_name, name)
+          klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            def new_#{full_name}(value=nil)
+              _#{full_name} = #{full_plural_name}.new_#{name}
+              _#{full_name}.value = value
+              if block_given?
+                yield _#{full_name}
+              else
+                _#{full_name}
+              end
             end
-            
-            def setup_#{full_plural_name}(rss, current)
-              @#{full_plural_name}.to_rss(rss, current)
-            end
-
-            def #{full_name}
-              @#{full_plural_name}[0] and @#{full_plural_name}[0].value
-            end
-            
-            def #{full_name}=(new_value)
-              @#{full_plural_name}[0] = #{full_klass_name}.new(self)
-              @#{full_plural_name}[0].value = new_value
-            end
-EOC
+          EOC
         end
+
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          # For backward compatibility
+          alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list
+        EOC
       end
 
       ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name|
         plural_name ||= "#{name}s"
+        full_name ||= "#{DC_PREFIX}_#{name}"
+        full_plural_name ||= "#{DC_PREFIX}_#{plural_name}"
         klass_name = Utils.to_class_name(name)
+        full_klass_name = "DublinCore#{klass_name}"
         plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
-        module_eval(<<-EOC, __FILE__, __LINE__)
-        class #{plural_klass_name}Base
-          include Base
+        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        class #{plural_klass_name}Base < Base
+          def_array_element(#{name.dump}, #{full_plural_name.dump},
+                            #{full_klass_name.dump})
 
-          def_array_element(#{plural_name.dump})
-                            
-          def new_#{name}
-            #{name} = self.class::#{klass_name}.new(self)
-            @#{plural_name} << #{name}
-            if block_given?
-              yield #{name}
-            else
-              #{name}
-            end
-          end
-
-          def to_rss(rss, current)
-            @#{plural_name}.each do |#{name}|
-              #{name}.to_rss(rss, current)
-            end
-          end
-        
-          class #{klass_name}Base
-            include Base
-
+          class #{full_klass_name}Base < Base
             attr_accessor :value
             add_need_initialize_variable("value")
             alias_method(:content, :value)
@@ -77,7 +57,15 @@
             def have_required_values?
               @value
             end
+
+            def to_feed(feed, current)
+              if value and current.respond_to?(:#{full_name})
+                new_item = current.class::#{full_klass_name}.new(value)
+                current.#{full_plural_name} << new_item
+              end
+            end
           end
+          #{klass_name}Base = #{full_klass_name}Base
         end
         EOC
       end
@@ -86,18 +74,13 @@
         ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name|
           plural_name ||= "#{name}s"
           klass_name = Utils.to_class_name(name)
-          plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
           full_klass_name = "DublinCore#{klass_name}"
-          klass.module_eval(<<-EOC, *Utils.get_file_and_line_from_caller(1))
+          plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
+          klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
           class #{plural_klass_name} < #{plural_klass_name}Base
-            class #{klass_name} < #{klass_name}Base
-              def to_rss(rss, current)
-                if value and current.respond_to?(:dc_#{name})
-                  new_item = current.class::#{full_klass_name}.new(value)
-                  current.dc_#{plural_name} << new_item
-                end
-              end
+            class #{full_klass_name} < #{full_klass_name}Base
             end
+            #{klass_name} = #{full_klass_name}
           end
 EOC
         end
@@ -106,64 +89,36 @@
 
     class ChannelBase
       include DublinCoreModel
-      
-      remove_method(:date)
-      remove_method(:date=)
-      alias_method(:date, :dc_date)
-      alias_method(:date=, :dc_date=)
     end
     
     class ImageBase; include DublinCoreModel; end
     class ItemsBase
       class ItemBase
         include DublinCoreModel
-        
-        remove_method(:date)
-        remove_method(:date=)
-        alias_method(:date, :dc_date)
-        alias_method(:date=, :dc_date=)
       end
     end
     class TextinputBase; include DublinCoreModel; end
 
-    class RSS10
-      class Channel
-        DublinCoreModel.install_dublin_core(self)
-      end
+    makers.each do |maker|
+      maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        class Channel
+          DublinCoreModel.install_dublin_core(self)
+        end
 
-      class Image
-        DublinCoreModel.install_dublin_core(self)
-      end
-
-      class Items
-        class Item
+        class Image
           DublinCoreModel.install_dublin_core(self)
         end
-      end
 
-      class Textinput
-        DublinCoreModel.install_dublin_core(self)
-      end
-    end
-    
-    class RSS09
-      class Channel
-        DublinCoreModel.install_dublin_core(self)
-      end
+        class Items
+          class Item
+            DublinCoreModel.install_dublin_core(self)
+          end
+        end
 
-      class Image
-        DublinCoreModel.install_dublin_core(self)
-      end
-
-      class Items
-        class Item
+        class Textinput
           DublinCoreModel.install_dublin_core(self)
         end
-      end
-
-      class Textinput
-        DublinCoreModel.install_dublin_core(self)
-      end
+      EOC
     end
   end
 end
Index: ruby_1_8/lib/rss/maker/itunes.rb
===================================================================
--- ruby_1_8/lib/rss/maker/itunes.rb	(revision 0)
+++ ruby_1_8/lib/rss/maker/itunes.rb	(revision 13747)
@@ -0,0 +1,242 @@
+require 'rss/itunes'
+require 'rss/maker/2.0'
+
+module RSS
+  module Maker
+    module ITunesBaseModel
+      def def_class_accessor(klass, name, type, *args)
+        name = name.gsub(/-/, "_").gsub(/^itunes_/, '')
+        full_name = "#{RSS::ITUNES_PREFIX}_#{name}"
+        case type
+        when nil
+          klass.def_other_element(full_name)
+        when :yes_other
+          def_yes_other_accessor(klass, full_name)
+        when :yes_clean_other
+          def_yes_clean_other_accessor(klass, full_name)
+        when :csv
+          def_csv_accessor(klass, full_name)
+        when :element, :attribute
+          recommended_attribute_name, = *args
+          klass_name = "ITunes#{Utils.to_class_name(name)}"
+          klass.def_classed_element(full_name, klass_name,
+                                    recommended_attribute_name)
+        when :elements
+          plural_name, recommended_attribute_name = args
+          plural_name ||= "#{name}s"
+          full_plural_name = "#{RSS::ITUNES_PREFIX}_#{plural_name}"
+          klass_name = "ITunes#{Utils.to_class_name(name)}"
+          plural_klass_name = "ITunes#{Utils.to_class_name(plural_name)}"
+          def_elements_class_accessor(klass, full_name, full_plural_name,
+                                      klass_name, plural_klass_name,
+                                      recommended_attribute_name)
+        end
+      end
+
+      def def_yes_other_accessor(klass, full_name)
+        klass.def_other_element(full_name)
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          def #{full_name}?
+            Utils::YesOther.parse(@#{full_name})
+          end
+        EOC
+      end
+
+      def def_yes_clean_other_accessor(klass, full_name)
+        klass.def_other_element(full_name)
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          def #{full_name}?
+            Utils::YesCleanOther.parse(#{full_name})
+          end
+        EOC
+      end
+
+      def def_csv_accessor(klass, full_name)
+        klass.def_csv_element(full_name)
+      end
+
+      def def_elements_class_accessor(klass, full_name, full_plural_name,
+                                      klass_name, plural_klass_name,
+                                      recommended_attribute_name=nil)
+        if recommended_attribute_name
+          klass.def_classed_elements(full_name, recommended_attribute_name,
+                                     plural_klass_name, full_plural_name)
+        else
+          klass.def_classed_element(full_plural_name, plural_klass_name)
+        end
+        klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          def new_#{full_name}(text=nil)
+            #{full_name} = @#{full_plural_name}.new_#{full_name}
+            #{full_name}.text = text
+            if block_given?
+              yield #{full_name}
+            else
+              #{full_name}
+            end
+          end
+        EOC
+      end
+    end
+
+    module ITunesChannelModel
+      extend ITunesBaseModel
+
+      class << self
+        def append_features(klass)
+          super
+
+          ::RSS::ITunesChannelModel::ELEMENT_INFOS.each do |name, type, *args|
+            def_class_accessor(klass, name, type, *args)
+          end
+        end
+      end
+
+      class ITunesCategoriesBase < Base
+        def_array_element("category", "itunes_categories",
+                          "ITunesCategory")
+        class ITunesCategoryBase < Base
+          attr_accessor :text
+          add_need_initialize_variable("text")
+          def_array_element("category", "itunes_categories",
+                            "ITunesCategory")
+
+          def have_required_values?
+            text
+          end
+
+          alias_method :to_feed_for_categories, :to_feed
+          def to_feed(feed, current)
+            if text and current.respond_to?(:itunes_category)
+              new_item = current.class::ITunesCategory.new(text)
+              to_feed_for_categories(feed, new_item)
+              current.itunes_categories << new_item
+            end
+          end
+        end
+      end
+
+      class ITunesImageBase < Base
+        add_need_initialize_variable("href")
+        attr_accessor("href")
+
+        def to_feed(feed, current)
+          if @href and current.respond_to?(:itunes_image)
+            current.itunes_image ||= current.class::ITunesImage.new
+            current.itunes_image.href = @href
+          end
+        end
+      end
+
+      class ITunesOwnerBase < Base
+        %w(itunes_name itunes_email).each do |name|
+          add_need_initialize_variable(name)
+          attr_accessor(name)
+        end
+
+        def to_feed(feed, current)
+          if current.respond_to?(:itunes_owner=)
+            _not_set_required_variables = not_set_required_variables
+            if (required_variable_names - _not_set_required_variables).empty?
+              return
+            end
+
+            unless have_required_values?
+              raise NotSetError.new("maker.channel.itunes_owner",
+                                    _not_set_required_variables)
+            end
+            current.itunes_owner ||= current.class::ITunesOwner.new
+            current.itunes_owner.itunes_name = @itunes_name
+            current.itunes_owner.itunes_email = @itunes_email
+          end
+        end
+
+        private
+        def required_variable_names
+          %w(itunes_name itunes_email)
+        end
+      end
+    end
+
+    module ITunesItemModel
+      extend ITunesBaseModel
+
+      class << self
+        def append_features(klass)
+          super
+
+          ::RSS::ITunesItemModel::ELEMENT_INFOS.each do |name, type, *args|
+            def_class_accessor(klass, name, type, *args)
+          end
+        end
+      end
+
+      class ITunesDurationBase < Base
+        attr_reader :content
+        add_need_initialize_variable("content")
+
+        %w(hour minute second).each do |name|
+          attr_reader(name)
+          add_need_initialize_variable(name, '0')
+        end
+
+        def content=(content)
+          if content.nil?
+            @hour, @minute, @second, @content = nil
+          else
+            @hour, @minute, @second =
+              ::RSS::ITunesItemModel::ITunesDuration.parse(content)
+            @content = content
+          end
+        end
+
+        def hour=(hour)
+          @hour = Integer(hour)
+          update_content
+        end
+
+        def minute=(minute)
+          @minute = Integer(minute)
+          update_content
+        end
+
+        def second=(second)
+          @second = Integer(second)
+          update_content
+        end
+
+        def to_feed(feed, current)
+          if @content and current.respond_to?(:itunes_duration=)
+            current.itunes_duration ||= current.class::ITunesDuration.new
+            current.itunes_duration.content = @content
+          end
+        end
+
+        private
+        def update_content
+          components = [@hour, @minute, @second]
+          @content =
+            ::RSS::ITunesItemModel::ITunesDuration.construct(*components)
+        end
+      end
+    end
+
+    class ChannelBase
+      include Maker::ITunesChannelModel
+      class ITunesCategories < ITunesCategoriesBase
+        class ITunesCategory < ITunesCategoryBase
+          ITunesCategory = self
+        end
+      end
+
+      class ITunesImage < ITunesImageBase; end
+      class ITunesOwner < ITunesOwnerBase; end
+    end
+
+    class ItemsBase
+      class ItemBase
+        include Maker::ITunesItemModel
+        class ITunesDuration < ITunesDurationBase; end
+      end
+    end
+  end
+end
Index: ruby_1_8/lib/rss/maker/base.rb
===================================================================
--- ruby_1_8/lib/rss/maker/base.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/base.rb	(revision 13747)
@@ -4,70 +4,184 @@
 
 module RSS
   module Maker
+    class Base
+      extend Utils::InheritedReader
 
-    module Base
+      OTHER_ELEMENTS = []
+      NEED_INITIALIZE_VARIABLES = []
 
-      def self.append_features(klass)
-        super
+      class << self
+        def other_elements
+          inherited_array_reader("OTHER_ELEMENTS")
+        end
+        def need_initialize_variables
+          inherited_array_reader("NEED_INITIALIZE_VARIABLES")
+        end
 
-        klass.module_eval(<<-EOC, __FILE__, __LINE__)
+        def inherited_base
+          ::RSS::Maker::Base
+        end
 
-        OTHER_ELEMENTS = []
-        NEED_INITIALIZE_VARIABLES = []
-
-        def self.inherited(subclass)
+        def inherited(subclass)
           subclass.const_set("OTHER_ELEMENTS", [])
           subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
+        end
 
-          subclass.module_eval(<<-EOEOC, __FILE__, __LINE__)
-            def self.other_elements
-              OTHER_ELEMENTS + super
+        def add_other_element(variable_name)
+          self::OTHER_ELEMENTS << variable_name
+        end
+
+        def add_need_initialize_variable(variable_name, init_value="nil")
+          self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
+        end
+
+        def def_array_element(name, plural=nil, klass_name=nil)
+          include Enumerable
+          extend Forwardable
+
+          plural ||= "#{name}s"
+          klass_name ||= Utils.to_class_name(name)
+          def_delegators("@#{plural}", :<<, :[], :[]=, :first, :last)
+          def_delegators("@#{plural}", :push, :pop, :shift, :unshift)
+          def_delegators("@#{plural}", :each, :size, :empty?, :clear)
+
+          add_need_initialize_variable(plural, "[]")
+
+          module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            def new_#{name}
+              #{name} = self.class::#{klass_name}.new(@maker)
+              @#{plural} << #{name}
+              if block_given?
+                yield #{name}
+              else
+                #{name}
+              end
             end
+            alias new_child new_#{name}
 
-            def self.need_initialize_variables
-              NEED_INITIALIZE_VARIABLES + super
+            def to_feed(*args)
+              @#{plural}.each do |#{name}|
+                #{name}.to_feed(*args)
+              end
             end
-          EOEOC
+
+            def replace(elements)
+              @#{plural}.replace(elements.to_a)
+            end
+          EOC
         end
 
-        def self.add_other_element(variable_name)
-          OTHER_ELEMENTS << variable_name
+        def def_classed_element_without_accessor(name, class_name=nil)
+          class_name ||= Utils.to_class_name(name)
+          add_other_element(name)
+          add_need_initialize_variable(name, "make_#{name}")
+          module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            private
+            def setup_#{name}(feed, current)
+              @#{name}.to_feed(feed, current)
+            end
+
+            def make_#{name}
+              self.class::#{class_name}.new(@maker)
+            end
+          EOC
         end
 
-        def self.other_elements
-          OTHER_ELEMENTS
+        def def_classed_element(name, class_name=nil, attribute_name=nil)
+          def_classed_element_without_accessor(name, class_name)
+          if attribute_name
+            module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+              def #{name}
+                if block_given?
+                  yield(@#{name})
+                else
+                  @#{name}.#{attribute_name}
+                end
+              end
+
+              def #{name}=(new_value)
+                @#{name}.#{attribute_name} = new_value
+              end
+            EOC
+          else
+            attr_reader name
+          end
         end
 
-        def self.add_need_initialize_variable(variable_name, init_value="nil")
-          NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
+        def def_classed_elements(name, attribute, plural_class_name=nil,
+                                 plural_name=nil, new_name=nil)
+          plural_name ||= "#{name}s"
+          new_name ||= name
+          def_classed_element(plural_name, plural_class_name)
+          local_variable_name = "_#{name}"
+          new_value_variable_name = "new_value"
+          additional_setup_code = nil
+          if block_given?
+            additional_setup_code = yield(local_variable_name,
+                                          new_value_variable_name)
+          end
+          module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            def #{name}
+              #{local_variable_name} = #{plural_name}.first
+              #{local_variable_name} ? #{local_variable_name}.#{attribute} : nil
+            end
+
+            def #{name}=(#{new_value_variable_name})
+              #{local_variable_name} =
+                #{plural_name}.first || #{plural_name}.new_#{new_name}
+              #{additional_setup_code}
+              #{local_variable_name}.#{attribute} = #{new_value_variable_name}
+            end
+          EOC
         end
 
-        def self.need_initialize_variables
-          NEED_INITIALIZE_VARIABLES
+        def def_other_element(name)
+          attr_accessor name
+          def_other_element_without_accessor(name)
         end
 
-        def self.def_array_element(name)
-          include Enumerable
-          extend Forwardable
+        def def_other_element_without_accessor(name)
+          add_need_initialize_variable(name)
+          add_other_element(name)
+          module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            def setup_#{name}(feed, current)
+              if !@#{name}.nil? and current.respond_to?(:#{name}=)
+                current.#{name} = @#{name}
+              end
+            end
+          EOC
+        end
 
-          def_delegators("@\#{name}", :<<, :[], :[]=, :first, :last)
-          def_delegators("@\#{name}", :push, :pop, :shift, :unshift)
-          def_delegators("@\#{name}", :each, :size)
-          
-          add_need_initialize_variable(name, "[]")
+        def def_csv_element(name, type=nil)
+          def_other_element_without_accessor(name)
+          attr_reader(name)
+          converter = ""
+          if type == :integer
+            converter = "{|v| Integer(v)}"
+          end
+          module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+            def #{name}=(value)
+              @#{name} = Utils::CSV.parse(value)#{converter}
+            end
+          EOC
         end
-        EOC
       end
-      
+
+      attr_reader :maker
       def initialize(maker)
         @maker = maker
+        @default_values_are_set = false
         initialize_variables
       end
 
       def have_required_values?
-        true
+        not_set_required_variables.empty?
       end
-      
+
+      def variable_is_set?
+        variables.any? {|var| not __send__(var).nil?}
+      end
+
       private
       def initialize_variables
         self.class.need_initialize_variables.each do |variable_name, init_value|
@@ -75,16 +189,32 @@
         end
       end
 
-      def setup_other_elements(rss)
+      def setup_other_elements(feed, current=nil)
+        current ||= current_element(feed)
         self.class.other_elements.each do |element|
-          __send__("setup_#{element}", rss, current_element(rss))
+          __send__("setup_#{element}", feed, current)
         end
       end
 
-      def current_element(rss)
-        rss
+      def current_element(feed)
+        feed
       end
-      
+
+      def set_default_values(&block)
+        return yield if @default_values_are_set
+
+        begin
+          @default_values_are_set = true
+          _set_default_values(&block)
+        ensure
+          @default_values_are_set = false
+        end
+      end
+
+      def _set_default_values(&block)
+        yield
+      end
+
       def setup_values(target)
         set = false
         if have_required_values?
@@ -102,6 +232,10 @@
         set
       end
 
+      def set_parent(target, parent)
+        target.parent = parent if target.class.need_parent?
+      end
+
       def variables
         self.class.need_initialize_variables.find_all do |name, init|
           "nil" == init
@@ -110,10 +244,6 @@
         end
       end
 
-      def variable_is_set?
-        variables.find {|var| !__send__(var).nil?}
-      end
-
       def not_set_required_variables
         required_variable_names.find_all do |var|
           __send__(var).nil?
@@ -126,12 +256,106 @@
         end
         true
       end
-      
     end
 
-    class RSSBase
-      include Base
+    module AtomPersonConstructBase
+      def self.append_features(klass)
+        super
 
+        klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          %w(name uri email).each do |element|
+            attr_accessor element
+            add_need_initialize_variable(element)
+          end
+        EOC
+      end
+    end
+
+    module AtomTextConstructBase
+      module EnsureXMLContent
+        class << self
+          def included(base)
+            super
+            base.class_eval do
+              %w(type content xml_content).each do |element|
+                attr_reader element
+                attr_writer element if element != "xml_content"
+                add_need_initialize_variable(element)
+              end
+
+              alias_method(:xhtml, :xml_content)
+            end
+          end
+        end
+
+        def ensure_xml_content(content)
+          xhtml_uri = ::RSS::Atom::XHTML_URI
+          unless content.is_a?(RSS::XML::Element) and
+              ["div", xhtml_uri] == [content.name, content.uri]
+            children = content
+            children = [children] unless content.is_a?(Array)
+            children = set_xhtml_uri_as_default_uri(children)
+            content = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                            {"xmlns" => xhtml_uri},
+                                            children)
+          end
+          content
+        end
+
+        def xml_content=(content)
+          @xml_content = ensure_xml_content(content)
+        end
+
+        def xhtml=(content)
+          self.xml_content = content
+        end
+
+        private
+        def set_xhtml_uri_as_default_uri(children)
+          children.collect do |child|
+            if child.is_a?(RSS::XML::Element) and
+                child.prefix.nil? and child.uri.nil?
+              RSS::XML::Element.new(child.name, nil, ::RSS::Atom::XHTML_URI,
+                                    child.attributes.dup,
+                                    set_xhtml_uri_as_default_uri(child.children))
+            else
+              child
+            end
+          end
+        end
+      end
+
+      def self.append_features(klass)
+        super
+
+        klass.class_eval do
+          include EnsureXMLContent
+        end
+      end
+    end
+
+    module SetupDefaultDate
+      private
+      def _set_default_values(&block)
+        keep = {
+          :date => date,
+          :dc_dates => dc_dates.to_a.dup,
+        }
+        _date = date
+        if _date and !dc_dates.any? {|dc_date| dc_date.value == _date}
+          dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self)
+          dc_date.value = _date.dup
+          dc_dates.unshift(dc_date)
+        end
+        self.date ||= self.dc_date
+        super(&block)
+      ensure
+        date = keep[:date]
+        dc_dates.replace(keep[:dc_dates])
+      end
+    end
+
+    class RSSBase < Base
       class << self
         def make(&block)
           new.make(&block)
@@ -143,22 +367,25 @@
         add_need_initialize_variable(element, "make_#{element}")
         module_eval(<<-EOC, __FILE__, __LINE__)
           private
-          def setup_#{element}(rss)
-            @#{element}.to_rss(rss)
+          def setup_#{element}(feed)
+            @#{element}.to_feed(feed)
           end
 
           def make_#{element}
             self.class::#{Utils.to_class_name(element)}.new(self)
           end
-EOC
+        EOC
       end
       
-      attr_reader :rss_version
+      attr_reader :feed_version
+      alias_method(:rss_version, :feed_version)
       attr_accessor :version, :encoding, :standalone
-      
-      def initialize(rss_version)
+
+      def initialize(feed_version)
         super(self)
-        @rss_version = rss_version
+        @feed_type = nil
+        @feed_subtype = nil
+        @feed_version = feed_version
         @version = "1.0"
         @encoding = "UTF-8"
         @standalone = nil
@@ -167,19 +394,19 @@
       def make
         if block_given?
           yield(self)
-          to_rss
+          to_feed
         else
           nil
         end
       end
 
-      def to_rss
-        rss = make_rss
-        setup_xml_stylesheets(rss)
-        setup_elements(rss)
-        setup_other_elements(rss)
-        if rss.channel
-          rss
+      def to_feed
+        feed = make_feed
+        setup_xml_stylesheets(feed)
+        setup_elements(feed)
+        setup_other_elements(feed)
+        if feed.valid?
+          feed
         else
           nil
         end
@@ -190,51 +417,27 @@
       def make_xml_stylesheets
         XMLStyleSheets.new(self)
       end
-      
     end
 
-    class XMLStyleSheets
-      include Base
+    class XMLStyleSheets < Base
+      def_array_element("xml_stylesheet", nil, "XMLStyleSheet")
 
-      def_array_element("xml_stylesheets")
+      class XMLStyleSheet < Base
 
-      def to_rss(rss)
-        @xml_stylesheets.each do |xss|
-          xss.to_rss(rss)
-        end
-      end
-
-      def new_xml_stylesheet
-        xss = XMLStyleSheet.new(@maker)
-        @xml_stylesheets << xss
-        if block_given?
-          yield xss
-        else
-          xss
-        end
-      end
-
-      class XMLStyleSheet
-        include Base
-
         ::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute|
           attr_accessor attribute
           add_need_initialize_variable(attribute)
         end
         
-        def to_rss(rss)
+        def to_feed(feed)
           xss = ::RSS::XMLStyleSheet.new
           guess_type_if_need(xss)
           set = setup_values(xss)
           if set
-            rss.xml_stylesheets << xss
+            feed.xml_stylesheets << xss
           end
         end
 
-        def have_required_values?
-          @href and @type
-        end
-
         private
         def guess_type_if_need(xss)
           if @type.nil?
@@ -242,172 +445,183 @@
             @type = xss.type
           end
         end
+
+        def required_variable_names
+          %w(href type)
+        end
       end
     end
     
-    class ChannelBase
-      include Base
+    class ChannelBase < Base
+      include SetupDefaultDate
 
-      %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
+      %w(cloud categories skipDays skipHours).each do |name|
+        def_classed_element(name)
+      end
 
-          def make_#{element}
-            self.class::#{Utils.to_class_name(element)}.new(@maker)
-          end
-EOC
+      %w(generator copyright description title).each do |name|
+        def_classed_element(name, nil, "content")
       end
 
-      %w(about title link description language copyright
+      [
+       ["link", "href", Proc.new {|target,| "#{target}.href = 'self'"}],
+       ["author", "name"],
+       ["contributor", "name"],
+      ].each do |name, attribute, additional_setup_maker|
+        def_classed_elements(name, attribute, &additional_setup_maker)
+      end
+
+      %w(id about language
          managingEditor webMaster rating docs date
-         lastBuildDate generator ttl).each do |element|
+         lastBuildDate ttl).each do |element|
         attr_accessor element
         add_need_initialize_variable(element)
       end
 
-      alias_method(:pubDate, :date)
-      alias_method(:pubDate=, :date=)
+      def pubDate
+        date
+      end
 
-      def current_element(rss)
-        rss.channel
+      def pubDate=(date)
+        self.date = date
       end
 
-      class SkipDaysBase
-        include Base
+      def updated
+        date
+      end
 
-        def_array_element("days")
+      def updated=(date)
+        self.date = date
+      end
 
-        def new_day
-          day = self.class::Day.new(@maker)
-          @days << day
-          if block_given?
-            yield day
-          else
-            day
-          end
-        end
-        
-        def current_element(rss)
-          rss.channel.skipDays
-        end
+      alias_method(:rights, :copyright)
+      alias_method(:rights=, :copyright=)
 
-        class DayBase
-          include Base
-          
+      alias_method(:subtitle, :description)
+      alias_method(:subtitle=, :description=)
+
+      def icon
+        image_favicon.about
+      end
+
+      def icon=(url)
+        image_favicon.about = url
+      end
+
+      def logo
+        maker.image.url
+      end
+
+      def logo=(url)
+        maker.image.url = url
+      end
+
+      class SkipDaysBase < Base
+        def_array_element("day")
+
+        class DayBase < 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
+      class SkipHoursBase < Base
+        def_array_element("hour")
 
-        def_array_element("hours")
-
-        def new_hour
-          hour = self.class::Hour.new(@maker)
-          @hours << hour
-          if block_given?
-            yield hour
-          else
-            hour
-          end
-        end
-        
-        def current_element(rss)
-          rss.channel.skipHours
-        end
-
-        class HourBase
-          include Base
-          
+        class HourBase < 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
-        include Base
-        
+      class CloudBase < Base
         %w(domain port path registerProcedure protocol).each do |element|
           attr_accessor element
           add_need_initialize_variable(element)
         end
-        
-        def current_element(rss)
-          rss.channel.cloud
-        end
-
       end
 
-      class CategoriesBase
-        include Base
-        
-        def_array_element("categories")
+      class CategoriesBase < Base
+        def_array_element("category", "categories")
 
-        def new_category
-          category = self.class::Category.new(@maker)
-          @categories << category
-          if block_given?
-            yield category
-          else
-            category
+        class CategoryBase < Base
+          %w(domain content label).each do |element|
+            attr_accessor element
+            add_need_initialize_variable(element)
           end
+
+          alias_method(:term, :domain)
+          alias_method(:term=, :domain=)
+          alias_method(:scheme, :content)
+          alias_method(:scheme=, :content=)
         end
+      end
 
-        class CategoryBase
-          include Base
+      class LinksBase < Base
+        def_array_element("link")
 
-          %w(domain content).each do |element|
+        class LinkBase < Base
+          %w(href rel type hreflang title length).each do |element|
             attr_accessor element
             add_need_initialize_variable(element)
           end
         end
       end
+
+      class AuthorsBase < Base
+        def_array_element("author")
+
+        class AuthorBase < Base
+          include AtomPersonConstructBase
+        end
+      end
+
+      class ContributorsBase < Base
+        def_array_element("contributor")
+
+        class ContributorBase < Base
+          include AtomPersonConstructBase
+        end
+      end
+
+      class GeneratorBase < Base
+        %w(uri version content).each do |element|
+          attr_accessor element
+          add_need_initialize_variable(element)
+        end
+      end
+
+      class CopyrightBase < Base
+        include AtomTextConstructBase
+      end
+
+      class DescriptionBase < Base
+        include AtomTextConstructBase
+      end
+
+      class TitleBase < Base
+        include AtomTextConstructBase
+      end
     end
     
-    class ImageBase
-      include Base
-
+    class ImageBase < Base
       %w(title url width height description).each do |element|
         attr_accessor element
         add_need_initialize_variable(element)
       end
-      
+
       def link
         @maker.channel.link
       end
-
-      def current_element(rss)
-        rss.image
-      end
     end
     
-    class ItemsBase
-      include Base
+    class ItemsBase < Base
+      def_array_element("item")
 
-      def_array_element("items")
-      
       attr_accessor :do_sort, :max_size
       
       def initialize(maker)
@@ -423,21 +637,7 @@
           sort_if_need[0..@max_size]
         end
       end
-      
-      def current_element(rss)
-        rss.items
-      end
 
-      def new_item
-        item = self.class::Item.new(@maker)
-        @items << item
-        if block_given?
-          yield item
-        else
-          item
-        end
-      end
-      
       private
       def sort_if_need
         if @do_sort.respond_to?(:call)
@@ -453,94 +653,216 @@
         end
       end
 
-      class ItemBase
-        include Base
-        
-        %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)
-            @#{element}.to_rss(rss, current)
-          end
+      class ItemBase < Base
+        include SetupDefaultDate
 
-          def make_#{element}
-            self.class::#{Utils.to_class_name(element)}.new(@maker)
-          end
-EOC
+        %w(guid enclosure source categories content).each do |name|
+          def_classed_element(name)
         end
-      
-        %w(title link description date author comments).each do |element|
+
+        %w(rights description title).each do |name|
+          def_classed_element(name, nil, "content")
+        end
+
+        [
+         ["author", "name"],
+         ["link", "href", Proc.new {|target,| "#{target}.href = 'alternate'"}],
+         ["contributor", "name"],
+        ].each do |name, attribute|
+          def_classed_elements(name, attribute)
+	end
+
+        %w(date comments id published).each do |element|
           attr_accessor element
           add_need_initialize_variable(element)
         end
 
-        alias_method(:pubDate, :date)
-        alias_method(:pubDate=, :date=)
+        def pubDate
+          date
+        end
 
+        def pubDate=(date)
+          self.date = date
+        end
+
+        def updated
+          date
+        end
+
+        def updated=(date)
+          self.date = date
+        end
+
+        alias_method(:summary, :description)
+        alias_method(:summary=, :description=)
+
         def <=>(other)
-          if date and other.date
-            date <=> other.date
-          elsif date
+          _date = date || dc_date
+          _other_date = other.date || other.dc_date
+          if _date and _other_date
+            _date <=> _other_date
+          elsif _date
             1
-          elsif other.date
+          elsif _other_date
             -1
           else
             0
           end
         end
-      
-        def current_element(rss)
-          rss.items.last
-        end
 
-        class GuidBase
-          include Base
-
+        class GuidBase < Base
           %w(isPermaLink content).each do |element|
             attr_accessor element
             add_need_initialize_variable(element)
           end
         end
-      
-        class EnclosureBase
-          include Base
 
+        class EnclosureBase < Base
           %w(url length type).each do |element|
             attr_accessor element
             add_need_initialize_variable(element)
           end
         end
-      
-        class SourceBase
-          include Base
 
-          %w(url content).each do |element|
+        class SourceBase < Base
+          %w(authors categories contributors generator icon
+             logo rights subtitle title).each do |name|
+            def_classed_element(name)
+          end
+
+          [
+           ["link", "href"],
+          ].each do |name, attribute|
+            def_classed_elements(name, attribute)
+          end
+
+          %w(id content date).each do |element|
             attr_accessor element
             add_need_initialize_variable(element)
           end
+
+          alias_method(:url, :link)
+          alias_method(:url=, :link=)
+
+          def updated
+            date
+          end
+
+          def updated=(date)
+            self.date = date
+          end
+
+          private
+          AuthorsBase = ChannelBase::AuthorsBase
+          CategoriesBase = ChannelBase::CategoriesBase
+          ContributorsBase = ChannelBase::ContributorsBase
+          GeneratorBase = ChannelBase::GeneratorBase
+
+          class IconBase < Base
+            %w(url).each do |element|
+              attr_accessor element
+              add_need_initialize_variable(element)
+            end
+          end
+
+          LinksBase = ChannelBase::LinksBase
+
+          class LogoBase < Base
+            %w(uri).each do |element|
+              attr_accessor element
+              add_need_initialize_variable(element)
+            end
+          end
+
+          class RightsBase < Base
+            include AtomTextConstructBase
+          end
+
+          class SubtitleBase < Base
+            include AtomTextConstructBase
+          end
+
+          class TitleBase < Base
+            include AtomTextConstructBase
+          end
         end
-      
+
         CategoriesBase = ChannelBase::CategoriesBase
-      
+        AuthorsBase = ChannelBase::AuthorsBase
+        LinksBase = ChannelBase::LinksBase
+        ContributorsBase = ChannelBase::ContributorsBase
+
+        class RightsBase < Base
+          include AtomTextConstructBase
+        end
+
+        class DescriptionBase < Base
+          include AtomTextConstructBase
+        end
+
+        class ContentBase < Base
+          include AtomTextConstructBase::EnsureXMLContent
+
+          %w(src).each do |element|
+            attr_accessor(element)
+            add_need_initialize_variable(element)
+          end
+
+          def xml_content=(content)
+            content = ensure_xml_content(content) if inline_xhtml?
+            @xml_content = content
+          end
+
+          alias_method(:xml, :xml_content)
+          alias_method(:xml=, :xml_content=)
+
+          def inline_text?
+            [nil, "text", "html"].include?(@type)
+          end
+
+          def inline_html?
+            @type == "html"
+          end
+
+          def inline_xhtml?
+            @type == "xhtml"
+          end
+
+          def inline_other?
+            !out_of_line? and ![nil, "text", "html", "xhtml"].include?(@type)
+          end
+
+          def inline_other_text?
+            return false if @type.nil? or out_of_line?
+            /\Atext\//i.match(@type) ? true : false
+          end
+
+          def inline_other_xml?
+            return false if @type.nil? or out_of_line?
+            /[\+\/]xml\z/i.match(@type) ? true : false
+          end
+
+          def inline_other_base64?
+            return false if @type.nil? or out_of_line?
+            @type.include?("/") and !inline_other_text? and !inline_other_xml?
+          end
+
+          def out_of_line?
+            not @src.nil? and @content.nil?
+          end
+        end
+
+        class TitleBase < Base
+          include AtomTextConstructBase
+        end
       end
     end
 
-    class TextinputBase
-      include Base
-
+    class TextinputBase < Base
       %w(title description name link).each do |element|
         attr_accessor element
         add_need_initialize_variable(element)
       end
-      
-      def current_element(rss)
-        rss.textinput
-      end
-
     end
-    
   end
 end
Index: ruby_1_8/lib/rss/maker/content.rb
===================================================================
--- ruby_1_8/lib/rss/maker/content.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker/content.rb	(revision 13747)
@@ -7,17 +7,8 @@
       def self.append_features(klass)
         super
 
-        ::RSS::ContentModel::ELEMENTS.each do |element|
-          klass.add_need_initialize_variable(element)
-          klass.add_other_element(element)
-          klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
-            attr_accessor :#{element}
-            def setup_#{element}(rss, current)
-              if #{element} and current.respond_to?(:#{element}=)
-                current.#{element} = @#{element} if @#{element}
-              end
-            end
-          EOC
+        ::RSS::ContentModel::ELEMENTS.each do |name|
+          klass.def_other_element(name)
         end
       end
     end
Index: ruby_1_8/lib/rss/maker/slash.rb
===================================================================
--- ruby_1_8/lib/rss/maker/slash.rb	(revision 0)
+++ ruby_1_8/lib/rss/maker/slash.rb	(revision 13747)
@@ -0,0 +1,33 @@
+require 'rss/slash'
+require 'rss/maker/1.0'
+
+module RSS
+  module Maker
+    module SlashModel
+      def self.append_features(klass)
+        super
+
+        ::RSS::SlashModel::ELEMENT_INFOS.each do |name, type|
+          full_name = "#{RSS::SLASH_PREFIX}_#{name}"
+          case type
+          when :csv_integer
+            klass.def_csv_element(full_name, :integer)
+          else
+            klass.def_other_element(full_name)
+          end
+        end
+
+        klass.module_eval do
+          alias_method(:slash_hit_parades, :slash_hit_parade)
+          alias_method(:slash_hit_parades=, :slash_hit_parade=)
+        end
+      end
+    end
+
+    class ItemsBase
+      class ItemBase
+        include SlashModel
+      end
+    end
+  end
+end
Index: ruby_1_8/lib/rss/1.0.rb
===================================================================
--- ruby_1_8/lib/rss/1.0.rb	(revision 13746)
+++ ruby_1_8/lib/rss/1.0.rb	(revision 13747)
@@ -45,10 +45,10 @@
       __send__("install_have_#{type}_element", tag, ::RSS::URI, occurs)
     end
 
-    attr_accessor :rss_version, :version, :encoding, :standalone
-    
+    alias_method(:rss_version, :feed_version)
     def initialize(version=nil, encoding=nil, standalone=nil)
       super('1.0', version, encoding, standalone)
+      @feed_type = "rss"
     end
 
     def full_name
@@ -430,21 +430,22 @@
   end
 
   RSS10::ELEMENTS.each do |name|
-    BaseListener.install_get_text_element(URI, name, "#{name}=")
+    BaseListener.install_get_text_element(URI, name, name)
   end
 
   module ListenerMixin
     private
-    def start_RDF(tag_name, prefix, attrs, ns)
+    def initial_start_RDF(tag_name, prefix, attrs, ns)
       check_ns(tag_name, prefix, ns, RDF::URI)
 
       @rss = RDF.new(@version, @encoding, @standalone)
       @rss.do_validate = @do_validate
       @rss.xml_stylesheets = @xml_stylesheets
       @last_element = @rss
-      @proc_stack.push Proc.new { |text, tags|
+      pr = Proc.new do |text, tags|
         @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate
-      }
+      end
+      @proc_stack.push(pr)
     end
   end
 
Index: ruby_1_8/lib/rss/maker.rb
===================================================================
--- ruby_1_8/lib/rss/maker.rb	(revision 13746)
+++ ruby_1_8/lib/rss/maker.rb	(revision 13747)
@@ -1,14 +1,14 @@
 require "rss/rss"
 
 module RSS
-
   module Maker
+    MAKERS = {}
 
-    MAKERS = {}
-    
     class << self
       def make(version, &block)
-        maker(version).make(&block)
+        m = maker(version)
+        raise UnsupportedMakerVersionError.new(version) if m.nil?
+        m.make(&block)
       end
 
       def maker(version)
@@ -19,19 +19,26 @@
         MAKERS[version] = maker
       end
 
-      def filename_to_version(filename)
-        File.basename(filename, ".*")
+      def versions
+        MAKERS.keys.uniq.sort
       end
+
+      def makers
+        MAKERS.values.uniq
+      end
     end
   end
-  
 end
 
 require "rss/maker/1.0"
 require "rss/maker/2.0"
+require "rss/maker/feed"
+require "rss/maker/entry"
 require "rss/maker/content"
 require "rss/maker/dublincore"
+require "rss/maker/slash"
 require "rss/maker/syndication"
 require "rss/maker/taxonomy"
 require "rss/maker/trackback"
 require "rss/maker/image"
+require "rss/maker/itunes"
Index: ruby_1_8/lib/rss/2.0.rb
===================================================================
--- ruby_1_8/lib/rss/2.0.rb	(revision 13746)
+++ ruby_1_8/lib/rss/2.0.rb	(revision 13747)
@@ -105,7 +105,7 @@
   end
 
   RSS09::ELEMENTS.each do |name|
-    BaseListener.install_get_text_element("", name, "#{name}=")
+    BaseListener.install_get_text_element("", name, name)
   end
 
 end
Index: ruby_1_8/lib/rss/prelude.rb
===================================================================
--- ruby_1_8/lib/rss/prelude.rb	(revision 0)
+++ ruby_1_8/lib/rss/prelude.rb	(revision 13747)
@@ -0,0 +1,25 @@
+
+# Mutex
+
+class Mutex
+  def synchronize
+    self.lock
+    begin
+      yield
+    ensure
+      self.unlock
+    end
+  end
+end
+
+# Thread
+
+class Thread
+  MUTEX_FOR_THREAD_EXCLUSIVE = Mutex.new
+  def self.exclusive
+    MUTEX_FOR_THREAD_EXCLUSIVE.synchronize{
+      yield
+    }
+  end
+end
+

Property changes on: ruby_1_8/lib/rss/prelude.rb
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + LF

Index: ruby_1_8/lib/rss/atom.rb
===================================================================
--- ruby_1_8/lib/rss/atom.rb	(revision 0)
+++ ruby_1_8/lib/rss/atom.rb	(revision 13747)
@@ -0,0 +1,749 @@
+require 'base64'
+require 'rss/parser'
+
+module RSS
+  module Atom
+    URI = "http://www.w3.org/2005/Atom"
+    XHTML_URI = "http://www.w3.org/1999/xhtml"
+
+    module CommonModel
+      NSPOOL = {}
+      ELEMENTS = []
+
+      def self.append_features(klass)
+        super
+        klass.install_must_call_validator("atom", URI)
+        [
+         ["lang", :xml],
+         ["base", :xml],
+        ].each do |name, uri, required|
+          klass.install_get_attribute(name, uri, required, [nil, :inherit])
+        end
+        klass.class_eval do
+          class << self
+            def required_uri
+              URI
+            end
+
+            def need_parent?
+              true
+            end
+          end
+        end
+      end
+    end
+
+    module ContentModel
+      module ClassMethods
+        def content_type
+          @content_type ||= nil
+        end
+      end
+
+      class << self
+        def append_features(klass)
+          super
+          klass.extend(ClassMethods)
+          klass.content_setup(klass.content_type, klass.tag_name)
+        end
+      end
+
+      def maker_target(target)
+        target
+      end
+
+      private
+      def setup_maker_element_writer
+        "#{self.class.name.split(/::/).last.downcase}="
+      end
+
+      def setup_maker_element(target)
+        target.__send__(setup_maker_element_writer, content)
+        super
+      end
+    end
+
+    module URIContentModel
+      class  << self
+        def append_features(klass)
+          super
+          klass.class_eval do
+            @content_type = [nil, :uri]
+            include(ContentModel)
+          end
+        end
+      end
+    end
+
+    module TextConstruct
+      def self.append_features(klass)
+        super
+        klass.class_eval do
+          [
+           ["type", ""],
+          ].each do |name, uri, required|
+            install_get_attribute(name, uri, required, :text_type)
+          end
+
+          content_setup
+          add_need_initialize_variable("xhtml")
+
+          class << self
+            def xml_getter
+              "xhtml"
+            end
+
+            def xml_setter
+              "xhtml="
+            end
+          end
+        end
+      end
+
+      attr_writer :xhtml
+      def xhtml
+        return @xhtml if @xhtml.nil?
+        if @xhtml.is_a?(XML::Element) and
+            [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI]
+          return @xhtml
+        end
+
+        children = @xhtml
+        children = [children] unless children.is_a?(Array)
+        XML::Element.new("div", nil, XHTML_URI,
+                         {"xmlns" => XHTML_URI}, children)
+      end
+
+      def have_xml_content?
+        @type == "xhtml"
+      end
+
+      def atom_validate(ignore_unknown_element, tags, uri)
+        if have_xml_content?
+          if @xhtml.nil?
+            raise MissingTagError.new("div", tag_name)
+          end
+          unless [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI]
+            raise NotExpectedTagError.new(@xhtml.name, @xhtml.uri, tag_name)
+          end
+        end
+      end
+
+      private
+      def maker_target(target)
+        target.__send__(self.class.name.split(/::/).last.downcase) {|x| x}
+      end
+
+      def setup_maker_attributes(target)
+        target.type = type
+        target.content = content
+        target.xml_content = @xhtml
+      end
+    end
+
+    module PersonConstruct
+      def self.append_features(klass)
+        super
+        klass.class_eval do
+          [
+           ["name", nil],
+           ["uri", "?"],
+           ["email", "?"],
+          ].each do |tag, occurs|
+            install_have_attribute_element(tag, URI, occurs, nil, :content)
+          end
+        end
+      end
+
+      def maker_target(target)
+        target.__send__("new_#{self.class.name.split(/::/).last.downcase}")
+      end
+
+      class Name < RSS::Element
+        include CommonModel
+        include ContentModel
+      end
+
+      class Uri < RSS::Element
+        include CommonModel
+        include URIContentModel
+      end
+
+      class Email < RSS::Element
+        include CommonModel
+        include ContentModel
+      end
+    end
+
+    module DateConstruct
+      def self.append_features(klass)
+        super
+        klass.class_eval do
+          @content_type = :w3cdtf
+          include(ContentModel)
+        end
+      end
+
+      def atom_validate(ignore_unknown_element, tags, uri)
+        raise NotAvailableValueError.new(tag_name, "") if content.nil?
+      end
+    end
+
+    module DuplicateLinkChecker
+      def validate_duplicate_links(links)
+        link_infos = {}
+        links.each do |link|
+          rel = link.rel || "alternate"
+          next unless rel == "alternate"
+          key = [link.hreflang, link.type]
+          if link_infos.has_key?(key)
+            raise TooMuchTagError.new("link", tag_name)
+          end
+          link_infos[key] = true
+        end
+      end
+    end
+
+    class Feed < RSS::Element
+      include RootElementMixin
+      include CommonModel
+      include DuplicateLinkChecker
+
+      install_ns('', URI)
+
+      [
+       ["author", "*", :children],
+       ["category", "*", :children, "categories"],
+       ["contributor", "*", :children],
+       ["generator", "?"],
+       ["icon", "?", nil, :content],
+       ["id", nil, nil, :content],
+       ["link", "*", :children],
+       ["logo", "?"],
+       ["rights", "?"],
+       ["subtitle", "?", nil, :content],
+       ["title", nil, nil, :content],
+       ["updated", nil, nil, :content],
+       ["entry", "*", :children, "entries"],
+      ].each do |tag, occurs, type, *args|
+        type ||= :child
+        __send__("install_have_#{type}_element",
+                 tag, URI, occurs, tag, *args)
+      end
+
+      def initialize(version=nil, encoding=nil, standalone=nil)
+        super("1.0", version, encoding, standalone)
+        @feed_type = "atom"
+        @feed_subtype = "feed"
+      end
+
+      alias_method :items, :entries
+
+      def have_author?
+        authors.any? {|author| !author.to_s.empty?} or
+          entries.any? {|entry| entry.have_author?(false)}
+      end
+
+      private
+      def atom_validate(ignore_unknown_element, tags, uri)
+        unless have_author?
+          raise MissingTagError.new("author", tag_name)
+        end
+        validate_duplicate_links(links)
+      end
+
+      def have_required_elements?
+        super and have_author?
+      end
+
+      def maker_target(maker)
+        maker.channel
+      end
+
+      def setup_maker_element(channel)
+        prev_dc_dates = channel.dc_dates.to_a.dup
+        super
+        channel.about = id.content if id
+        channel.dc_dates.replace(prev_dc_dates)
+      end
+
+      def setup_maker_elements(channel)
+        super
+        items = channel.maker.items
+        entries.each do |entry|
+          entry.setup_maker(items)
+        end
+      end
+
+      class Author < RSS::Element
+        include CommonModel
+        include PersonConstruct
+      end
+
+      class Category < RSS::Element
+        include CommonModel
+
+        [
+         ["term", "", true],
+         ["scheme", "", false, [nil, :uri]],
+         ["label", ""],
+        ].each do |name, uri, required, type|
+          install_get_attribute(name, uri, required, type)
+        end
+
+        private
+        def maker_target(target)
+          target.new_category
+        end
+      end
+
+      class Contributor < RSS::Element
+        include CommonModel
+        include PersonConstruct
+      end
+
+      class Generator < RSS::Element
+        include CommonModel
+        include ContentModel
+
+        [
+         ["uri", "", false, [nil, :uri]],
+         ["version", ""],
+        ].each do |name, uri, required, type|
+          install_get_attribute(name, uri, required, type)
+        end
+
+        private
+        def setup_maker_attributes(target)
+          target.generator do |generator|
+            generator.uri = uri if uri
+            generator.version = version if version
+          end
+        end
+      end
+
+      class Icon < RSS::Element
+        include CommonModel
+        include URIContentModel
+      end
+
+      class Id < RSS::Element
+        include CommonModel
+        include URIContentModel
+      end
+
+      class Link < RSS::Element
+        include CommonModel
+
+        [
+         ["href", "", true, [nil, :uri]],
+         ["rel", ""],
+         ["type", ""],
+         ["hreflang", ""],
+         ["title", ""],
+         ["length", ""],
+        ].each do |name, uri, required, type|
+          install_get_attribute(name, uri, required, type)
+        end
+
+        private
+        def maker_target(target)
+          target.new_link
+        end
+      end
+
+      class Logo < RSS::Element
+        include CommonModel
+        include URIContentModel
+
+        def maker_target(target)
+          target.maker.image
+        end
+
+        private
+        def setup_maker_element_writer
+          "url="
+        end
+      end
+
+      class Rights < RSS::Element
+        include CommonModel
+        include TextConstruct
+      end
+
+      class Subtitle < RSS::Element
+        include CommonModel
+        include TextConstruct
+      end
+
+      class Title < RSS::Element
+        include CommonModel
+        include TextConstruct
+      end
+
+      class Updated < RSS::Element
+        include CommonModel
+        include DateConstruct
+      end
+
+      class Entry < RSS::Element
+        include CommonModel
+        include DuplicateLinkChecker
+
+        [
+         ["author", "*", :children],
+         ["category", "*", :children, "categories"],
+         ["content", "?", :child],
+         ["contributor", "*", :children],
+         ["id", nil, nil, :content],
+         ["link", "*", :children],
+         ["published", "?", :child, :content],
+         ["rights", "?", :child],
+         ["source", "?"],
+         ["summary", "?", :child],
+         ["title", nil],
+         ["updated", nil, :child, :content],
+        ].each do |tag, occurs, type, *args|
+          type ||= :attribute
+          __send__("install_have_#{type}_element",
+                   tag, URI, occurs, tag, *args)
+        end
+
+        def have_author?(check_parent=true)
+          authors.any? {|author| !author.to_s.empty?} or
+            (check_parent and @parent and @parent.have_author?) or
+            (source and source.have_author?)
+        end
+
+        private
+        def atom_validate(ignore_unknown_element, tags, uri)
+          unless have_author?
+            raise MissingTagError.new("author", tag_name)
+          end
+          validate_duplicate_links(links)
+        end
+
+        def have_required_elements?
+          super and have_author?
+        end
+
+        def maker_target(items)
+          if items.respond_to?("items")
+            # For backward compatibility
+            items = items.items
+          end
+          items.new_item
+        end
+
+        Author = Feed::Author
+        Category = Feed::Category
+
+        class Content < RSS::Element
+          include CommonModel
+
+          class << self
+            def xml_setter
+              "xml="
+            end
+
+            def xml_getter
+              "xml"
+            end
+          end
+
+          [
+           ["type", ""],
+           ["src", "", false, [nil, :uri]],
+          ].each do |name, uri, required, type|
+            install_get_attribute(name, uri, required, type)
+          end
+
+          content_setup
+          add_need_initialize_variable("xml")
+
+          attr_writer :xml
+          def have_xml_content?
+            inline_xhtml? or inline_other_xml?
+          end
+
+          def xml
+            return @xml unless inline_xhtml?
+            return @xml if @xml.nil?
+            if @xml.is_a?(XML::Element) and
+                [@xml.name, @xml.uri] == ["div", XHTML_URI]
+              return @xml
+            end
+
+            children = @xml
+            children = [children] unless children.is_a?(Array)
+            XML::Element.new("div", nil, XHTML_URI,
+                             {"xmlns" => XHTML_URI}, children)
+          end
+
+          def xhtml
+            if inline_xhtml?
+              xml
+            else
+              nil
+            end
+          end
+
+          def atom_validate(ignore_unknown_element, tags, uri)
+            if out_of_line?
+              raise MissingAttributeError.new(tag_name, "type") if @type.nil?
+              unless (content.nil? or content.empty?)
+                raise NotAvailableValueError.new(tag_name, content)
+              end
+            elsif inline_xhtml?
+              if @xml.nil?
+                raise MissingTagError.new("div", tag_name)
+              end
+              unless @xml.name == "div" and @xml.uri == XHTML_URI
+                raise NotExpectedTagError.new(@xml.name, @xml.uri, tag_name)
+              end
+            end
+          end
+
+          def inline_text?
+            !out_of_line? and [nil, "text", "html"].include?(@type)
+          end
+
+          def inline_html?
+            return false if out_of_line?
+            @type == "html" or mime_split == ["text", "html"]
+          end
+
+          def inline_xhtml?
+            !out_of_line? and @type == "xhtml"
+          end
+
+          def inline_other?
+            return false if out_of_line?
+            media_type, subtype = mime_split
+            return false if media_type.nil? or subtype.nil?
+            true
+          end
+
+          def inline_other_text?
+            return false unless inline_other?
+            return false if inline_other_xml?
+
+            media_type, subtype = mime_split
+            return true if "text" == media_type.downcase
+            false
+          end
+
+          def inline_other_xml?
+            return false unless inline_other?
+
+            media_type, subtype = mime_split
+            normalized_mime_type = "#{media_type}/#{subtype}".downcase
+            if /(?:\+xml|^xml)$/ =~ subtype or
+                %w(text/xml-external-parsed-entity
+                   application/xml-external-parsed-entity
+                   application/xml-dtd).find {|x| x == normalized_mime_type}
+              return true
+            end
+            false
+          end
+
+          def inline_other_base64?
+            inline_other? and !inline_other_text? and !inline_other_xml?
+          end
+
+          def out_of_line?
+            not @src.nil?
+          end
+
+          def mime_split
+            media_type = subtype = nil
+            if /\A\s*([a-z]+)\/([a-z\+]+)\s*(?:;.*)?\z/i =~ @type.to_s
+              media_type = $1.downcase
+              subtype = $2.downcase
+            end
+            [media_type, subtype]
+          end
+
+          def need_base64_encode?
+            inline_other_base64?
+          end
+
+          private
+          def empty_content?
+            out_of_line? or super
+          end
+        end
+
+        Contributor = Feed::Contributor
+        Id = Feed::Id
+        Link = Feed::Link
+
+        class Published < RSS::Element
+          include CommonModel
+          include DateConstruct
+        end
+
+        Rights = Feed::Rights
+
+        class Source < RSS::Element
+          include CommonModel
+
+          [
+           ["author", "*", :children],
+           ["category", "*", :children, "categories"],
+           ["contributor", "*", :children],
+           ["generator", "?"],
+           ["icon", "?"],
+           ["id", "?", nil, :content],
+           ["link", "*", :children],
+           ["logo", "?"],
+           ["rights", "?"],
+           ["subtitle", "?"],
+           ["title", "?"],
+           ["updated", "?", nil, :content],
+          ].each do |tag, occurs, type, *args|
+            type ||= :attribute
+            __send__("install_have_#{type}_element",
+                     tag, URI, occurs, tag, *args)
+          end
+
+          def have_author?
+            !author.to_s.empty?
+          end
+
+          Author = Feed::Author
+          Category = Feed::Category
+          Contributor = Feed::Contributor
+          Generator = Feed::Generator
+          Icon = Feed::Icon
+          Id = Feed::Id
+          Link = Feed::Link
+          Logo = Feed::Logo
+          Rights = Feed::Rights
+          Subtitle = Feed::Subtitle
+          Title = Feed::Title
+          Updated = Feed::Updated
+        end
+
+        class Summary < RSS::Element
+          include CommonModel
+          include TextConstruct
+        end
+
+        Title = Feed::Title
+        Updated = Feed::Updated
+      end
+    end
+
+    class Entry < RSS::Element
+      include RootElementMixin
+      include CommonModel
+      include DuplicateLinkChecker
+
+      [
+       ["author", "*", :children],
+       ["category", "*", :children, "categories"],
+       ["content", "?"],
+       ["contributor", "*", :children],
+       ["id", nil, nil, :content],
+       ["link", "*", :children],
+       ["published", "?", :child, :content],
+       ["rights", "?"],
+       ["source", "?"],
+       ["summary", "?"],
+       ["title", nil],
+       ["updated", nil, nil, :content],
+      ].each do |tag, occurs, type, *args|
+        type ||= :attribute
+        __send__("install_have_#{type}_element",
+                 tag, URI, occurs, tag, *args)
+      end
+
+      def initialize(version=nil, encoding=nil, standalone=nil)
+        super("1.0", version, encoding, standalone)
+        @feed_type = "atom"
+        @feed_subtype = "entry"
+      end
+
+      def items
+        [self]
+      end
+
+      def setup_maker(maker)
+        maker = maker.maker if maker.respond_to?("maker")
+        super(maker)
+      end
+
+      def have_author?
+        authors.any? {|author| !author.to_s.empty?} or
+          (source and source.have_author?)
+      end
+
+      private
+      def atom_validate(ignore_unknown_element, tags, uri)
+        unless have_author?
+          raise MissingTagError.new("author", tag_name)
+        end
+        validate_duplicate_links(links)
+      end
+
+      def have_required_elements?
+        super and have_author?
+      end
+
+      def maker_target(maker)
+        maker.items.new_item
+      end
+
+      Author = Feed::Entry::Author
+      Category = Feed::Entry::Category
+      Content = Feed::Entry::Content
+      Contributor = Feed::Entry::Contributor
+      Id = Feed::Entry::Id
+      Link = Feed::Entry::Link
+      Published = Feed::Entry::Published
+      Rights = Feed::Entry::Rights
+      Source = Feed::Entry::Source
+      Summary = Feed::Entry::Summary
+      Title = Feed::Entry::Title
+      Updated = Feed::Entry::Updated
+    end
+  end
+
+  Atom::CommonModel::ELEMENTS.each do |name|
+    BaseListener.install_get_text_element(Atom::URI, name, "#{name}=")
+  end
+
+  module ListenerMixin
+    private
+    def initial_start_feed(tag_name, prefix, attrs, ns)
+      check_ns(tag_name, prefix, ns, Atom::URI)
+
+      @rss = Atom::Feed.new(@version, @encoding, @standalone)
+      @rss.do_validate = @do_validate
+      @rss.xml_stylesheets = @xml_stylesheets
+      @rss.lang = attrs["xml:lang"]
+      @rss.base = attrs["xml:base"]
+      @last_element = @rss
+      pr = Proc.new do |text, tags|
+        @rss.validate_for_stream(tags) if @do_validate
+      end
+      @proc_stack.push(pr)
+    end
+
+    def initial_start_entry(tag_name, prefix, attrs, ns)
+      check_ns(tag_name, prefix, ns, Atom::URI)
+
+      @rss = Atom::Entry.new(@version, @encoding, @standalone)
+      @rss.do_validate = @do_validate
+      @rss.xml_stylesheets = @xml_stylesheets
+      @rss.lang = attrs["xml:lang"]
+      @rss.base = attrs["xml:base"]
+      @last_element = @rss
+      pr = Proc.new do |text, tags|
+        @rss.validate_for_stream(tags) if @do_validate
+      end
+      @proc_stack.push(pr)
+    end
+  end
+end
Index: ruby_1_8/lib/rss/utils.rb
===================================================================
--- ruby_1_8/lib/rss/utils.rb	(revision 13746)
+++ ruby_1_8/lib/rss/utils.rb	(revision 13747)
@@ -4,14 +4,16 @@
 
     # Convert a name_with_underscores to CamelCase.
     def to_class_name(name)
-      name.split(/_/).collect do |part|
+      name.split(/[_\-]/).collect do |part|
         "#{part[0, 1].upcase}#{part[1..-1]}"
       end.join("")
     end
     
     def get_file_and_line_from_caller(i=0)
       file, line, = caller[i].split(':')
-      [file, line.to_i]
+      line = line.to_i
+      line += 1 if i.zero?
+      [file, line]
     end
 
     # escape '&', '"', '<' and '>' for use in HTML.
@@ -33,5 +35,77 @@
     def element_initialize_arguments?(args)
       [true, false].include?(args[0]) and args[1].is_a?(Hash)
     end
+
+    module YesCleanOther
+      module_function
+      def parse(value)
+        if [true, false, nil].include?(value)
+          value
+        else
+          case value.to_s
+          when /\Ayes\z/i
+            true
+          when /\Aclean\z/i
+            false
+          else
+            nil
+          end
+        end
+      end
+    end
+
+    module YesOther
+      module_function
+      def parse(value)
+        if [true, false].include?(value)
+          value
+        else
+          /\Ayes\z/i.match(value.to_s) ? true : false
+        end
+      end
+    end
+
+    module CSV
+      module_function
+      def parse(value, &block)
+        if value.is_a?(String)
+          value = value.strip.split(/\s*,\s*/)
+          value = value.collect(&block) if block_given?
+          value
+        else
+          value
+        end
+      end
+    end
+
+    module InheritedReader
+      def inherited_reader(constant_name)
+        base_class = inherited_base
+        result = base_class.const_get(constant_name)
+        found_base_class = false
+        ancestors.reverse_each do |klass|
+          if found_base_class
+            if klass.const_defined?(constant_name)
+              result = yield(result, klass.const_get(constant_name))
+            end
+          else
+            found_base_class = klass == base_class
+          end
+        end
+        result
+      end
+
+      def inherited_array_reader(constant_name)
+        inherited_reader(constant_name) do |result, current|
+          current + result
+        end
+      end
+
+      def inherited_hash_reader(constant_name)
+        inherited_reader(constant_name) do |result, current|
+          result.merge(current)
+        end
+      end
+    end
   end
 end
Index: ruby_1_8/lib/rss/xml.rb
===================================================================
--- ruby_1_8/lib/rss/xml.rb	(revision 0)
+++ ruby_1_8/lib/rss/xml.rb	(revision 13747)
@@ -0,0 +1,71 @@
+require "rss/utils"
+
+module RSS
+  module XML
+    class Element
+      include Enumerable
+
+      attr_reader :name, :prefix, :uri, :attributes, :children
+      def initialize(name, prefix=nil, uri=nil, attributes={}, children=[])
+        @name = name
+        @prefix = prefix
+        @uri = uri
+        @attributes = attributes
+        if children.is_a?(String) or !children.respond_to?(:each)
+          @children = [children]
+        else
+          @children = children
+        end
+      end
+
+      def [](name)
+        @attributes[name]
+      end
+
+      def []=(name, value)
+        @attributes[name] = value
+      end
+
+      def <<(child)
+        @children << child
+      end
+
+      def each(&block)
+        @children.each(&block)
+      end
+
+      def ==(other)
+        other.kind_of?(self.class) and
+          @name == other.name and
+          @uri == other.uri and
+          @attributes == other.attributes and
+          @children == other.children
+      end
+
+      def to_s
+        rv = "<#{full_name}"
+        attributes.each do |key, value|
+          rv << " #{Utils.html_escape(key)}=\"#{Utils.html_escape(value)}\""
+        end
+        if children.empty?
+          rv << "/>"
+        else
+          rv << ">"
+          children.each do |child|
+            rv << child.to_s
+          end
+          rv << "</#{full_name}>"
+        end
+        rv
+      end
+
+      def full_name
+        if @prefix
+          "#{@prefix}:#{@name}"
+        else
+          @name
+        end
+      end
+    end
+  end
+end
Index: ruby_1_8/lib/rss/0.9.rb
===================================================================
--- ruby_1_8/lib/rss/0.9.rb	(revision 13746)
+++ ruby_1_8/lib/rss/0.9.rb	(revision 13747)
@@ -22,10 +22,13 @@
       install_have_child_element(name, "", nil)
     end
 
-    attr_accessor :rss_version, :version, :encoding, :standalone
-    
-    def initialize(rss_version, version=nil, encoding=nil, standalone=nil)
+    attr_writer :feed_version
+    alias_method(:rss_version, :feed_version)
+    alias_method(:rss_version=, :feed_version=)
+
+    def initialize(feed_version, version=nil, encoding=nil, standalone=nil)
       super
+      @feed_type = "rss"
     end
 
     def items
@@ -57,12 +60,14 @@
       items.each do |item|
         item.setup_maker(maker.items)
       end
+      image.setup_maker(maker) if image
+      textinput.setup_maker(maker) if textinput
     end
 
     private
     def _attrs
       [
-        ["version", true, "rss_version"],
+        ["version", true, "feed_version"],
       ]
     end
 
@@ -400,21 +405,22 @@
   end
 
   RSS09::ELEMENTS.each do |name|
-    BaseListener.install_get_text_element("", name, "#{name}=")
+    BaseListener.install_get_text_element("", name, name)
   end
 
   module ListenerMixin
     private
-    def start_rss(tag_name, prefix, attrs, ns)
+    def initial_start_rss(tag_name, prefix, attrs, ns)
       check_ns(tag_name, prefix, ns, "")
       
       @rss = Rss.new(attrs['version'], @version, @encoding, @standalone)
       @rss.do_validate = @do_validate
       @rss.xml_stylesheets = @xml_stylesheets
       @last_element = @rss
-      @proc_stack.push Proc.new { |text, tags|
+      pr = Proc.new do |text, tags|
         @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate
-      }
+      end
+      @proc_stack.push(pr)
     end
     
   end
Index: ruby_1_8/lib/rss/itunes.rb
===================================================================
--- ruby_1_8/lib/rss/itunes.rb	(revision 0)
+++ ruby_1_8/lib/rss/itunes.rb	(revision 13747)
@@ -0,0 +1,410 @@
+require 'rss/2.0'
+
+module RSS
+  ITUNES_PREFIX = 'itunes'
+  ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
+
+  Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
+
+  module ITunesModelUtils
+    include Utils
+
+    def def_class_accessor(klass, name, type, *args)
+        normalized_name = name.gsub(/-/, "_")
+      full_name = "#{ITUNES_PREFIX}_#{normalized_name}"
+      klass_name = "ITunes#{Utils.to_class_name(normalized_name)}"
+
+      case type
+      when :element, :attribute
+        klass::ELEMENTS << full_name
+        def_element_class_accessor(klass, name, full_name, klass_name, *args)
+      when :elements
+        klass::ELEMENTS << full_name
+        def_elements_class_accessor(klass, name, full_name, klass_name, *args)
+      else
+        klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
+        klass.install_text_element(normalized_name, ITUNES_URI, "?",
+                                   full_name, type, name)
+      end
+    end
+
+    def def_element_class_accessor(klass, name, full_name, klass_name,
+                                   recommended_attribute_name=nil)
+      klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name)
+    end
+
+    def def_elements_class_accessor(klass, name, full_name, klass_name,
+                                    plural_name, recommended_attribute_name=nil)
+      full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}"
+      klass.install_have_children_element(name, ITUNES_PREFIX, "*",
+                                          full_name, full_plural_name)
+    end
+  end
+
+  module ITunesBaseModel
+    extend ITunesModelUtils
+
+    ELEMENTS = []
+
+    ELEMENT_INFOS = [["author"],
+                     ["block", :yes_other],
+                     ["explicit", :yes_clean_other],
+                     ["keywords", :csv],
+                     ["subtitle"],
+                     ["summary"]]
+  end
+
+  module ITunesChannelModel
+    extend BaseModel
+    extend ITunesModelUtils
+    include ITunesBaseModel
+
+    ELEMENTS = []
+
+    class << self
+      def append_features(klass)
+        super
+
+        return if klass.instance_of?(Module)
+        ELEMENT_INFOS.each do |name, type, *additional_infos|
+          def_class_accessor(klass, name, type, *additional_infos)
+        end
+      end
+    end
+
+    ELEMENT_INFOS = [
+                     ["category", :elements, "categories", "text"],
+                     ["image", :attribute, "href"],
+                     ["owner", :element],
+                     ["new-feed-url"],
+                    ] + ITunesBaseModel::ELEMENT_INFOS
+
+    class ITunesCategory < Element
+      include RSS09
+
+      @tag_name = "category"
+
+      class << self
+        def required_prefix
+          ITUNES_PREFIX
+        end
+
+        def required_uri
+          ITUNES_URI
+        end
+      end
+
+      [
+        ["text", "", true]
+      ].each do |name, uri, required|
+        install_get_attribute(name, uri, required)
+      end
+
+      ITunesCategory = self
+      install_have_children_element("category", ITUNES_URI, "*",
+                                    "#{ITUNES_PREFIX}_category",
+                                    "#{ITUNES_PREFIX}_categories")
+
+      def initialize(*args)
+        if Utils.element_initialize_arguments?(args)
+          super
+        else
+          super()
+          self.text = args[0]
+        end
+      end
+
+      def full_name
+        tag_name_with_prefix(ITUNES_PREFIX)
+      end
+
+      private
+      def maker_target(categories)
+        if text or !itunes_categories.empty?
+          categories.new_category
+        else
+          nil
+        end
+      end
+
+      def setup_maker_attributes(category)
+        category.text = text if text
+      end
+
+      def setup_maker_elements(category)
+        super(category)
+        itunes_categories.each do |sub_category|
+          sub_category.setup_maker(category)
+        end
+      end
+    end
+
+    class ITunesImage < Element
+      include RSS09
+
+      @tag_name = "image"
+
+      class << self
+        def required_prefix
+          ITUNES_PREFIX
+        end
+
+        def required_uri
+          ITUNES_URI
+        end
+      end
+
+      [
+        ["href", "", true]
+      ].each do |name, uri, required|
+        install_get_attribute(name, uri, required)
+      end
+
+      def initialize(*args)
+        if Utils.element_initialize_arguments?(args)
+          super
+        else
+          super()
+          self.href = args[0]
+        end
+      end
+
+      def full_name
+        tag_name_with_prefix(ITUNES_PREFIX)
+      end
+
+      private
+      def maker_target(target)
+        if href
+          target.itunes_image {|image| image}
+        else
+          nil
+        end
+      end
+
+      def setup_maker_attributes(image)
+        image.href = href
+      end
+    end
+
+    class ITunesOwner < Element
+      include RSS09
+
+      @tag_name = "owner"
+
+      class << self
+        def required_prefix
+          ITUNES_PREFIX
+        end
+
+        def required_uri
+          ITUNES_URI
+        end
+      end
+
+      install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
+      [
+        ["name"],
+        ["email"],
+      ].each do |name,|
+        ITunesBaseModel::ELEMENT_INFOS << name
+        install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}")
+      end
+
+      def initialize(*args)
+        if Utils.element_initialize_arguments?(args)
+          super
+        else
+          super()
+          self.itunes_name = args[0]
+          self.itunes_email = args[1]
+        end
+      end
+
+      def full_name
+        tag_name_with_prefix(ITUNES_PREFIX)
+      end
+
+      private
+      def maker_target(target)
+        target.itunes_owner
+      end
+
+      def setup_maker_element(owner)
+        super(owner)
+        owner.itunes_name = itunes_name
+        owner.itunes_email = itunes_email
+      end
+    end
+  end
+
+  module ITunesItemModel
+    extend BaseModel
+    extend ITunesModelUtils
+    include ITunesBaseModel
+
+    class << self
+      def append_features(klass)
+        super
+
+        return if klass.instance_of?(Module)
+        ELEMENT_INFOS.each do |name, type|
+          def_class_accessor(klass, name, type)
+        end
+      end
+    end
+
+    ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS +
+      [["duration", :element, "content"]]
+
+    class ITunesDuration < Element
+      include RSS09
+
+      @tag_name = "duration"
+
+      class << self
+        def required_prefix
+          ITUNES_PREFIX
+        end
+
+        def required_uri
+          ITUNES_URI
+        end
+
+        def parse(duration, do_validate=true)
+          if do_validate and /\A(?:
+                                  \d?\d:[0-5]\d:[0-5]\d|
+                                  [0-5]?\d:[0-5]\d
+                                )\z/x !~ duration
+            raise ArgumentError,
+                    "must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " +
+                    duration.inspect
+          end
+
+          components = duration.split(':')
+          components[3..-1] = nil if components.size > 3
+
+          components.unshift("00") until components.size == 3
+
+          components.collect do |component|
+            component.to_i
+          end
+        end
+
+        def construct(hour, minute, second)
+          components = [minute, second]
+          if components.include?(nil)
+            nil
+          else
+            components.unshift(hour) if hour and hour > 0
+            components.collect do |component|
+              "%02d" % component
+            end.join(":")
+          end
+        end
+      end
+
+      content_setup
+      alias_method(:value, :content)
+      remove_method(:content=)
+
+      attr_reader :hour, :minute, :second
+      def initialize(*args)
+        if Utils.element_initialize_arguments?(args)
+          super
+        else
+          super()
+          args = args[0] if args.size == 1 and args[0].is_a?(Array)
+          if args.size == 1
+            self.content = args[0]
+          elsif args.size > 3
+            raise ArgumentError,
+                    "must be (do_validate, params), (content), " +
+                    "(minute, second), ([minute, second]), "  +
+                    "(hour, minute, second) or ([hour, minute, second]): " +
+                    args.inspect
+          else
+            @second, @minute, @hour = args.reverse
+            update_content
+          end
+        end
+      end
+
+      def content=(value)
+        if value.nil?
+          @content = nil
+        elsif value.is_a?(self.class)
+          self.content = value.content
+        else
+          begin
+            @hour, @minute, @second = self.class.parse(value, @do_validate)
+          rescue ArgumentError
+            raise NotAvailableValueError.new(tag_name, value)
+          end
+          @content = value
+        end
+      end
+      alias_method(:value=, :content=)
+
+      def hour=(hour)
+        @hour = @do_validate ? Integer(hour) : hour.to_i
+        update_content
+        hour
+      end
+
+      def minute=(minute)
+        @minute = @do_validate ? Integer(minute) : minute.to_i
+        update_content
+        minute
+      end
+
+      def second=(second)
+        @second = @do_validate ? Integer(second) : second.to_i
+        update_content
+        second
+      end
+
+      def full_name
+        tag_name_with_prefix(ITUNES_PREFIX)
+      end
+
+      private
+      def update_content
+        @content = self.class.construct(hour, minute, second)
+      end
+
+      def maker_target(target)
+        if @content
+          target.itunes_duration {|duration| duration}
+        else
+          nil
+        end
+      end
+
+      def setup_maker_element(duration)
+        super(duration)
+        duration.content = @content
+      end
+    end
+  end
+
+  class Rss
+    class Channel
+      include ITunesChannelModel
+      class Item; include ITunesItemModel; end
+    end
+  end
+
+  element_infos =
+    ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS
+  element_infos.each do |name, type|
+    case type
+    when :element, :elements, :attribute
+      class_name = Utils.to_class_name(name)
+      BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}")
+    else
+      accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}"
+      BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base)
+    end
+  end
+end
Index: ruby_1_8/lib/rss/converter.rb
===================================================================
--- ruby_1_8/lib/rss/converter.rb	(revision 13746)
+++ ruby_1_8/lib/rss/converter.rb	(revision 13747)
@@ -80,8 +80,12 @@
         end
       rescue LoadError
         require 'nkf'
-        def_convert(1) do |value|
-          "NKF.nkf(#{nkf_arg.dump}, #{value})"
+        if NKF.const_defined?(:UTF8)
+          def_convert(1) do |value|
+            "NKF.nkf(#{nkf_arg.dump}, #{value})"
+          end
+        else
+          def_iconv_convert(to_enc, from_enc, 1)
         end
       end
     end
Index: ruby_1_8/lib/rss/rss.rb
===================================================================
--- ruby_1_8/lib/rss/rss.rb	(revision 13746)
+++ ruby_1_8/lib/rss/rss.rb	(revision 13747)
@@ -11,11 +11,19 @@
             (\.\d+)?
             (Z|[+-]\d\d:\d\d)?)?
             \s*\z/ix =~ date and (($5 and $8) or (!$5 and !$8))
-          datetime = [$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i] 
-          datetime << $7.to_f * 1000000 if $7
-          if $8
-            Time.utc(*datetime) - zone_offset($8)
+          datetime = [$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i]
+          usec = 0
+          usec = $7.to_f * 1000000 if $7
+          zone = $8
+          if zone
+            off = zone_offset(zone, datetime[0])
+            datetime = apply_offset(*(datetime + [off]))
+            datetime << usec
+            time = Time.utc(*datetime)
+            time.localtime unless zone_utc?(zone)
+            time
           else
+            datetime << usec
             Time.local(*datetime)
           end
         else
@@ -25,8 +33,15 @@
     end
   end
 
-  unless instance_methods.include?("w3cdtf")
-    alias w3cdtf iso8601
+  unless method_defined?(:w3cdtf)
+    def w3cdtf
+      if usec.zero?
+        fraction_digits = 0
+      else
+        fraction_digits = Math.log10(usec.to_s.sub(/0*$/, '').to_i).floor + 1
+      end
+      xmlschema(fraction_digits)
+    end
   end
 end
 
@@ -37,7 +52,7 @@
 
 module RSS
 
-  VERSION = "0.1.6"
+  VERSION = "0.2.0"
 
   URI = "http://purl.org/rss/1.0/"
 
@@ -136,17 +151,26 @@
       super("required variables of #{@name} are not set: #{@variables.join(', ')}")
     end
   end
-  
+
+  class UnsupportedMakerVersionError < Error
+    attr_reader :version
+    def initialize(version)
+      @version = version
+      super("Maker doesn't support version: #{@version}")
+    end
+  end
+
   module BaseModel
-
     include Utils
 
-    def install_have_child_element(tag_name, uri, occurs, name=nil)
+    def install_have_child_element(tag_name, uri, occurs, name=nil, type=nil)
       name ||= tag_name
       add_need_initialize_variable(name)
       install_model(tag_name, uri, occurs, name)
 
-      attr_accessor name
+      writer_type, reader_type = type
+      def_corresponded_attr_writer name, writer_type
+      def_corresponded_attr_reader name, reader_type
       install_element(name) do |n, elem_name|
         <<-EOC
         if @#{n}
@@ -164,7 +188,7 @@
       plural_name ||= "#{name}s"
       add_have_children_element(name, plural_name)
       add_plural_form(name, plural_name)
-      install_model(tag_name, uri, occurs, plural_name)
+      install_model(tag_name, uri, occurs, plural_name, true)
 
       def_children_accessor(name, plural_name)
       install_element(name, "s") do |n, elem_name|
@@ -179,20 +203,26 @@
       end
     end
 
-    def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
+    def install_text_element(tag_name, uri, occurs, name=nil, type=nil,
+                             disp_name=nil)
       name ||= tag_name
       disp_name ||= name
       self::ELEMENTS << name
       add_need_initialize_variable(name)
       install_model(tag_name, uri, occurs, name)
 
-      def_corresponded_attr_writer name, type, disp_name
-      convert_attr_reader name
+      def_corresponded_attr_writer(name, type, disp_name)
+      def_corresponded_attr_reader(name, type || :convert)
       install_element(name) do |n, elem_name|
         <<-EOC
-        if @#{n}
+        if respond_to?(:#{n}_content)
+          content = #{n}_content
+        else
+          content = @#{n}
+        end
+        if content
           rv = "\#{indent}<#{elem_name}>"
-          value = html_escape(@#{n})
+          value = html_escape(content)
           if need_convert
             rv << convert(value)
           else
@@ -252,26 +282,112 @@
 EOC
     end
 
-    def convert_attr_reader(*attrs)
+    def inherit_convert_attr_reader(*attrs)
       attrs.each do |attr|
         attr = attr.id2name if attr.kind_of?(Integer)
         module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+        def #{attr}_without_inherit
+          convert(@#{attr})
+        end
+
         def #{attr}
-          if @converter
-            @converter.convert(@#{attr})
+          if @#{attr}
+            #{attr}_without_inherit
+          elsif @parent
+            @parent.#{attr}
           else
-            @#{attr}
+            nil
           end
         end
 EOC
       end
     end
 
+    def uri_convert_attr_reader(*attrs)
+      attrs.each do |attr|
+        attr = attr.id2name if attr.kind_of?(Integer)
+        module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+        def #{attr}_without_base
+          convert(@#{attr})
+        end
+
+        def #{attr}
+          value = #{attr}_without_base
+          return nil if value.nil?
+          if /\\A[a-z][a-z0-9+.\\-]*:/i =~ value
+            value
+          else
+            "\#{base}\#{value}"
+          end
+        end
+EOC
+      end
+    end
+
+    def convert_attr_reader(*attrs)
+      attrs.each do |attr|
+        attr = attr.id2name if attr.kind_of?(Integer)
+        module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+        def #{attr}
+          convert(@#{attr})
+        end
+EOC
+      end
+    end
+
+    def yes_clean_other_attr_reader(*attrs)
+      attrs.each do |attr|
+        attr = attr.id2name if attr.kind_of?(Integer)
+        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          attr_reader(:#{attr})
+          def #{attr}?
+            YesCleanOther.parse(@#{attr})
+          end
+        EOC
+      end
+    end
+
+    def yes_other_attr_reader(*attrs)
+      attrs.each do |attr|
+        attr = attr.id2name if attr.kind_of?(Integer)
+        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          attr_reader(:#{attr})
+          def #{attr}?
+            Utils::YesOther.parse(@#{attr})
+          end
+        EOC
+      end
+    end
+
+    def csv_attr_reader(*attrs)
+      separator = nil
+      if attrs.last.is_a?(Hash)
+        options = attrs.pop
+        separator = options[:separator]
+      end
+      separator ||= ", "
+      attrs.each do |attr|
+        attr = attr.id2name if attr.kind_of?(Integer)
+        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+          attr_reader(:#{attr})
+          def #{attr}_content
+            if @#{attr}.nil?
+              @#{attr}
+            else
+              @#{attr}.join(#{separator.dump})
+            end
+          end
+        EOC
+      end
+    end
+
     def date_writer(name, type, disp_name=name)
       module_eval(<<-EOC, *get_file_and_line_from_caller(2))
       def #{name}=(new_value)
-        if new_value.nil? or new_value.kind_of?(Time)
+        if new_value.nil?
           @#{name} = new_value
+        elsif new_value.kind_of?(Time)
+          @#{name} = new_value.dup
         else
           if @do_validate
             begin
@@ -283,7 +399,9 @@
             @#{name} = nil
             if /\\A\\s*\\z/ !~ new_value.to_s
               begin
-                @#{name} = Time.parse(new_value)
+                unless Date._parse(new_value, false).empty?
+                  @#{name} = Time.parse(new_value)
+                end
               rescue ArgumentError
               end
             end
@@ -364,6 +482,68 @@
 EOC
     end
 
+    def text_type_writer(name, disp_name=name)
+      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+      def #{name}=(new_value)
+        if @do_validate and
+            !["text", "html", "xhtml", nil].include?(new_value)
+          raise NotAvailableValueError.new('#{disp_name}', new_value)
+        end
+        @#{name} = new_value
+      end
+EOC
+    end
+
+    def content_writer(name, disp_name=name)
+      klass_name = "self.class::#{Utils.to_class_name(name)}"
+      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
+      def #{name}=(new_value)
+        if new_value.is_a?(#{klass_name})
+          @#{name} = new_value
+        else
+          @#{name} = #{klass_name}.new
+          @#{name}.content = new_value
+        end
+      end
+EOC
+    end
+
+    def yes_clean_other_writer(name, disp_name=name)
+      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        def #{name}=(value)
+          value = (value ? "yes" : "no") if [true, false].include?(value)
+          @#{name} = value
+        end
+      EOC
+    end
+
+    def yes_other_writer(name, disp_name=name)
+      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        def #{name}=(new_value)
+          if [true, false].include?(new_value)
+            new_value = new_value ? "yes" : "no"
+          end
+          @#{name} = new_value
+        end
+      EOC
+    end
+
+    def csv_writer(name, disp_name=name)
+      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        def #{name}=(new_value)
+          @#{name} = Utils::CSV.parse(new_value)
+        end
+      EOC
+    end
+
+    def csv_integer_writer(name, disp_name=name)
+      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+        def #{name}=(new_value)
+          @#{name} = Utils::CSV.parse(new_value) {|v| Integer(v)}
+        end
+      EOC
+    end
+
     def def_children_accessor(accessor_name, plural_name)
       module_eval(<<-EOC, *get_file_and_line_from_caller(2))
       def #{plural_name}
@@ -379,10 +559,12 @@
       end
 
       def #{accessor_name}=(*args)
+        receiver = self.class.name
         warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \
-             "Don't use `#{accessor_name} = XXX'/`set_#{accessor_name}(XXX)'. " \
+             "Don't use `\#{receiver}\##{accessor_name} = XXX'/" \
+             "`\#{receiver}\#set_#{accessor_name}(XXX)'. " \
              "Those APIs are not sense of Ruby. " \
-             "Use `#{plural_name} << XXX' instead of them.")
+             "Use `\#{receiver}\##{plural_name} << XXX' instead of them.")
         if args.size == 1
           @#{accessor_name}.push(args[0])
         else
@@ -394,10 +576,61 @@
     end
   end
 
+  module SetupMaker
+    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 maker_target(maker)
+      nil
+    end
+
+    def setup_maker_attributes(target)
+    end
+
+    def setup_maker_element(target)
+      self.class.need_initialize_variables.each do |var|
+        value = __send__(var)
+        next if value.nil?
+        if value.respond_to?("setup_maker") and
+            !not_need_to_call_setup_maker_variables.include?(var)
+          value.setup_maker(target)
+        else
+          setter = "#{var}="
+          if target.respond_to?(setter)
+            target.__send__(setter, value)
+          end
+        end
+      end
+    end
+
+    def not_need_to_call_setup_maker_variables
+      []
+    end
+
+    def setup_maker_elements(parent)
+      self.class.have_children_elements.each do |name, plural_name|
+        if parent.respond_to?(plural_name)
+          target = parent.__send__(plural_name)
+          __send__(plural_name).each do |elem|
+            elem.setup_maker(target)
+          end
+        end
+      end
+    end
+  end
+
   class Element
-
     extend BaseModel
     include Utils
+    extend Utils::InheritedReader
+    include SetupMaker
 
     INDENT = "  "
     
@@ -408,32 +641,34 @@
     TO_ELEMENT_METHODS = []
     NEED_INITIALIZE_VARIABLES = []
     PLURAL_FORMS = {}
-    
+
     class << self
-
       def must_call_validators
-        MUST_CALL_VALIDATORS
+        inherited_hash_reader("MUST_CALL_VALIDATORS")
       end
       def models
-        MODELS
+        inherited_array_reader("MODELS")
       end
       def get_attributes
-        GET_ATTRIBUTES
+        inherited_array_reader("GET_ATTRIBUTES")
       end
       def have_children_elements
-        HAVE_CHILDREN_ELEMENTS
+        inherited_array_reader("HAVE_CHILDREN_ELEMENTS")
       end
       def to_element_methods
-        TO_ELEMENT_METHODS
+        inherited_array_reader("TO_ELEMENT_METHODS")
       end
       def need_initialize_variables
-        NEED_INITIALIZE_VARIABLES
+        inherited_array_reader("NEED_INITIALIZE_VARIABLES")
       end
       def plural_forms
-        PLURAL_FORMS
+        inherited_hash_reader("PLURAL_FORMS")
       end
 
-      
+      def inherited_base
+        ::RSS::Element
+      end
+
       def inherited(klass)
         klass.const_set("MUST_CALL_VALIDATORS", {})
         klass.const_set("MODELS", [])
@@ -443,107 +678,114 @@
         klass.const_set("NEED_INITIALIZE_VARIABLES", [])
         klass.const_set("PLURAL_FORMS", {})
 
-        klass.module_eval(<<-EOC)
-        public
-        
-        @tag_name = name.split(/::/).last
-        @tag_name[0,1] = @tag_name[0,1].downcase
-        @have_content = false
+        tag_name = klass.name.split(/::/).last
+        tag_name[0, 1] = tag_name[0, 1].downcase
+        klass.instance_variable_set("@tag_name", tag_name)
+        klass.instance_variable_set("@have_content", false)
+      end
 
-        def self.must_call_validators
-          super.merge(MUST_CALL_VALIDATORS)
+      def install_must_call_validator(prefix, uri)
+        self::MUST_CALL_VALIDATORS[uri] = prefix
+      end
+
+      def install_model(tag, uri, occurs=nil, getter=nil, plural=false)
+        getter ||= tag
+        if m = self::MODELS.find {|t, u, o, g, p| t == tag and u == uri}
+          m[2] = occurs
+        else
+          self::MODELS << [tag, uri, occurs, getter, plural]
         end
-        def self.models
-          MODELS + super
+      end
+
+      def install_get_attribute(name, uri, required=true,
+                                type=nil, disp_name=nil,
+                                element_name=nil)
+        disp_name ||= name
+        element_name ||= name
+        writer_type, reader_type = type
+        def_corresponded_attr_writer name, writer_type, disp_name
+        def_corresponded_attr_reader name, reader_type
+        if type == :boolean and /^is/ =~ name
+          alias_method "#{$POSTMATCH}?", name
         end
-        def self.get_attributes
-          GET_ATTRIBUTES + super
-        end
-        def self.have_children_elements
-          HAVE_CHILDREN_ELEMENTS + super
-        end
-        def self.to_element_methods
-          TO_ELEMENT_METHODS + super
-        end
-        def self.need_initialize_variables
-          NEED_INITIALIZE_VARIABLES + super
-        end
-        def self.plural_forms
-          super.merge(PLURAL_FORMS)
-        end
+        self::GET_ATTRIBUTES << [name, uri, required, element_name]
+        add_need_initialize_variable(disp_name)
+      end
 
-      
-        def self.install_must_call_validator(prefix, uri)
-          MUST_CALL_VALIDATORS[uri] = prefix
+      def def_corresponded_attr_writer(name, type=nil, disp_name=nil)
+        disp_name ||= name
+        case type
+        when :integer
+          integer_writer name, disp_name
+        when :positive_integer
+          positive_integer_writer name, disp_name
+        when :boolean
+          boolean_writer name, disp_name
+        when :w3cdtf, :rfc822, :rfc2822
+          date_writer name, type, disp_name
+        when :text_type
+          text_type_writer name, disp_name
+        when :content
+          content_writer name, disp_name
+        when :yes_clean_other
+          yes_clean_other_writer name, disp_name
+        when :yes_other
+          yes_other_writer name, disp_name
+        when :csv
+          csv_writer name
+        when :csv_integer
+          csv_integer_writer name
+        else
+          attr_writer name
         end
-        
-        def self.install_model(tag, uri, occurs=nil, getter=nil)
-          getter ||= tag
-          if m = MODELS.find {|t, u, o, g| t == tag and u == uri}
-            m[2] = occurs
-          else
-            MODELS << [tag, uri, occurs, getter]
-          end
-        end
+      end
 
-        def self.install_get_attribute(name, uri, required=true,
-                                       type=nil, disp_name=nil,
-                                       element_name=nil)
-          disp_name ||= name
-          element_name ||= name
-          def_corresponded_attr_writer name, type, disp_name
+      def def_corresponded_attr_reader(name, type=nil)
+        case type
+        when :inherit
+          inherit_convert_attr_reader name
+        when :uri
+          uri_convert_attr_reader name
+        when :yes_clean_other
+          yes_clean_other_attr_reader name
+        when :yes_other
+          yes_other_attr_reader name
+        when :csv
+          csv_attr_reader name
+        when :csv_integer
+          csv_attr_reader name, :separator => ","
+        else
           convert_attr_reader name
-          if type == :boolean and /^is/ =~ name
-            alias_method "\#{$POSTMATCH}?", name
-          end
-          GET_ATTRIBUTES << [name, uri, required, element_name]
-          add_need_initialize_variable(disp_name)
         end
+      end
 
-        def self.def_corresponded_attr_writer(name, type=nil, disp_name=name)
-          case type
-          when :integer
-            integer_writer name, disp_name
-          when :positive_integer
-            positive_integer_writer name, disp_name
-          when :boolean
-            boolean_writer name, disp_name
-          when :w3cdtf, :rfc822, :rfc2822
-            date_writer name, type, disp_name
-          else
-            attr_writer name
-          end
-        end
+      def content_setup(type=nil, disp_name=nil)
+        writer_type, reader_type = type
+        def_corresponded_attr_writer :content, writer_type, disp_name
+        def_corresponded_attr_reader :content, reader_type
+        @have_content = true
+      end
 
-        def self.content_setup(type=nil)
-          def_corresponded_attr_writer "content", type
-          convert_attr_reader :content
-          @have_content = true
-        end
+      def have_content?
+        @have_content
+      end
 
-        def self.have_content?
-          @have_content
-        end
+      def add_have_children_element(variable_name, plural_name)
+        self::HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
+      end
 
-        def self.add_have_children_element(variable_name, plural_name)
-          HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
-        end
-        
-        def self.add_to_element_method(method_name)
-          TO_ELEMENT_METHODS << method_name
-        end
+      def add_to_element_method(method_name)
+        self::TO_ELEMENT_METHODS << method_name
+      end
 
-        def self.add_need_initialize_variable(variable_name)
-          NEED_INITIALIZE_VARIABLES << variable_name
-        end
-        
-        def self.add_plural_form(singular, plural)
-          PLURAL_FORMS[singular] = plural
-        end
-        
-        EOC
+      def add_need_initialize_variable(variable_name)
+        self::NEED_INITIALIZE_VARIABLES << variable_name
       end
 
+      def add_plural_form(singular, plural)
+        self::PLURAL_FORMS[singular] = plural
+      end
+
       def required_prefix
         nil
       end
@@ -551,7 +793,11 @@
       def required_uri
         ""
       end
-      
+
+      def need_parent?
+        false
+      end
+
       def install_ns(prefix, uri)
         if self::NSPOOL.has_key?(prefix)
           raise OverlappedPrefixError.new(prefix)
@@ -564,12 +810,16 @@
       end
     end
 
-    attr_accessor :do_validate
+    attr_accessor :parent, :do_validate
 
-    def initialize(do_validate=true, attrs={})
+    def initialize(do_validate=true, attrs=nil)
+      @parent = nil
       @converter = nil
+      if attrs.nil? and (do_validate.is_a?(Hash) or do_validate.is_a?(Array))
+        do_validate, attrs = true, do_validate
+      end
       @do_validate = do_validate
-      initialize_variables(attrs)
+      initialize_variables(attrs || {})
     end
 
     def tag_name
@@ -598,10 +848,21 @@
         value
       end
     end
-    
+
+    def valid?(ignore_unknown_element=true)
+      validate(ignore_unknown_element)
+      true
+    rescue RSS::Error
+      false
+    end
+
     def validate(ignore_unknown_element=true)
+      do_validate = @do_validate
+      @do_validate = true
       validate_attribute
       __validate(ignore_unknown_element)
+    ensure
+      @do_validate = do_validate
     end
     
     def validate_for_stream(tags, ignore_unknown_element=true)
@@ -609,20 +870,15 @@
       __validate(ignore_unknown_element, 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
-
     def to_s(need_convert=true, indent='')
       if self.class.have_content?
-        return "" unless @content
+        return "" if !empty_content? and !content_is_set?
         rv = tag(indent) do |next_indent|
-          h(@content)
+          if empty_content?
+            ""
+          else
+            xmled_content
+          end
         end
       else
         rv = tag(indent) do |next_indent|
@@ -635,6 +891,44 @@
       rv
     end
 
+    def have_xml_content?
+      false
+    end
+
+    def need_base64_encode?
+      false
+    end
+
+    def set_next_element(tag_name, next_element)
+      klass = next_element.class
+      prefix = ""
+      prefix << "#{klass.required_prefix}_" if klass.required_prefix
+      key = "#{prefix}#{tag_name.gsub(/-/, '_')}"
+      if self.class.plural_forms.has_key?(key)
+        ary = __send__("#{self.class.plural_forms[key]}")
+        ary << next_element
+      else
+        __send__("#{key}=", next_element)
+      end
+    end
+
+    protected
+    def have_required_elements?
+      self.class::MODELS.all? do |tag, uri, occurs, getter|
+        if occurs.nil? or occurs == "+"
+          child = __send__(getter)
+          if child.is_a?(Array)
+            children = child
+            children.any? {|c| c.have_required_elements?}
+          else
+            !child.to_s.empty?
+          end
+        else
+          true
+        end
+      end
+    end
+
     private
     def initialize_variables(attrs)
       normalized_attrs = {}
@@ -646,16 +940,16 @@
         if value
           __send__("#{variable_name}=", value)
         else
-          instance_eval("@#{variable_name} = nil")
+          instance_variable_set("@#{variable_name}", nil)
         end
       end
       initialize_have_children_elements
-      @content = "" if self.class.have_content?
+      @content = normalized_attrs["content"] if self.class.have_content?
     end
 
     def initialize_have_children_elements
       self.class.have_children_elements.each do |variable_name, plural_name|
-        instance_eval("@#{variable_name} = []")
+        instance_variable_set("@#{variable_name}", [])
       end
     end
 
@@ -665,8 +959,10 @@
       attrs = collect_attrs
       return "" if attrs.nil?
 
+      return "" unless have_required_elements?
+
       attrs.update(additional_attrs)
-      start_tag = make_start_tag(indent, next_indent, attrs)
+      start_tag = make_start_tag(indent, next_indent, attrs.dup)
 
       if block
         content = block.call(next_indent)
@@ -681,6 +977,7 @@
       else
         content = content.reject{|x| x.empty?}
         if content.empty?
+          return "" if attrs.empty?
           end_tag = "/>"
         else
           start_tag << ">\n"
@@ -722,56 +1019,6 @@
       ''
     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|
-        value = __send__(var)
-        if value.respond_to?("setup_maker") and
-            !not_need_to_call_setup_maker_variables.include?(var)
-          value.setup_maker(target)
-        else
-          setter = "#{var}="
-          if target.respond_to?(setter)
-            target.__send__(setter, value)
-          end
-        end
-      end
-    end
-
-    def not_need_to_call_setup_maker_variables
-      []
-    end
-    
-    def setup_maker_elements(parent)
-      self.class.have_children_elements.each do |name, plural_name|
-        if parent.respond_to?(plural_name)
-          target = parent.__send__(plural_name)
-          __send__(plural_name).each do |elem|
-            elem.setup_maker(target)
-          end
-        end
-      end
-    end
-
-    def set_next_element(tag_name, next_element)
-      klass = next_element.class
-      prefix = ""
-      prefix << "#{klass.required_prefix}_" if klass.required_prefix
-      key = "#{prefix}#{tag_name}"
-      if self.class.plural_forms.has_key?(key)
-        ary = __send__("#{self.class.plural_forms[key]}")
-        ary << next_element
-      else
-        __send__("#{prefix}#{tag_name}=", next_element)
-      end
-    end
-
     def children
       rv = []
       self.class.models.each do |name, uri, occurs, getter|
@@ -787,10 +1034,10 @@
 
     def _tags
       rv = []
-      self.class.models.each do |name, uri, occurs, getter|
+      self.class.models.each do |name, uri, occurs, getter, plural|
         value = __send__(getter)
         next if value.nil?
-        if value.is_a?(Array)
+        if plural and value.is_a?(Array)
           rv.concat([[uri, name]] * value.size)
         else
           rv << [uri, name]
@@ -817,7 +1064,7 @@
       must_call_validators.each do |uri, prefix|
         _validate(ignore_unknown_element, tags[uri], uri)
         meth = "#{prefix}_validate"
-        if respond_to?(meth, true)
+        if !prefix.empty? and respond_to?(meth, true)
           __send__(meth, ignore_unknown_element, tags[uri], uri)
         end
       end
@@ -825,9 +1072,11 @@
 
     def validate_attribute
       _attrs.each do |a_name, required, alias_name|
-        if required and __send__(alias_name || a_name).nil?
+        value = instance_variable_get("@#{alias_name || a_name}")
+        if required and value.nil?
           raise MissingAttributeError.new(tag_name, a_name)
         end
+        __send__("#{alias_name || a_name}=", value)
       end
     end
 
@@ -843,11 +1092,12 @@
         tags = tags.sort_by {|x| element_names.index(x) || tags_size}
       end
 
+      _tags = tags.dup if tags
       models.each_with_index do |model, i|
         name, model_uri, occurs, getter = model
 
         if DEBUG
-          p "before" 
+          p "before"
           p tags
           p model
         end
@@ -933,6 +1183,27 @@
       rv
     end
 
+    def empty_content?
+      false
+    end
+
+    def content_is_set?
+      if have_xml_content?
+        __send__(self.class.xml_getter)
+      else
+        content
+      end
+    end
+
+    def xmled_content
+      if have_xml_content?
+        __send__(self.class.xml_getter).to_s
+      else
+        _content = content
+        _content = Base64.encode64(_content) if need_base64_encode?
+        h(_content)
+      end
+    end
   end
 
   module RootElementMixin
@@ -940,16 +1211,23 @@
     include XMLStyleSheetMixin
     
     attr_reader :output_encoding
-
-    def initialize(rss_version, version=nil, encoding=nil, standalone=nil)
+    attr_reader :feed_type, :feed_subtype, :feed_version
+    attr_accessor :version, :encoding, :standalone
+    def initialize(feed_version, version=nil, encoding=nil, standalone=nil)
       super()
-      @rss_version = rss_version
+      @feed_type = nil
+      @feed_subtype = nil
+      @feed_version = feed_version
       @version = version || '1.0'
       @encoding = encoding
       @standalone = standalone
       @output_encoding = nil
     end
 
+    def feed_info
+      [@feed_type, @feed_version, @feed_subtype]
+    end
+
     def output_encoding=(enc)
       @output_encoding = enc
       self.converter = Converter.new(@output_encoding, @encoding)
@@ -964,25 +1242,48 @@
         xss.setup_maker(maker)
       end
 
-      setup_maker_elements(maker)
+      super
     end
 
-    def to_xml(version=nil, &block)
-      if version.nil? or version == @rss_version
+    def to_feed(type, &block)
+      Maker.make(type) do |maker|
+        setup_maker(maker)
+        block.call(maker) if block
+      end
+    end
+
+    def to_rss(type, &block)
+      to_feed("rss#{type}", &block)
+    end
+
+    def to_atom(type, &block)
+      to_feed("atom:#{type}", &block)
+    end
+
+    def to_xml(type=nil, &block)
+      if type.nil? or same_feed_type?(type)
         to_s
       else
-        RSS::Maker.make(version) do |maker|
-          setup_maker(maker)
-          block.call(maker) if block
-        end.to_s
+        to_feed(type, &block).to_s
       end
     end
 
     private
+    def same_feed_type?(type)
+      if /^(atom|rss)?(\d+\.\d+)?(?::(.+))?$/i =~ type
+        feed_type = ($1 || @feed_type).downcase
+        feed_version = $2 || @feed_version
+        feed_subtype = $3 || @feed_subtype
+        [feed_type, feed_version, feed_subtype] == feed_info
+      else
+        false
+      end
+    end
+
     def tag(indent, attrs={}, &block)
-      rv = xmldecl + xml_stylesheet_pi
-      rv << super(indent, ns_declarations.merge(attrs), &block)
-      rv
+      rv = super(indent, ns_declarations.merge(attrs), &block)
+      return rv if rv.empty?
+      "#{xmldecl}#{xml_stylesheet_pi}#{rv}"
     end
 
     def xmldecl
@@ -1003,13 +1304,9 @@
       end
       decls
     end
-    
-    def setup_maker_elements(maker)
-      channel.setup_maker(maker) if channel
-      image.setup_maker(maker) if image
-      textinput.setup_maker(maker) if textinput
-      super(maker)
+
+    def maker_target(target)
+      target
     end
   end
-
 end
Index: ruby_1_8/lib/rss/content.rb
===================================================================
--- ruby_1_8/lib/rss/content.rb	(revision 13746)
+++ ruby_1_8/lib/rss/content.rb	(revision 13747)
@@ -32,7 +32,7 @@
   ContentModel::ELEMENTS.uniq!
   ContentModel::ELEMENTS.each do |full_name|
     name = full_name[prefix_size..-1]
-    BaseListener.install_get_text_element(CONTENT_URI, name, "#{full_name}=")
+    BaseListener.install_get_text_element(CONTENT_URI, name, full_name)
   end
 
 end
Index: ruby_1_8/lib/rss/slash.rb
===================================================================
--- ruby_1_8/lib/rss/slash.rb	(revision 0)
+++ ruby_1_8/lib/rss/slash.rb	(revision 13747)
@@ -0,0 +1,49 @@
+require 'rss/1.0'
+
+module RSS
+  SLASH_PREFIX = 'slash'
+  SLASH_URI = "http://purl.org/rss/1.0/modules/slash/"
+
+  RDF.install_ns(SLASH_PREFIX, SLASH_URI)
+
+  module SlashModel
+    extend BaseModel
+
+    ELEMENT_INFOS = \
+    [
+     ["section"],
+     ["department"],
+     ["comments", :positive_integer],
+     ["hit_parade", :csv_integer],
+    ]
+
+    class << self
+      def append_features(klass)
+        super
+
+        return if klass.instance_of?(Module)
+        klass.install_must_call_validator(SLASH_PREFIX, SLASH_URI)
+        ELEMENT_INFOS.each do |name, type, *additional_infos|
+          full_name = "#{SLASH_PREFIX}_#{name}"
+          klass.install_text_element(full_name, SLASH_URI, "?",
+                                     full_name, type, name)
+        end
+
+        klass.module_eval do
+          alias_method(:slash_hit_parades, :slash_hit_parade)
+          undef_method(:slash_hit_parade)
+          alias_method(:slash_hit_parade, :slash_hit_parade_content)
+        end
+      end
+    end
+  end
+
+  class RDF
+    class Item; include SlashModel; end
+  end
+
+  SlashModel::ELEMENT_INFOS.each do |name, type|
+    accessor_base = "#{SLASH_PREFIX}_#{name}"
+    BaseListener.install_get_text_element(SLASH_URI, name, accessor_base)
+  end
+end
Index: ruby_1_8/lib/rss.rb
===================================================================
--- ruby_1_8/lib/rss.rb	(revision 13746)
+++ ruby_1_8/lib/rss.rb	(revision 13747)
@@ -1,4 +1,4 @@
-# Copyright (c) 2003-2005 Kouhei Sutou.  You can redistribute it and/or
+# Copyright (c) 2003-2007 Kouhei Sutou.  You can redistribute it and/or
 # modify it under the same terms as Ruby.
 #
 # Author:: Kouhei Sutou <kou@c...>
@@ -6,11 +6,14 @@
 
 require 'rss/1.0'
 require 'rss/2.0'
+require 'rss/atom'
 require 'rss/content'
 require 'rss/dublincore'
 require 'rss/image'
+require 'rss/itunes'
+require 'rss/slash'
 require 'rss/syndication'
-#require 'rss/taxonomy'
+require 'rss/taxonomy'
 require 'rss/trackback'
 
 require "rss/maker"
Index: ruby_1_8/test/rss/test_maker_2.0.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_2.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_2.0.rb	(revision 13747)
@@ -353,7 +353,7 @@
       assert_nil(rss.image)
     end
     
-    def test_items
+    def test_items(with_convenience_way=true)
       title = "TITLE"
       link = "http://hoge.com/"
       description = "text hoge fuga"
@@ -407,7 +407,11 @@
           end
         end
         maker.items.do_sort = Proc.new do |x, y|
-          y.title[-1] <=> x.title[-1]
+          if with_convenience_way
+            y.title[-1] <=> x.title[-1]
+          else
+            y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]}
+          end
         end
       end
       assert_equal(item_size, rss.items.size)
@@ -422,6 +426,10 @@
       end
     end
 
+    def test_items_with_new_api_since_018
+      test_items(false)
+    end
+
     def test_guid
       isPermaLink = "true"
       content = "http://inessential.com/2002/09/01.php#a2"
@@ -606,15 +614,16 @@
       assert_equal(name, textInput.name)
       assert_equal(link, textInput.link)
 
-      rss = RSS::Maker.make("2.0") do |maker|
-        # setup_dummy_channel(maker)
+      assert_not_set_error("maker.channel", %w(link description title)) do
+        RSS::Maker.make("2.0") do |maker|
+          # setup_dummy_channel(maker)
 
-        maker.textinput.title = title
-        maker.textinput.description = description
-        maker.textinput.name = name
-        maker.textinput.link = link
+          maker.textinput.title = title
+          maker.textinput.description = description
+          maker.textinput.name = name
+          maker.textinput.link = link
+        end
       end
-      assert_nil(rss)
     end
     
     def test_not_valid_textInput
Index: ruby_1_8/test/rss/test_setup_maker_atom_entry.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_atom_entry.rb	(revision 0)
+++ ruby_1_8/test/rss/test_setup_maker_atom_entry.rb	(revision 13747)
@@ -0,0 +1,409 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestSetupMakerAtomEntry < TestCase
+    def setup
+      t = Time.iso8601("2000-01-01T12:00:05+00:00")
+      class << t
+        alias_method(:to_s, :iso8601)
+      end
+
+      @dc_elems = {
+        :title => "hoge",
+        :description =>
+          " XML is placing increasingly heavy loads on
+          the existing technical infrastructure of the Internet.",
+        :creator => "Rael Dornfest (mailto:rael@o...)",
+        :subject => "XML",
+        :publisher => "The O'Reilly Network",
+        :contributor => "hogehoge",
+        :type => "fugafuga",
+        :format => "hohoho",
+        :identifier => "fufufu",
+        :source => "barbar",
+        :language => "ja",
+        :relation => "cococo",
+        :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
+        :date => t,
+      }
+    end
+
+    def test_setup_maker_entry(with_dc=true)
+      authors = [
+                 {
+                   :name => "Bob",
+                   :uri => "http://example.com/~bob/",
+                   :email => "bob@e...",
+                 },
+                 {
+                   :name => "Alice",
+                   :uri => "http://example.com/~alice/",
+                   :email => "alice@e...",
+                 },
+                ]
+      categories = [
+                    {
+                      :term => "music",
+                      :label => "Music",
+                    },
+                    {
+                      :term => "book",
+                      :scheme => "http://example.com/category/book/",
+                      :label => "Book",
+                    },
+                   ]
+      contributors = [
+                      {
+                        :name => "Chris",
+                        :email => "chris@e...",
+                      },
+                      {
+                        :name => "Eva",
+                        :uri => "http://example.com/~eva/",
+                      },
+                     ]
+      id = "urn:uuid:8b105336-7e20-45fc-bb78-37fb3e1db25a"
+      link = "http://hoge.com"
+      published = Time.now - 60 * 3600
+      rights = "Copyrights (c) 2007 Alice and Bob"
+      description = "fugafugafugafuga"
+      title = "fugafuga"
+      updated = Time.now
+
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        maker.items.new_item do |item|
+          authors.each do |author_info|
+            item.authors.new_author do |author|
+              author_info.each do |key, value|
+                author.__send__("#{key}=", value)
+              end
+            end
+          end
+
+          categories.each do |category_info|
+            item.categories.new_category do |category|
+              category_info.each do |key, value|
+                category.__send__("#{key}=", value)
+              end
+            end
+          end
+
+          contributors.each do |contributor_info|
+            item.contributors.new_contributor do |contributor|
+              contributor_info.each do |key, value|
+                contributor.__send__("#{key}=", value)
+              end
+            end
+          end
+
+          item.id = id
+          item.link = link
+          item.published = published
+          item.rights = rights
+          item.description = description
+          item.title = title
+          item.updated = updated
+
+          if with_dc
+            @dc_elems.each do |var, value|
+              if var == :date
+                item.new_dc_date(value)
+              else
+                item.__send__("dc_#{var}=", value)
+              end
+            end
+          end
+        end
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("atom:entry") do |maker|
+        feed.setup_maker(maker)
+      end
+      assert_not_nil(new_feed)
+
+      new_authors = new_feed.authors.collect do |author|
+        {
+          :name => author.name.content,
+          :uri => author.uri.content,
+          :email => author.email.content,
+        }
+      end
+      assert_equal(authors, new_authors)
+
+      new_categories = new_feed.categories.collect do |category|
+        {
+          :term => category.term,
+          :scheme => category.scheme,
+          :label => category.label,
+        }.reject {|key, value| value.nil?}
+      end
+      assert_equal(categories, new_categories)
+
+      new_contributors = new_feed.contributors.collect do |contributor|
+        info = {}
+        info[:name] = contributor.name.content
+        info[:uri] = contributor.uri.content if contributor.uri
+        info[:email] = contributor.email.content if contributor.email
+        info
+      end
+      assert_equal(contributors, new_contributors)
+
+      assert_equal(id, new_feed.id.content)
+      assert_equal(link, new_feed.link.href)
+      assert_equal(published, new_feed.published.content)
+      assert_equal(rights, new_feed.rights.content)
+      assert_equal(description, new_feed.summary.content)
+      assert_equal(title, new_feed.title.content)
+      assert_equal(updated, new_feed.updated.content)
+
+      if with_dc
+        @dc_elems.each do |var, value|
+          if var == :date
+            assert_equal([updated, value],
+                         new_feed.dc_dates.collect {|date| date.value})
+          else
+            assert_equal(value, new_feed.__send__("dc_#{var}"))
+          end
+        end
+      end
+
+      assert_equal(1, new_feed.items.size)
+    end
+
+    def test_setup_maker_entry_without_dc
+      test_setup_maker_entry(false)
+    end
+
+    def test_setup_maker_items(for_backward_compatibility=false)
+      title = "TITLE"
+      link = "http://hoge.com/"
+      description = "text hoge fuga"
+      updated = Time.now
+
+      item_size = 5
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        item_size.times do |i|
+          maker.items.new_item do |item|
+            item.title = "#{title}#{i}"
+            item.link = "#{link}#{i}"
+            item.description = "#{description}#{i}"
+            item.updated = updated + i * 60
+          end
+        end
+      end
+
+      new_feed = RSS::Maker.make("atom:entry") do |maker|
+        feed.items.each do |item|
+          if for_backward_compatibility
+            item.setup_maker(maker)
+          else
+            item.setup_maker(maker.items)
+          end
+        end
+
+        feed.items.clear
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(1, new_feed.items.size)
+      new_feed.items[0..1].each_with_index do |item, i|
+        assert_equal("#{title}#{i}", item.title.content)
+        assert_equal("#{link}#{i}", item.link.href)
+        assert_equal("#{description}#{i}", item.summary.content)
+        assert_equal(updated + i * 60, item.updated.content)
+      end
+    end
+
+    def test_setup_maker_items_sort
+      title = "TITLE"
+      link = "http://hoge.com/"
+      summary = "text hoge fuga"
+      updated = Time.now
+
+      feed_size = 5
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        feed_size.times do |i|
+          entry_class = RSS::Atom::Entry
+          entry = entry_class.new
+          entry.title = entry_class::Title.new(:content => "#{title}#{i}")
+          entry.links << entry_class::Link.new(:href => "#{link}#{i}")
+          entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}")
+          entry.updated = entry_class::Updated.new(:content => updated + i * 60)
+          entry.setup_maker(maker.items)
+        end
+        maker.items.do_sort = false
+      end
+      assert_equal(1, feed.items.size)
+
+      assert_equal("#{title}0", feed.title.content)
+      assert_equal("#{link}0", feed.link.href)
+      assert_equal("#{summary}0", feed.summary.content)
+
+
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        feed_size.times do |i|
+          entry_class = RSS::Atom::Entry
+          entry = entry_class.new
+          entry.title = entry_class::Title.new(:content => "#{title}#{i}")
+          entry.links << entry_class::Link.new(:href => "#{link}#{i}")
+          entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}")
+          entry.updated = entry_class::Updated.new(:content => updated + i * 60)
+          entry.setup_maker(maker.items)
+        end
+        maker.items.do_sort = true
+      end
+      assert_equal(1, feed.items.size)
+
+      assert_equal("#{title}#{feed_size - 1}", feed.title.content)
+      assert_equal("#{link}#{feed_size - 1}", feed.link.href)
+      assert_equal("#{summary}#{feed_size - 1}", feed.summary.content)
+    end
+
+    def test_setup_maker_items_backward_compatibility
+      test_setup_maker_items(true)
+    end
+
+    def test_setup_maker
+      encoding = "EUC-JP"
+      standalone = true
+
+      href = 'a.xsl'
+      type = 'text/xsl'
+      title = 'sample'
+      media = 'printer'
+      charset = 'UTF-8'
+      alternate = 'yes'
+
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        maker.encoding = encoding
+        maker.standalone = standalone
+
+        maker.xml_stylesheets.new_xml_stylesheet do |xss|
+          xss.href = href
+          xss.type = type
+          xss.title = title
+          xss.media = media
+          xss.charset = charset
+          xss.alternate = alternate
+        end
+
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("atom:entry") do |maker|
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(["atom", "1.0", "entry"], new_feed.feed_info)
+      assert_equal(encoding, new_feed.encoding)
+      assert_equal(standalone, new_feed.standalone)
+
+      xss = new_feed.xml_stylesheets.first
+      assert_equal(1, new_feed.xml_stylesheets.size)
+      assert_equal(href, xss.href)
+      assert_equal(type, xss.type)
+      assert_equal(title, xss.title)
+      assert_equal(media, xss.media)
+      assert_equal(charset, xss.charset)
+      assert_equal(alternate, xss.alternate)
+    end
+
+    def test_setup_maker_full
+      encoding = "EUC-JP"
+      standalone = true
+
+      href = 'a.xsl'
+      type = 'text/xsl'
+      title = 'sample'
+      media = 'printer'
+      charset = 'UTF-8'
+      alternate = 'yes'
+
+      channel_about = "http://hoge.com"
+      channel_title = "fugafuga"
+      channel_link = "http://hoge.com"
+      channel_description = "fugafugafugafuga"
+      channel_author = "Bob"
+
+      image_url = "http://hoge.com/hoge.png"
+
+      item_title = "TITLE"
+      item_link = "http://hoge.com/"
+      item_description = "text hoge fuga"
+
+      entry_size = 5
+      feed = RSS::Maker.make("atom:entry") do |maker|
+        maker.encoding = encoding
+        maker.standalone = standalone
+
+        maker.xml_stylesheets.new_xml_stylesheet do |xss|
+          xss.href = href
+          xss.type = type
+          xss.title = title
+          xss.media = media
+          xss.charset = charset
+          xss.alternate = alternate
+        end
+
+        maker.channel.about = channel_about
+        maker.channel.title = channel_title
+        maker.channel.link = channel_link
+        maker.channel.description = channel_description
+        maker.channel.author = channel_author
+        @dc_elems.each do |var, value|
+          maker.channel.__send__("dc_#{var}=", value)
+        end
+
+        maker.image.url = image_url
+
+        entry_size.times do |i|
+          maker.items.new_item do |item|
+            item.title = "#{item_title}#{i}"
+            item.link = "#{item_link}#{i}"
+            item.description = "#{item_description}#{i}"
+
+            @dc_elems.each do |var, value|
+              item.__send__("dc_#{var}=", value)
+            end
+          end
+        end
+      end
+
+      new_feed = RSS::Maker.make("atom:entry") do |maker|
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(["atom", "1.0", "entry"], new_feed.feed_info)
+      assert_equal(encoding, new_feed.encoding)
+      assert_equal(standalone, new_feed.standalone)
+
+      xss = new_feed.xml_stylesheets.first
+      assert_equal(1, new_feed.xml_stylesheets.size)
+      assert_equal(href, xss.href)
+      assert_equal(type, xss.type)
+      assert_equal(title, xss.title)
+      assert_equal(media, xss.media)
+      assert_equal(charset, xss.charset)
+      assert_equal(alternate, xss.alternate)
+
+      assert_equal("#{item_title}0", new_feed.title.content)
+      assert_equal("#{item_link}0", new_feed.link.href)
+      assert_equal("#{item_description}0", new_feed.summary.content)
+      @dc_elems.each do |var, value|
+        assert_equal(value, new_feed.__send__("dc_#{var}"))
+      end
+      assert_equal(1, new_feed.items.size)
+    end
+  end
+end
Index: ruby_1_8/test/rss/rss-testcase.rb
===================================================================
--- ruby_1_8/test/rss/rss-testcase.rb	(revision 13746)
+++ ruby_1_8/test/rss/rss-testcase.rb	(revision 13747)
@@ -3,6 +3,8 @@
 require "test/unit"
 require 'rss-assertions'
 
+require "rss"
+
 module RSS
   class TestCase < Test::Unit::TestCase
     include ERB::Util
@@ -22,7 +24,7 @@
     NAME_VALUE = "hogehoge"
     LANGUAGE_VALUE = "ja"
     DESCRIPTION_VALUE = "
-    XML.com features a rich mix of information and services 
+    XML.com features a rich mix of information and services
     for the XML community.
     "
     RESOURCES = [
@@ -42,6 +44,45 @@
     
     CATEGORY_DOMAIN = "http://www.superopendirectory.com/"
 
+    FEED_TITLE = "dive into mark"
+    FEED_UPDATED = "2003-12-13T18:30:02Z"
+    FEED_AUTHOR_NAME = "John Doe"
+    FEED_ID = "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6"
+
+    ENTRY_TITLE = "Atom-Powered Robots Run Amok"
+    ENTRY_LINK = "http://example.org/2003/12/13/atom03"
+    ENTRY_ID = "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a"
+    ENTRY_UPDATED = "2003-12-13T18:30:02Z"
+    ENTRY_SUMMARY = "Some text."
+
+    t = Time.iso8601("2000-01-01T12:00:05+00:00")
+    class << t
+      alias_method(:to_s, :iso8601)
+    end
+
+    DC_ELEMENTS = {
+      :title => "hoge",
+      :description =>
+        " XML is placing increasingly heavy loads on
+          the existing technical infrastructure of the Internet.",
+      :creator => "Rael Dornfest (mailto:rael@o...)",
+      :subject => "XML",
+      :publisher => "The O'Reilly Network",
+      :contributor => "hogehoge",
+      :type => "fugafuga",
+      :format => "hohoho",
+      :identifier => "fufufu",
+      :source => "barbar",
+      :language => "ja",
+      :relation => "cococo",
+      :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
+      :date => t,
+    }
+
+    DC_NODES = DC_ELEMENTS.collect do |name, value|
+      "<#{DC_PREFIX}:#{name}>#{value}</#{DC_PREFIX}:#{name}>"
+    end.join("\n")
+
     def default_test
       # This class isn't tested
     end
@@ -205,6 +246,82 @@
 EOR
     end
 
+    def make_feed_without_entry(content=nil, xmlns=[])
+      <<-EOA
+<feed xmlns="#{Atom::URI}"
+#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
+  <id>#{FEED_ID}</id>
+  <title>#{FEED_TITLE}</title>
+  <updated>#{FEED_UPDATED}</updated>
+  <author>
+    <name>#{FEED_AUTHOR_NAME}</name>
+  </author>
+#{block_given? ? yield : content}
+</feed>
+EOA
+    end
+
+    def make_entry(content=nil)
+      <<-EOA
+  <entry>
+    <title>#{ENTRY_TITLE}</title>
+    <id>#{ENTRY_ID}</id>
+    <updated>#{ENTRY_UPDATED}</updated>
+#{block_given? ? yield : content}
+  </entry>
+EOA
+    end
+
+    def make_feed_with_open_entry(content=nil, xmlns=[], &block)
+      make_feed_without_entry(<<-EOA, xmlns)
+#{make_entry(content, &block)}
+EOA
+    end
+
+    def make_feed_with_open_entry_source(content=nil, xmlns=[])
+      make_feed_with_open_entry(<<-EOA, xmlns)
+  <source>
+#{block_given? ? yield : content}
+  </source>
+EOA
+    end
+
+    def make_feed(content=nil, xmlns=[])
+      make_feed_without_entry(<<-EOA, xmlns)
+  <entry>
+    <title>#{ENTRY_TITLE}</title>
+    <link href="#{ENTRY_LINK}"/>
+    <id>#{ENTRY_ID}</id>
+    <updated>#{ENTRY_UPDATED}</updated>
+    <summary>#{ENTRY_SUMMARY}</summary>
+  </entry>
+#{block_given? ? yield : content}
+EOA
+    end
+
+    def make_entry_document(content=nil, xmlns=[])
+      <<-EOA
+<entry xmlns="#{Atom::URI}"
+#{xmlns.collect {|pre, uri| "xmlns:#{pre}='#{uri}'"}.join(' ')}>
+  <id>#{ENTRY_ID}</id>
+  <title>#{ENTRY_TITLE}</title>
+  <updated>#{ENTRY_UPDATED}</updated>
+  <author>
+    <name>#{FEED_AUTHOR_NAME}</name>
+  </author>
+#{block_given? ? yield : content}
+</entry>
+EOA
+    end
+
+    def make_entry_document_with_open_source(content=nil, xmlns=[])
+      make_entry_document(<<-EOA, xmlns)
+  <source>
+#{block_given? ? yield : content}
+  </source>
+EOA
+    end
+
     def make_element(elem_name, attrs, contents)
       attrs_str = attrs.collect do |name, value|
         "#{h name}='#{h value}'"
@@ -215,12 +332,61 @@
 
       "<#{h elem_name} #{attrs_str}>\n#{contents_str}\n</#{h elem_name}>"
     end
+
+    def xmlns_container(xmlns_decls, content)
+      attributes = xmlns_decls.collect do |prefix, uri|
+        "xmlns:#{h prefix}=\"#{h uri}\""
+      end.join(" ")
+      "<dummy #{attributes}>#{content}</dummy>"
+    end
+
+    private
+    def setup_rss10(rdf)
+      assert_equal("", rdf.to_s)
+
+      channel = RDF::Channel.new
+      assert_equal("", channel.to_s)
+      channel.about = "http://example.com/index.rdf"
+      channel.title = "title"
+      channel.link = "http://example.com/"
+      channel.description = "description"
+      assert_equal("", channel.to_s)
+
+      item_title = "item title"
+      item_link = "http://example.com/item"
+      channel.items = RDF::Channel::Items.new
+      channel.items.Seq.lis << RDF::Channel::Items::Seq::Li.new(item_link)
+      assert_not_equal("", channel.to_s)
+
+      rdf.channel = channel
+      assert_equal("", rdf.to_s)
+
+      item = RDF::Item.new
+      item.title = item_title
+      item.link = item_link
+      item.about = item_link
+      rdf.items << item
+      assert_not_equal("", rdf.to_s)
+    end
     
-    private
+    def setup_rss20(rss)
+      assert_equal("", rss.to_s)
+
+      channel = Rss::Channel.new
+      assert_equal("", channel.to_s)
+      channel.title = "title"
+      channel.link = "http://example.com/"
+      channel.description = "description"
+      assert_not_equal("", channel.to_s)
+
+      rss.channel = channel
+      assert_not_equal("", rss.to_s)
+    end
+    
     def setup_dummy_channel(maker)
       about = "http://hoge.com"
       title = "fugafuga"
-      link = "http://hoge.com"
+      link = "http://hoge.com/feed.xml"
       description = "fugafugafugafuga"
       language = "ja"
 
@@ -231,6 +397,17 @@
       maker.channel.language = language
     end
 
+    def setup_dummy_channel_atom(maker)
+      updated = Time.now
+      author = "Foo"
+
+      setup_dummy_channel(maker)
+      maker.channel.links.first.rel = "self"
+      maker.channel.links.first.type = "application/atom+xml"
+      maker.channel.updated = updated
+      maker.channel.author = author
+    end
+
     def setup_dummy_image(maker)
       title = "fugafuga"
       link = "http://hoge.com"
@@ -262,7 +439,15 @@
       item.title = title
       item.link = link
     end
-    
+
+    def setup_dummy_item_atom(maker)
+      setup_dummy_item(maker)
+
+      item = maker.items.first
+      item.id = "http://example.net/xxx"
+      item.updated = Time.now
+    end
+
     def setup_taxo_topic(target, topics)
       topics.each do |topic|
         taxo_topic = target.taxo_topics.new_taxo_topic
Index: ruby_1_8/test/rss/test_setup_maker_atom_feed.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_atom_feed.rb	(revision 0)
+++ ruby_1_8/test/rss/test_setup_maker_atom_feed.rb	(revision 13747)
@@ -0,0 +1,445 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestSetupMakerAtomFeed < TestCase
+    def setup
+      t = Time.iso8601("2000-01-01T12:00:05+00:00")
+      class << t
+        alias_method(:to_s, :iso8601)
+      end
+
+      @dc_elems = {
+        :title => "hoge",
+        :description =>
+          " XML is placing increasingly heavy loads on
+          the existing technical infrastructure of the Internet.",
+        :creator => "Rael Dornfest (mailto:rael@o...)",
+        :subject => "XML",
+        :publisher => "The O'Reilly Network",
+        :contributor => "hogehoge",
+        :type => "fugafuga",
+        :format => "hohoho",
+        :identifier => "fufufu",
+        :source => "barbar",
+        :language => "ja",
+        :relation => "cococo",
+        :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
+        :date => t,
+      }
+    end
+
+    def test_setup_maker_feed(with_dc=true)
+      authors = [
+                 {
+                   :name => "Bob",
+                   :uri => "http://example.com/~bob/",
+                   :email => "bob@e...",
+                 },
+                 {
+                   :name => "Alice",
+                   :uri => "http://example.com/~alice/",
+                   :email => "alice@e...",
+                 },
+                ]
+      categories = [
+                    {
+                      :term => "music",
+                      :label => "Music",
+                    },
+                    {
+                      :term => "book",
+                      :scheme => "http://example.com/category/book/",
+                      :label => "Book",
+                    },
+                   ]
+      contributors = [
+                      {
+                        :name => "Chris",
+                        :email => "chris@e...",
+                      },
+                      {
+                        :name => "Eva",
+                        :uri => "http://example.com/~eva/",
+                      },
+                     ]
+      generator = {
+        :uri => "http://example.com/generator/",
+        :version => "0.0.1",
+        :content => "Feed Generator",
+      }
+      icon = "http://example.com/icon.png"
+      about = "http://hoge.com"
+      title = "fugafuga"
+      link = "http://hoge.com"
+      logo = "http://example.com/logo.png"
+      rights = "Copyrights (c) 2007 Alice and Bob"
+      description = "fugafugafugafuga"
+      updated = Time.now
+
+      feed = RSS::Maker.make("atom") do |maker|
+        authors.each do |author_info|
+          maker.channel.authors.new_author do |author|
+            author_info.each do |key, value|
+              author.__send__("#{key}=", value)
+            end
+          end
+        end
+
+        categories.each do |category_info|
+          maker.channel.categories.new_category do |category|
+            category_info.each do |key, value|
+              category.__send__("#{key}=", value)
+            end
+          end
+        end
+
+        contributors.each do |contributor_info|
+          maker.channel.contributors.new_contributor do |contributor|
+            contributor_info.each do |key, value|
+              contributor.__send__("#{key}=", value)
+            end
+          end
+        end
+
+        generator.each do |key, value|
+          maker.channel.generator do |g|
+            g.__send__("#{key}=", value)
+          end
+        end
+
+        maker.channel.icon = icon
+
+        maker.channel.about = about
+        maker.channel.link = link
+        maker.channel.logo = logo
+        maker.channel.rights = rights
+        maker.channel.title = title
+        maker.channel.description = description
+        maker.channel.updated = updated
+
+        if with_dc
+          @dc_elems.each do |var, value|
+            if var == :date
+              maker.channel.new_dc_date(value)
+            else
+              maker.channel.__send__("dc_#{var}=", value)
+            end
+          end
+        end
+
+        setup_dummy_item_atom(maker)
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("atom") do |maker|
+        feed.setup_maker(maker)
+      end
+      assert_not_nil(new_feed)
+
+      new_authors = new_feed.authors.collect do |author|
+        {
+          :name => author.name.content,
+          :uri => author.uri.content,
+          :email => author.email.content,
+        }
+      end
+      assert_equal(authors, new_authors)
+
+      new_categories = new_feed.categories.collect do |category|
+        {
+          :term => category.term,
+          :scheme => category.scheme,
+          :label => category.label,
+        }.reject {|key, value| value.nil?}
+      end
+      assert_equal(categories, new_categories)
+
+      new_contributors = new_feed.contributors.collect do |contributor|
+        info = {}
+        info[:name] = contributor.name.content
+        info[:uri] = contributor.uri.content if contributor.uri
+        info[:email] = contributor.email.content if contributor.email
+        info
+      end
+      assert_equal(contributors, new_contributors)
+
+      new_generator = {
+        :uri => new_feed.generator.uri,
+        :version => new_feed.generator.version,
+        :content => new_feed.generator.content,
+      }
+      assert_equal(generator, new_generator)
+
+      assert_equal(icon, new_feed.icon.content)
+      assert_equal(about, new_feed.id.content)
+      assert_equal(link, new_feed.link.href)
+      assert_equal(logo, new_feed.logo.content)
+      assert_equal(rights, new_feed.rights.content)
+      assert_equal(description, new_feed.subtitle.content)
+      assert_equal(title, new_feed.title.content)
+      assert_equal(updated, new_feed.updated.content)
+
+      if with_dc
+        @dc_elems.each do |var, value|
+          if var == :date
+            assert_equal([updated, value],
+                         new_feed.dc_dates.collect {|date| date.value})
+          else
+            assert_equal(value, new_feed.__send__("dc_#{var}"))
+          end
+        end
+      end
+
+      assert_equal(1, new_feed.items.size)
+    end
+
+    def test_setup_maker_feed_without_dc
+      test_setup_maker_feed(false)
+    end
+
+    def test_setup_maker_items(for_backward_compatibility=false)
+      title = "TITLE"
+      link = "http://hoge.com/"
+      description = "text hoge fuga"
+      updated = Time.now
+
+      item_size = 5
+      feed = RSS::Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        item_size.times do |i|
+          maker.items.new_item do |item|
+            item.title = "#{title}#{i}"
+            item.link = "#{link}#{i}"
+            item.description = "#{description}#{i}"
+            item.updated = updated + i * 60
+          end
+        end
+      end
+
+      new_feed = RSS::Maker.make("atom") do |maker|
+        feed.items.each do |item|
+          if for_backward_compatibility
+            item.setup_maker(maker)
+          else
+            item.setup_maker(maker.items)
+          end
+        end
+
+        feed.items.clear
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(item_size, new_feed.items.size)
+      new_feed.items.each_with_index do |item, i|
+        assert_equal("#{title}#{i}", item.title.content)
+        assert_equal("#{link}#{i}", item.link.href)
+        assert_equal("#{description}#{i}", item.summary.content)
+        assert_equal(updated + i * 60, item.updated.content)
+      end
+    end
+
+    def test_setup_maker_items_sort
+      title = "TITLE"
+      link = "http://hoge.com/"
+      summary = "text hoge fuga"
+      updated = Time.now
+
+      feed_size = 5
+      feed = RSS::Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        feed_size.times do |i|
+          entry_class = RSS::Atom::Feed::Entry
+          entry = entry_class.new
+          entry.title = entry_class::Title.new(:content => "#{title}#{i}")
+          entry.links << entry_class::Link.new(:href => "#{link}#{i}")
+          entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}")
+          entry.updated = entry_class::Updated.new(:content => updated + i * 60)
+          entry.setup_maker(maker.items)
+        end
+        maker.items.do_sort = false
+      end
+      assert_equal(feed_size, feed.entries.size)
+      feed.entries.each_with_index do |entry, i|
+        assert_equal("#{title}#{i}", entry.title.content)
+        assert_equal("#{link}#{i}", entry.link.href)
+        assert_equal("#{summary}#{i}", entry.summary.content)
+      end
+
+
+      feed = RSS::Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+
+        feed_size.times do |i|
+          entry_class = RSS::Atom::Feed::Entry
+          entry = entry_class.new
+          entry.title = entry_class::Title.new(:content => "#{title}#{i}")
+          entry.links << entry_class::Link.new(:href => "#{link}#{i}")
+          entry.summary = entry_class::Summary.new(:content => "#{summary}#{i}")
+          entry.updated = entry_class::Updated.new(:content => updated + i * 60)
+          entry.setup_maker(maker.items)
+        end
+        maker.items.do_sort = true
+       end
+      assert_equal(feed_size, feed.entries.size)
+      feed.entries.reverse.each_with_index do |entry, i|
+        assert_equal("#{title}#{i}", entry.title.content)
+        assert_equal("#{link}#{i}", entry.link.href)
+        assert_equal("#{summary}#{i}", entry.summary.content)
+      end
+    end
+
+    def test_setup_maker_items_backward_compatibility
+      test_setup_maker_items(true)
+    end
+
+    def test_setup_maker
+      encoding = "EUC-JP"
+      standalone = true
+      
+      href = 'a.xsl'
+      type = 'text/xsl'
+      title = 'sample'
+      media = 'printer'
+      charset = 'UTF-8'
+      alternate = 'yes'
+
+      feed = RSS::Maker.make("atom") do |maker|
+        maker.encoding = encoding
+        maker.standalone = standalone
+
+        maker.xml_stylesheets.new_xml_stylesheet do |xss|
+          xss.href = href
+          xss.type = type
+          xss.title = title
+          xss.media = media
+          xss.charset = charset
+          xss.alternate = alternate
+        end
+
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("atom") do |maker|
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(["atom", "1.0", "feed"], new_feed.feed_info)
+      assert_equal(encoding, new_feed.encoding)
+      assert_equal(standalone, new_feed.standalone)
+
+      xss = new_feed.xml_stylesheets.first
+      assert_equal(1, new_feed.xml_stylesheets.size)
+      assert_equal(href, xss.href)
+      assert_equal(type, xss.type)
+      assert_equal(title, xss.title)
+      assert_equal(media, xss.media)
+      assert_equal(charset, xss.charset)
+      assert_equal(alternate, xss.alternate)
+    end
+
+    def test_setup_maker_full
+      encoding = "EUC-JP"
+      standalone = true
+
+      href = 'a.xsl'
+      type = 'text/xsl'
+      title = 'sample'
+      media = 'printer'
+      charset = 'UTF-8'
+      alternate = 'yes'
+
+      channel_about = "http://hoge.com"
+      channel_title = "fugafuga"
+      channel_link = "http://hoge.com"
+      channel_description = "fugafugafugafuga"
+      channel_author = "Bob"
+
+      image_url = "http://hoge.com/hoge.png"
+
+      item_title = "TITLE"
+      item_link = "http://hoge.com/"
+      item_description = "text hoge fuga"
+
+      entry_size = 5
+      feed = RSS::Maker.make("atom") do |maker|
+        maker.encoding = encoding
+        maker.standalone = standalone
+
+        maker.xml_stylesheets.new_xml_stylesheet do |xss|
+          xss.href = href
+          xss.type = type
+          xss.title = title
+          xss.media = media
+          xss.charset = charset
+          xss.alternate = alternate
+        end
+
+        maker.channel.about = channel_about
+        maker.channel.title = channel_title
+        maker.channel.link = channel_link
+        maker.channel.description = channel_description
+        maker.channel.author = channel_author
+        @dc_elems.each do |var, value|
+          maker.channel.__send__("dc_#{var}=", value)
+        end
+
+        maker.image.url = image_url
+
+        entry_size.times do |i|
+          maker.items.new_item do |item|
+            item.title = "#{item_title}#{i}"
+            item.link = "#{item_link}#{i}"
+            item.description = "#{item_description}#{i}"
+
+            @dc_elems.each do |var, value|
+              item.__send__("dc_#{var}=", value)
+            end
+          end
+        end
+      end
+
+      new_feed = RSS::Maker.make("atom") do |maker|
+        feed.setup_maker(maker)
+      end
+
+      assert_equal(["atom", "1.0", "feed"], new_feed.feed_info)
+      assert_equal(encoding, new_feed.encoding)
+      assert_equal(standalone, new_feed.standalone)
+
+      xss = new_feed.xml_stylesheets.first
+      assert_equal(1, new_feed.xml_stylesheets.size)
+      assert_equal(href, xss.href)
+      assert_equal(type, xss.type)
+      assert_equal(title, xss.title)
+      assert_equal(media, xss.media)
+      assert_equal(charset, xss.charset)
+      assert_equal(alternate, xss.alternate)
+
+      assert_equal(channel_title, new_feed.title.content)
+      assert_equal(channel_link, new_feed.link.href)
+      assert_equal(channel_description, new_feed.subtitle.content)
+      assert_equal(channel_author, new_feed.author.name.content)
+      assert_equal(image_url, new_feed.logo.content)
+      @dc_elems.each do |var, value|
+        assert_equal(value, new_feed.__send__("dc_#{var}"))
+      end
+
+      assert_equal(entry_size, new_feed.entries.size)
+      new_feed.entries.each_with_index do |entry, i|
+        assert_equal("#{item_title}#{i}", entry.title.content)
+        assert_equal("#{item_link}#{i}", entry.link.href)
+        assert_equal("#{item_description}#{i}", entry.summary.content)
+
+        @dc_elems.each do |var, value|
+          assert_equal(value, entry.__send__("dc_#{var}"))
+        end
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_maker_slash.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_slash.rb	(revision 0)
+++ ruby_1_8/test/rss/test_maker_slash.rb	(revision 13747)
@@ -0,0 +1,37 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestMakerSlash < TestCase
+    def setup
+      @elements = {
+        "section" => "articles",
+        "department" => "not-an-ocean-unless-there-are-lobsters",
+        "comments" => 177,
+        "hit_parades" => [177, 155, 105, 33, 6, 3, 0],
+      }
+    end
+
+    def test_rss10
+      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("slash_#{name}=", value)
+        end
+      end
+
+      item = rss.items.last
+      assert_not_nil(item)
+      assert_slash_elements(item)
+    end
+
+    private
+    def assert_slash_elements(target)
+      super(@elements, target)
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_setup_maker_1.0.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_1.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_setup_maker_1.0.rb	(revision 13747)
@@ -87,10 +87,15 @@
         @sy_elems.each do |var, value|
           maker.channel.__send__("sy_#{var}=", value)
         end
+
+        setup_dummy_item(maker)
       end
 
       new_rss = RSS::Maker.make("1.0") do |maker|
         rss.channel.setup_maker(maker)
+        rss.items.each do |item|
+          item.setup_maker(maker)
+        end
       end
       channel = new_rss.channel
       
@@ -98,7 +103,7 @@
       assert_equal(title, channel.title)
       assert_equal(link, channel.link)
       assert_equal(description, channel.description)
-      assert_equal(true, channel.items.Seq.lis.empty?)
+      assert_equal(1, channel.items.Seq.lis.size)
       assert_nil(channel.image)
       assert_nil(channel.textinput)
 
@@ -128,11 +133,16 @@
         @dc_elems.each do |var, value|
           maker.image.__send__("dc_#{var}=", value)
         end
+
+        setup_dummy_item(maker)
       end
       
       new_rss = RSS::Maker.make("1.0") do |maker|
         rss.channel.setup_maker(maker)
         rss.image.setup_maker(maker)
+        rss.items.each do |item|
+          item.setup_maker(maker)
+        end
       end
       
       image = new_rss.image
@@ -164,11 +174,16 @@
         @dc_elems.each do |var, value|
           maker.textinput.__send__("dc_#{var}=", value)
         end
+
+        setup_dummy_item(maker)
       end
       
       new_rss = RSS::Maker.make("1.0") do |maker|
         rss.channel.setup_maker(maker)
         rss.textinput.setup_maker(maker)
+        rss.items.each do |item|
+          item.setup_maker(maker)
+        end
       end
       
       textinput = new_rss.textinput
@@ -247,8 +262,8 @@
       
         assert_equal(@trackback_elems[:ping], item.trackback_ping)
         assert_equal(@trackback_elems[:about].size, item.trackback_abouts.size)
-        item.trackback_abouts.each_with_index do |about, i|
-          assert_equal(@trackback_elems[:about][i], about.value)
+        item.trackback_abouts.each_with_index do |about, j|
+          assert_equal(@trackback_elems[:about][j], about.value)
         end
       end
     end
@@ -333,6 +348,7 @@
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
       
       new_rss = RSS::Maker.make("1.0") do |maker|
@@ -522,8 +538,8 @@
       
         assert_equal(@trackback_elems[:ping], item.trackback_ping)
         assert_equal(@trackback_elems[:about].size, item.trackback_abouts.size)
-        item.trackback_abouts.each_with_index do |about, i|
-          assert_equal(@trackback_elems[:about][i], about.value)
+        item.trackback_abouts.each_with_index do |about, j|
+          assert_equal(@trackback_elems[:about][j], about.value)
         end
       end
 
Index: ruby_1_8/test/rss/test_parser_atom_entry.rb
===================================================================
--- ruby_1_8/test/rss/test_parser_atom_entry.rb	(revision 0)
+++ ruby_1_8/test/rss/test_parser_atom_entry.rb	(revision 13747)
@@ -0,0 +1,163 @@
+require "rss-testcase"
+
+require "rss/atom"
+
+module RSS
+  class TestParserAtom < TestCase
+    def test_entry_validation
+      assert_ns("", Atom::URI) do
+        Parser.parse(<<-EOA)
+<entry/>
+EOA
+      end
+
+      assert_ns("", Atom::URI) do
+        Parser.parse(<<-EOA)
+<entry xmlns="hoge"/>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "id", "entry") do
+<entry xmlns="#{Atom::URI}"/>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "title", "entry") do
+<entry xmlns="#{Atom::URI}">
+  <id>urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746</id>
+</entry>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "updated", "entry") do
+<entry xmlns="#{Atom::URI}">
+  <id>urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746</id>
+  <title>Example Entry</title>
+</entry>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "author", "entry") do
+<entry xmlns="#{Atom::URI}">
+  <id>urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746</id>
+  <title>Example Entry</title>
+  <updated>2003-10-10T18:30:02Z</updated>
+</entry>
+EOA
+      end
+
+      assert_parse(<<-EOA, :nothing_raised) do
+<entry xmlns="#{Atom::URI}">
+  <id>urn:uuid:506e336c-a26e-4457-917b-b89dca7ae746</id>
+  <title>Example Entry</title>
+  <updated>2003-10-10T18:30:02Z</updated>
+  <author>
+    <name>A person</name>
+  </author>
+</entry>
+EOA
+      end
+    end
+
+    def test_entry
+      entry = RSS::Parser.parse(<<-EOA)
+<?xml version="1.0" encoding="utf-8"?>
+<entry xmlns="http://www.w3.org/2005/Atom">
+  <author>
+    <name>A person</name>
+  </author>
+  <title>Atom-Powered Robots Run Amok</title>
+  <link href="http://example.org/2003/12/13/atom03"/>
+  <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <summary>Some text.</summary>
+</entry>
+EOA
+      assert_not_nil(entry)
+      assert_equal("Atom-Powered Robots Run Amok", entry.title.content)
+      assert_equal("http://example.org/2003/12/13/atom03", entry.link.href)
+      assert_equal("urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
+                   entry.id.content)
+      assert_equal(Time.parse("2003-12-13T18:30:02Z"), entry.updated.content)
+      assert_equal("Some text.", entry.summary.content)
+    end
+
+    def test_entry_author
+      assert_atom_person("author", method(:make_entry_document)) do |entry|
+        assert_equal(2, entry.authors.size)
+        entry.authors.last
+      end
+    end
+
+    def test_entry_category
+      assert_atom_category(method(:make_entry_document)) do |entry|
+        assert_equal(1, entry.categories.size)
+        entry.category
+      end
+    end
+
+    def test_entry_content_text
+      assert_atom_content(method(:make_entry_document)) do |entry|
+        entry.content
+      end
+    end
+
+    def test_entry_contributor
+      assert_atom_person("contributor", method(:make_entry_document)) do |entry|
+        assert_equal(1, entry.contributors.size)
+        entry.contributor
+      end
+    end
+
+    def test_entry_id
+      entry = RSS::Parser.parse(make_entry_document)
+      assert_equal(ENTRY_ID, entry.id.content)
+    end
+
+    def test_entry_link
+      assert_atom_link(method(:make_entry_document)) do |entry|
+        assert_equal(1, entry.links.size)
+        entry.link
+      end
+    end
+
+    def test_published
+      generator = method(:make_entry_document)
+      assert_atom_date_construct("published", generator) do |entry|
+        entry.published
+      end
+    end
+
+    def test_entry_rights
+      generator = method(:make_entry_document)
+      assert_atom_text_construct("rights", generator) do |entry|
+        entry.rights
+      end
+    end
+
+    def test_entry_source
+      generator = method(:make_entry_document_with_open_source)
+      assert_atom_source(generator) do |entry|
+        assert_not_nil(entry.source)
+        entry.source
+      end
+    end
+
+    def test_entry_summary
+      generator = method(:make_entry_document)
+      assert_atom_text_construct("summary", generator) do |entry|
+        entry.summary
+      end
+    end
+
+    def test_entry_title
+      entry = RSS::Parser.parse(make_entry_document)
+      assert_equal(ENTRY_TITLE, entry.title.content)
+    end
+
+    def test_entry_updated
+      entry = RSS::Parser.parse(make_entry_document)
+      assert_equal(Time.parse(ENTRY_UPDATED), entry.updated.content)
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_2.0.rb
===================================================================
--- ruby_1_8/test/rss/test_2.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_2.0.rb	(revision 13747)
@@ -2,8 +2,6 @@
 
 require "rss-testcase"
 
-require "rss/2.0"
-
 module RSS
   class TestRSS20Core < TestCase
 
@@ -17,6 +15,7 @@
       standalone = false
       
       rss = Rss.new(@rss_version, version, encoding, standalone)
+      setup_rss20(rss)
       
       doc = REXML::Document.new(rss.to_s(false))
       
@@ -48,7 +47,9 @@
           {:href => "a.css", :type => "text/css"},
         ],
       ].each do |attrs_ary|
-        assert_xml_stylesheet_pis(attrs_ary, Rss.new(@rss_version))
+        rss = Rss.new(@rss_version)
+        setup_rss20(rss)
+        assert_xml_stylesheet_pis(attrs_ary, rss)
       end
     end
 
@@ -253,6 +254,10 @@
       pubDate = Time.parse("Sat, 07 Sep 2002 00:00:01 GMT")
 
       channel = Rss::Channel.new
+      channel.title = "title"
+      channel.link = "http://example.com/"
+      channel.description = "description"
+
       item = Rss::Channel::Item.new
       channel.items << item
       
@@ -378,13 +383,28 @@
       rss = RSS::Parser.parse(make_sample_rss20)
       assert_equal(rss.to_s, rss.to_xml)
       assert_equal(rss.to_s, rss.to_xml("2.0"))
-      rss09 = RSS::Parser.parse(rss.to_xml("0.91"))
+      rss09_xml = rss.to_xml("0.91") do |maker|
+        setup_dummy_image(maker)
+      end
+      rss09 = RSS::Parser.parse(rss09_xml)
       assert_equal("0.91", rss09.rss_version)
       rss10 = rss.to_xml("1.0") do |maker|
         maker.channel.about = "http://www.example.com/index.rdf"
       end
       rss10 = RSS::Parser.parse(rss10)
       assert_equal("1.0", rss10.rss_version)
+
+      atom_xml = rss.to_xml("atom1.0") do |maker|
+        maker.channel.id = "http://www.example.com/atom.xml"
+        maker.channel.author = "Alice"
+        maker.channel.updated = Time.now
+        maker.items.each do |item|
+          item.author = "Bob"
+          item.updated = Time.now
+        end
+      end
+      atom = RSS::Parser.parse(atom_xml)
+      assert_equal(["atom", "1.0", "feed"], atom.feed_info)
     end
   end
 end
Index: ruby_1_8/test/rss/rss-assertions.rb
===================================================================
--- ruby_1_8/test/rss/rss-assertions.rb	(revision 13746)
+++ ruby_1_8/test/rss/rss-assertions.rb	(revision 13747)
@@ -1,19 +1,7 @@
-module Test
-  module Unit
-    module Assertions
-      # For backward compatibility
-      unless instance_methods.include?("assert_raise")
-        def assert_raise(*args, &block)
-          assert_raises(*args, &block)
-        end
-      end
-    end
-  end
-end
+require 'erb'
 
 module RSS
   module Assertions
-    
     def assert_parse(rss, assert_method, *args)
       __send__("assert_#{assert_method}", *args) do
         ::RSS::Parser.parse(rss)
@@ -104,6 +92,7 @@
           flunk("Not raise NotSetError")
         rescue ::RSS::NotSetError => e
           assert_equal(name, e.name)
+          assert_kind_of(Array, variables)
           assert_equal(variables.sort, e.variables.sort)
         end
       end
@@ -143,10 +132,13 @@
     
     def assert_xml_stylesheet_pis(attrs_ary, rss=nil)
       _wrap_assertion do
-        rss ||= ::RSS::RDF.new()
+        if rss.nil?
+          rss = ::RSS::RDF.new
+          setup_rss10(rss)
+        end
         xss_strs = []
         attrs_ary.each do |attrs|
-          xss = ::RSS::XMLStyleSheet.new(*attrs)
+          xss = ::RSS::XMLStyleSheet.new(attrs)
           xss_strs.push(xss.to_s)
           rss.xml_stylesheets.push(xss)
         end
@@ -163,239 +155,650 @@
       end
     end
 
-    
-    def assert_channel10(attrs, channel)
+
+    def assert_atom_person(tag_name, generator)
       _wrap_assertion do
-        n_attrs = normalized_attrs(attrs)
-        
-        names = %w(about title link description)
-        assert_attributes(attrs, names, channel)
+        name = "Mark Pilgrim"
+        uri = "http://example.org/"
+        email = "f8dy@e..."
 
-        %w(image items textinput).each do |name|
-          value = n_attrs[name]
-          if value
-            target = channel.__send__(name)
-            __send__("assert_channel10_#{name}", value, target)
+        assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name)
+  <#{tag_name}/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :missing_tag, "name", tag_name)
+  <#{tag_name}>
+    <uri>#{uri}</uri>
+    <email>#{email}</email>
+  </#{tag_name}>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <#{tag_name}>
+    <name>#{name}</name>
+  </#{tag_name}>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <#{tag_name}>
+    <name>#{name}</name>
+    <uri>#{uri}</uri>
+    <email>#{email}</email>
+  </#{tag_name}>
+EOA
+
+        person = yield(feed)
+        assert_not_nil(person)
+        assert_equal(name, person.name.content)
+        assert_equal(uri, person.uri.content)
+        assert_equal(email, person.email.content)
+      end
+    end
+
+    def assert_atom_category(generator)
+      _wrap_assertion do
+        term = "Music"
+        scheme = "http://xmlns.com/wordnet/1.6/"
+        label = "music"
+
+        missing_args = [:missing_attribute, "category", "term"]
+        assert_parse(generator.call(<<-EOA), *missing_args)
+  <category/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), *missing_args)
+  <category scheme="#{scheme}" label="#{label}"/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <category term="#{term}"/>
+EOA
+
+      feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <category term="#{term}" scheme="#{scheme}" label="#{label}"/>
+EOA
+
+        category = yield(feed)
+        assert_not_nil(category)
+        assert_equal(term, category.term)
+        assert_equal(scheme, category.scheme)
+        assert_equal(label, category.label)
+      end
+    end
+
+    def assert_atom_link(generator)
+      _wrap_assertion do
+        href = "http://example.org/feed.atom"
+        rel = "self"
+        type = "application/atom+xml"
+        hreflang = "en"
+        title = "Atom"
+        length = "1024"
+
+        assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href")
+  <link/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :missing_attribute, "link", "href")
+  <link rel="#{rel}" type="#{type}" hreflang="#{hreflang}"
+        title="#{title}" length="#{length}"/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <link href="#{href}"/>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <link href="#{href}" rel="#{rel}" type="#{type}" hreflang="#{hreflang}"
+        title="#{title}" length="#{length}"/>
+EOA
+
+        link = yield(feed)
+        assert_not_nil(link)
+        assert_equal(href, link.href)
+        assert_equal(rel, link.rel)
+        assert_equal(type, link.type)
+        assert_equal(hreflang, link.hreflang)
+        assert_equal(title, link.title)
+        assert_equal(length, link.length)
+
+
+        href = "http://example.org/index.html.ja"
+        parent = link.parent.tag_name
+        return if parent == "source"
+
+        optional_attributes = %w(hreflang="ja" type="text/html")
+        0.upto(optional_attributes.size) do |i|
+          combination(optional_attributes, i).each do |attributes|
+            attrs = attributes.join(" ")
+            assert_parse(generator.call(<<-EOA), :too_much_tag, "link", parent)
+  <link rel="alternate" #{attrs} href="#{href}"/>
+  <link rel="alternate" #{attrs} href="#{href}"/>
+EOA
           end
         end
       end
     end
 
-    def assert_channel10_image(attrs, image)
+    def assert_atom_generator(generator)
       _wrap_assertion do
-        assert_attributes(attrs, %w(resource), image)
+        uri = "http://www.example.com/"
+        version = "1.0"
+        content = "Example Toolkit"
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <generator/>
+EOA
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <generator uri="#{uri}" version="#{version}"/>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <generator uri="#{uri}" version="#{version}">#{content}</generator>
+EOA
+
+        gen = yield(feed)
+        assert_not_nil(gen)
+        assert_equal(uri, gen.uri)
+        assert_equal(version, gen.version)
+        assert_equal(content, gen.content)
       end
     end
-    
-    def assert_channel10_textinput(attrs, textinput)
+
+    def assert_atom_icon(generator)
       _wrap_assertion do
-        assert_attributes(attrs, %w(resource), textinput)
+        content = "http://www.example.com/example.png"
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <icon/>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <icon>#{content}</icon>
+EOA
+
+        icon = yield(feed)
+        assert_not_nil(icon)
+        assert_equal(content, icon.content)
       end
     end
 
-    def assert_channel10_items(attrs, items)
+    def assert_atom_text_construct(tag_name, generator)
       _wrap_assertion do
-        assert_equal(items.resources, items.Seq.lis.collect {|x| x.resource})
-        items.Seq.lis.each_with_index do |li, i|
-          assert_attributes(attrs[i], %w(resource), li)
+        [nil, "text", "html"].each do |type|
+          attr = ""
+          attr = " type=\"#{type}\""if type
+          assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <#{tag_name}#{attr}/>
+EOA
         end
+
+        assert_parse(generator.call(<<-EOA), :missing_tag, "div", tag_name)
+  <#{tag_name} type="xhtml"/>
+EOA
+
+        args = ["x", Atom::URI, tag_name]
+        assert_parse(generator.call(<<-EOA), :not_expected_tag, *args)
+  <#{tag_name} type="xhtml"><x/></#{tag_name}>
+EOA
+
+        invalid_value = "invalid"
+        args = ["type", invalid_value]
+        assert_parse(generator.call(<<-EOA), :not_available_value, *args)
+  <#{tag_name} type="#{invalid_value}"/>
+EOA
+
+        [
+         [nil, "A lot of effort went into making this effortless"],
+         ["text", "A lot of effort went into making this effortless"],
+         ["html", "A <em>lot</em> of effort went into making this effortless"],
+        ].each do |type, content|
+          attr = ""
+          attr = " type=\"#{type}\"" if type
+          feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <#{tag_name}#{attr}>#{h content}</#{tag_name}>
+EOA
+
+          element = yield(feed)
+          assert_not_nil(element)
+          assert_equal(type, element.type)
+          assert_equal(content, element.content)
+        end
+
+        [false, true].each do |with_space|
+          xhtml_uri = "http://www.w3.org/1999/xhtml"
+          xhtml_content = "<div xmlns=\"#{xhtml_uri}\">abc</div>"
+          xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                                {"xmlns" => xhtml_uri},
+                                                ["abc"])
+          content = xhtml_content
+          content = "  #{content}  " if with_space
+          feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <#{tag_name} type="xhtml">#{content}</#{tag_name}>
+EOA
+
+          element = yield(feed)
+          assert_not_nil(element)
+          assert_equal("xhtml", element.type)
+          assert_equal(xhtml_content, element.content)
+          assert_equal(xhtml_element, element.xhtml)
+        end
       end
     end
 
-    def assert_image10(attrs, image)
+    def assert_atom_date_construct(tag_name, generator)
       _wrap_assertion do
-        names = %w(about title url link)
-        assert_attributes(attrs, names, image)
+        args = [tag_name, ""]
+        assert_parse(generator.call(<<-EOR), :not_available_value, *args)
+  <#{tag_name}/>
+EOR
+
+        [
+         ["xxx", false],
+         ["2007", false],
+         ["2007/02/09", true],
+        ].each do |invalid_value, can_parse|
+          assert_not_available_value(tag_name, invalid_value) do
+            RSS::Parser.parse(generator.call(<<-EOR))
+  <#{tag_name}>#{invalid_value}</#{tag_name}>
+EOR
+          end
+
+          feed = RSS::Parser.parse(generator.call(<<-EOR), false)
+  <#{tag_name}>#{invalid_value}</#{tag_name}>
+EOR
+          value = yield(feed).content
+          if can_parse
+            assert_equal(Time.parse(invalid_value), value)
+          else
+            assert_nil(value)
+          end
+        end
+
+        [
+         "2003-12-13T18:30:02Z",
+         "2003-12-13T18:30:02.25Z",
+         "2003-12-13T18:30:02+01:00",
+         "2003-12-13T18:30:02.25+01:00",
+        ].each do |valid_value|
+          assert_parse(generator.call(<<-EOR), :nothing_raised)
+  <#{tag_name}>#{valid_value}</#{tag_name}>
+EOR
+
+          feed = RSS::Parser.parse(generator.call(<<-EOR))
+  <#{tag_name}>#{valid_value}</#{tag_name}>
+EOR
+          assert_equal(Time.parse(valid_value), yield(feed).content)
+        end
       end
     end
 
-    def assert_items10(attrs, items)
+    def assert_atom_logo(generator)
       _wrap_assertion do
-        names = %w(about title link description)
-        items.each_with_index do |item, i|
-          assert_attributes(attrs[i], names, item)
-        end
+        content = "http://www.example.com/example.png"
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <logo/>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <logo>#{content}</logo>
+EOA
+
+        logo = yield(feed)
+        assert_not_nil(logo)
+        assert_equal(content, logo.content)
       end
     end
 
-    def assert_textinput10(attrs, textinput)
+    def assert_atom_content(generator, &getter)
       _wrap_assertion do
-        names = %w(about title description name link)
-        assert_attributes(attrs, names, textinput)
+        assert_atom_content_inline_text(generator, &getter)
+        assert_atom_content_inline_xhtml(generator, &getter)
+        assert_atom_content_inline_other(generator, &getter)
+        assert_atom_content_out_of_line(generator, &getter)
       end
     end
 
-
-    def assert_channel09(attrs, channel)
+    def assert_atom_content_inline_text(generator)
       _wrap_assertion do
-        n_attrs = normalized_attrs(attrs)
+        [nil, "text", "html"].each do |type|
+          content = "<content"
+          content << " type='#{type}'" if type
 
-        names = %w(title description link language rating
-                   copyright pubDate lastBuildDate docs
-                   managingEditor webMaster)
-        assert_attributes(attrs, names, channel)
-        
-        %w(skipHours skipDays).each do |name|
-          value = n_attrs[name]
-          if value
-            target = channel.__send__(name)
-            __send__("assert_channel09_#{name}", value, target)
+          suffix = "/>"
+          assert_parse(generator.call(content + suffix), :nothing_raised)
+          suffix = ">xxx</content>"
+          assert_parse(generator.call(content + suffix), :nothing_raised)
+        end
+
+        [
+         ["text", "sample content"],
+         ["text/plain", "sample content"],
+         ["html", "<em>sample</em> content"]
+        ].each do |type, content_content|
+          feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <content type="#{type}">#{h content_content}</content>
+EOA
+          content = yield(feed)
+          assert_equal(type, content.type)
+          if %w(text html).include?(type)
+            assert(content.inline_text?)
+          else
+            assert(!content.inline_text?)
           end
+          if type == "html"
+            assert(content.inline_html?)
+          else
+            assert(!content.inline_html?)
+          end
+          assert(!content.inline_xhtml?)
+          if type == "text/plain"
+            assert(content.inline_other?)
+            assert(content.inline_other_text?)
+          else
+            assert(!content.inline_other?)
+            assert(!content.inline_other_text?)
+          end
+          assert(!content.inline_other_xml?)
+          assert(!content.inline_other_base64?)
+          assert(!content.out_of_line?)
+          assert(!content.have_xml_content?)
+          assert_equal(content_content, content.content)
         end
       end
     end
 
-    def assert_channel09_skipDays(contents, skipDays)
+    def assert_atom_content_inline_xhtml(generator)
       _wrap_assertion do
-        days = skipDays.days
-        contents.each_with_index do |content, i|
-          assert_equal(content, days[i].content)
-        end
+        args = ["div", "content"]
+        assert_parse(generator.call(<<-EOA), :missing_tag, *args)
+  <content type="xhtml"/>
+EOA
+
+        args = ["x", Atom::URI, "content"]
+        assert_parse(generator.call(<<-EOA), :not_expected_tag, *args)
+  <content type="xhtml"><x/></content>
+EOA
+
+        xhtml_uri = "http://www.w3.org/1999/xhtml"
+        xhtml_content = "<div xmlns=\"#{xhtml_uri}\">abc</div>"
+        xhtml_element = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                              {"xmlns" => xhtml_uri},
+                                              ["abc"])
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <content type="xhtml">#{xhtml_content}</content>
+EOA
+
+        content = yield(feed)
+        assert_not_nil(content)
+        assert_equal("xhtml", content.type)
+        assert(!content.inline_text?)
+        assert(!content.inline_html?)
+        assert(content.inline_xhtml?)
+        assert(!content.inline_other?)
+        assert(!content.inline_other_text?)
+        assert(!content.inline_other_xml?)
+        assert(!content.inline_other_base64?)
+        assert(!content.out_of_line?)
+        assert(content.have_xml_content?)
+        assert_equal(xhtml_content, content.content)
+        assert_equal(xhtml_element, content.xhtml)
       end
     end
-    
-    def assert_channel09_skipHours(contents, skipHours)
+
+    def assert_atom_content_inline_other(generator, &getter)
       _wrap_assertion do
-        hours = skipHours.hours
-        contents.each_with_index do |content, i|
-          assert_equal(content.to_i, hours[i].content)
-        end
+        assert_atom_content_inline_other_text(generator, &getter)
+        assert_atom_content_inline_other_xml(generator, &getter)
       end
     end
-    
-    def assert_image09(attrs, image)
+
+    def assert_atom_content_inline_other_text(generator)
       _wrap_assertion do
-        names = %w(url link title description)
-        names << ["width", :integer]
-        names << ["height", :integer]
-        assert_attributes(attrs, names, image)
+        require "zlib"
+
+        type = "application/zip"
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <content type="#{type}"/>
+EOA
+
+        text = ""
+        char = "a"
+        100.times do |i|
+          text << char
+          char.succ!
+        end
+        base64_content = Base64.encode64(Zlib::Deflate.deflate(text))
+
+        [false, true].each do |with_space|
+          xml_content = base64_content
+          xml_content = "  #{base64_content}" if with_space
+          feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <content type="#{type}">#{xml_content}</content>
+EOA
+
+          content = yield(feed)
+          assert_not_nil(content)
+          assert_equal(type, content.type)
+          assert(!content.inline_text?)
+          assert(!content.inline_html?)
+          assert(!content.inline_xhtml?)
+          assert(content.inline_other?)
+          assert(!content.inline_other_text?)
+          assert(!content.inline_other_xml?)
+          assert(content.inline_other_base64?)
+          assert(!content.out_of_line?)
+          assert(!content.have_xml_content?)
+          assert_equal(text, Zlib::Inflate.inflate(content.content))
+
+          xml = REXML::Document.new(content.to_s).root
+          assert_rexml_element([], {"type" => type}, base64_content, xml)
+        end
       end
     end
 
-    def assert_items09(attrs, items)
+    def assert_atom_content_inline_other_xml(generator)
       _wrap_assertion do
-        names = %w(title link description)
-        items.each_with_index do |item, i|
-          assert_attributes(attrs[i], names, item)
-        end
+        type = "image/svg+xml"
+
+        assert_parse(generator.call(<<-EOA), :nothing_raised)
+  <content type="#{type}"/>
+EOA
+
+        svg_uri = "http://www.w3.org/2000/svg"
+        svg_width = "50pt"
+        svg_height = "20pt"
+        svg_version = "1.0"
+        text_x = "15"
+        text_y = "15"
+        text = "text"
+        svg_content = <<-EOS
+<svg
+   xmlns="#{svg_uri}"
+   width="#{svg_width}"
+   height="#{svg_height}"
+   version="#{svg_version}"
+><text x="#{text_x}" y="#{text_y}">#{text}</text
+></svg>
+EOS
+
+        text_element = RSS::XML::Element.new("text", nil, svg_uri,
+                                             {
+                                               "x" => text_x,
+                                               "y" => text_y,
+                                             },
+                                             [text])
+        svg_element = RSS::XML::Element.new("svg", nil, svg_uri,
+                                            {
+                                              "xmlns" => svg_uri,
+                                              "width" => svg_width,
+                                              "height" => svg_height,
+                                              "version" => svg_version,
+                                            },
+                                            [text_element])
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <content type="#{type}">#{svg_content}</content>
+EOA
+
+        content = yield(feed)
+        assert_not_nil(content)
+        assert_equal(type, content.type)
+        assert(!content.inline_text?)
+        assert(!content.inline_html?)
+        assert(!content.inline_xhtml?)
+        assert(content.inline_other?)
+        assert(!content.inline_other_text?)
+        assert(content.inline_other_xml?)
+        assert(!content.inline_other_base64?)
+        assert(!content.out_of_line?)
+        assert(content.have_xml_content?)
+        assert_equal(REXML::Document.new(svg_content).to_s.chomp,
+                     REXML::Document.new(content.content).to_s.chomp)
+        assert_equal(svg_element, content.xml)
+        assert_nil(content.xhtml)
       end
     end
-    
-    def assert_textinput09(attrs, textinput)
+
+    def assert_atom_content_out_of_line(generator)
       _wrap_assertion do
-        names = %w(title description name link)
-        assert_attributes(attrs, names, textinput)
+        text_type = "text/plain"
+        text_src = "http://example.com/README.txt"
+
+        missing_args = [:missing_attribute, "content", "type"]
+        # RSS Parser raises error even if this is "should" not "must".
+        assert_parse(generator.call(<<-EOA), *missing_args)
+  <content src="#{text_src}"/>
+EOA
+
+        content_content = "xxx"
+        not_available_value_args = [:not_available_value,
+                                    "content", content_content]
+        assert_parse(generator.call(<<-EOA), *not_available_value_args)
+  <content type="#{text_type}" src="#{text_src}">#{content_content}</content>
+EOA
+
+        feed = RSS::Parser.parse(generator.call(<<-EOA))
+  <content type="#{text_type}" src="#{text_src}"/>
+EOA
+        content = yield(feed)
+        assert_not_nil(content)
+        assert_equal(text_type, content.type)
+        assert_equal(text_src, content.src)
+        assert(!content.inline_text?)
+        assert(!content.inline_html?)
+        assert(!content.inline_xhtml?)
+        assert(!content.inline_other?)
+        assert(!content.inline_other_text?)
+        assert(!content.inline_other_xml?)
+        assert(!content.inline_other_base64?)
+        assert(content.out_of_line?)
+        assert(!content.have_xml_content?)
+        assert_nil(content.xml)
+        assert_nil(content.xhtml)
+        assert_equal("", content.content)
       end
     end
 
-
-    def assert_channel20(attrs, channel)
+    def assert_atom_source(generator, &getter)
       _wrap_assertion do
-        n_attrs = normalized_attrs(attrs)
-        
-        names = %w(title link description language copyright
-                   managingEditor webMaster pubDate
-                   lastBuildDate generator docs rating)
-        names << ["ttl", :integer]
-        assert_attributes(attrs, names, channel)
+        assert_atom_source_author(generator, &getter)
+        assert_atom_source_category(generator, &getter)
+        assert_atom_source_contributor(generator, &getter)
+        assert_atom_source_generator(generator, &getter)
+        assert_atom_source_icon(generator, &getter)
+        assert_atom_source_id(generator, &getter)
+        assert_atom_source_link(generator, &getter)
+        assert_atom_source_logo(generator, &getter)
+        assert_atom_source_rights(generator, &getter)
+        assert_atom_source_subtitle(generator, &getter)
+        assert_atom_source_title(generator, &getter)
+        assert_atom_source_updated(generator, &getter)
+      end
+    end
 
-        %w(cloud categories skipHours skipDays).each do |name|
-          value = n_attrs[name]
-          if value
-            target = channel.__send__(name)
-            __send__("assert_channel20_#{name}", value, target)
-          end
-        end
+    def assert_atom_source_author(generator)
+      assert_atom_person("author", generator) do |feed|
+        source = yield(feed)
+        assert_equal(1, source.authors.size)
+        source.author
       end
     end
 
-    def assert_channel20_skipDays(contents, skipDays)
-      assert_channel09_skipDays(contents, skipDays)
+    def assert_atom_source_category(generator)
+      assert_atom_category(generator) do |feed|
+        source = yield(feed)
+        assert_equal(1, source.categories.size)
+        source.category
+      end
     end
-    
-    def assert_channel20_skipHours(contents, skipHours)
-      assert_channel09_skipHours(contents, skipHours)
-    end
-    
-    def assert_channel20_cloud(attrs, cloud)
-      _wrap_assertion do
-        names = %w(domain path registerProcedure protocol)
-        names << ["port", :integer]
-        assert_attributes(attrs, names, cloud)
+
+    def assert_atom_source_contributor(generator)
+      assert_atom_person("contributor", generator) do |feed|
+        source = yield(feed)
+        assert_equal(1, source.contributors.size)
+        source.contributor
       end
     end
-    
-    def assert_channel20_categories(attrs, categories)
-      _wrap_assertion do
-        names = %w(domain content)
-        categories.each_with_index do |category, i|
-          assert_attributes(attrs[i], names, category)
-        end
+
+    def assert_atom_source_generator(generator)
+      assert_atom_generator(generator) do |feed|
+        yield(feed).generator
       end
     end
-    
-    def assert_image20(attrs, image)
-      _wrap_assertion do
-        names = %w(url link title description)
-        names << ["width", :integer]
-        names << ["height", :integer]
-        assert_attributes(attrs, names, image)
+
+    def assert_atom_source_icon(generator)
+      assert_atom_icon(generator) do |feed|
+        yield(feed).icon
       end
     end
 
-    def assert_items20(attrs, items)
-      _wrap_assertion do
-        names = %w(about title link description)
-        items.each_with_index do |item, i|
-          assert_attributes(attrs[i], names, item)
+    def assert_atom_source_id(generator)
+      id_content = "urn:uuid:a2fb588b-5674-4898-b420-265a734fea69"
+      id = "<id>#{id_content}</id>"
+      feed = RSS::Parser.parse(generator.call(id))
+      assert_equal(id_content, yield(feed).id.content)
+    end
 
-          n_attrs = normalized_attrs(attrs[i])
-
-          %w(source enclosure categories guid).each do |name|
-            value = n_attrs[name]
-            if value
-              target = item.__send__(name)
-              __send__("assert_items20_#{name}", value, target)
-            end
-          end
-        end
+    def assert_atom_source_link(generator)
+      assert_atom_link(generator) do |feed|
+        source = yield(feed)
+        assert_equal(1, source.links.size)
+        source.link
       end
     end
 
-    def assert_items20_source(attrs, source)
-      _wrap_assertion do
-        assert_attributes(attrs, %w(url content), source)
+    def assert_atom_source_logo(generator)
+      assert_atom_logo(generator) do |feed|
+        yield(feed).logo
       end
     end
-    
-    def assert_items20_enclosure(attrs, enclosure)
-      _wrap_assertion do
-        names = ["url", ["length", :integer], "type"]
-        assert_attributes(attrs, names, enclosure)
+
+    def assert_atom_source_rights(generator)
+      assert_atom_text_construct("rights", generator) do |feed|
+        yield(feed).rights
       end
     end
-    
-    def assert_items20_categories(attrs, categories)
-      _wrap_assertion do
-        assert_channel20_categories(attrs, categories)
+
+    def assert_atom_source_subtitle(generator)
+      assert_atom_text_construct("subtitle", generator) do |feed|
+        yield(feed).subtitle
       end
     end
-    
-    def assert_items20_guid(attrs, guid)
-      _wrap_assertion do
-        names = [["isPermaLink", :boolean], ["content"]]
-        assert_attributes(attrs, names, guid)
+
+    def assert_atom_source_title(generator)
+      assert_atom_text_construct("title", generator) do |feed|
+        yield(feed).title
       end
     end
 
-    def assert_textinput20(attrs, textinput)
-      _wrap_assertion do
-        names = %w(title description name link)
-        assert_attributes(attrs, names, textinput)
+    def assert_atom_source_updated(generator)
+      assert_atom_date_construct("updated", generator) do |feed|
+        yield(feed).updated
       end
     end
 
-
     def assert_dublin_core(elems, target)
       _wrap_assertion do
         elems.each do |name, value|
@@ -493,7 +896,1147 @@
         end
       end
     end
-    
+
+    def assert_rexml_element(children, attrs, text, element, text_type=nil)
+      _wrap_assertion do
+        if children
+          children_info = element.elements.collect {|e| [e.namespace, e.name]}
+          assert_equal(children.collect {|uri, name| [uri, name]}.sort,
+                       children_info.sort)
+        end
+        if attrs
+          assert_equal(attrs.collect {|k, v| [k, v]}.sort,
+                       element.attributes.collect {|k, v| [k, v]}.sort)
+        end
+        case text_type
+        when :time
+          assert_not_nil(element.text)
+          assert_equal(Time.parse(text).to_s, Time.parse(element.text).to_s)
+        else
+          assert_equal(text, element.text)
+        end
+      end
+    end
+
+    def _assert_maker_atom_persons(feed_type, maker_readers, feed_readers)
+      _wrap_assertion do
+        persons = []
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          targets.each do |target|
+            person = {
+              :name => target.name,
+              :uri => target.uri,
+              :email => target.email,
+            }
+            persons << person if person[:name]
+          end
+        end
+
+        actual_persons = chain_reader(feed, feed_readers) || []
+        actual_persons = actual_persons.collect do |person|
+          {
+            :name => person.name ? person.name.content : nil,
+            :uri => person.uri ? person.uri.content : nil,
+            :email => person.email ? person.email.content : nil,
+          }
+        end
+        assert_equal(persons, actual_persons)
+      end
+    end
+
+    def assert_maker_atom_persons(feed_type, maker_readers, feed_readers,
+                                  not_set_error_name=nil,
+                                  parent_not_set_error_name=nil,
+                                  parent_not_set_variable=nil)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        args = [feed_type, maker_readers, feed_readers]
+        if parent_not_set_error_name or parent_not_set_variable
+          assert_not_set_error(parent_not_set_error_name,
+                               parent_not_set_variable) do
+            _assert_maker_atom_persons(*args) do |maker|
+              yield maker
+            end
+          end
+        else
+          _assert_maker_atom_persons(*args) do |maker|
+            yield maker
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(name)) do
+          _assert_maker_atom_persons(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+            yield maker
+            targets = chain_reader(maker, maker_readers)
+            target = targets.new_child
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(name)) do
+          _assert_maker_atom_persons(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+            yield maker
+            targets = chain_reader(maker, maker_readers)
+            target = targets.new_child
+            target.uri = "http://example.com/~me/"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(name)) do
+          _assert_maker_atom_persons(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+            yield maker
+            targets = chain_reader(maker, maker_readers)
+            target = targets.new_child
+            target.email = "me@e..."
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(name)) do
+          _assert_maker_atom_persons(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+            yield maker
+            targets = chain_reader(maker, maker_readers)
+            target = targets.new_child
+            target.uri = "http://example.com/~me/"
+            target.email = "me@e..."
+          end
+        end
+
+        _assert_maker_atom_persons(feed_type, maker_readers,
+                                   feed_readers) do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          target = targets.new_child
+          target.name = "me"
+        end
+
+        _assert_maker_atom_persons(feed_type, maker_readers,
+                                   feed_readers) do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          target = targets.new_child
+          target.name = "me"
+          target.uri = "http://example.com/~me/"
+        end
+
+        _assert_maker_atom_persons(feed_type, maker_readers,
+                                   feed_readers) do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          target = targets.new_child
+          target.name = "me"
+          target.email = "me@e..."
+        end
+
+        _assert_maker_atom_persons(feed_type, maker_readers,
+                                   feed_readers) do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          target = targets.new_child
+          target.name = "me"
+          target.uri = "http://example.com/~me/"
+          target.email = "me@e..."
+        end
+
+        _assert_maker_atom_persons(feed_type, maker_readers,
+                                   feed_readers) do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+
+          target = targets.new_child
+          target.name = "me"
+          target.uri = "http://example.com/~me/"
+          target.email = "me@e..."
+
+          target = targets.new_child
+          target.name = "you"
+          target.uri = "http://example.com/~you/"
+          target.email = "you@e..."
+        end
+
+        assert_not_set_error(not_set_error_name, %w(name)) do
+          _assert_maker_atom_persons(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+            yield maker
+            targets = chain_reader(maker, maker_readers)
+
+            target = targets.new_child
+            target.name = "me"
+            target.uri = "http://example.com/~me/"
+            target.email = "me@e..."
+
+            target = targets.new_child
+          end
+        end
+      end
+    end
+
+    def _assert_maker_atom_text_construct(feed_type, maker_readers,
+                                          feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        text = {
+          :type => target.type,
+          :content => target.content,
+          :xml_content => target.xml_content,
+        }
+        if text[:type] == "xhtml"
+          if text[:xml_content]
+            xml_content = text[:xml_content]
+            xhtml_uri = "http://www.w3.org/1999/xhtml"
+            unless xml_content.is_a?(RSS::XML::Element) and
+                ["div", xhtml_uri] == [xml_content.name, xml_content.uri]
+              children = xml_content
+              children = [children] unless children.is_a?(Array)
+              xml_content = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                                  {"xmlns" => xhtml_uri},
+                                                  children)
+              text[:xml_content] = xml_content
+            end
+            text
+          else
+            nil
+          end
+        else
+          text[:content] ? text : nil
+        end
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :type => target.type,
+          :content => target.content,
+          :xml_content => target.xhtml,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_text_construct(feed_type, maker_readers, feed_readers,
+                                         parent_not_set_error_name=nil,
+                                         parent_not_set_variable=nil,
+                                         not_set_error_name=nil)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        args = [feed_type, maker_readers, feed_readers]
+        if parent_not_set_error_name or parent_not_set_variable
+          assert_not_set_error(parent_not_set_error_name,
+                               parent_not_set_variable) do
+            _assert_maker_atom_text_construct(*args) do |maker|
+              yield maker
+            end
+          end
+        else
+          _assert_maker_atom_text_construct(*args) do |maker|
+            yield maker
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          _assert_maker_atom_text_construct(*args) do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers) {|x| x}
+            target.type = "text"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          _assert_maker_atom_text_construct(*args) do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers) {|x| x}
+            target.type = "html"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          _assert_maker_atom_text_construct(*args) do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers) {|x| x}
+            target.type = "xhtml"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          _assert_maker_atom_text_construct(*args) do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers) {|x| x}
+            target.type = "xhtml"
+            target.content = "Content"
+          end
+        end
+
+        _assert_maker_atom_text_construct(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers) {|x| x}
+          target.type = "text"
+          target.content = "Content"
+        end
+
+        _assert_maker_atom_text_construct(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers) {|x| x}
+          target.type = "html"
+          target.content = "<em>Content</em>"
+        end
+
+        _assert_maker_atom_text_construct(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers) {|x| x}
+          target.type = "xhtml"
+          target.xml_content = "text only"
+        end
+
+        _assert_maker_atom_text_construct(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers) {|x| x}
+          target.type = "xhtml"
+          target.xml_content = RSS::XML::Element.new("unknown")
+        end
+      end
+    end
+
+    def _assert_maker_atom_date_construct(feed_type, maker_readers,
+                                          feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        date = {
+          :content => target,
+        }
+        date[:content] ? date : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :content => target.content,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_date_construct(feed_type, maker_readers, feed_readers,
+                                         parent_not_set_error_name=nil,
+                                         parent_not_set_variable=nil)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        if parent_not_set_error_name or parent_not_set_variable
+          assert_not_set_error(parent_not_set_error_name,
+                               parent_not_set_variable) do
+            _assert_maker_atom_date_construct(*args) do |maker|
+              yield maker
+            end
+          end
+        else
+          _assert_maker_atom_date_construct(*args) do |maker|
+            yield maker
+          end
+        end
+
+        maker_readers = maker_readers.dup
+        writer = "#{maker_readers.pop}="
+        _assert_maker_atom_date_construct(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.__send__(writer, Time.now)
+        end
+      end
+    end
+
+    def _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                   maker_extractor, feed_extractor)
+      _wrap_assertion do
+        element = nil
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers) {|x| x}
+          element = maker_extractor.call(target)
+        end
+
+        target = chain_reader(feed, feed_readers)
+        if target
+          actual_element = feed_extractor.call(target)
+        else
+          actual_element = nil
+        end
+        assert_equal(element, actual_element)
+      end
+    end
+
+    def _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                    maker_extractor, feed_extractor,
+                                    invalid_feed_checker=nil)
+      _wrap_assertion do
+        elements = []
+        invalid_feed = false
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          targets = chain_reader(maker, maker_readers)
+          targets.each do |target|
+            element = maker_extractor.call(target)
+            elements << element if element
+          end
+          if invalid_feed_checker
+            invalid_feed = invalid_feed_checker.call(targets)
+          end
+        end
+
+        if invalid_feed
+          assert_nil(feed)
+        else
+          actual_elements = chain_reader(feed, feed_readers) || []
+          actual_elements = actual_elements.collect do |target|
+            feed_extractor.call(target)
+          end
+          assert_equal(elements, actual_elements)
+        end
+      end
+    end
+
+    def assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                  setup_target, optional_variables,
+                                  required_variable, assert_method_name,
+                                  not_set_error_name=nil,
+                                  *additional_args)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        0.upto(optional_variables.size) do |i|
+          combination(optional_variables, i).each do |names|
+            have = {}
+            names.each do |name|
+              have[name.intern] = true
+            end
+            have_required_variable_too =
+              have.merge({required_variable.intern => true})
+
+            assert_not_set_error(not_set_error_name, [required_variable]) do
+              __send__(assert_method_name, feed_type, maker_readers,
+                       feed_readers, *additional_args) do |maker|
+                yield maker
+                target = chain_reader(maker, maker_readers) {|x| x}
+                setup_target.call(target, have)
+              end
+            end
+
+            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
+                     *additional_args) do |maker|
+              yield maker
+              target = chain_reader(maker, maker_readers) {|x| x}
+              setup_target.call(target, have_required_variable_too)
+            end
+          end
+        end
+      end
+    end
+
+    def assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                   setup_target, optional_variables,
+                                   required_variable, assert_method_name,
+                                   not_set_error_name=nil,
+                                   *additional_args)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        0.upto(optional_variables.size) do |i|
+          combination(optional_variables, i).each do |names|
+            have = {}
+            names.each do |name|
+              have[name.intern] = true
+            end
+            have_required_variable_too =
+              have.merge({required_variable.intern => true})
+
+            assert_not_set_error(not_set_error_name, [required_variable]) do
+              __send__(assert_method_name, feed_type, maker_readers,
+                       feed_readers, *additional_args) do |maker|
+                yield maker
+                targets = chain_reader(maker, maker_readers)
+                setup_target.call(targets, have)
+              end
+            end
+
+            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
+                     *additional_args) do |maker|
+              yield maker
+              targets = chain_reader(maker, maker_readers)
+              setup_target.call(targets, have_required_variable_too)
+            end
+
+            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
+                     *additional_args) do |maker|
+              yield maker
+              targets = chain_reader(maker, maker_readers)
+              setup_target.call(targets, have_required_variable_too)
+              setup_target.call(targets, have_required_variable_too)
+            end
+
+            assert_not_set_error(not_set_error_name, [required_variable]) do
+            __send__(assert_method_name, feed_type, maker_readers, feed_readers,
+                     *additional_args) do |maker|
+                yield maker
+                targets = chain_reader(maker, maker_readers)
+                setup_target.call(targets, have_required_variable_too)
+                setup_target.call(targets, have)
+              end
+            end
+          end
+        end
+      end
+    end
+
+    def _assert_maker_atom_categories(feed_type, maker_readers,
+                                      feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        category = {
+          :term => target.term,
+          :scheme => target.scheme,
+          :label => target.label,
+        }
+        category[:term] ? category : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :term => target.term,
+          :scheme => target.scheme,
+          :label => target.label,
+        }
+      end
+      _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                  maker_extractor, feed_extractor, &block)
+    end
+
+    def assert_maker_atom_categories(feed_type, maker_readers, feed_readers,
+                                     not_set_error_name=nil, &block)
+      _wrap_assertion do
+        _assert_maker_atom_categories(feed_type, maker_readers,
+                                      feed_readers) do |maker|
+          yield maker
+        end
+
+        setup_target = Proc.new do |targets, have|
+          target = targets.new_child
+          target.term = "music" if have[:term]
+          target.scheme = "http://example.com/category/music" if have[:scheme]
+          target.label = "Music" if have[:label]
+        end
+
+        optional_variables = %w(scheme label)
+
+        assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                   setup_target, optional_variables,
+                                   "term", :_assert_maker_atom_categories,
+                                   not_set_error_name, &block)
+      end
+    end
+
+    def _assert_maker_atom_generator(feed_type, maker_readers,
+                                     feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        generator = {
+          :uri => target.uri,
+          :version => target.version,
+          :content => target.content,
+        }
+        generator[:content] ? generator : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :uri => target.uri,
+          :version => target.version,
+          :content => target.content,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+     end
+
+    def assert_maker_atom_generator(feed_type, maker_readers, feed_readers,
+                                    not_set_error_name=nil, &block)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        _assert_maker_atom_generator(feed_type, maker_readers,
+                                     feed_readers) do |maker|
+          yield maker
+        end
+
+        setup_target = Proc.new do |target, have|
+          target.content = "RSS Maker" if have[:content]
+          target.uri = "http://example.com/rss/maker" if have[:uri]
+          target.version = "0.0.1" if have[:version]
+        end
+
+        optional_variables = %w(uri version)
+
+        assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                  setup_target, optional_variables,
+                                  "content", :_assert_maker_atom_generator,
+                                  not_set_error_name, &block)
+      end
+    end
+
+    def _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
+                                accessor_base, &block)
+      maker_extractor = Proc.new do |target|
+        icon = {
+          :content => target.__send__(accessor_base),
+        }
+        icon[:content] ? icon : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :content => target.content,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
+                               accessor_base=nil, not_set_error_name=nil)
+      _wrap_assertion do
+        accessor_base ||= "url"
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
+                                accessor_base) do |maker|
+          yield maker
+        end
+
+        _assert_maker_atom_icon(feed_type, maker_readers, feed_readers,
+                                accessor_base) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.__send__("#{accessor_base}=", "http://example.com/icon.png")
+        end
+      end
+    end
+
+    def _assert_maker_atom_links(feed_type, maker_readers, feed_readers,
+                                 allow_duplication=false, &block)
+      maker_extractor = Proc.new do |target|
+        link = {
+          :href => target.href,
+          :rel => target.rel,
+          :type => target.type,
+          :hreflang => target.hreflang,
+          :title => target.title,
+          :length => target.length,
+        }
+        link[:href] ? link : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :href => target.href,
+          :rel => target.rel,
+          :type => target.type,
+          :hreflang => target.hreflang,
+          :title => target.title,
+          :length => target.length,
+        }
+      end
+      invalid_feed_checker = Proc.new do |targets|
+        infos = {}
+        invalid = false
+        targets.each do |target|
+          key = [target.hreflang, target.type]
+          if infos.has_key?(key)
+            invalid = true
+            break
+          end
+          infos[key] = true if target.rel.nil? or target.rel == "alternate"
+        end
+        invalid
+      end
+      invalid_feed_checker = nil if allow_duplication
+      _assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                  maker_extractor, feed_extractor,
+                                  invalid_feed_checker,
+                                  &block)
+    end
+
+    def assert_maker_atom_links(feed_type, maker_readers, feed_readers,
+                                not_set_error_name=nil, allow_duplication=false,
+                                &block)
+      _wrap_assertion do
+        _assert_maker_atom_links(feed_type, maker_readers,
+                                 feed_readers) do |maker|
+          yield maker
+        end
+
+        langs = %(ja en fr zh po)
+        setup_target = Proc.new do |targets, have|
+          target = targets.new_child
+          lang = langs[targets.size % langs.size]
+          target.href = "http://example.com/index.html.#{lang}" if have[:href]
+          target.rel = "alternate" if have[:rel]
+          target.type = "text/xhtml" if have[:type]
+          target.hreflang = lang if have[:hreflang]
+          target.title = "FrontPage(#{lang})" if have[:title]
+          target.length = 1024 if have[:length]
+        end
+
+        optional_variables = %w(rel type hreflang title length)
+
+        assert_maker_atom_elements(feed_type, maker_readers, feed_readers,
+                                   setup_target, optional_variables,
+                                   "href", :_assert_maker_atom_links,
+                                   not_set_error_name, allow_duplication,
+                                   &block)
+      end
+    end
+
+    def _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
+                                accessor_base, &block)
+      maker_extractor = Proc.new do |target|
+        logo = {
+          :uri => target.__send__(accessor_base),
+        }
+        logo[:uri] ? logo : nil
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :uri => target.content,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
+                               accessor_base=nil, not_set_error_name=nil)
+      _wrap_assertion do
+        accessor_base ||= "uri"
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
+                                accessor_base) do |maker|
+          yield maker
+        end
+
+        _assert_maker_atom_logo(feed_type, maker_readers, feed_readers,
+                                accessor_base) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.__send__("#{accessor_base}=", "http://example.com/logo.png")
+        end
+      end
+    end
+
+    def _assert_maker_atom_id(feed_type, maker_readers, feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        id = {
+          :uri => target.id,
+        }
+        id[:uri] ? id : nil
+      end
+      feed_extractor = Proc.new do |target|
+        if target.id
+          {
+            :uri => target.id.content,
+          }
+        else
+          nil
+        end
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_id(feed_type, maker_readers, feed_readers,
+                             not_set_error_name=nil)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+
+        args = [feed_type, maker_readers, feed_readers]
+        _assert_maker_atom_id(*args) do |maker|
+          yield maker
+        end
+
+        _assert_maker_atom_id(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.id = "http://example.com/id/1"
+        end
+      end
+    end
+
+    def _assert_maker_atom_content(feed_type, maker_readers,
+                                   feed_readers, &block)
+      maker_extractor = Proc.new do |target|
+        content = {
+          :type => target.type,
+          :src => target.src,
+          :content => target.content,
+          :xml => target.xml,
+          :inline_text => target.inline_text?,
+          :inline_html => target.inline_html?,
+          :inline_xhtml => target.inline_xhtml?,
+          :inline_other => target.inline_other?,
+          :inline_other_text => target.inline_other_text?,
+          :inline_other_xml => target.inline_other_xml?,
+          :inline_other_base64 => target.inline_other_base64?,
+          :out_of_line => target.out_of_line?,
+        }
+        content[:src] = nil if content[:src] and content[:content]
+        if content[:type] or content[:content]
+          content
+        else
+          nil
+        end
+      end
+      feed_extractor = Proc.new do |target|
+        {
+          :type => target.type,
+          :src => target.src,
+          :content => target.content,
+          :xml => target.xml,
+          :inline_text => target.inline_text?,
+          :inline_html => target.inline_html?,
+          :inline_xhtml => target.inline_xhtml?,
+          :inline_other => target.inline_other?,
+          :inline_other_text => target.inline_other_text?,
+          :inline_other_xml => target.inline_other_xml?,
+          :inline_other_base64 => target.inline_other_base64?,
+          :out_of_line => target.out_of_line?,
+        }
+      end
+      _assert_maker_atom_element(feed_type, maker_readers, feed_readers,
+                                 maker_extractor, feed_extractor,
+                                 &block)
+    end
+
+    def assert_maker_atom_content(feed_type, maker_readers, feed_readers,
+                                  not_set_error_name=nil, &block)
+      _wrap_assertion do
+        not_set_error_name ||= "maker.#{maker_readers.join('.')}"
+        args = [feed_type, maker_readers, feed_readers, not_set_error_name]
+        assert_maker_atom_content_inline_text(*args, &block)
+        assert_maker_atom_content_inline_xhtml(*args, &block)
+        assert_maker_atom_content_inline_other(*args, &block)
+        assert_maker_atom_content_out_of_line(*args, &block)
+      end
+    end
+
+    def assert_maker_atom_content_inline_text(feed_type, maker_readers,
+                                              feed_readers, not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+        end
+
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "text"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "html"
+          end
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.content = ""
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "text"
+          target.content = "example content"
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "html"
+          target.content = "<em>text</em>"
+        end
+      end
+    end
+
+    def assert_maker_atom_content_inline_xhtml(feed_type, maker_readers,
+                                               feed_readers, not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "xhtml"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "xhtml"
+            target.content = "dummy"
+          end
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml_content = "text"
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml = "text"
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml_content =
+            RSS::XML::Element.new("em", nil, nil, {}, ["text"])
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml = RSS::XML::Element.new("em", nil, nil, {}, ["text"])
+        end
+
+
+        xhtml_uri = "http://www.w3.org/1999/xhtml"
+        em = RSS::XML::Element.new("em", nil, nil, {}, ["text"])
+        em_with_xhtml_uri =
+          RSS::XML::Element.new("em", nil, xhtml_uri, {}, ["text"])
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml = em
+        end
+        assert_equal(RSS::XML::Element.new("div", nil, xhtml_uri,
+                                           {"xmlns" => xhtml_uri},
+                                           [em_with_xhtml_uri]),
+                     chain_reader(feed, feed_readers).xml)
+
+        div = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                    {"xmlns" => xhtml_uri,
+                                     "class" => "sample"},
+                                    ["text"])
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "xhtml"
+          target.xml = div
+        end
+        assert_equal(div, chain_reader(feed, feed_readers).xml)
+      end
+    end
+
+    def assert_maker_atom_content_inline_other(*args, &block)
+      _wrap_assertion do
+        assert_maker_atom_content_inline_other_xml(*args, &block)
+        assert_maker_atom_content_inline_other_text(*args, &block)
+        assert_maker_atom_content_inline_other_base64(*args, &block)
+      end
+    end
+
+    def assert_maker_atom_content_inline_other_xml(feed_type, maker_readers,
+                                                   feed_readers,
+                                                   not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "application/xml"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(xml_content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "svg/image+xml"
+          end
+        end
+
+        svg_uri = "http://www.w3.org/2000/svg"
+        rect = RSS::XML::Element.new("rect", nil, svg_uri,
+                                     {"x" => "0.5cm",
+                                      "y" => "0.5cm",
+                                      "width" => "2cm",
+                                      "height" => "1cm"})
+        svg = RSS::XML::Element.new("svg", nil, svg_uri,
+                                    {"xmlns" => svg_uri,
+                                     "version" => "1.1",
+                                     "width" => "5cm",
+                                     "height" => "4cm"},
+                                    [rect])
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/svg+xml"
+          target.xml = svg
+        end
+
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/svg+xml"
+          target.xml = svg
+        end
+        assert_equal(svg, chain_reader(feed, feed_readers).xml)
+      end
+    end
+
+    def assert_maker_atom_content_inline_other_text(feed_type, maker_readers,
+                                                    feed_readers,
+                                                    not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "text/plain"
+          end
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "text/plain"
+          target.content = "text"
+        end
+      end
+    end
+
+    def assert_maker_atom_content_inline_other_base64(feed_type, maker_readers,
+                                                      feed_readers,
+                                                      not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        content = "\211PNG\r\n\032\n"
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/png"
+          target.content = content
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/png"
+          target.src = "http://example.com/logo.png"
+          target.content = content
+        end
+
+        feed = RSS::Maker.make("atom:#{feed_type}") do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/png"
+          target.src = "http://example.com/logo.png"
+          target.content = content
+        end
+        target = chain_reader(feed, feed_readers)
+        assert_nil(target.src)
+        assert_equal(content, target.content)
+      end
+    end
+
+    def assert_maker_atom_content_out_of_line(feed_type, maker_readers,
+                                              feed_readers, not_set_error_name)
+      _wrap_assertion do
+        args = [feed_type, maker_readers, feed_readers]
+        assert_not_set_error(not_set_error_name, %w(content)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.type = "image/png"
+          end
+        end
+
+        assert_not_set_error(not_set_error_name, %w(type)) do
+          RSS::Maker.make("atom:#{feed_type}") do |maker|
+            yield maker
+            target = chain_reader(maker, maker_readers)
+            target.src = "http://example.com/logo.png"
+          end
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/png"
+          target.src = "http://example.com/logo.png"
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "image/png"
+          target.content = "\211PNG\r\n\032\n"
+        end
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "application/xml"
+          target.src = "http://example.com/sample.xml"
+        end
+
+
+        _assert_maker_atom_content(*args) do |maker|
+          yield maker
+          target = chain_reader(maker, maker_readers)
+          target.type = "text/plain"
+          target.src = "http://example.com/README.txt"
+        end
+      end
+    end
+
+    def assert_slash_elements(expected, target)
+      assert_equal(expected,
+                   {
+                     "section" => target.slash_section,
+                     "department" => target.slash_department,
+                     "comments" => target.slash_comments,
+                     "hit_parades" => target.slash_hit_parades,
+                   })
+      assert_equal(expected["hit_parades"].join(","),
+                   target.slash_hit_parade)
+    end
+
+    def chain_reader(target, readers, &block)
+      readers.inject(target) do |result, reader|
+        return nil if result.nil?
+        result.__send__(reader, &block)
+      end
+    end
+
     def normalized_attrs(attrs)
       n_attrs = {}
       attrs.each do |name, value|
@@ -501,6 +2044,31 @@
       end
       n_attrs
     end
-    
+
+    def combination(elements, n)
+      if n <= 0 or elements.size < n
+        []
+      elsif n == 1
+        elements.collect {|element| [element]}
+      else
+        first, *rest = elements
+        combination(rest, n - 1).collect do |sub_elements|
+          [first, *sub_elements]
+        end + combination(rest, n)
+      end
+    end
+
+    def tag(name, content=nil, attributes={})
+      attributes = attributes.collect do |key, value|
+        "#{ERB::Util.h(key)}=\"#{ERB::Util.h(value)}\""
+      end.join(" ")
+      begin_tag = "<#{name}"
+      begin_tag << " #{attributes}" unless attributes.empty?
+      if content
+        "#{begin_tag}>#{content}</#{name}>\n"
+      else
+        "#{begin_tag}/>\n"
+      end
+    end
   end
 end
Index: ruby_1_8/test/rss/test_maker_atom_entry.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_atom_entry.rb	(revision 0)
+++ ruby_1_8/test/rss/test_maker_atom_entry.rb	(revision 13747)
@@ -0,0 +1,367 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestMakerAtomEntry < TestCase
+    def test_root_element
+      entry = Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+      assert_equal(["atom", "1.0", "entry"], entry.feed_info)
+
+      entry = Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.encoding = "EUC-JP"
+      end
+      assert_equal(["atom", "1.0", "entry"], entry.feed_info)
+      assert_equal("EUC-JP", entry.encoding)
+
+      entry = Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.standalone = "yes"
+      end
+      assert_equal(["atom", "1.0", "entry"], entry.feed_info)
+      assert_equal("yes", entry.standalone)
+
+      entry = Maker.make("atom:entry") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.encoding = "EUC-JP"
+        maker.standalone = "yes"
+      end
+      assert_equal(["atom", "1.0", "entry"], entry.feed_info)
+      assert_equal("EUC-JP", entry.encoding)
+      assert_equal("yes", entry.standalone)
+    end
+
+    def test_invalid_feed
+      assert_not_set_error("maker.item", %w(id title author updated)) do
+        Maker.make("atom:entry") do |maker|
+        end
+      end
+
+      assert_not_set_error("maker.item", %w(id title updated)) do
+        Maker.make("atom:entry") do |maker|
+          maker.channel.author = "foo"
+        end
+      end
+
+      assert_not_set_error("maker.item", %w(title updated)) do
+        Maker.make("atom:entry") do |maker|
+          maker.channel.author = "foo"
+          maker.channel.id = "http://example.com"
+        end
+      end
+
+      assert_not_set_error("maker.item", %w(updated)) do
+        Maker.make("atom:entry") do |maker|
+          maker.channel.author = "foo"
+          maker.channel.id = "http://example.com"
+          maker.channel.title = "Atom Feed"
+        end
+      end
+
+      assert_not_set_error("maker.item", %w(author)) do
+        Maker.make("atom:entry") do |maker|
+          maker.channel.id = "http://example.com"
+          maker.channel.title = "Atom Feed"
+          maker.channel.updated = Time.now
+        end
+      end
+
+      entry = Maker.make("atom:entry") do |maker|
+        maker.channel.author = "Foo"
+        maker.channel.id = "http://example.com"
+        maker.channel.title = "Atom Feed"
+        maker.channel.updated = Time.now
+      end
+      assert_not_nil(entry)
+    end
+
+    def test_author
+      assert_maker_atom_persons("entry",
+                                ["channel", "authors"],
+                                ["authors"],
+                                "maker.channel.author") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_persons("entry",
+                                ["items", "first", "authors"],
+                                ["authors"],
+                                "maker.item.author",
+                                "maker.item", ["author"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.authors.clear
+        maker.items.first.authors.clear
+      end
+
+      assert_maker_atom_persons("entry",
+                                ["items", "first", "source", "authors"],
+                                ["source", "authors"],
+                                "maker.item.source.author") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_category
+      assert_maker_atom_categories("entry",
+                                   ["channel", "categories"],
+                                   ["categories"],
+                                   "maker.channel.category") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_categories("entry",
+                                   ["items", "first", "categories"],
+                                   ["categories"],
+                                   "maker.item.category") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_categories("entry",
+                                   ["items", "first", "source", "categories"],
+                                   ["source", "categories"],
+                                   "maker.item.source.category") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_content
+      assert_maker_atom_content("entry",
+                                ["items", "first", "content"],
+                                ["content"],
+                                "maker.item.content") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_contributor
+      assert_maker_atom_persons("entry",
+                                ["channel", "contributors"],
+                                ["contributors"],
+                                "maker.channel.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_persons("entry",
+                                ["items", "first", "contributors"],
+                                ["contributors"],
+                                "maker.item.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_persons("entry",
+                                ["items", "first", "source", "contributors"],
+                                ["source", "contributors"],
+                                "maker.item.source.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_link
+      assert_maker_atom_links("entry",
+                              ["channel", "links"],
+                              ["links"],
+                              "maker.channel.link") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.links.clear
+        maker.items.first.links.clear
+      end
+
+      assert_maker_atom_links("entry",
+                              ["items", "first", "links"],
+                              ["links"],
+                              "maker.item.link") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.links.clear
+        maker.items.first.links.clear
+      end
+
+      assert_maker_atom_links("entry",
+                              ["items", "first", "source", "links"],
+                              ["source", "links"],
+                              "maker.item.source.link", true) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_published
+      assert_maker_atom_date_construct("entry",
+                                       ["items", "first", "published"],
+                                       ["published"]
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_rights
+      assert_maker_atom_text_construct("entry",
+                                       ["channel", "copyright"],
+                                       ["rights"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "rights"],
+                                       ["rights"],
+                                       nil, nil, "maker.item.rights"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "source", "rights"],
+                                       ["source", "rights"],
+                                       nil, nil, "maker.item.source.rights"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+
+    def test_source_generator
+      assert_maker_atom_generator("entry",
+                                  ["items", "first", "source", "generator"],
+                                  ["source", "generator"],
+                                  "maker.item.source.generator") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_source_icon
+      assert_maker_atom_icon("entry",
+                             ["items", "first", "source", "icon"],
+                             ["source", "icon"],
+                             nil, "maker.item.source.icon") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_source_id
+      assert_maker_atom_id("entry",
+                           ["items", "first", "source"],
+                           ["source"],
+                           "maker.item.source") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_source_logo
+      assert_maker_atom_logo("entry",
+                             ["items", "first", "source", "logo"],
+                             ["source", "logo"],
+                             nil,
+                             "maker.item.source.logo") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_source_subtitle
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "source", "subtitle"],
+                                       ["source", "subtitle"],
+                                       nil, nil,
+                                       "maker.item.source.subtitle") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_summary
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "description"],
+                                       ["summary"],
+                                       nil, nil, "maker.item.description"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_title
+      assert_maker_atom_text_construct("entry",
+                                       ["channel", "title"], ["title"],
+                                       "maker.item", ["title"],
+                                       "maker.channel.title") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.title = nil
+        maker.items.first.title = nil
+      end
+
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "title"],
+                                       ["title"],
+                                       "maker.item", ["title"],
+                                       "maker.item.title") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.title = nil
+        maker.items.first.title = nil
+      end
+
+      assert_maker_atom_text_construct("entry",
+                                       ["items", "first", "source", "title"],
+                                       ["source", "title"],
+                                       nil, nil, "maker.item.source.title"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_updated
+      assert_maker_atom_date_construct("entry",
+                                       ["channel", "updated"], ["updated"],
+                                       "maker.item", ["updated"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.updated = nil
+        maker.items.first.updated = nil
+      end
+
+      assert_maker_atom_date_construct("entry",
+                                       ["items", "first", "updated"],
+                                       ["updated"],
+                                       "maker.item", ["updated"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.channel.updated = nil
+        maker.items.first.updated = nil
+      end
+
+      assert_maker_atom_date_construct("entry",
+                                       ["items", "first", "source", "updated"],
+                                       ["source", "updated"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_inherit.rb
===================================================================
--- ruby_1_8/test/rss/test_inherit.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_inherit.rb	(revision 13747)
@@ -9,7 +9,7 @@
       def self.indent_size; 1; end
       def self.tag_name; 'image'; end
     end
-    
+
     def setup
       @rss = make_RDF(<<-EOR)
 #{make_channel}
@@ -18,7 +18,7 @@
 #{make_textinput}
 EOR
     end
-    
+
     def test_inherit
       rss = RSS::Parser.parse(@rss)
       orig_image = rss.image
@@ -36,6 +36,5 @@
       assert_equal("#{prefix} #{orig_image.url}", new_image.url)
       assert_equal("#{prefix} #{orig_image.link}", new_image.link)
     end
-    
   end
 end
Index: ruby_1_8/test/rss/test_maker_atom_feed.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_atom_feed.rb	(revision 0)
+++ ruby_1_8/test/rss/test_maker_atom_feed.rb	(revision 13747)
@@ -0,0 +1,389 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestMakerAtomFeed < TestCase
+    def test_root_element
+      feed = Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+      assert_equal(["atom", "1.0", "feed"], feed.feed_info)
+
+      feed = Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.encoding = "EUC-JP"
+      end
+      assert_equal(["atom", "1.0", "feed"], feed.feed_info)
+      assert_equal("EUC-JP", feed.encoding)
+
+      feed = Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.standalone = "yes"
+      end
+      assert_equal(["atom", "1.0", "feed"], feed.feed_info)
+      assert_equal("yes", feed.standalone)
+
+      feed = Maker.make("atom") do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.encoding = "EUC-JP"
+        maker.standalone = "yes"
+      end
+      assert_equal(["atom", "1.0", "feed"], feed.feed_info)
+      assert_equal("EUC-JP", feed.encoding)
+      assert_equal("yes", feed.standalone)
+    end
+
+    def test_invalid_feed
+      assert_not_set_error("maker.channel", %w(id title author updated)) do
+        Maker.make("atom") do |maker|
+        end
+      end
+
+      assert_not_set_error("maker.channel", %w(id title updated)) do
+        Maker.make("atom") do |maker|
+          maker.channel.author = "foo"
+        end
+      end
+
+      assert_not_set_error("maker.channel", %w(title updated)) do
+        Maker.make("atom") do |maker|
+          maker.channel.author = "foo"
+          maker.channel.id = "http://example.com"
+        end
+      end
+
+      assert_not_set_error("maker.channel", %w(updated)) do
+        Maker.make("atom") do |maker|
+          maker.channel.author = "foo"
+          maker.channel.id = "http://example.com"
+          maker.channel.title = "Atom Feed"
+        end
+      end
+
+      assert_not_set_error("maker.channel", %w(author)) do
+        Maker.make("atom") do |maker|
+          maker.channel.id = "http://example.com"
+          maker.channel.title = "Atom Feed"
+          maker.channel.updated = Time.now
+        end
+      end
+
+      feed = Maker.make("atom") do |maker|
+        maker.channel.author = "Foo"
+        maker.channel.id = "http://example.com"
+        maker.channel.title = "Atom Feed"
+        maker.channel.updated = Time.now
+      end
+      assert_not_nil(feed)
+    end
+
+    def test_author
+      assert_maker_atom_persons("feed",
+                                ["channel", "authors"],
+                                ["authors"],
+                                "maker.channel.author") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_not_set_error("maker.channel", %w(author)) do
+        RSS::Maker.make("atom") do |maker|
+          setup_dummy_channel_atom(maker)
+          setup_dummy_item_atom(maker)
+          maker.channel.authors.clear
+        end
+      end
+
+      assert_maker_atom_persons("feed",
+                                ["items", "first", "authors"],
+                                ["entries", "first", "authors"],
+                                "maker.item.author") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_persons("feed",
+                                ["items", "first", "source", "authors"],
+                                ["entries", "first", "source", "authors"],
+                                "maker.item.source.author") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_category
+      assert_maker_atom_categories("feed",
+                                   ["channel", "categories"],
+                                   ["categories"],
+                                   "maker.channel.category") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_categories("feed",
+                                   ["items", "first", "categories"],
+                                   ["entries", "first", "categories"],
+                                   "maker.item.category") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_categories("feed",
+                                   ["items", "first", "source", "categories"],
+                                   ["entries", "first", "source", "categories"],
+                                   "maker.item.source.category") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_contributor
+      assert_maker_atom_persons("feed",
+                                ["channel", "contributors"],
+                                ["contributors"],
+                                "maker.channel.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_persons("feed",
+                                ["items", "first", "contributors"],
+                                ["entries", "first", "contributors"],
+                                "maker.item.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_persons("feed",
+                                ["items", "first", "source", "contributors"],
+                                ["entries", "first", "source", "contributors"],
+                                "maker.item.source.contributor") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_generator
+      assert_maker_atom_generator("feed",
+                                  ["channel", "generator"],
+                                  ["generator"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_generator("feed",
+                                  ["items", "first", "source", "generator"],
+                                  ["entries", "first", "source", "generator"],
+                                  "maker.item.source.generator") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_icon
+      assert_maker_atom_icon("feed", ["channel"], ["icon"], "icon") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_icon("feed",
+                             ["items", "first", "source", "icon"],
+                             ["entries", "first", "source", "icon"],
+                             nil, "maker.item.source.icon") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_link
+      assert_maker_atom_links("feed",
+                              ["channel", "links"],
+                              ["links"],
+                              "maker.channel.link") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_links("feed",
+                              ["items", "first", "links"],
+                              ["entries", "first", "links"],
+                              "maker.item.link") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_links("feed",
+                              ["items", "first", "source", "links"],
+                              ["entries", "first", "source", "links"],
+                              "maker.item.source.link", true) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_logo
+      assert_maker_atom_logo("feed", ["channel"], ["logo"], "logo") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_logo("feed", ["image"], ["logo"], "url") do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_logo("feed",
+                             ["items", "first", "source", "logo"],
+                             ["entries", "first", "source", "logo"],
+                             nil, "maker.item.source.logo") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_rights
+      assert_maker_atom_text_construct("feed",
+                                       ["channel", "copyright"],
+                                       ["rights"]) do |maker|
+        setup_dummy_channel_atom(maker)
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "rights"],
+                                       ["entries", "first", "rights"],
+                                       nil, nil, "maker.item.rights"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "source", "rights"],
+                                       ["entries", "first", "source", "rights"],
+                                       nil, nil, "maker.item.source.rights"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_subtitle
+      assert_maker_atom_text_construct("feed",
+                                       ["channel", "subtitle"],
+                                       ["subtitle"],
+                                       nil, nil,
+                                       "maker.channel.description") do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.channel.description = nil
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["channel", "subtitle"],
+                                       ["subtitle"],
+                                       nil, nil,
+                                       "maker.channel.description") do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.channel.description {|d| d.content = nil}
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "source", "subtitle"],
+                                       ["entries", "first",
+                                        "source", "subtitle"],
+                                       nil, nil,
+                                       "maker.item.source.subtitle") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_title
+      assert_maker_atom_text_construct("feed",
+                                       ["channel", "title"], ["title"],
+                                       "maker.channel", ["title"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.channel.title = nil
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "title"],
+                                       ["entries", "first", "title"],
+                                       "maker.item", ["title"],
+                                       "maker.item.title") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.items.first.title = nil
+      end
+
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "source", "title"],
+                                       ["entries", "first", "source", "title"],
+                                       nil, nil, "maker.item.source.title"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_updated
+      assert_maker_atom_date_construct("feed",
+                                       ["channel", "updated"], ["updated"],
+                                       "maker.channel", ["updated"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        maker.channel.updated = nil
+      end
+
+      assert_maker_atom_date_construct("feed",
+                                       ["items", "first", "updated"],
+                                       ["entries", "first", "updated"],
+                                       "maker.item", ["updated"]) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+        maker.items.first.updated = nil
+      end
+
+      assert_maker_atom_date_construct("feed",
+                                       ["items", "first", "source", "updated"],
+                                       ["entries", "first", "source", "updated"]
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_published
+      assert_maker_atom_date_construct("feed",
+                                       ["items", "first", "published"],
+                                       ["entries", "first", "published"]
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_summary
+      assert_maker_atom_text_construct("feed",
+                                       ["items", "first", "description"],
+                                       ["entries", "first", "summary"],
+                                       nil, nil, "maker.item.description"
+                                       ) do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_content
+      assert_maker_atom_content("feed",
+                                ["items", "first", "content"],
+                                ["entries", "first", "content"],
+                                "maker.item.content") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+
+    def test_id
+      assert_maker_atom_id("feed",
+                           ["items", "first", "source"],
+                           ["entries", "first", "source"],
+                           "maker.item.source") do |maker|
+        setup_dummy_channel_atom(maker)
+        setup_dummy_item_atom(maker)
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_to_s.rb
===================================================================
--- ruby_1_8/test/rss/test_to_s.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_to_s.rb	(revision 13747)
@@ -12,7 +12,6 @@
 
 module RSS
   class TestToS < TestCase
-    
     def setup
       @image_url = "http://example.com/foo.png"
       @textinput_link = "http://example.com/search.cgi"
@@ -435,6 +434,237 @@
         new_about.value = about
       end
     end
+
+
+    def assert_channel10(attrs, channel)
+      _wrap_assertion do
+        n_attrs = normalized_attrs(attrs)
+        
+        names = %w(about title link description)
+        assert_attributes(attrs, names, channel)
+
+        %w(image items textinput).each do |name|
+          value = n_attrs[name]
+          if value
+            target = channel.__send__(name)
+            __send__("assert_channel10_#{name}", value, target)
+          end
+        end
+      end
+    end
+
+    def assert_channel10_image(attrs, image)
+      _wrap_assertion do
+        assert_attributes(attrs, %w(resource), image)
+      end
+    end
     
+    def assert_channel10_textinput(attrs, textinput)
+      _wrap_assertion do
+        assert_attributes(attrs, %w(resource), textinput)
+      end
+    end
+
+    def assert_channel10_items(attrs, items)
+      _wrap_assertion do
+        assert_equal(items.resources, items.Seq.lis.collect {|x| x.resource})
+        items.Seq.lis.each_with_index do |li, i|
+          assert_attributes(attrs[i], %w(resource), li)
+        end
+      end
+    end
+
+    def assert_image10(attrs, image)
+      _wrap_assertion do
+        names = %w(about title url link)
+        assert_attributes(attrs, names, image)
+      end
+    end
+
+    def assert_items10(attrs, items)
+      _wrap_assertion do
+        names = %w(about title link description)
+        items.each_with_index do |item, i|
+          assert_attributes(attrs[i], names, item)
+        end
+      end
+    end
+
+    def assert_textinput10(attrs, textinput)
+      _wrap_assertion do
+        names = %w(about title description name link)
+        assert_attributes(attrs, names, textinput)
+      end
+    end
+
+
+    def assert_channel09(attrs, channel)
+      _wrap_assertion do
+        n_attrs = normalized_attrs(attrs)
+
+        names = %w(title description link language rating
+                   copyright pubDate lastBuildDate docs
+                   managingEditor webMaster)
+        assert_attributes(attrs, names, channel)
+        
+        %w(skipHours skipDays).each do |name|
+          value = n_attrs[name]
+          if value
+            target = channel.__send__(name)
+            __send__("assert_channel09_#{name}", value, target)
+          end
+        end
+      end
+    end
+
+    def assert_channel09_skipDays(contents, skipDays)
+      _wrap_assertion do
+        days = skipDays.days
+        contents.each_with_index do |content, i|
+          assert_equal(content, days[i].content)
+        end
+      end
+    end
+    
+    def assert_channel09_skipHours(contents, skipHours)
+      _wrap_assertion do
+        hours = skipHours.hours
+        contents.each_with_index do |content, i|
+          assert_equal(content.to_i, hours[i].content)
+        end
+      end
+    end
+    
+    def assert_image09(attrs, image)
+      _wrap_assertion do
+        names = %w(url link title description)
+        names << ["width", :integer]
+        names << ["height", :integer]
+        assert_attributes(attrs, names, image)
+      end
+    end
+
+    def assert_items09(attrs, items)
+      _wrap_assertion do
+        names = %w(title link description)
+        items.each_with_index do |item, i|
+          assert_attributes(attrs[i], names, item)
+        end
+      end
+    end
+    
+    def assert_textinput09(attrs, textinput)
+      _wrap_assertion do
+        names = %w(title description name link)
+        assert_attributes(attrs, names, textinput)
+      end
+    end
+
+
+    def assert_channel20(attrs, channel)
+      _wrap_assertion do
+        n_attrs = normalized_attrs(attrs)
+        
+        names = %w(title link description language copyright
+                   managingEditor webMaster pubDate
+                   lastBuildDate generator docs rating)
+        names << ["ttl", :integer]
+        assert_attributes(attrs, names, channel)
+
+        %w(cloud categories skipHours skipDays).each do |name|
+          value = n_attrs[name]
+          if value
+            target = channel.__send__(name)
+            __send__("assert_channel20_#{name}", value, target)
+          end
+        end
+      end
+    end
+
+    def assert_channel20_skipDays(contents, skipDays)
+      assert_channel09_skipDays(contents, skipDays)
+    end
+    
+    def assert_channel20_skipHours(contents, skipHours)
+      assert_channel09_skipHours(contents, skipHours)
+    end
+    
+    def assert_channel20_cloud(attrs, cloud)
+      _wrap_assertion do
+        names = %w(domain path registerProcedure protocol)
+        names << ["port", :integer]
+        assert_attributes(attrs, names, cloud)
+      end
+    end
+    
+    def assert_channel20_categories(attrs, categories)
+      _wrap_assertion do
+        names = %w(domain content)
+        categories.each_with_index do |category, i|
+          assert_attributes(attrs[i], names, category)
+        end
+      end
+    end
+    
+    def assert_image20(attrs, image)
+      _wrap_assertion do
+        names = %w(url link title description)
+        names << ["width", :integer]
+        names << ["height", :integer]
+        assert_attributes(attrs, names, image)
+      end
+    end
+
+    def assert_items20(attrs, items)
+      _wrap_assertion do
+        names = %w(about title link description)
+        items.each_with_index do |item, i|
+          assert_attributes(attrs[i], names, item)
+
+          n_attrs = normalized_attrs(attrs[i])
+
+          %w(source enclosure categories guid).each do |name|
+            value = n_attrs[name]
+            if value
+              target = item.__send__(name)
+              __send__("assert_items20_#{name}", value, target)
+            end
+          end
+        end
+      end
+    end
+
+    def assert_items20_source(attrs, source)
+      _wrap_assertion do
+        assert_attributes(attrs, %w(url content), source)
+      end
+    end
+    
+    def assert_items20_enclosure(attrs, enclosure)
+      _wrap_assertion do
+        names = ["url", ["length", :integer], "type"]
+        assert_attributes(attrs, names, enclosure)
+      end
+    end
+    
+    def assert_items20_categories(attrs, categories)
+      _wrap_assertion do
+        assert_channel20_categories(attrs, categories)
+      end
+    end
+    
+    def assert_items20_guid(attrs, guid)
+      _wrap_assertion do
+        names = [["isPermaLink", :boolean], ["content"]]
+        assert_attributes(attrs, names, guid)
+      end
+    end
+
+    def assert_textinput20(attrs, textinput)
+      _wrap_assertion do
+        names = %w(title description name link)
+        assert_attributes(attrs, names, textinput)
+      end
+    end
   end
 end
Index: ruby_1_8/test/rss/test_setup_maker_0.9.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_0.9.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_setup_maker_0.9.rb	(revision 13747)
@@ -49,10 +49,19 @@
             new_hour.content = hour
           end
         end
+
+        setup_dummy_image(maker)
       end
 
+      assert_not_set_error("maker.image", %w(title url)) do
+        RSS::Maker.make("0.91") do |maker|
+          rss.channel.setup_maker(maker)
+        end
+      end
+
       new_rss = RSS::Maker.make("0.91") do |maker|
         rss.channel.setup_maker(maker)
+        setup_dummy_image(maker)
       end
       channel = new_rss.channel
       
@@ -74,9 +83,8 @@
       skipHours.each_with_index do |hour, i|
         assert_equal(hour.to_i, channel.skipHours.hours[i].content)
       end
-      
+
       assert(channel.items.empty?)
-      assert_nil(channel.image)
       assert_nil(channel.textInput)
     end
 
@@ -121,6 +129,7 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
 
         maker.textinput.title = title
         maker.textinput.description = description
@@ -130,6 +139,7 @@
 
       new_rss = RSS::Maker.make("0.91") do |maker|
         rss.channel.setup_maker(maker)
+        rss.image.setup_maker(maker)
         rss.textinput.setup_maker(maker)
       end
       
@@ -157,6 +167,8 @@
             item.description = "#{description}#{i}"
           end
         end
+
+        setup_dummy_image(maker)
       end
       
       new_rss = RSS::Maker.make("0.91") do |maker|
@@ -169,15 +181,16 @@
             item.setup_maker(maker.items)
           end
         end
+
+        rss.image.setup_maker(maker)
       end
-      
+
       assert_equal(item_size, new_rss.items.size)
       new_rss.items.each_with_index do |item, i|
         assert_equal("#{title}#{i}", item.title)
         assert_equal("#{link}#{i}", item.link)
         assert_equal("#{description}#{i}", item.description)
       end
-
     end
 
     def test_setup_maker_items_backward_compatibility
@@ -209,8 +222,9 @@
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
       end
-      
+
       new_rss = RSS::Maker.make("0.91") do |maker|
         rss.setup_maker(maker)
       end
@@ -228,6 +242,5 @@
       assert_equal(charset, xss.charset)
       assert_equal(alternate, xss.alternate)
     end
-    
   end
 end
Index: ruby_1_8/test/rss/test_maker_dc.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_dc.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_dc.rb	(revision 13747)
@@ -57,9 +57,14 @@
     end
 
     def test_rss10_multiple
+      assert_multiple_dublin_core_rss10("_list")
+      assert_multiple_dublin_core_rss10("es")
+    end
+
+    def assert_multiple_dublin_core_rss10(multiple_rights_suffix)
       elems = []
       @elements.each do |name, value|
-        plural = name.to_s + (name == :rights ? "es" : "s")
+        plural = name.to_s + (name == :rights ? multiple_rights_suffix : "s")
         values = [value]
         if name == :date
           values << value + 60
@@ -68,7 +73,7 @@
         end
         elems << [name, values, plural]
       end
-      
+
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         set_multiple_elements(maker.channel, elems)
Index: ruby_1_8/test/rss/test_setup_maker_itunes.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_itunes.rb	(revision 0)
+++ ruby_1_8/test/rss/test_setup_maker_itunes.rb	(revision 13747)
@@ -0,0 +1,144 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestSetupMakerITunes < TestCase
+    def test_setup_maker_simple
+      author = "John Doe"
+      block = true
+      categories = ["Audio Blogs"]
+      image = "http://example.com/podcasts/everything/AllAboutEverything.jpg"
+      duration = "4:05"
+      duration_components = [0, 4, 5]
+      explicit = true
+      keywords = ["salt", "pepper", "shaker", "exciting"]
+      new_feed_url = "http://newlocation.com/example.rss"
+      owner = {:name => "John Doe", :email => "john.doe@e..."}
+      subtitle = "A show about everything"
+      summary = "All About Everything is a show about " +
+        "everything. Each week we dive into any " +
+        "subject known to man and talk about it " +
+        "as much as we can. Look for our Podcast " +
+        "in the iTunes Music Store"
+
+      feed = RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        channel = maker.channel
+        channel.itunes_author = author
+        channel.itunes_block = block
+        categories.each do |category|
+          channel.itunes_categories.new_category.text = category
+        end
+        channel.itunes_image = image
+        channel.itunes_explicit = explicit
+        channel.itunes_keywords = keywords
+        channel.itunes_owner.itunes_name = owner[:name]
+        channel.itunes_owner.itunes_email = owner[:email]
+        channel.itunes_subtitle = subtitle
+        channel.itunes_summary = summary
+
+        item = maker.items.last
+        item.itunes_author = author
+        item.itunes_block = block
+        item.itunes_duration = duration
+        item.itunes_explicit = explicit
+        item.itunes_keywords = keywords
+        item.itunes_subtitle = subtitle
+        item.itunes_summary = summary
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("rss2.0") do |maker|
+        feed.setup_maker(maker)
+      end
+      assert_not_nil(new_feed)
+
+      channel = new_feed.channel
+      item = new_feed.items.last
+
+      assert_equal(author, channel.itunes_author)
+      assert_equal(author, item.itunes_author)
+
+      assert_equal(block, channel.itunes_block?)
+      assert_equal(block, item.itunes_block?)
+
+      assert_equal(categories,
+                   collect_itunes_categories(channel.itunes_categories))
+
+      assert_equal(image, channel.itunes_image.href)
+
+      assert_equal(duration_components,
+                   [item.itunes_duration.hour,
+                    item.itunes_duration.minute,
+                    item.itunes_duration.second])
+
+      assert_equal(explicit, channel.itunes_explicit?)
+      assert_equal(explicit, item.itunes_explicit?)
+
+      assert_equal(keywords, channel.itunes_keywords)
+      assert_equal(keywords, item.itunes_keywords)
+
+      assert_equal(owner,
+                   {
+                     :name => channel.itunes_owner.itunes_name,
+                     :email => channel.itunes_owner.itunes_email
+                   })
+
+      assert_equal(subtitle, channel.itunes_subtitle)
+      assert_equal(subtitle, item.itunes_subtitle)
+
+      assert_equal(summary, channel.itunes_summary)
+      assert_equal(summary, item.itunes_summary)
+    end
+
+    def test_setup_maker_with_nested_categories
+      categories = [["Arts & Entertainment", "Games"],
+                    ["Technology", "Computers"],
+                    "Audio Blogs"]
+
+      feed = RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        channel = maker.channel
+        categories.each do |category|
+          target = channel.itunes_categories
+          if category.is_a?(Array)
+            category.each do |sub_category|
+              target = target.new_category
+              target.text = sub_category
+            end
+          else
+            target.new_category.text = category
+          end
+        end
+      end
+      assert_not_nil(feed)
+
+      new_feed = RSS::Maker.make("rss2.0") do |maker|
+        feed.setup_maker(maker)
+      end
+      assert_not_nil(new_feed)
+
+      channel = new_feed.channel
+
+      assert_equal(categories,
+                   collect_itunes_categories(channel.itunes_categories))
+    end
+
+    private
+    def collect_itunes_categories(categories)
+      categories.collect do |c|
+        rest = collect_itunes_categories(c.itunes_categories)
+        if rest.empty?
+          c.text
+        else
+          [c.text, *rest]
+        end
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_itunes.rb
===================================================================
--- ruby_1_8/test/rss/test_itunes.rb	(revision 0)
+++ ruby_1_8/test/rss/test_itunes.rb	(revision 13747)
@@ -0,0 +1,347 @@
+require "cgi"
+require "rexml/document"
+
+require "rss-testcase"
+
+require "rss/2.0"
+require "rss/itunes"
+
+module RSS
+  class TestITunes < TestCase
+    def test_author
+      assert_itunes_author(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+
+      assert_itunes_author(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_block
+      assert_itunes_block(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_category
+      assert_itunes_category(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+    end
+
+    def test_image
+      assert_itunes_image(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+    end
+
+    def test_duration
+      assert_itunes_duration(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_explicit
+      assert_itunes_explicit(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+
+      assert_itunes_explicit(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_keywords
+      assert_itunes_keywords(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+
+      assert_itunes_keywords(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_new_feed_url
+      assert_itunes_new_feed_url(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+    end
+
+    def test_owner
+      assert_itunes_owner(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+    end
+
+    def test_subtitle
+      assert_itunes_subtitle(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+
+      assert_itunes_subtitle(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    def test_summary
+      assert_itunes_summary(%w(channel)) do |content, xmlns|
+        make_rss20(make_channel20(content), xmlns)
+      end
+
+      assert_itunes_summary(%w(items last)) do |content, xmlns|
+        make_rss20(make_channel20(make_item20(content)), xmlns)
+      end
+    end
+
+    private
+    def itunes_rss20_parse(content, &maker)
+      xmlns = {"itunes" => "http://www.itunes.com/dtds/podcast-1.0.dtd"}
+      rss20_xml = maker.call(content, xmlns)
+      ::RSS::Parser.parse(rss20_xml)
+    end
+
+    def assert_itunes_author(readers, &rss20_maker)
+      _wrap_assertion do
+        author = "John Lennon"
+        rss20 = itunes_rss20_parse(tag("itunes:author", author), &rss20_maker)
+        target = chain_reader(rss20, readers)
+        assert_equal(author, target.itunes_author)
+      end
+    end
+
+    def _assert_itunes_block(value, boolean_value, readers, &rss20_maker)
+      rss20 = itunes_rss20_parse(tag("itunes:block", value), &rss20_maker)
+      target = chain_reader(rss20, readers)
+      assert_equal(value, target.itunes_block)
+      assert_equal(boolean_value, target.itunes_block?)
+    end
+
+    def assert_itunes_block(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_block("yes", true, readers, &rss20_maker)
+        _assert_itunes_block("Yes", true, readers, &rss20_maker)
+        _assert_itunes_block("no", false, readers, &rss20_maker)
+        _assert_itunes_block("", false, readers, &rss20_maker)
+      end
+    end
+
+    def _assert_itunes_category(categories, readers, &rss20_maker)
+      cats = categories.collect do |category|
+        if category.is_a?(Array)
+          category, sub_category = category
+          tag("itunes:category",
+              tag("itunes:category", nil, {"text" => sub_category}),
+              {"text" => category})
+        else
+          tag("itunes:category", nil, {"text" => category})
+        end
+      end.join
+      rss20 = itunes_rss20_parse(cats, &rss20_maker)
+      target = chain_reader(rss20, readers)
+      actual_categories = target.itunes_categories.collect do |category|
+        cat = category.text
+        if category.itunes_categories.empty?
+          cat
+        else
+          [cat, *category.itunes_categories.collect {|c| c.text}]
+        end
+      end
+      assert_equal(categories, actual_categories)
+    end
+
+    def assert_itunes_category(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_category(["Audio Blogs"], readers, &rss20_maker)
+        _assert_itunes_category([["Arts & Entertainment", "Games"]],
+                                readers, &rss20_maker)
+        _assert_itunes_category([["Arts & Entertainment", "Games"],
+                                 ["Technology", "Computers"],
+                                 "Audio Blogs"],
+                                readers, &rss20_maker)
+      end
+    end
+
+    def assert_itunes_image(readers, &rss20_maker)
+      _wrap_assertion do
+        url = "http://example.com/podcasts/everything/AllAboutEverything.jpg"
+        content = tag("itunes:image", nil, {"href" => url})
+        rss20 = itunes_rss20_parse(content, &rss20_maker)
+        target = chain_reader(rss20, readers)
+        assert_not_nil(target.itunes_image)
+        assert_equal(url, target.itunes_image.href)
+
+        assert_missing_attribute("image", "href") do
+          content = tag("itunes:image")
+          itunes_rss20_parse(content, &rss20_maker)
+        end
+      end
+    end
+
+    def _assert_itunes_duration(hour, minute, second, value,
+                                readers, &rss20_maker)
+      content = tag("itunes:duration", value)
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      duration = chain_reader(rss20, readers).itunes_duration
+      assert_equal(value, duration.content)
+      assert_equal(hour, duration.hour)
+      assert_equal(minute, duration.minute)
+      assert_equal(second, duration.second)
+    end
+
+    def _assert_itunes_duration_not_available_value(value, &rss20_maker)
+      assert_not_available_value("duration", value) do
+        content = tag("itunes:duration", value)
+        itunes_rss20_parse(content, &rss20_maker)
+      end
+    end
+
+    def assert_itunes_duration(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_duration(7, 14, 5, "07:14:05", readers, &rss20_maker)
+        _assert_itunes_duration(7, 14, 5, "7:14:05", readers, &rss20_maker)
+        _assert_itunes_duration(0, 4, 55, "04:55", readers, &rss20_maker)
+        _assert_itunes_duration(0, 4, 5, "4:05", readers, &rss20_maker)
+
+        _assert_itunes_duration_not_available_value("5", &rss20_maker)
+        _assert_itunes_duration_not_available_value("09:07:14:05", &rss20_maker)
+        _assert_itunes_duration_not_available_value("10:5", &rss20_maker)
+        _assert_itunes_duration_not_available_value("10:03:5", &rss20_maker)
+        _assert_itunes_duration_not_available_value("10:3:05", &rss20_maker)
+
+        _assert_itunes_duration_not_available_value("xx:xx:xx", &rss20_maker)
+      end
+    end
+
+    def _assert_itunes_explicit(explicit, value, readers, &rss20_maker)
+      content = tag("itunes:explicit", value)
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      target = chain_reader(rss20, readers)
+      assert_equal(value, target.itunes_explicit)
+      assert_equal(explicit, target.itunes_explicit?)
+    end
+
+    def assert_itunes_explicit(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_explicit(true, "yes", readers, &rss20_maker)
+        _assert_itunes_explicit(false, "clean", readers, &rss20_maker)
+        _assert_itunes_explicit(nil, "no", readers, &rss20_maker)
+      end
+    end
+
+    def _assert_itunes_keywords(keywords, value, readers, &rss20_maker)
+      content = tag("itunes:keywords", value)
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      target = chain_reader(rss20, readers)
+      assert_equal(keywords, target.itunes_keywords)
+    end
+
+    def assert_itunes_keywords(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_keywords(["salt"], "salt", readers, &rss20_maker)
+        _assert_itunes_keywords(["salt"], " salt ", readers, &rss20_maker)
+        _assert_itunes_keywords(["salt", "pepper", "shaker", "exciting"],
+                                "salt, pepper, shaker, exciting",
+                                readers, &rss20_maker)
+        _assert_itunes_keywords(["metric", "socket", "wrenches", "toolsalt"],
+                                "metric, socket, wrenches, toolsalt",
+                                readers, &rss20_maker)
+        _assert_itunes_keywords(["olitics", "red", "blue", "state"],
+                                "olitics, red, blue, state",
+                                readers, &rss20_maker)
+      end
+    end
+
+    def assert_itunes_new_feed_url(readers, &rss20_maker)
+      _wrap_assertion do
+        url = "http://newlocation.com/example.rss"
+        content = tag("itunes:new-feed-url", url)
+        rss20 = itunes_rss20_parse(content, &rss20_maker)
+        target = chain_reader(rss20, readers)
+        assert_equal(url, target.itunes_new_feed_url)
+      end
+    end
+
+    def _assert_itunes_owner(name, email, readers, &rss20_maker)
+      content = tag("itunes:owner",
+                    tag("itunes:name", name) + tag("itunes:email", email))
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      owner = chain_reader(rss20, readers).itunes_owner
+      assert_equal(name, owner.itunes_name)
+      assert_equal(email, owner.itunes_email)
+    end
+
+    def assert_itunes_owner(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_owner("John Doe", "john.doe@e...",
+                             readers, &rss20_maker)
+
+        assert_missing_tag("name", "owner")  do
+          content = tag("itunes:owner")
+          itunes_rss20_parse(content, &rss20_maker)
+        end
+
+        assert_missing_tag("name", "owner")  do
+          content = tag("itunes:owner",
+                        tag("itunes:email", "john.doe@e..."))
+          itunes_rss20_parse(content, &rss20_maker)
+        end
+
+        assert_missing_tag("email", "owner")  do
+          content = tag("itunes:owner", tag("itunes:name", "John Doe"))
+          itunes_rss20_parse(content, &rss20_maker)
+        end
+      end
+    end
+
+    def _assert_itunes_subtitle(value, readers, &rss20_maker)
+      content = tag("itunes:subtitle", value)
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      target = chain_reader(rss20, readers)
+      assert_equal(value, target.itunes_subtitle)
+    end
+
+    def assert_itunes_subtitle(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_subtitle("A show about everything", readers, &rss20_maker)
+        _assert_itunes_subtitle("A short primer on table spices",
+                                readers, &rss20_maker)
+        _assert_itunes_subtitle("Comparing socket wrenches is fun!",
+                                readers, &rss20_maker)
+        _assert_itunes_subtitle("Red + Blue != Purple", readers, &rss20_maker)
+      end
+    end
+
+    def _assert_itunes_summary(value, readers, &rss20_maker)
+      content = tag("itunes:summary", value)
+      rss20 = itunes_rss20_parse(content, &rss20_maker)
+      target = chain_reader(rss20, readers)
+      assert_equal(value, target.itunes_summary)
+    end
+
+    def assert_itunes_summary(readers, &rss20_maker)
+      _wrap_assertion do
+        _assert_itunes_summary("All About Everything is a show about " +
+                               "everything. Each week we dive into any " +
+                               "subject known to man and talk about it as " +
+                               "much as we can. Look for our Podcast in " +
+                               "the iTunes Music Store",
+                               readers, &rss20_maker)
+        _assert_itunes_summary("This week we talk about salt and pepper " +
+                               "shakers, comparing and contrasting pour " +
+                               "rates, construction materials, and overall " +
+                               "aesthetics. Come and join the party!",
+                               readers, &rss20_maker)
+        _assert_itunes_summary("This week we talk about metric vs. old " +
+                               "english socket wrenches. Which one is " +
+                               "better? Do you really need both? Get all " +
+                               "of your answers here.",
+                               readers, &rss20_maker)
+        _assert_itunes_summary("This week we talk about surviving in a " +
+                               "Red state if youe a Blue person. Or " +
+                               "vice versa.",
+                               readers, &rss20_maker)
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_slash.rb
===================================================================
--- ruby_1_8/test/rss/test_slash.rb	(revision 0)
+++ ruby_1_8/test/rss/test_slash.rb	(revision 13747)
@@ -0,0 +1,64 @@
+require "cgi"
+require "rexml/document"
+
+require "rss-testcase"
+
+require "rss/1.0"
+require "rss/slash"
+
+module RSS
+  class TestSlash < TestCase
+    def setup
+      @elements = {
+        "section" => "articles",
+        "department" => "not-an-ocean-unless-there-are-lobsters",
+        "comments" => 177,
+        "hit_parades" => [177, 155, 105, 33, 6, 3, 0],
+      }
+
+      slash_nodes = @elements.collect do |name, value|
+        if name == "hit_parades"
+          name = "hit_parade"
+          value = value.join(",")
+        end
+        "<slash:#{name}>#{value}</slash:#{name}>"
+      end.join("\n")
+
+      slash_ns = {"slash" => "http://purl.org/rss/1.0/modules/slash/"}
+      @source = make_RDF(<<-EOR, slash_ns)
+#{make_channel}
+#{make_image}
+#{make_item(slash_nodes)}
+#{make_textinput}
+EOR
+    end
+
+    def test_parser
+      rss = RSS::Parser.parse(@source)
+
+      assert_not_nil(rss)
+
+      item = rss.items[0]
+      assert_not_nil(item)
+
+      assert_slash_elements(item)
+    end
+
+    def test_to_s
+      rss = RSS::Parser.parse(@source)
+      rss = RSS::Parser.parse(rss.to_s)
+
+      assert_not_nil(rss)
+
+      item = rss.items[0]
+      assert_not_nil(item)
+
+      assert_slash_elements(item)
+    end
+
+    private
+    def assert_slash_elements(target)
+      super(@elements, target)
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_maker_1.0.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_1.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_1.0.rb	(revision 13747)
@@ -8,12 +8,15 @@
     def test_rdf
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
       assert_equal("1.0", rss.rss_version)
       
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         maker.encoding = "EUC-JP"
+
+        setup_dummy_item(maker)
       end
       assert_equal("1.0", rss.rss_version)
       assert_equal("EUC-JP", rss.encoding)
@@ -21,6 +24,8 @@
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         maker.standalone = "yes"
+
+        setup_dummy_item(maker)
       end
       assert_equal("1.0", rss.rss_version)
       assert_equal("yes", rss.standalone)
@@ -29,6 +34,8 @@
         setup_dummy_channel(maker)
         maker.encoding = "EUC-JP"
         maker.standalone = "yes"
+
+        setup_dummy_item(maker)
       end
       assert_equal("1.0", rss.rss_version)
       assert_equal("EUC-JP", rss.encoding)
@@ -49,13 +56,15 @@
         maker.channel.title = title
         maker.channel.link = link
         maker.channel.description = description
+
+        setup_dummy_item(maker)
       end
       channel = rss.channel
       assert_equal(about, channel.about)
       assert_equal(title, channel.title)
       assert_equal(link, channel.link)
       assert_equal(description, channel.description)
-      assert(channel.items.Seq.lis.empty?)
+      assert_equal(1, channel.items.Seq.lis.size)
       assert_nil(channel.image)
       assert_nil(channel.textinput)
 
@@ -68,13 +77,15 @@
         setup_dummy_image(maker)
 
         setup_dummy_textinput(maker)
+
+        setup_dummy_item(maker)
       end
       channel = rss.channel
       assert_equal(about, channel.about)
       assert_equal(title, channel.title)
       assert_equal(link, channel.link)
       assert_equal(description, channel.description)
-      assert(channel.items.Seq.lis.empty?)
+      assert_equal(1, channel.items.Seq.lis.size)
       assert_equal(rss.image.about, channel.image.resource)
       assert_equal(rss.textinput.about, channel.textinput.resource)
     end
@@ -134,6 +145,8 @@
         
         maker.image.title = title
         maker.image.url = url
+
+        setup_dummy_item(maker)
       end
       image = rss.image
       assert_equal(url, image.about)
@@ -164,6 +177,8 @@
         
         # maker.image.url = url
         maker.image.title = title
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.image)
       assert_nil(rss.image)
@@ -174,6 +189,8 @@
         
         maker.image.url = url
         # maker.image.title = title
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.image)
       assert_nil(rss.image)
@@ -186,19 +203,22 @@
           
           maker.image.url = url
           maker.image.title = title
+
+          setup_dummy_item(maker)
         end
       end
     end
-    
-    def test_items
+
+    def test_items(with_convenience_way=true)
       title = "TITLE"
       link = "http://hoge.com/"
       description = "text hoge fuga"
 
-      rss = RSS::Maker.make("1.0") do |maker|
-        setup_dummy_channel(maker)
+      assert_not_set_error("maker", %w(items)) do
+        RSS::Maker.make("1.0") do |maker|
+          setup_dummy_channel(maker)
+        end
       end
-      assert(rss.items.empty?)
 
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
@@ -222,42 +242,46 @@
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.do_sort = true
       end
       assert_equal(item_size, rss.items.size)
-      rss.items.each_with_index do |item, i|
-        assert_equal("#{link}#{i}", item.about)
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.items.each_with_index do |_item, i|
+        assert_equal("#{link}#{i}", _item.about)
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
 
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.do_sort = Proc.new do |x, y|
-          y.title[-1] <=> x.title[-1]
+          if with_convenience_way
+            y.title[-1] <=> x.title[-1]
+          else
+            y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]}
+          end
         end
       end
       assert_equal(item_size, rss.items.size)
-      rss.items.reverse.each_with_index do |item, i|
-        assert_equal("#{link}#{i}", item.about)
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.items.reverse.each_with_index do |_item, i|
+        assert_equal("#{link}#{i}", _item.about)
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
 
       max_size = item_size / 2
@@ -265,84 +289,102 @@
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.max_size = max_size
       end
       assert_equal(max_size, rss.items.size)
-      rss.items.each_with_index do |item, i|
-        assert_equal("#{link}#{i}", item.about)
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.items.each_with_index do |_item, i|
+        assert_equal("#{link}#{i}", _item.about)
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
 
       max_size = 0
-      rss = RSS::Maker.make("1.0") do |maker|
-        setup_dummy_channel(maker)
-        
-        item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+      assert_not_set_error("maker", %w(items)) do
+        RSS::Maker.make("1.0") do |maker|
+          setup_dummy_channel(maker)
+
+          item_size.times do |i|
+            maker.items.new_item do |_item|
+              _item.title = "#{title}#{i}"
+              _item.link = "#{link}#{i}"
+              _item.description = "#{description}#{i}"
+            end
           end
+          maker.items.max_size = max_size
         end
-        maker.items.max_size = max_size
       end
-      assert_equal(max_size, rss.items.size)
 
       max_size = -2
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.max_size = max_size
       end
       assert_equal(item_size + max_size + 1, rss.items.size)
-      rss.items.each_with_index do |item, i|
-        assert_equal("#{link}#{i}", item.about)
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.items.each_with_index do |_item, i|
+        assert_equal("#{link}#{i}", _item.about)
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
     end
 
+    def test_items_with_new_api_since_018
+      test_items(false)
+    end
+
     def test_not_valid_items
       title = "TITLE"
       link = "http://hoge.com/"
 
-      rss = RSS::Maker.make("1.0") do |maker|
-        setup_dummy_channel(maker)
-        
-        maker.items.new_item do |item|
-          # item.title = title
-          item.link = link
+      assert_not_set_error("maker.item", %w(title)) do
+        RSS::Maker.make("1.0") do |maker|
+          setup_dummy_channel(maker)
+
+          maker.items.new_item do |item|
+            # item.title = title
+            item.link = link
+          end
         end
       end
-      assert(rss.items.empty?)
 
-      rss = RSS::Maker.make("1.0") do |maker|
-        setup_dummy_channel(maker)
-        
-        maker.items.new_item do |item|
-          item.title = title
-          # item.link = link
+      assert_not_set_error("maker.item", %w(link)) do
+        RSS::Maker.make("1.0") do |maker|
+          setup_dummy_channel(maker)
+
+          maker.items.new_item do |item|
+            item.title = title
+            # item.link = link
+          end
         end
       end
-      assert(rss.items.empty?)
+
+      assert_not_set_error("maker.item", %w(title link)) do
+        RSS::Maker.make("1.0") do |maker|
+          setup_dummy_channel(maker)
+
+          maker.items.new_item do |item|
+            # item.title = title
+            # item.link = link
+          end
+        end
+      end
     end
-    
+
     def test_textinput
       title = "fugafuga"
       description = "text hoge fuga"
@@ -356,6 +398,8 @@
         maker.textinput.title = title
         maker.textinput.description = description
         maker.textinput.name = name
+
+        setup_dummy_item(maker)
       end
       textinput = rss.textinput
       assert_equal(link, textinput.about)
@@ -365,15 +409,16 @@
       assert_equal(description, textinput.description)
       assert_equal(link, textinput.link)
 
-      rss = RSS::Maker.make("1.0") do |maker|
-        # setup_dummy_channel(maker)
+      assert_not_set_error("maker.channel", %w(about link description title)) do
+        RSS::Maker.make("1.0") do |maker|
+          # setup_dummy_channel(maker)
 
-        maker.textinput.link = link
-        maker.textinput.title = title
-        maker.textinput.description = description
-        maker.textinput.name = name
+          maker.textinput.link = link
+          maker.textinput.title = title
+          maker.textinput.description = description
+          maker.textinput.name = name
+        end
       end
-      assert_nil(rss)
     end
     
     def test_not_valid_textinput
@@ -389,6 +434,8 @@
         maker.textinput.title = title
         maker.textinput.description = description
         maker.textinput.name = name
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.textinput)
       assert_nil(rss.textinput)
@@ -400,6 +447,8 @@
         # maker.textinput.title = title
         maker.textinput.description = description
         maker.textinput.name = name
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.textinput)
       assert_nil(rss.textinput)
@@ -411,6 +460,8 @@
         maker.textinput.title = title
         # maker.textinput.description = description
         maker.textinput.name = name
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.textinput)
       assert_nil(rss.textinput)
@@ -422,6 +473,8 @@
         maker.textinput.title = title
         maker.textinput.description = description
         # maker.textinput.name = name
+
+        setup_dummy_item(maker)
       end
       assert_nil(rss.channel.textinput)
       assert_nil(rss.textinput)
Index: ruby_1_8/test/rss/test_taxonomy.rb
===================================================================
--- ruby_1_8/test/rss/test_taxonomy.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_taxonomy.rb	(revision 13747)
@@ -144,8 +144,10 @@
       end
 
       @topic_nodes.each_with_index do |node, i|
-        expected = REXML::Document.new(node).root
-        actual = REXML::Document.new(@rss.taxo_topics[i].to_s(true, "")).root
+        expected_xml = taxo_xmlns_container(node)
+        expected = REXML::Document.new(expected_xml).root.elements[1]
+        actual_xml = taxo_xmlns_container(@rss.taxo_topics[i].to_s(true, ""))
+        actual = REXML::Document.new(actual_xml).root.elements[1]
         expected_elems = expected.reject {|x| x.is_a?(REXML::Text)}
         actual_elems = actual.reject {|x| x.is_a?(REXML::Text)}
         expected_elems.sort! {|x, y| x.name <=> y.name}
@@ -155,6 +157,16 @@
         assert_equal(expected.attributes.sort, actual.attributes.sort)
       end
     end
+
+    private
+    def taxo_xmlns_container(content)
+      xmlns_container({
+                        @prefix => @uri,
+                        "dc" => "http://purl.org/dc/elements/1.1/",
+                        "rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+                      },
+                      content)
+    end
   end
 end
 
Index: ruby_1_8/test/rss/test_image.rb
===================================================================
--- ruby_1_8/test/rss/test_image.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_image.rb	(revision 13747)
@@ -11,7 +11,7 @@
 
     def setup
       @prefix = "image"
-      @uri = "http://web.resource.org/rss/1.0/modules/image/"
+      @uri = "http://purl.org/rss/1.0/modules/image/"
 
       @favicon_attrs = {
         "rdf:about" => "http://www.kuro5hin.org/favicon.ico",
@@ -65,20 +65,30 @@
 
       @rss = Parser.parse(@rss_source)
     end
-  
+
     def test_parser
       assert_nothing_raised do
         Parser.parse(@rss_source)
       end
-      
+
       assert_too_much_tag("favicon", "channel") do
         Parser.parse(make_RDF(<<-EOR, @ns))
 #{make_channel(@channel_nodes * 2)}
 #{make_item}
 EOR
       end
+
+      attrs = {"rdf:about" => "http://www.example.org/item.png"}
+      contents = [["#{@prefix}:width", "80"]] * 5
+      image_item = make_element("#{@prefix}:item", attrs, contents)
+      assert_too_much_tag("width", "item") do
+        Parser.parse(make_RDF(<<-EOR, @ns))
+#{make_channel}
+#{make_item(image_item)}
+EOR
+      end
     end
-  
+
     def test_favicon_accessor
       favicon = @rss.channel.image_favicon
       [
@@ -135,7 +145,7 @@
           image_item.__send__("#{name}=", attrs[full_name])
           assert_equal(attrs[full_name], image_item.__send__(name))
         end
-        
+
         [
           ["width", "image:width", "111"],
           ["image_width", "image:width", "44"],
@@ -163,22 +173,26 @@
 
     def test_favicon_to_s
       favicon = @rss.channel.image_favicon
-      expected = REXML::Document.new(make_element("#{@prefix}:favicon",
-                                                  @favicon_attrs,
-                                                  @favicon_contents))
-      actual = REXML::Document.new(favicon.to_s(false, ""))
+      expected_xml = image_xmlns_container(make_element("#{@prefix}:favicon",
+                                                        @favicon_attrs,
+                                                        @favicon_contents))
+      expected = REXML::Document.new(expected_xml)
+      actual_xml = image_xmlns_container(favicon.to_s(false, ""))
+      actual = REXML::Document.new(actual_xml)
       assert_equal(expected.to_s, actual.to_s)
     end
 
     def test_item_to_s
       @rss.items.each_with_index do |item, i|
         attrs, contents = @items[i]
-        expected_s = make_element("#{@prefix}:item", attrs, contents)
-        expected = REXML::Document.new(expected_s)
-        actual = REXML::Document.new(item.image_item.to_s(false, ""))
+        expected_xml = make_element("#{@prefix}:item", attrs, contents)
+        expected_xml = image_xmlns_container(expected_xml)
+        expected = REXML::Document.new(expected_xml)
+        actual_xml = image_xmlns_container(item.image_item.to_s(false, ""))
+        actual = REXML::Document.new(actual_xml)
 
         assert_equal(expected[0].attributes, actual[0].attributes)
-        
+
         %w(image:height image:width dc:title).each do |name|
           actual_target = actual.elements["//#{name}"]
           expected_target = expected.elements["//#{name}"]
@@ -187,5 +201,14 @@
       end
     end
 
+    private
+    def image_xmlns_container(content)
+      xmlns_container({
+                        @prefix => @uri,
+                        "dc" => "http://purl.org/dc/elements/1.1/",
+                        "rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
+                      },
+                      content)
+    end
   end
 end
Index: ruby_1_8/test/rss/test_syndication.rb
===================================================================
--- ruby_1_8/test/rss/test_syndication.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_syndication.rb	(revision 13747)
@@ -93,7 +93,7 @@
       
       %w(-2 0.3 -0.4).each do |x|
         @parents.each do |parent|
-          assert_not_available_value("updateBase", x) do
+          assert_not_available_value("sy:updateBase", x) do
             @rss.__send__(parent).sy_updateBase = x
           end
         end
@@ -120,8 +120,6 @@
           end
         end
       end
-      
     end
-  
   end
 end
Index: ruby_1_8/test/rss/test_maker_0.9.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_0.9.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_0.9.rb	(revision 13747)
@@ -11,18 +11,21 @@
       
       rss = RSS::Maker.make("0.9") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
       end
       assert_equal("0.91", rss.rss_version)
       
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
       end
       assert_equal("0.91", rss.rss_version)
 
       
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.encoding = "EUC-JP"
       end
       assert_equal("0.91", rss.rss_version)
@@ -30,7 +33,8 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.standalone = "yes"
       end
       assert_equal("0.91", rss.rss_version)
@@ -38,7 +42,8 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.encoding = "EUC-JP"
         maker.standalone = "yes"
       end
@@ -67,7 +72,10 @@
       ]
       pubDate = Time.now
       lastBuildDate = Time.now
-      
+
+      image_url = "http://example.com/logo.png"
+      image_title = "Logo"
+
       rss = RSS::Maker.make("0.91") do |maker|
         maker.channel.title = title
         maker.channel.link = link
@@ -91,6 +99,9 @@
             new_hour.content = hour
           end
         end
+
+        maker.image.url = image_url
+        maker.image.title = image_title
       end
       channel = rss.channel
       
@@ -115,7 +126,11 @@
       end
       
       assert(channel.items.empty?)
-      assert_nil(channel.image)
+
+      assert_equal(image_url, channel.image.url)
+      assert_equal(image_title, channel.image.title)
+      assert_equal(link, channel.image.link)
+
       assert_nil(channel.textInput)
     end
 
@@ -211,17 +226,18 @@
       height = "400"
       description = "an image"
 
-      rss = RSS::Maker.make("0.91") do |maker|
-        setup_dummy_channel(maker)
-        maker.channel.link = link
-        
-        # maker.image.title = title
-        maker.image.url = url
-        maker.image.width = width
-        maker.image.height = height
-        maker.image.description = description
+      assert_not_set_error("maker.image", %w(title)) do
+        RSS::Maker.make("0.91") do |maker|
+          setup_dummy_channel(maker)
+          maker.channel.link = link
+
+          # maker.image.title = title
+          maker.image.url = url
+          maker.image.width = width
+          maker.image.height = height
+          maker.image.description = description
+        end
       end
-      assert_nil(rss.channel.image)
 
       assert_not_set_error("maker.channel", %w(link)) do
         RSS::Maker.make("0.91") do |maker|
@@ -237,26 +253,28 @@
         end
       end
 
-      rss = RSS::Maker.make("0.91") do |maker|
-        setup_dummy_channel(maker)
-        maker.channel.link = link
-        
-        maker.image.title = title
-        # maker.image.url = url
-        maker.image.width = width
-        maker.image.height = height
-        maker.image.description = description
+      assert_not_set_error("maker.image", %w(url)) do
+        RSS::Maker.make("0.91") do |maker|
+          setup_dummy_channel(maker)
+          maker.channel.link = link
+
+          maker.image.title = title
+          # maker.image.url = url
+          maker.image.width = width
+          maker.image.height = height
+          maker.image.description = description
+        end
       end
-      assert_nil(rss.channel.image)
     end
     
-    def test_items
+    def test_items(with_convenience_way=true)
       title = "TITLE"
       link = "http://hoge.com/"
       description = "text hoge fuga"
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
       end
       assert(rss.channel.items.empty?)
 
@@ -268,6 +286,8 @@
           item.link = link
           # item.description = description
         end
+
+        setup_dummy_image(maker)
       end
       assert_equal(1, rss.channel.items.size)
       item = rss.channel.items.first
@@ -281,43 +301,55 @@
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.do_sort = true
+
+        setup_dummy_image(maker)
       end
       assert_equal(item_size, rss.items.size)
-      rss.channel.items.each_with_index do |item, i|
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.channel.items.each_with_index do |_item, i|
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
         
         item_size.times do |i|
-          maker.items.new_item do |item|
-            item.title = "#{title}#{i}"
-            item.link = "#{link}#{i}"
-            item.description = "#{description}#{i}"
+          maker.items.new_item do |_item|
+            _item.title = "#{title}#{i}"
+            _item.link = "#{link}#{i}"
+            _item.description = "#{description}#{i}"
           end
         end
         maker.items.do_sort = Proc.new do |x, y|
-          y.title[-1] <=> x.title[-1]
+          if with_convenience_way
+            y.title[-1] <=> x.title[-1]
+          else
+            y.title {|t| t.content[-1]} <=> x.title {|t| t.content[-1]}
+          end
         end
+
+        setup_dummy_image(maker)
       end
       assert_equal(item_size, rss.items.size)
-      rss.channel.items.reverse.each_with_index do |item, i|
-        assert_equal("#{title}#{i}", item.title)
-        assert_equal("#{link}#{i}", item.link)
-        assert_equal("#{description}#{i}", item.description)
+      rss.channel.items.reverse.each_with_index do |_item, i|
+        assert_equal("#{title}#{i}", _item.title)
+        assert_equal("#{link}#{i}", _item.link)
+        assert_equal("#{description}#{i}", _item.description)
       end
     end
 
+    def test_items_with_new_api_since_018
+      test_items(false)
+    end
+
     def test_textInput
       title = "fugafuga"
       description = "text hoge fuga"
@@ -326,6 +358,7 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
 
         maker.textinput.title = title
         maker.textinput.description = description
@@ -338,15 +371,17 @@
       assert_equal(name, textInput.name)
       assert_equal(link, textInput.link)
 
-      rss = RSS::Maker.make("0.91") do |maker|
-        # setup_dummy_channel(maker)
+      assert_not_set_error("maker.channel",
+                           %w(link language description title)) do
+        RSS::Maker.make("0.91") do |maker|
+          # setup_dummy_channel(maker)
 
-        maker.textinput.title = title
-        maker.textinput.description = description
-        maker.textinput.name = name
-        maker.textinput.link = link
+          maker.textinput.title = title
+          maker.textinput.description = description
+          maker.textinput.name = name
+          maker.textinput.link = link
+        end
       end
-      assert_nil(rss)
     end
     
     def test_not_valid_textInput
@@ -357,6 +392,7 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
+        setup_dummy_image(maker)
 
         # maker.textinput.title = title
         maker.textinput.description = description
@@ -367,7 +403,8 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.textinput.title = title
         # maker.textinput.description = description
         maker.textinput.name = name
@@ -377,7 +414,8 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.textinput.title = title
         maker.textinput.description = description
         # maker.textinput.name = name
@@ -387,7 +425,8 @@
 
       rss = RSS::Maker.make("0.91") do |maker|
         setup_dummy_channel(maker)
-        
+        setup_dummy_image(maker)
+
         maker.textinput.title = title
         maker.textinput.description = description
         maker.textinput.name = name
Index: ruby_1_8/test/rss/test_version.rb
===================================================================
--- ruby_1_8/test/rss/test_version.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_version.rb	(revision 13747)
@@ -3,7 +3,7 @@
 module RSS
   class TestVersion < TestCase
     def test_version
-      assert_equal("0.1.6", ::RSS::VERSION)
+      assert_equal("0.2.0", ::RSS::VERSION)
     end
   end
 end
Index: ruby_1_8/test/rss/test_maker_itunes.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_itunes.rb	(revision 0)
+++ ruby_1_8/test/rss/test_maker_itunes.rb	(revision 13747)
@@ -0,0 +1,471 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestMakerITunes < TestCase
+    def test_author
+      assert_maker_itunes_author(%w(channel))
+      assert_maker_itunes_author(%w(items last))
+    end
+
+    def test_block
+      assert_maker_itunes_block(%w(channel))
+      assert_maker_itunes_block(%w(items last))
+    end
+
+    def test_category
+      assert_maker_itunes_category(%w(channel))
+    end
+
+    def test_image
+      assert_maker_itunes_image(%w(channel))
+    end
+
+    def test_duration
+      assert_maker_itunes_duration(%w(items last))
+    end
+
+    def test_explicit
+      assert_maker_itunes_explicit(%w(channel))
+      assert_maker_itunes_explicit(%w(items last))
+    end
+
+    def test_keywords
+      assert_maker_itunes_keywords(%w(channel))
+      assert_maker_itunes_keywords(%w(items last))
+    end
+
+    def test_new_feed_url
+      assert_maker_itunes_new_feed_url(%w(channel))
+    end
+
+    def test_owner
+      assert_maker_itunes_owner(%w(channel))
+    end
+
+    def test_subtitle
+      assert_maker_itunes_subtitle(%w(channel))
+      assert_maker_itunes_subtitle(%w(items last))
+    end
+
+    def test_summary
+      assert_maker_itunes_summary(%w(channel))
+      assert_maker_itunes_summary(%w(items last))
+    end
+
+    private
+
+    def assert_maker_itunes_author(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        author = "John Doe"
+        rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+          setup_dummy_channel(maker)
+          setup_dummy_item(maker)
+
+          target = chain_reader(maker, maker_readers)
+          target.itunes_author = author
+        end
+        target = chain_reader(rss20, feed_readers)
+        assert_equal(author, target.itunes_author)
+      end
+    end
+
+    def _assert_maker_itunes_block(value, boolean_value, maker_readers,
+                                   feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        target.itunes_block = value
+        assert_equal(value, target.itunes_block)
+        assert_equal(boolean_value, target.itunes_block?)
+      end
+      target = chain_reader(rss20, feed_readers)
+      if [true, false].include?(value)
+        feed_expected_value = value = value ? "yes" : "no"
+      else
+        feed_expected_value = value
+      end
+      assert_equal(value, target.itunes_block)
+      assert_equal(boolean_value, target.itunes_block?)
+    end
+
+    def assert_maker_itunes_block(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_block("yes", true, maker_readers, feed_readers)
+        _assert_maker_itunes_block("Yes", true, maker_readers, feed_readers)
+        _assert_maker_itunes_block("no", false, maker_readers, feed_readers)
+        _assert_maker_itunes_block("", false, maker_readers, feed_readers)
+        _assert_maker_itunes_block(true, true, maker_readers, feed_readers)
+        _assert_maker_itunes_block(false, false, maker_readers, feed_readers)
+        _assert_maker_itunes_block(nil, false, maker_readers, feed_readers)
+      end
+    end
+
+    def _assert_maker_itunes_category(categories, maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        categories.each do |category|
+          sub_target = target.itunes_categories
+          if category.is_a?(Array)
+            category.each do |sub_category|
+              sub_target = sub_target.new_category
+              sub_target.text = sub_category
+            end
+          else
+            sub_target.new_category.text = category
+          end
+        end
+      end
+
+      target = chain_reader(rss20, feed_readers)
+      actual_categories = target.itunes_categories.collect do |category|
+        cat = category.text
+        if category.itunes_categories.empty?
+          cat
+        else
+          [cat, *category.itunes_categories.collect {|c| c.text}]
+        end
+      end
+      assert_equal(categories, actual_categories)
+    end
+
+    def assert_maker_itunes_category(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_category(["Audio Blogs"],
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_category([["Arts & Entertainment", "Games"]],
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_category([["Arts & Entertainment", "Games"],
+                                       ["Technology", "Computers"],
+                                       "Audio Blogs"],
+                                      maker_readers, feed_readers)
+      end
+    end
+
+    def assert_maker_itunes_image(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        url = "http://example.com/podcasts/everything/AllAboutEverything.jpg"
+
+        rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+          setup_dummy_channel(maker)
+          setup_dummy_item(maker)
+
+          target = chain_reader(maker, maker_readers)
+          target.itunes_image = url
+        end
+
+        target = chain_reader(rss20, feed_readers)
+        assert_not_nil(target.itunes_image)
+        assert_equal(url, target.itunes_image.href)
+      end
+    end
+
+    def _assert_maker_itunes_duration(hour, minute, second, value,
+                                      maker_readers, feed_readers)
+      _assert_maker_itunes_duration_by_value(hour, minute, second, value,
+                                             maker_readers, feed_readers)
+      _assert_maker_itunes_duration_by_hour_minute_second(hour, minute, second,
+                                                          value,
+                                                          maker_readers,
+                                                          feed_readers)
+    end
+
+    def _assert_maker_itunes_duration_by(hour, minute, second, value,
+                                         maker_readers, feed_readers)
+      expected_value = nil
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        expected_value = yield(target)
+        assert_equal(expected_value, target.itunes_duration)
+        target.itunes_duration do |duration|
+          assert_equal([hour, minute, second, expected_value],
+                       [duration.hour, duration.minute,
+                        duration.second, duration.content])
+        end
+      end
+      target = chain_reader(rss20, feed_readers)
+      duration = target.itunes_duration
+      assert_not_nil(duration)
+      assert_equal([hour, minute, second, expected_value],
+                   [duration.hour, duration.minute,
+                    duration.second, duration.content])
+    end
+
+    def _assert_maker_itunes_duration_by_value(hour, minute, second, value,
+                                               maker_readers, feed_readers)
+      _assert_maker_itunes_duration_by(hour, minute, second, value,
+                                       maker_readers, feed_readers) do |target|
+        target.itunes_duration = value
+        value
+      end
+    end
+
+    def _assert_maker_itunes_duration_by_hour_minute_second(hour, minute, second,
+                                                            value,
+                                                            maker_readers,
+                                                            feed_readers)
+      _assert_maker_itunes_duration_by(hour, minute, second, value,
+                                       maker_readers, feed_readers) do |target|
+        target.itunes_duration do |duration|
+          duration.hour = hour
+          duration.minute = minute
+          duration.second = second
+        end
+        value.split(":").collect {|v| "%02d" % v.to_i}.join(":")
+      end
+    end
+
+    def _assert_maker_itunes_duration_invalid_value(value, maker_readers)
+      assert_raise(ArgumentError) do
+        ::RSS::Maker.make("rss2.0") do |maker|
+          setup_dummy_channel(maker)
+          setup_dummy_item(maker)
+
+          target = chain_reader(maker, maker_readers)
+          target.itunes_duration = value
+        end
+      end
+    end
+
+    def assert_maker_itunes_duration(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_duration(7, 14, 5, "07:14:05", maker_readers,
+                                      feed_readers)
+        _assert_maker_itunes_duration(7, 14, 5, "7:14:05", maker_readers,
+                                      feed_readers)
+        _assert_maker_itunes_duration(0, 4, 55, "04:55", maker_readers,
+                                      feed_readers)
+        _assert_maker_itunes_duration(0, 4, 5, "4:05", maker_readers,
+                                      feed_readers)
+
+        _assert_maker_itunes_duration_invalid_value("5", maker_readers)
+        _assert_maker_itunes_duration_invalid_value("09:07:14:05", maker_readers)
+        _assert_maker_itunes_duration_invalid_value("10:5", maker_readers)
+        _assert_maker_itunes_duration_invalid_value("10:03:5", maker_readers)
+        _assert_maker_itunes_duration_invalid_value("10:3:05", maker_readers)
+
+        _assert_maker_itunes_duration_invalid_value("xx:xx:xx", maker_readers)
+      end
+    end
+
+    def _assert_maker_itunes_explicit(explicit, value,
+                                      maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        target.itunes_explicit = value
+        assert_equal(explicit, target.itunes_explicit?)
+      end
+      target = chain_reader(rss20, feed_readers)
+      assert_equal(value, target.itunes_explicit)
+      assert_equal(explicit, target.itunes_explicit?)
+    end
+
+    def assert_maker_itunes_explicit(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_explicit(true, "yes", maker_readers, feed_readers)
+        _assert_maker_itunes_explicit(false, "clean",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_explicit(nil, "no", maker_readers, feed_readers)
+      end
+    end
+
+    def _assert_maker_itunes_keywords(keywords, value,
+                                      maker_readers, feed_readers)
+      _assert_maker_itunes_keywords_by_value(keywords, value,
+                                             maker_readers, feed_readers)
+      _assert_maker_itunes_keywords_by_keywords(keywords, maker_readers,
+                                                feed_readers)
+    end
+
+    def _assert_maker_itunes_keywords_by(keywords, maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        yield(target)
+      end
+      assert_nothing_raised do
+        rss20 = ::RSS::Parser.parse(rss20.to_s)
+      end
+      target = chain_reader(rss20, feed_readers)
+      assert_equal(keywords, target.itunes_keywords)
+    end
+
+    def _assert_maker_itunes_keywords_by_value(keywords, value,
+                                               maker_readers, feed_readers)
+      _assert_maker_itunes_keywords_by(keywords, maker_readers,
+                                       feed_readers) do |target|
+        target.itunes_keywords = value
+      end
+    end
+
+    def _assert_maker_itunes_keywords_by_keywords(keywords,
+                                                  maker_readers, feed_readers)
+      _assert_maker_itunes_keywords_by(keywords, maker_readers,
+                                       feed_readers) do |target|
+        target.itunes_keywords = keywords
+      end
+    end
+
+    def assert_maker_itunes_keywords(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_keywords(["salt"], "salt",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_keywords(["salt"], " salt ",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_keywords(["salt", "pepper", "shaker", "exciting"],
+                                      "salt, pepper, shaker, exciting",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_keywords(["metric", "socket", "wrenches",
+                                       "toolsalt"],
+                                      "metric, socket, wrenches, toolsalt",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_keywords(["olitics", "red", "blue", "state"],
+                                      "olitics, red, blue, state",
+                                      maker_readers, feed_readers)
+      end
+    end
+
+    def assert_maker_itunes_new_feed_url(maker_readers, feed_readers=nil)
+      feed_readers ||= maker_readers
+      url = "http://newlocation.com/example.rss"
+
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        target.itunes_new_feed_url = url
+      end
+      target = chain_reader(rss20, feed_readers)
+      assert_equal(url, target.itunes_new_feed_url)
+    end
+
+    def _assert_maker_itunes_owner(name, email, maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        owner = target.itunes_owner
+        owner.itunes_name = name
+        owner.itunes_email = email
+      end
+      owner = chain_reader(rss20, feed_readers).itunes_owner
+      if name.nil? and email.nil?
+        assert_nil(owner)
+      else
+        assert_not_nil(owner)
+        assert_equal(name, owner.itunes_name)
+        assert_equal(email, owner.itunes_email)
+      end
+    end
+
+    def assert_maker_itunes_owner(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_owner("John Doe", "john.doe@e...",
+                                   maker_readers, feed_readers)
+
+        not_set_name = (["maker"] + maker_readers + ["itunes_owner"]).join(".")
+        assert_not_set_error(not_set_name, ["itunes_name"]) do
+          _assert_maker_itunes_owner(nil, "john.doe@e...",
+                                     maker_readers, feed_readers)
+        end
+        assert_not_set_error(not_set_name, ["itunes_email"]) do
+          _assert_maker_itunes_owner("John Doe", nil,
+                                     maker_readers, feed_readers)
+        end
+
+        _assert_maker_itunes_owner(nil, nil, maker_readers, feed_readers)
+      end
+    end
+
+    def _assert_maker_itunes_subtitle(subtitle, maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        target.itunes_subtitle = subtitle
+      end
+
+      target = chain_reader(rss20, feed_readers)
+      assert_equal(subtitle, target.itunes_subtitle)
+    end
+
+    def assert_maker_itunes_subtitle(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_subtitle("A show about everything",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_subtitle("A short primer on table spices",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_subtitle("Comparing socket wrenches is fun!",
+                                      maker_readers, feed_readers)
+        _assert_maker_itunes_subtitle("Red + Blue != Purple",
+                                      maker_readers, feed_readers)
+      end
+    end
+
+    def _assert_maker_itunes_summary(summary, maker_readers, feed_readers)
+      rss20 = ::RSS::Maker.make("rss2.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        target = chain_reader(maker, maker_readers)
+        target.itunes_summary = summary
+      end
+
+      target = chain_reader(rss20, feed_readers)
+      assert_equal(summary, target.itunes_summary)
+    end
+
+    def assert_maker_itunes_summary(maker_readers, feed_readers=nil)
+      _wrap_assertion do
+        feed_readers ||= maker_readers
+        _assert_maker_itunes_summary("All About Everything is a show about " +
+                                     "everything. Each week we dive into any " +
+                                     "subject known to man and talk about it " +
+                                     "as much as we can. Look for our Podcast " +
+                                     "in the iTunes Music Store",
+                                     maker_readers, feed_readers)
+        _assert_maker_itunes_summary("This week we talk about salt and pepper " +
+                                     "shakers, comparing and contrasting pour " +
+                                     "rates, construction materials, and " +
+                                     "overall aesthetics. Come and join the " +
+                                     "party!",
+                                     maker_readers, feed_readers)
+        _assert_maker_itunes_summary("This week we talk about metric vs. old " +
+                                     "english socket wrenches. Which one is " +
+                                     "better? Do you really need both? Get " +
+                                     "all of your answers here.",
+                                     maker_readers, feed_readers)
+        _assert_maker_itunes_summary("This week we talk about surviving in a " +
+                                     "Red state if youe a Blue person. Or " +
+                                     "vice versa.",
+                                     maker_readers, feed_readers)
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_dublincore.rb
===================================================================
--- ruby_1_8/test/rss/test_dublincore.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_dublincore.rb	(revision 13747)
@@ -8,86 +8,168 @@
 
 module RSS
   class TestDublinCore < TestCase
-
     def setup
-      @prefix = "dc"
-      @uri = "http://purl.org/dc/elements/1.1/"
-      
-      @parents = %w(channel image item textinput)
-      
-      t = Time.iso8601("2000-01-01T12:00:05+00:00")
-      class << t
-        alias_method(:to_s, :iso8601)
-      end
-      
-      @elems = {
-        :title => "hoge",
-        :description =>
-          " XML is placing increasingly heavy loads on
-          the existing technical infrastructure of the Internet.",
-        :creator => "Rael Dornfest (mailto:rael@o...)",
-        :subject => "XML",
-        :publisher => "The O'Reilly Network",
-        :contributor => "hogehoge",
-        :type => "fugafuga",
-        :format => "hohoho",
-        :identifier => "fufufu",
-        :source => "barbar",
-        :language => "ja",
-        :relation => "cococo",
-        :rights => "Copyright (c) 2000 O'Reilly &amp; Associates, Inc.",
-        :date => t,
-      }
+      @rss10_parents = [%w(channel), %w(image), %w(item), %w(textinput)]
 
-      @dc_nodes = @elems.collect do |name, value|
-        "<#{@prefix}:#{name}>#{value}</#{@prefix}:#{name}>"
-      end.join("\n")
+      @rss10_source = make_RDF(<<-EOR, {DC_PREFIX =>  DC_URI})
+#{make_channel(DC_NODES)}
+#{make_image(DC_NODES)}
+#{make_item(DC_NODES)}
+#{make_textinput(DC_NODES)}
+EOR
 
-      @rss_source = make_RDF(<<-EOR, {@prefix =>  @uri})
-#{make_channel(@dc_nodes)}
-#{make_image(@dc_nodes)}
-#{make_item(@dc_nodes)}
-#{make_textinput(@dc_nodes)}
+      @rss20_parents = [%w(channel), %w(items last)]
+
+      @rss20_source = make_rss20(<<-EOR, {DC_PREFIX =>  DC_URI})
+#{make_channel20(DC_NODES + make_item20(DC_NODES))}
 EOR
 
-      @rss = Parser.parse(@rss_source)
+      @atom_feed_parents = [[], %w(entries last)]
+
+      @atom_feed_source = make_feed(<<-EOR, {DC_PREFIX =>  DC_URI})
+#{DC_NODES}
+#{make_entry(DC_NODES)}
+EOR
+
+      @atom_entry_parents = [[]]
+
+      @atom_entry_source = make_entry_document(<<-EOR, {DC_PREFIX =>  DC_URI})
+#{DC_NODES}
+EOR
     end
-  
+
     def test_parser
-      assert_nothing_raised do
-        Parser.parse(@rss_source)
+      rss10_maker = Proc.new do |content, xmlns|
+        make_RDF(<<-EOR, xmlns)
+#{make_channel(content)}
+#{make_image(content)}
+#{make_item(content)}
+#{make_textinput(content)}
+EOR
       end
-    
-      @elems.each do |tag, value|
-        rss = nil
-        assert_nothing_raised do
-          rss = Parser.parse(make_RDF(<<-EOR, {@prefix => @uri}))
-#{make_channel(("<" + @prefix + ":" + tag.to_s + ">" +
-  value.to_s +
-  "</" + @prefix + ":" + tag.to_s + ">") * 2)}
-#{make_item}
+      assert_dc_parse(@rss10_source, @rss10_parents, false, &rss10_maker)
+      assert_dc_parse(@rss10_source, @rss10_parents, true, &rss10_maker)
+
+      rss20_maker = Proc.new do |content, xmlns|
+        make_rss20(<<-EOR, xmlns)
+#{make_channel20(content + make_item20(content))}
 EOR
+      end
+      assert_dc_parse(@rss20_source, @rss20_parents, false, &rss20_maker)
+      assert_dc_parse(@rss20_source, @rss20_parents, true, &rss20_maker)
+
+      atom_feed_maker = Proc.new do |content, xmlns|
+        make_feed(<<-EOR, xmlns)
+#{content}
+#{make_entry(content)}
+EOR
+      end
+      assert_dc_parse(@atom_feed_source, @atom_feed_parents, false,
+                      &atom_feed_maker)
+      assert_dc_parse(@atom_feed_source, @atom_feed_parents, true,
+                      &atom_feed_maker)
+
+      atom_entry_maker = Proc.new do |content, xmlns|
+        make_entry_document(<<-EOR, xmlns)
+#{content}
+EOR
+      end
+      assert_dc_parse(@atom_entry_source, @atom_entry_parents, false,
+                      &atom_entry_maker)
+      assert_dc_parse(@atom_entry_source, @atom_entry_parents, true,
+                      &atom_entry_maker)
+    end
+
+    def test_singular_accessor
+      assert_dc_singular_accessor(@rss10_source, @rss10_parents)
+      assert_dc_singular_accessor(@rss20_source, @rss20_parents)
+      assert_dc_singular_accessor(@atom_feed_source, @atom_feed_parents)
+      assert_dc_singular_accessor(@atom_entry_source, @atom_entry_parents)
+    end
+
+    def test_plural_accessor
+      assert_dc_plural_accessor(@rss10_source, @rss10_parents, false)
+      assert_dc_plural_accessor(@rss10_source, @rss10_parents, true)
+
+      assert_dc_plural_accessor(@rss20_source, @rss20_parents, false)
+      assert_dc_plural_accessor(@rss20_source, @rss20_parents, true)
+
+      assert_dc_plural_accessor(@atom_feed_source, @atom_feed_parents, false)
+      assert_dc_plural_accessor(@atom_feed_source, @atom_feed_parents, true)
+
+      assert_dc_plural_accessor(@atom_entry_source, @atom_entry_parents, false)
+      assert_dc_plural_accessor(@atom_entry_source, @atom_entry_parents, true)
+    end
+
+    def test_to_s
+      assert_dc_to_s(@rss10_source, @rss10_parents, false)
+      assert_dc_to_s(@rss10_source, @rss10_parents, true)
+
+      targets = ["channel", "channel/item[3]"]
+      assert_dc_to_s(@rss20_source, @rss20_parents, false, targets)
+      assert_dc_to_s(@rss20_source, @rss20_parents, true, targets)
+
+      targets = [".", "entry"]
+      assert_dc_to_s(@atom_feed_source, @atom_feed_parents, false, targets)
+      assert_dc_to_s(@atom_feed_source, @atom_feed_parents, true, targets)
+
+      targets = ["."]
+      assert_dc_to_s(@atom_entry_source, @atom_entry_parents, false, targets)
+      assert_dc_to_s(@atom_entry_source, @atom_entry_parents, true, targets)
+    end
+
+    private
+    def dc_plural_suffix(name, check_backward_compatibility)
+      if name == :rights
+        if check_backward_compatibility
+          "es"
+        else
+          "_list"
         end
-        plural_reader = "dc_#{tag}" + (tag == :rights ? "es" : "s")
-        values = rss.channel.__send__(plural_reader).collect do |x|
-          val = x.value
-          if val.kind_of?(String)
-            CGI.escapeHTML(val)
-          else
-            val
+      else
+        "s"
+      end
+    end
+
+    def assert_dc_parse(source, parents, check_backward_compatibility, &maker)
+      assert_nothing_raised do
+        Parser.parse(source)
+      end
+
+      DC_ELEMENTS.each do |name, value|
+        parents.each do |parent_readers|
+          feed = nil
+          assert_nothing_raised do
+            tag = "#{DC_PREFIX}:#{name}"
+            dc_content = "<#{tag}>#{value}</#{tag}>\n"
+            dc_content *= 2
+            feed = Parser.parse(maker.call(dc_content, {DC_PREFIX => DC_URI}))
           end
+          parent = chain_reader(feed, parent_readers)
+
+          plural_suffix = dc_plural_suffix(name, check_backward_compatibility)
+          plural_reader = "dc_#{name}#{plural_suffix}"
+          values = parent.__send__(plural_reader).collect do |x|
+            val = x.value
+            if val.kind_of?(String)
+              CGI.escapeHTML(val)
+            else
+              val
+            end
+          end
+          assert_equal([value, value], values)
         end
-        assert_equal([value, value], values)
       end
-
     end
 
-    def test_singular_accessor
+    def assert_dc_singular_accessor(source, parents)
+      feed = Parser.parse(source)
       new_value = "hoge"
 
-      @elems.each do |name, value|
-        @parents.each do |parent|
-          parsed_value = @rss.__send__(parent).__send__("dc_#{name}")
+      parents.each do |parent_readers|
+        parent = chain_reader(feed, parent_readers)
+        DC_ELEMENTS.each do |name, value|
+          parsed_value = parent.__send__("dc_#{name}")
           if parsed_value.kind_of?(String)
             parsed_value = CGI.escapeHTML(parsed_value)
           end
@@ -97,34 +179,40 @@
             class << t
               alias_method(:to_s, :iso8601)
             end
-            @rss.__send__(parent).__send__("dc_#{name}=", t.iso8601)
-            assert_equal(t, @rss.__send__(parent).__send__("dc_#{name}"))
-            assert_equal(t, @rss.__send__(parent).date)
-            
-            @rss.__send__(parent).date = value
-            assert_equal(value, @rss.__send__(parent).date)
-            assert_equal(value, @rss.__send__(parent).__send__("dc_#{name}"))
+            parent.__send__("dc_#{name}=", t.iso8601)
+            assert_equal(t, parent.__send__("dc_#{name}"))
+            if parent.class.method_defined?(:date_without_dc_date=)
+              assert_nil(parent.date)
+            else
+              assert_equal(t, parent.date)
+            end
+
+            parent.date = value
+            assert_equal(value, parent.date)
+            assert_equal(value, parent.__send__("dc_#{name}"))
           else
-            @rss.__send__(parent).__send__("dc_#{name}=", new_value)
-            assert_equal(new_value,
-                         @rss.__send__(parent).__send__("dc_#{name}"))
+            parent.__send__("dc_#{name}=", new_value)
+            assert_equal(new_value, parent.__send__("dc_#{name}"))
           end
         end
       end
     end
 
-    def test_plural_accessor
+    def assert_dc_plural_accessor(source, parents, check_backward_compatibility)
+      feed = Parser.parse(source)
       new_value = "hoge"
-      
-      @elems.each do |name, value|
-        @parents.each do |parent|
-          parsed_value = @rss.__send__(parent).__send__("dc_#{name}")
+
+      DC_ELEMENTS.each do |name, value|
+        parents.each do |parent_readers|
+          parent = chain_reader(feed, parent_readers)
+          parsed_value = parent.__send__("dc_#{name}")
           if parsed_value.kind_of?(String)
             parsed_value = CGI.escapeHTML(parsed_value)
           end
           assert_equal(value, parsed_value)
 
-          plural_reader = "dc_#{name}" + (name == :rights ? "es" : "s")
+          plural_suffix = dc_plural_suffix(name, check_backward_compatibility)
+          plural_reader = "dc_#{name}#{plural_suffix}"
           klass_name = "DublinCore#{Utils.to_class_name(name.to_s)}"
           klass = DublinCoreModel.const_get(klass_name)
           if name == :date
@@ -132,58 +220,60 @@
             class << t
               alias_method(:to_s, :iso8601)
             end
-            elems = @rss.__send__(parent).__send__(plural_reader)
+            elems = parent.__send__(plural_reader)
             elems << klass.new(t.iso8601)
-            new_elems = @rss.__send__(parent).__send__(plural_reader)
+            new_elems = parent.__send__(plural_reader)
             values = new_elems.collect{|x| x.value}
-            assert_equal([@rss.__send__(parent).__send__("dc_#{name}"), t],
-                         values)
+            assert_equal([parent.__send__("dc_#{name}"), t], values)
           else
-            elems = @rss.__send__(parent).__send__(plural_reader)
+            elems = parent.__send__(plural_reader)
             elems << klass.new(new_value)
-            new_elems = @rss.__send__(parent).__send__(plural_reader)
+            new_elems = parent.__send__(plural_reader)
             values = new_elems.collect{|x| x.value}
-            assert_equal([
-                          @rss.__send__(parent).__send__("dc_#{name}"),
-                          new_value
-                         ],
+            assert_equal([parent.__send__("dc_#{name}"), new_value],
                          values)
           end
         end
       end
     end
 
-    def test_to_s
-      @elems.each do |name, value|
-        excepted = "<#{@prefix}:#{name}>#{value}</#{@prefix}:#{name}>"
-        @parents.each do |parent|
-          assert_equal(excepted,
-                       @rss.__send__(parent).__send__("dc_#{name}_elements"))
+    def assert_dc_to_s(source, parents, check_backward_compatibility,
+                       targets=nil)
+      feed = Parser.parse(source)
+
+      DC_ELEMENTS.each do |name, value|
+        excepted = "<#{DC_PREFIX}:#{name}>#{value}</#{DC_PREFIX}:#{name}>"
+        parents.each do |parent_readers|
+          parent = chain_reader(feed, parent_readers)
+          assert_equal(excepted, parent.__send__("dc_#{name}_elements"))
         end
-        
+
+        plural_suffix = dc_plural_suffix(name, check_backward_compatibility)
+        reader = "dc_#{name}#{plural_suffix}"
         excepted = Array.new(2, excepted).join("\n")
-        @parents.each do |parent|
-          reader = "dc_#{name}" + (name == :rights ? "es" : "s")
-          elems = @rss.__send__(parent).__send__(reader)
+        parents.each do |parent_readers|
+          parent = chain_reader(feed, parent_readers)
+          elems = parent.__send__(reader)
           klass_name = "DublinCore#{Utils.to_class_name(name.to_s)}"
           klass = DublinCoreModel.const_get(klass_name)
-          elems << klass.new(@rss.__send__(parent).__send__("dc_#{name}"))
-          assert_equal(excepted,
-                       @rss.__send__(parent).__send__("dc_#{name}_elements"))
+          elems << klass.new(parent.__send__("dc_#{name}"))
+          assert_equal(excepted, parent.__send__("dc_#{name}_elements"))
         end
       end
-      
-      REXML::Document.new(@rss_source).root.each_element do |parent|
-        if @parents.include?(parent.name)
-          parent.each_element do |elem|
-            if elem.namespace == @uri
-              assert_equal(CGI.escapeHTML(elem.text),
-                           @elems[elem.name.intern].to_s)
-            end
+
+      targets ||= parents.collect do |parent_readers|
+        parent_readers.first
+      end
+      feed_root = REXML::Document.new(source).root
+      targets.each do |target_xpath|
+        parent = feed_root.elements[target_xpath]
+        parent.each_element do |elem|
+          if elem.namespace == DC_URI
+            assert_equal(CGI.escapeHTML(elem.text),
+                         DC_ELEMENTS[elem.name.intern].to_s)
           end
         end
       end
     end
-
   end
 end
Index: ruby_1_8/test/rss/test_xml-stylesheet.rb
===================================================================
--- ruby_1_8/test/rss/test_xml-stylesheet.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_xml-stylesheet.rb	(revision 13747)
@@ -14,7 +14,7 @@
         {:media => "print", :title => "FOO"},
         {:charset => "UTF-8", :alternate => "yes"},
       ].each do |attrs|
-        assert_xml_stylesheet_attrs(attrs, XMLStyleSheet.new(*attrs))
+        assert_xml_stylesheet_attrs(attrs, XMLStyleSheet.new(attrs))
       end
     end
     
@@ -35,8 +35,8 @@
          :media => "printer", :charset => "UTF-8",
          :alternate => "yes"},
       ].each do |attrs|
-        target, contents = parse_pi(XMLStyleSheet.new(*attrs).to_s)
-        assert_xml_stylesheet(target, attrs, XMLStyleSheet.new(*contents))
+        target, contents = parse_pi(XMLStyleSheet.new(attrs).to_s)
+        assert_xml_stylesheet(target, attrs, XMLStyleSheet.new(contents))
       end
     end
     
Index: ruby_1_8/test/rss/test_parser.rb
===================================================================
--- ruby_1_8/test/rss/test_parser.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_parser.rb	(revision 13747)
@@ -1,14 +1,4 @@
-begin
-  require "fileutils"
-rescue LoadError
-  module FileUtils
-    module_function
-    def rm_f(target)
-      File.unlink(target)
-    rescue Errno::ENOENT
-    end
-  end
-end
+require "fileutils"
 
 require "rss-testcase"
 
@@ -28,7 +18,7 @@
       @rss_file = "rss10.rdf"
       File.open(@rss_file, "w") {|f| f.print(@rss10)}
     end
-    
+
     def teardown
       Parser.default_parser = @_default_parser
       FileUtils.rm_f(@rss_file)
Index: ruby_1_8/test/rss/test_1.0.rb
===================================================================
--- ruby_1_8/test/rss/test_1.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_1.0.rb	(revision 13747)
@@ -19,9 +19,9 @@
       standalone = false
       
       rdf = RDF.new(version, encoding, standalone)
+      setup_rss10(rdf)
+      doc = REXML::Document.new(rdf.to_s)
       
-      doc = REXML::Document.new(rdf.to_s(false))
-      
       xmldecl = doc.xml_decl
       
       %w(version encoding).each do |x|
@@ -59,16 +59,31 @@
       link = "http://hoge.com"
       description = "fugafugafugafuga"
       resource = "http://hoge.com/hoge.png"
+
+      item_title = "item title"
+      item_link = "http://hoge.com/item"
+
       image = RDF::Channel::Image.new(resource)
       items = RDF::Channel::Items.new
+      items.Seq.lis << items.class::Seq::Li.new(item_link)
       textinput = RDF::Channel::Textinput.new(resource)
-      
+
+      rss_item = RDF::Item.new
+      rss_item.title = item_title
+      rss_item.link = item_link
+      rss_item.about = item_link
+
       channel = RDF::Channel.new(about)
       %w(title link description image items textinput).each do |x|
         channel.__send__("#{x}=", instance_eval(x))
       end
       
-      doc = REXML::Document.new(make_RDF(channel.to_s))
+      doc = REXML::Document.new(make_RDF(<<-EOR))
+#{channel}
+<items>
+#{rss_item}
+</items>
+EOR
       c = doc.root.elements[1]
       
       assert_equal(about, c.attributes["about"])
@@ -123,8 +138,12 @@
       assert_equal(resource, res.value)
     end
     
-    def test_items
+    def test_channel_items
+      item_link = "http://example.com/item"
+
       items = RDF::Channel::Items.new
+      li = items.Seq.class::Li.new(item_link)
+      items.Seq.lis << li
       
       doc = REXML::Document.new(make_RDF(items.to_s))
       i = doc.root.elements[1]
@@ -133,18 +152,34 @@
       assert_equal(@uri, i.namespace)
       
       assert_equal(1, i.elements.size)
-      assert_equal("Seq", i.elements[1].name)
-      assert_equal(@rdf_uri, i.elements[1].namespace)
+      seq = i.elements[1]
+      assert_equal("Seq", seq.name)
+      assert_equal(@rdf_uri, seq.namespace)
+
+      assert_equal(1, seq.elements.size)
+      l = seq.elements[1]
+      assert_equal("li", l.name)
+      assert_equal(@rdf_uri, l.namespace)
+      assert_equal(item_link, l.attributes["resource"])
     end
     
     def test_seq
+      item_link = "http://example.com/item"
       seq = RDF::Seq.new
+      li = seq.class::Li.new(item_link)
+      seq.lis << li
       
       doc = REXML::Document.new(make_RDF(seq.to_s))
       s = doc.root.elements[1]
       
       assert_equal("Seq", s.name)
       assert_equal(@rdf_uri, s.namespace)
+
+      assert_equal(1, s.elements.size)
+      l = s.elements[1]
+      assert_equal("li", l.name)
+      assert_equal(@rdf_uri, l.namespace)
+      assert_equal(item_link, l.attributes["resource"])
     end
     
     def test_li
@@ -242,8 +277,20 @@
       end
       rss09 = RSS::Parser.parse(rss09)
       assert_equal("0.91", rss09.rss_version)
+      assert_equal(["rss", "0.91", nil], rss09.feed_info)
       rss20 = RSS::Parser.parse(rss.to_xml("2.0"))
       assert_equal("2.0", rss20.rss_version)
+      assert_equal(["rss", "2.0", nil], rss20.feed_info)
+
+      atom_xml = rss.to_xml("atom") do |maker|
+        maker.channel.author = "Alice"
+        maker.channel.updated ||= Time.now
+        maker.items.each do |item|
+          item.updated ||= Time.now
+        end
+      end
+      atom = RSS::Parser.parse(atom_xml)
+      assert_equal(["atom", "1.0", "feed"], atom.feed_info)
     end
   end
 end
Index: ruby_1_8/test/rss/test_parser_atom_feed.rb
===================================================================
--- ruby_1_8/test/rss/test_parser_atom_feed.rb	(revision 0)
+++ ruby_1_8/test/rss/test_parser_atom_feed.rb	(revision 13747)
@@ -0,0 +1,276 @@
+require "rss-testcase"
+
+require "rss/atom"
+
+module RSS
+  class TestParserAtomFeed < TestCase
+    def test_feed_validation
+      assert_ns("", Atom::URI) do
+        Parser.parse(<<-EOA)
+<feed/>
+EOA
+      end
+
+      assert_ns("", Atom::URI) do
+        Parser.parse(<<-EOA)
+<feed xmlns="hoge"/>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "id", "feed") do
+<feed xmlns="#{Atom::URI}"/>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "title", "feed") do
+<feed xmlns="#{Atom::URI}">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+</feed>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "updated", "feed") do
+<feed xmlns="#{Atom::URI}">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+  <title>Example Feed</title>
+</feed>
+EOA
+      end
+
+      assert_parse(<<-EOA, :missing_tag, "author", "feed") do
+<feed xmlns="#{Atom::URI}">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+  <title>Example Feed</title>
+  <updated>2003-12-13T18:30:02Z</updated>
+</feed>
+EOA
+      end
+
+      assert_parse(<<-EOA, :nothing_raised) do
+<feed xmlns="#{Atom::URI}">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+  <title>Example Feed</title>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <author>
+    <name>A person</name>
+  </author>
+</feed>
+EOA
+      end
+    end
+
+    def test_lang
+      feed = RSS::Parser.parse(<<-EOA)
+<feed xmlns="#{Atom::URI}" xml:lang="ja">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+  <title xml:lang="en">Example Feed</title>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <author xml:lang="en">
+    <name>A person</name>
+  </author>
+</feed>
+EOA
+
+      assert_equal("ja", feed.lang)
+      assert_equal("ja", feed.id.lang)
+      assert_equal("en", feed.title.lang)
+      assert_equal("ja", feed.updated.lang)
+      assert_equal("en", feed.author.lang)
+      assert_equal("en", feed.author.name.lang)
+    end
+
+    def test_base
+      feed = RSS::Parser.parse(<<-EOA)
+<feed xmlns="#{Atom::URI}" xml:base="http://example.com/">
+  <id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>
+  <title xml:lang="en">Example Feed</title>
+  <updated>2003-12-13T18:30:02Z</updated>
+  <generator uri="generator">Generator</generator>
+  <link hreflang="ja" href="http://example.org/link1"/>
+  <link hreflang="en" href="link2"/>
+  <link hreflang="fr" xml:base="http://example.net/" href="link3"/>
+  <author>
+    <name>A person</name>
+    <uri>person</uri>
+  </author>
+</feed>
+EOA
+
+      assert_equal("http://example.com/", feed.base)
+      assert_equal("http://example.com/", feed.id.base)
+      assert_equal("http://example.com/", feed.title.base)
+      assert_equal("http://example.com/", feed.updated.base)
+      assert_equal("http://example.com/", feed.generator.base)
+      assert_equal("http://example.com/generator", feed.generator.uri)
+
+      assert_equal("http://example.com/", feed.links[0].base)
+      assert_equal("http://example.org/link1", feed.links[0].href)
+      assert_equal("http://example.com/", feed.links[1].base)
+      assert_equal("http://example.com/link2", feed.links[1].href)
+      assert_equal("http://example.net/", feed.links[2].base)
+      assert_equal("http://example.net/link3", feed.links[2].href)
+      assert_equal("http://example.com/person", feed.author.uri.content)
+    end
+
+    def test_feed_author
+      assert_atom_person("author", method(:make_feed)) do |feed|
+        assert_equal(2, feed.authors.size)
+        feed.authors[1]
+      end
+    end
+
+    def test_entry_author
+      generator = method(:make_feed_with_open_entry)
+      assert_atom_person("author", generator) do |feed|
+        assert_equal(1, feed.entries.size)
+        assert_equal(1, feed.entry.authors.size)
+        feed.entry.author
+      end
+    end
+
+    def test_feed_category
+      assert_atom_category(method(:make_feed)) do |feed|
+        assert_equal(1, feed.categories.size)
+        feed.category
+      end
+    end
+
+    def test_entry_category
+      assert_atom_category(method(:make_feed_with_open_entry)) do |feed|
+        assert_equal(1, feed.entries.size)
+        assert_equal(1, feed.entry.categories.size)
+        feed.entry.category
+      end
+    end
+
+    def test_entry_content
+      assert_atom_content(method(:make_feed_with_open_entry)) do |feed|
+        assert_equal(1, feed.entries.size)
+        feed.entry.content
+      end
+    end
+
+    def test_feed_contributor
+      assert_atom_person("contributor", method(:make_feed)) do |feed|
+        assert_equal(1, feed.contributors.size)
+        feed.contributor
+      end
+    end
+
+    def test_entry_contributor
+      generator = method(:make_feed_with_open_entry)
+      assert_atom_person("contributor", generator) do |feed|
+        assert_equal(1, feed.entries.size)
+        assert_equal(1, feed.entry.contributors.size)
+        feed.entry.contributor
+      end
+    end
+
+    def test_feed_generator
+      assert_atom_generator(method(:make_feed)) do |feed|
+        feed.generator
+      end
+    end
+
+    def test_feed_icon
+      assert_atom_icon(method(:make_feed)) do |feed|
+        feed.icon
+      end
+    end
+
+    def test_feed_id
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(FEED_ID, feed.id.content)
+    end
+
+    def test_entry_id
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(ENTRY_ID, feed.entry.id.content)
+    end
+
+    def test_feed_link
+      assert_atom_link(method(:make_feed)) do |feed|
+        assert_equal(1, feed.links.size)
+        feed.link
+      end
+    end
+
+    def test_entry_link
+      assert_atom_link(method(:make_feed_with_open_entry)) do |feed|
+        assert_equal(1, feed.entries.size)
+        assert_equal(1, feed.entry.links.size)
+        feed.entry.link
+      end
+    end
+
+    def test_feed_logo
+      assert_atom_logo(method(:make_feed)) do |feed|
+        feed.logo
+      end
+    end
+
+    def test_feed_rights
+      assert_atom_text_construct("rights", method(:make_feed)) do |feed|
+        feed.rights
+      end
+    end
+
+    def test_entry_rights
+      generator = method(:make_feed_with_open_entry)
+      assert_atom_text_construct("rights", generator) do |feed|
+        assert_equal(1, feed.entries.size)
+        feed.entry.rights
+      end
+    end
+
+    def test_entry_source
+      assert_atom_source(method(:make_feed_with_open_entry_source)) do |feed|
+        assert_equal(1, feed.entries.size)
+        assert_not_nil(feed.entry.source)
+        feed.entry.source
+      end
+    end
+
+    def test_feed_subtitle
+      assert_atom_text_construct("subtitle", method(:make_feed)) do |feed|
+        feed.subtitle
+      end
+    end
+
+    def test_feed_title
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(FEED_TITLE, feed.title.content)
+    end
+
+    def test_entry_title
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(ENTRY_TITLE, feed.entry.title.content)
+    end
+
+    def test_feed_updated
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(Time.parse(FEED_UPDATED), feed.updated.content)
+    end
+
+    def test_entry_updated
+      feed = RSS::Parser.parse(make_feed(''))
+      assert_equal(Time.parse(ENTRY_UPDATED), feed.entry.updated.content)
+    end
+
+    def test_entry_published
+      generator = method(:make_feed_with_open_entry)
+      assert_atom_date_construct("published", generator) do |feed|
+        assert_equal(1, feed.entries.size)
+        feed.entry.published
+      end
+    end
+
+    def test_entry_summary
+      generator = method(:make_feed_with_open_entry)
+      assert_atom_text_construct("summary", generator) do |feed|
+        assert_equal(1, feed.entries.size)
+        feed.entry.summary
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_atom.rb
===================================================================
--- ruby_1_8/test/rss/test_atom.rb	(revision 0)
+++ ruby_1_8/test/rss/test_atom.rb	(revision 13747)
@@ -0,0 +1,688 @@
+require "rexml/document"
+
+require "rss-testcase"
+
+require "rss/atom"
+
+module RSS
+  class TestAtomCore < TestCase
+    def setup
+      @uri = "http://www.w3.org/2005/Atom"
+      @xhtml_uri = "http://www.w3.org/1999/xhtml"
+    end
+
+    def test_feed
+      version = "1.0"
+      encoding = "UTF-8"
+      standalone = false
+
+      feed = Atom::Feed.new(version, encoding, standalone)
+      assert_equal("", feed.to_s)
+
+      author = feed.class::Author.new
+      name = feed.class::Author::Name.new
+      name.content = "an author"
+      author.name = name
+      assert_not_equal("", author.to_s)
+      feed.authors << author
+      assert_equal("", feed.to_s)
+
+      id = feed.class::Id.new
+      id.content = "http://example.com/atom.xml"
+      assert_not_equal("", id.to_s)
+      feed.id = id
+      assert_equal("", feed.to_s)
+
+      title = feed.class::Title.new
+      title.content = "a title"
+      assert_not_equal("", title.to_s)
+      feed.title = title
+      assert_equal("", feed.to_s)
+
+      updated = feed.class::Updated.new
+      updated.content = Time.now
+      assert_not_equal("", updated.to_s)
+      feed.updated = updated
+      assert_not_equal("", feed.to_s)
+
+
+      feed.authors.clear
+      assert_equal("", feed.to_s)
+      entry = Atom::Feed::Entry.new
+      setup_entry(entry)
+      assert_not_equal("", entry.to_s)
+
+      author = entry.authors.first
+      entry.authors.clear
+      assert_equal("", entry.to_s)
+      entry.parent = feed
+      assert_equal("", entry.to_s)
+      feed.authors << author
+      assert_not_equal("", entry.to_s)
+      feed.authors.clear
+      feed.entries << entry
+      assert_equal("", feed.to_s)
+      entry.authors << author
+      assert_not_equal("", entry.to_s)
+      assert_not_equal("", feed.to_s)
+
+      doc = REXML::Document.new(feed.to_s)
+      xmldecl = doc.xml_decl
+
+      %w(version encoding).each do |x|
+        assert_equal(instance_eval(x), xmldecl.__send__(x))
+      end
+      assert_equal(standalone, !xmldecl.standalone.nil?)
+
+      assert_equal(@uri, doc.root.namespace)
+    end
+
+    def test_entry
+      version = "1.0"
+      encoding = "UTF-8"
+      standalone = false
+
+      entry = Atom::Entry.new(version, encoding, standalone)
+      setup_entry(entry)
+
+      author = entry.authors.first
+      entry.authors.clear
+      assert_equal("", entry.to_s)
+      source = Atom::Entry::Source.new
+      source.authors << author
+      entry.source = source
+      assert_not_equal("", entry.to_s)
+
+      doc = REXML::Document.new(entry.to_s)
+      xmldecl = doc.xml_decl
+
+      %w(version encoding).each do |x|
+        assert_equal(instance_eval(x), xmldecl.__send__(x))
+      end
+      assert_equal(standalone, !xmldecl.standalone.nil?)
+
+      assert_equal(@uri, doc.root.namespace)
+    end
+
+    def test_not_displayed_xml_stylesheets
+      feed = Atom::Feed.new
+      plain_feed = feed.to_s
+      3.times do
+        feed.xml_stylesheets.push(XMLStyleSheet.new)
+        assert_equal(plain_feed, feed.to_s)
+      end
+    end
+
+    def test_atom_author
+      assert_atom_person_to_s(Atom::Feed::Author)
+      assert_atom_person_to_s(Atom::Feed::Entry::Author)
+      assert_atom_person_to_s(Atom::Entry::Author)
+      assert_atom_person_to_s(Atom::Feed::Entry::Source::Author)
+      assert_atom_person_to_s(Atom::Entry::Source::Author)
+    end
+
+    def test_atom_category
+      assert_atom_category_to_s(Atom::Feed::Category)
+      assert_atom_category_to_s(Atom::Feed::Entry::Category)
+      assert_atom_category_to_s(Atom::Entry::Category)
+      assert_atom_category_to_s(Atom::Feed::Entry::Source::Category)
+      assert_atom_category_to_s(Atom::Entry::Source::Category)
+    end
+
+    def test_atom_contributor
+      assert_atom_person_to_s(Atom::Feed::Contributor)
+      assert_atom_person_to_s(Atom::Feed::Entry::Contributor)
+      assert_atom_person_to_s(Atom::Entry::Contributor)
+      assert_atom_person_to_s(Atom::Feed::Entry::Source::Contributor)
+      assert_atom_person_to_s(Atom::Entry::Source::Contributor)
+    end
+
+    def test_atom_generator
+      assert_atom_generator_to_s(Atom::Feed::Generator)
+      assert_atom_generator_to_s(Atom::Feed::Entry::Source::Generator)
+      assert_atom_generator_to_s(Atom::Entry::Source::Generator)
+    end
+
+    def test_atom_icon
+      assert_atom_icon_to_s(Atom::Feed::Icon)
+      assert_atom_icon_to_s(Atom::Feed::Entry::Source::Icon)
+      assert_atom_icon_to_s(Atom::Entry::Source::Icon)
+    end
+
+    def test_atom_id
+      assert_atom_id_to_s(Atom::Feed::Id)
+      assert_atom_id_to_s(Atom::Feed::Entry::Id)
+      assert_atom_id_to_s(Atom::Entry::Id)
+      assert_atom_id_to_s(Atom::Feed::Entry::Source::Id)
+      assert_atom_id_to_s(Atom::Entry::Source::Id)
+    end
+
+    def test_atom_link
+      assert_atom_link_to_s(Atom::Feed::Link)
+      assert_atom_link_to_s(Atom::Feed::Entry::Link)
+      assert_atom_link_to_s(Atom::Entry::Link)
+      assert_atom_link_to_s(Atom::Feed::Entry::Source::Link)
+      assert_atom_link_to_s(Atom::Entry::Source::Link)
+    end
+
+    def test_atom_logo
+      assert_atom_logo_to_s(Atom::Feed::Logo)
+      assert_atom_logo_to_s(Atom::Feed::Entry::Source::Logo)
+      assert_atom_logo_to_s(Atom::Entry::Source::Logo)
+    end
+
+    def test_atom_rights
+      assert_atom_text_construct_to_s(Atom::Feed::Rights)
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Rights)
+      assert_atom_text_construct_to_s(Atom::Entry::Rights)
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Rights)
+      assert_atom_text_construct_to_s(Atom::Entry::Source::Rights)
+    end
+
+    def test_atom_subtitle
+      assert_atom_text_construct_to_s(Atom::Feed::Subtitle)
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Subtitle)
+      assert_atom_text_construct_to_s(Atom::Entry::Source::Subtitle)
+    end
+
+    def test_atom_title
+      assert_atom_text_construct_to_s(Atom::Feed::Title)
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Title)
+      assert_atom_text_construct_to_s(Atom::Entry::Title)
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Source::Title)
+      assert_atom_text_construct_to_s(Atom::Entry::Source::Title)
+    end
+
+    def test_atom_updated
+      assert_atom_date_construct_to_s(Atom::Feed::Updated)
+      assert_atom_date_construct_to_s(Atom::Feed::Entry::Updated)
+      assert_atom_date_construct_to_s(Atom::Entry::Updated)
+      assert_atom_date_construct_to_s(Atom::Feed::Entry::Source::Updated)
+      assert_atom_date_construct_to_s(Atom::Entry::Source::Updated)
+    end
+
+    def test_atom_content
+      assert_atom_content_to_s(Atom::Feed::Entry::Content)
+      assert_atom_content_to_s(Atom::Entry::Content)
+    end
+
+    def test_atom_published
+      assert_atom_date_construct_to_s(Atom::Feed::Entry::Published)
+      assert_atom_date_construct_to_s(Atom::Entry::Published)
+    end
+
+    def test_atom_summary
+      assert_atom_text_construct_to_s(Atom::Feed::Entry::Summary)
+      assert_atom_text_construct_to_s(Atom::Entry::Summary)
+    end
+
+
+    def test_to_xml(with_convenience_way=true)
+      atom = RSS::Parser.parse(make_feed)
+      assert_equal(atom.to_s, atom.to_xml)
+      assert_equal(atom.to_s, atom.to_xml("atom"))
+      assert_equal(atom.to_s, atom.to_xml("atom1.0"))
+      assert_equal(atom.to_s, atom.to_xml("atom1.0:feed"))
+      assert_equal(atom.to_s, atom.to_xml("atom:feed"))
+
+      rss09_xml = atom.to_xml("0.91") do |maker|
+        maker.channel.language = "en-us"
+        maker.channel.link = "http://example.com/"
+        if with_convenience_way
+          maker.channel.description = atom.title.content
+        else
+          maker.channel.description {|d| d.content = atom.title.content}
+        end
+
+        maker.image.url = "http://example.com/logo.png"
+        maker.image.title = "Logo"
+      end
+      rss09 = RSS::Parser.parse(rss09_xml)
+      assert_equal(["rss", "0.91", nil], rss09.feed_info)
+
+      rss20_xml = atom.to_xml("2.0") do |maker|
+        maker.channel.link = "http://example.com/"
+        if with_convenience_way
+          maker.channel.description = atom.title.content
+        else
+          maker.channel.description {|d| d.content = atom.title.content}
+        end
+      end
+      rss20 = RSS::Parser.parse(rss20_xml)
+      assert_equal("2.0", rss20.rss_version)
+      assert_equal(["rss", "2.0", nil], rss20.feed_info)
+    end
+
+    def test_to_xml_with_new_api_since_018
+      test_to_xml(false)
+    end
+
+    private
+    def setup_entry(entry)
+      _wrap_assertion do
+        assert_equal("", entry.to_s)
+
+        author = entry.class::Author.new
+        name = entry.class::Author::Name.new
+        name.content = "an author"
+        author.name = name
+        assert_not_equal("", author.to_s)
+        entry.authors << author
+        assert_equal("", entry.to_s)
+
+        id = entry.class::Id.new
+        id.content = "http://example.com/atom.xml"
+        assert_not_equal("", id.to_s)
+        entry.id = id
+        assert_equal("", entry.to_s)
+
+        title = entry.class::Title.new
+        title.content = "a title"
+        assert_not_equal("", title.to_s)
+        entry.title = title
+        assert_equal("", entry.to_s)
+
+        updated = entry.class::Updated.new
+        updated.content = Time.now
+        assert_not_equal("", updated.to_s)
+        entry.updated = updated
+        assert_not_equal("", entry.to_s)
+      end
+    end
+
+
+    def assert_atom_person_to_s(target_class)
+      _wrap_assertion do
+        name = "A person"
+        uri = "http://example.com/person/"
+        email = "person@e..."
+
+        target = target_class.new
+        assert_equal("", target.to_s)
+
+        target = target_class.new
+        person_name = target_class::Name.new
+        person_name.content = name
+        target.name = person_name
+        xml_target = REXML::Document.new(target.to_s).root
+        assert_equal(["name"], xml_target.elements.collect {|e| e.name})
+        assert_equal([name], xml_target.elements.collect {|e| e.text})
+
+        person_uri = target_class::Uri.new
+        person_uri.content = uri
+        target.uri = person_uri
+        xml_target = REXML::Document.new(target.to_s).root
+        assert_equal(["name", "uri"], xml_target.elements.collect {|e| e.name})
+        assert_equal([name, uri], xml_target.elements.collect {|e| e.text})
+
+        person_email = target_class::Email.new
+        person_email.content = email
+        target.email = person_email
+        xml_target = REXML::Document.new(target.to_s).root
+        assert_equal(["name", "uri", "email"],
+                     xml_target.elements.collect {|e| e.name})
+        assert_equal([name, uri, email],
+                     xml_target.elements.collect {|e| e.text})
+      end
+    end
+
+    def assert_atom_category_to_s(target_class)
+      _wrap_assertion do
+        term = "music"
+        scheme = "http://example.com/music"
+        label = "Music"
+
+        category = target_class.new
+        assert_equal("", category.to_s)
+
+        category = target_class.new
+        category.scheme = scheme
+        assert_equal("", category.to_s)
+
+        category = target_class.new
+        category.label = label
+        assert_equal("", category.to_s)
+
+        category = target_class.new
+        category.scheme = scheme
+        category.label = label
+        assert_equal("", category.to_s)
+
+        category = target_class.new
+        category.term = term
+        xml = REXML::Document.new(category.to_s).root
+        assert_rexml_element([], {"term" => term}, nil, xml)
+
+        category = target_class.new
+        category.term = term
+        category.scheme = scheme
+        xml = REXML::Document.new(category.to_s).root
+        assert_rexml_element([], {"term" => term, "scheme" => scheme}, nil, xml)
+
+        category = target_class.new
+        category.term = term
+        category.label = label
+        xml = REXML::Document.new(category.to_s).root
+        assert_rexml_element([], {"term" => term, "label" => label}, nil, xml)
+
+        category = target_class.new
+        category.term = term
+        category.scheme = scheme
+        category.label = label
+        xml = REXML::Document.new(category.to_s).root
+        attrs = {"term" => term, "scheme" => scheme, "label" => label}
+        assert_rexml_element([], attrs, nil, xml)
+      end
+    end
+
+    def assert_atom_generator_to_s(target_class)
+      _wrap_assertion do
+        content = "Feed generator"
+        uri = "http://example.com/generator"
+        version = "0.0.1"
+
+        generator = target_class.new
+        assert_equal("", generator.to_s)
+
+        generator = target_class.new
+        generator.uri = uri
+        assert_equal("", generator.to_s)
+
+        generator = target_class.new
+        generator.version = version
+        assert_equal("", generator.to_s)
+
+        generator = target_class.new
+        generator.uri = uri
+        generator.version = version
+        assert_equal("", generator.to_s)
+
+        generator = target_class.new
+        generator.content = content
+        xml = REXML::Document.new(generator.to_s).root
+        assert_rexml_element([], {}, content, xml)
+
+        generator = target_class.new
+        generator.content = content
+        generator.uri = uri
+        xml = REXML::Document.new(generator.to_s).root
+        assert_rexml_element([], {"uri" => uri}, content, xml)
+
+        generator = target_class.new
+        generator.content = content
+        generator.version = version
+        xml = REXML::Document.new(generator.to_s).root
+        assert_rexml_element([], {"version" => version}, content, xml)
+
+        generator = target_class.new
+        generator.content = content
+        generator.uri = uri
+        generator.version = version
+        xml = REXML::Document.new(generator.to_s).root
+        assert_rexml_element([], {"uri" => uri, "version" => version},
+                             content, xml)
+      end
+    end
+
+    def assert_atom_icon_to_s(target_class)
+      _wrap_assertion do
+        content = "http://example.com/icon.png"
+
+        icon = target_class.new
+        assert_equal("", icon.to_s)
+
+        icon = target_class.new
+        icon.content = content
+        xml = REXML::Document.new(icon.to_s).root
+        assert_rexml_element([], {}, content, xml)
+      end
+    end
+
+    def assert_atom_id_to_s(target_class)
+      _wrap_assertion do
+        content = "http://example.com/1"
+
+        id = target_class.new
+        assert_equal("", id.to_s)
+
+        id = target_class.new
+        id.content = content
+        xml = REXML::Document.new(id.to_s).root
+        assert_rexml_element([], {}, content, xml)
+      end
+    end
+
+    def assert_atom_link_to_s(target_class)
+      _wrap_assertion do
+        href = "http://example.com/atom.xml"
+        rel = "self"
+        type = "application/atom+xml"
+        hreflang = "ja"
+        title = "Atom Feed"
+        length = "801"
+
+        link = target_class.new
+        assert_equal("", link.to_s)
+
+        link = target_class.new
+        link.href = href
+        xml = REXML::Document.new(link.to_s).root
+        assert_rexml_element([], {"href" => href}, nil, xml)
+
+        optional_arguments = %w(rel type hreflang title length)
+        optional_arguments.each do |name|
+          rest = optional_arguments.reject {|x| x == name}
+
+          link = target_class.new
+          link.__send__("#{name}=", eval(name))
+          assert_equal("", link.to_s)
+
+          rest.each do |n|
+            link.__send__("#{n}=", eval(n))
+            assert_equal("", link.to_s)
+          end
+
+          link = target_class.new
+          link.href = href
+          link.__send__("#{name}=", eval(name))
+          attrs = [["href", href], [name, eval(name)]]
+          xml = REXML::Document.new(link.to_s).root
+          assert_rexml_element([], attrs, nil, xml)
+
+          rest.each do |n|
+            link.__send__("#{n}=", eval(n))
+            attrs << [n, eval(n)]
+            xml = REXML::Document.new(link.to_s).root
+            assert_rexml_element([], attrs, nil, xml)
+          end
+        end
+      end
+    end
+
+    def assert_atom_logo_to_s(target_class)
+      _wrap_assertion do
+        content = "http://example.com/logo.png"
+
+        logo = target_class.new
+        assert_equal("", logo.to_s)
+
+        logo = target_class.new
+        logo.content = content
+        xml = REXML::Document.new(logo.to_s).root
+        assert_rexml_element([], {}, content, xml)
+      end
+    end
+
+    def assert_atom_text_construct_to_s(target_class)
+      _wrap_assertion do
+        text_content = "plain text"
+        html_content = "<em>#{text_content}</em>"
+        xhtml_uri = "http://www.w3.org/1999/xhtml"
+        xhtml_em = RSS::XML::Element.new("em", nil, xhtml_uri, {}, text_content)
+        xhtml_content = RSS::XML::Element.new("div", nil, xhtml_uri,
+                                              {"xmlns" => xhtml_uri},
+                                              [xhtml_em])
+
+        text = target_class.new
+        assert_equal("", text.to_s)
+
+        text = target_class.new
+        text.type = "text"
+        assert_equal("", text.to_s)
+
+        text = target_class.new
+        text.content = text_content
+        xml = REXML::Document.new(text.to_s).root
+        assert_rexml_element([], {}, text_content, xml)
+
+        text = target_class.new
+        text.type = "text"
+        text.content = text_content
+        xml = REXML::Document.new(text.to_s).root
+        assert_rexml_element([], {"type" => "text"}, text_content, xml)
+
+        text = target_class.new
+        text.type = "html"
+        text.content = html_content
+        xml = REXML::Document.new(text.to_s).root
+        assert_rexml_element([], {"type" => "html"}, html_content, xml)
+
+        text = target_class.new
+        text.type = "xhtml"
+        text.content = xhtml_content
+        assert_equal("", text.to_s)
+
+        text = target_class.new
+        text.type = "xhtml"
+        text.__send__(target_class.xml_setter, xhtml_content)
+        xml = REXML::Document.new(text.to_s).root
+        assert_rexml_element([[xhtml_uri, "div"]], {"type" => "xhtml"},
+                             nil, xml)
+        assert_rexml_element([[xhtml_uri, "em"]], nil, nil, xml.elements[1])
+        assert_rexml_element([], {}, text_content, xml.elements[1].elements[1])
+
+        text = target_class.new
+        text.type = "xhtml"
+        text.__send__(target_class.xml_setter, xhtml_em)
+        xml = REXML::Document.new(text.to_s).root
+        assert_rexml_element([[xhtml_uri, "div"]], {"type" => "xhtml"},
+                             nil, xml)
+        assert_rexml_element([[xhtml_uri, "em"]], nil, nil, xml.elements[1])
+        assert_rexml_element([], {}, text_content, xml.elements[1].elements[1])
+      end
+    end
+
+    def assert_atom_date_construct_to_s(target_class)
+      _wrap_assertion do
+        date = target_class.new
+        assert_equal("", date.to_s)
+
+        [
+         "2003-12-13T18:30:02Z",
+         "2003-12-13T18:30:02.25Z",
+         "2003-12-13T18:30:02+01:00",
+         "2003-12-13T18:30:02.25+01:00",
+        ].each do |content|
+          date = target_class.new
+          date.content = content
+          xml = REXML::Document.new(date.to_s).root
+          assert_rexml_element([], {}, content, xml, :time)
+
+          date = target_class.new
+          date.content = Time.parse(content)
+          xml = REXML::Document.new(date.to_s).root
+          assert_rexml_element([], {}, content, xml, :time)
+        end
+      end
+    end
+
+    def assert_atom_content_to_s(target_class)
+      _wrap_assertion do
+        assert_atom_text_construct_to_s(target_class)
+        assert_atom_content_inline_other_xml_to_s(target_class)
+        assert_atom_content_inline_other_text_to_s(target_class)
+        assert_atom_content_inline_other_base64_to_s(target_class)
+        assert_atom_content_out_of_line_to_s(target_class)
+      end
+    end
+
+    def assert_atom_content_inline_other_xml_to_s(target_class)
+      _wrap_assertion do
+        content = target_class.new
+        content.type = "text/xml"
+        assert_equal("", content.to_s)
+
+        content = target_class.new
+        content.type = "text/xml"
+        content.xml = RSS::XML::Element.new("em")
+        xml = REXML::Document.new(content.to_s).root
+        assert_rexml_element([["", "em"]], {"type" => "text/xml"}, nil, xml)
+      end
+    end
+
+    def assert_atom_content_inline_other_text_to_s(target_class)
+      _wrap_assertion do
+        content = target_class.new
+        content.type = "text/plain"
+        assert_equal("", content.to_s)
+
+        content = target_class.new
+        content.type = "text/plain"
+        content.xml = RSS::XML::Element.new("em")
+        assert_equal("", content.to_s)
+
+        content = target_class.new
+        content.type = "text/plain"
+        content.content = "content"
+        xml = REXML::Document.new(content.to_s).root
+        assert_rexml_element([], {"type" => "text/plain"}, "content", xml)
+      end
+    end
+
+    def assert_atom_content_inline_other_base64_to_s(target_class)
+      _wrap_assertion do
+        require "zlib"
+
+        text = ""
+        char = "a"
+        100.times do |i|
+          text << char
+          char.succ!
+        end
+
+        type = "application/zip"
+        original_content = Zlib::Deflate.deflate(text)
+
+        content = target_class.new
+        content.type = type
+        content.content = original_content
+        xml = REXML::Document.new(content.to_s).root
+        assert_rexml_element([], {"type" => type},
+                             Base64.encode64(original_content), xml)
+      end
+    end
+
+    def assert_atom_content_out_of_line_to_s(target_class)
+      _wrap_assertion do
+        type = "application/zip"
+        src = "http://example.com/xxx.zip"
+
+        content = target_class.new
+        assert(!content.out_of_line?)
+        content.src = src
+        assert(content.out_of_line?)
+        xml = REXML::Document.new(content.to_s).root
+        assert_rexml_element([], {"src" => src}, nil, xml)
+
+        content = target_class.new
+        assert(!content.out_of_line?)
+        content.type = type
+        assert(!content.out_of_line?)
+        content.src = src
+        assert(content.out_of_line?)
+        xml = REXML::Document.new(content.to_s).root
+        assert_rexml_element([], {"type" => type, "src" => src}, nil, xml)
+      end
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_maker_xml-stylesheet.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_xml-stylesheet.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_xml-stylesheet.rb	(revision 13747)
@@ -24,6 +24,7 @@
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
 
       xss = rss.xml_stylesheets.first
@@ -38,11 +39,12 @@
       href = 'http://example.com/index.xsl'
       type = 'text/xsl'
       rss = RSS::Maker.make("1.0") do |maker|
-        maker.xml_stylesheets.new_xml_stylesheet do |xss|
-          xss.href = href
+        maker.xml_stylesheets.new_xml_stylesheet do |_xss|
+          _xss.href = href
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
 
       xss = rss.xml_stylesheets.first
@@ -61,6 +63,7 @@
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
       assert(rss.xml_stylesheets.empty?)
 
@@ -71,6 +74,7 @@
         end
 
         setup_dummy_channel(maker)
+        setup_dummy_item(maker)
       end
       assert(rss.xml_stylesheets.empty?)
     end
Index: ruby_1_8/test/rss/test_setup_maker_slash.rb
===================================================================
--- ruby_1_8/test/rss/test_setup_maker_slash.rb	(revision 0)
+++ ruby_1_8/test/rss/test_setup_maker_slash.rb	(revision 13747)
@@ -0,0 +1,38 @@
+require "rss-testcase"
+
+require "rss/maker"
+
+module RSS
+  class TestSetupMakerSlash < TestCase
+    def test_setup_maker
+      elements = {
+        "section" => "articles",
+        "department" => "not-an-ocean-unless-there-are-lobsters",
+        "comments" => 177,
+        "hit_parades" => [177, 155, 105, 33, 6, 3, 0],
+      }
+
+      rss = RSS::Maker.make("rss1.0") do |maker|
+        setup_dummy_channel(maker)
+        setup_dummy_item(maker)
+
+        item = maker.items.last
+        item.slash_section = elements["section"]
+        item.slash_department = elements["department"]
+        item.slash_comments = elements["comments"]
+        item.slash_hit_parade = elements["hit_parades"].join(",")
+      end
+      assert_not_nil(rss)
+
+      new_rss = RSS::Maker.make("rss1.0") do |maker|
+        rss.setup_maker(maker)
+      end
+      assert_not_nil(new_rss)
+
+      item = new_rss.items.last
+      assert_not_nil(item)
+
+      assert_slash_elements(elements, item)
+    end
+  end
+end
Index: ruby_1_8/test/rss/test_parser_1.0.rb
===================================================================
--- ruby_1_8/test/rss/test_parser_1.0.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_parser_1.0.rb	(revision 13747)
@@ -498,6 +498,14 @@
         Parser.parse(rss, true, false)
       end
     end
+
+    def test_unknown_duplicated_element
+      xmlns = {"test" => "http://localhost/test"}
+      assert_parse(make_RDF(<<-EOR, xmlns), :nothing_raised)
+        #{make_channel("<test:string/>")}
+        #{make_item}
+        #{make_image}
+      EOR
+    end
   end
 end
-
Index: ruby_1_8/test/rss/test_maker_sy.rb
===================================================================
--- ruby_1_8/test/rss/test_maker_sy.rb	(revision 13746)
+++ ruby_1_8/test/rss/test_maker_sy.rb	(revision 13747)
@@ -24,6 +24,7 @@
       rss = RSS::Maker.make("1.0") do |maker|
         setup_dummy_channel(maker)
         set_elements(maker.channel)
+        setup_dummy_item(maker)
       end
       assert_syndication(@elements, rss.channel)
     end

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml

[前][次][番号順一覧][スレッド一覧]