summaryrefslogtreecommitdiff
path: root/trunk/lib/rss/maker
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2008-08-25 15:02:05 +0000
commit0dc342de848a642ecce8db697b8fecd83a63e117 (patch)
tree2b7ed4724aff1f86073e4740134bda9c4aac1a39 /trunk/lib/rss/maker
parentef70cf7138ab8034b5b806f466e4b484b24f0f88 (diff)
added tag v1_9_0_4
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/tags/v1_9_0_4@18845 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'trunk/lib/rss/maker')
-rw-r--r--trunk/lib/rss/maker/0.9.rb467
-rw-r--r--trunk/lib/rss/maker/1.0.rb434
-rw-r--r--trunk/lib/rss/maker/2.0.rb223
-rw-r--r--trunk/lib/rss/maker/atom.rb172
-rw-r--r--trunk/lib/rss/maker/base.rb880
-rw-r--r--trunk/lib/rss/maker/content.rb21
-rw-r--r--trunk/lib/rss/maker/dublincore.rb124
-rw-r--r--trunk/lib/rss/maker/entry.rb163
-rw-r--r--trunk/lib/rss/maker/feed.rb429
-rw-r--r--trunk/lib/rss/maker/image.rb111
-rw-r--r--trunk/lib/rss/maker/itunes.rb242
-rw-r--r--trunk/lib/rss/maker/slash.rb33
-rw-r--r--trunk/lib/rss/maker/syndication.rb18
-rw-r--r--trunk/lib/rss/maker/taxonomy.rb118
-rw-r--r--trunk/lib/rss/maker/trackback.rb61
15 files changed, 3496 insertions, 0 deletions
diff --git a/trunk/lib/rss/maker/0.9.rb b/trunk/lib/rss/maker/0.9.rb
new file mode 100644
index 0000000000..72b14dc977
--- /dev/null
+++ b/trunk/lib/rss/maker/0.9.rb
@@ -0,0 +1,467 @@
+require "rss/0.9"
+
+require "rss/maker/base"
+
+module RSS
+ module Maker
+
+ class RSS09 < RSSBase
+
+ def initialize(feed_version="0.92")
+ super
+ @feed_type = "rss"
+ end
+
+ private
+ def make_feed
+ Rss.new(@feed_version, @version, @encoding, @standalone)
+ end
+
+ def setup_elements(rss)
+ setup_channel(rss)
+ end
+
+ class Channel < ChannelBase
+ def to_feed(rss)
+ channel = Rss::Channel.new
+ set = setup_values(channel)
+ _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, channel)
+ rss
+ else
+ raise NotSetError.new("maker.channel", _not_set_required_variables)
+ end
+ end
+
+ private
+ def setup_items(rss)
+ @maker.items.to_feed(rss)
+ end
+
+ def setup_image(rss)
+ @maker.image.to_feed(rss)
+ end
+
+ def setup_textinput(rss)
+ @maker.textinput.to_feed(rss)
+ end
+
+ def variables
+ super + ["pubDate"]
+ end
+
+ def required_variable_names
+ %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_feed(rss, channel)
+ unless @days.empty?
+ skipDays = Rss::Channel::SkipDays.new
+ channel.skipDays = skipDays
+ set_parent(skipDays, channel)
+ @days.each do |day|
+ day.to_feed(rss, skipDays.days)
+ end
+ end
+ end
+
+ class Day < DayBase
+ def to_feed(rss, days)
+ day = Rss::Channel::SkipDays::Day.new
+ set = setup_values(day)
+ if set
+ days << day
+ set_parent(day, days)
+ setup_other_elements(rss, day)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(content)
+ end
+ end
+ end
+
+ class SkipHours < SkipHoursBase
+ 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_feed(rss, skipHours.hours)
+ end
+ end
+ end
+
+ class Hour < HourBase
+ def to_feed(rss, hours)
+ hour = Rss::Channel::SkipHours::Hour.new
+ set = setup_values(hour)
+ if set
+ hours << hour
+ set_parent(hour, hours)
+ setup_other_elements(rss, hour)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(content)
+ end
+ end
+ end
+
+ class Cloud < CloudBase
+ def to_feed(*args)
+ end
+ end
+
+ class Categories < CategoriesBase
+ 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_feed(rss)
+ image = Rss::Channel::Image.new
+ set = setup_values(image)
+ if set
+ image.link = link
+ rss.channel.image = image
+ set_parent(image, rss.channel)
+ setup_other_elements(rss, image)
+ elsif required_element?
+ raise NotSetError.new("maker.image", not_set_required_variables)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(url title link)
+ end
+
+ def required_element?
+ true
+ end
+ end
+
+ class Items < ItemsBase
+ def to_feed(rss)
+ if rss.channel
+ normalize.each do |item|
+ item.to_feed(rss)
+ end
+ setup_other_elements(rss, rss.items)
+ end
+ end
+
+ class Item < ItemBase
+ def to_feed(rss)
+ item = Rss::Channel::Item.new
+ set = setup_values(item)
+ _not_set_required_variables = not_set_required_variables
+ if _not_set_required_variables.empty?
+ rss.items << item
+ 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 required_variable_names
+ []
+ end
+
+ def not_set_required_variables
+ vars = super
+ if @maker.feed_version == "0.91"
+ vars << "title" unless title {|t| t.have_required_values?}
+ vars << "link" unless link {|l| l.have_required_values?}
+ end
+ vars
+ end
+
+ class Guid < GuidBase
+ def to_feed(*args)
+ end
+ end
+
+ class Enclosure < EnclosureBase
+ def to_feed(*args)
+ end
+ end
+
+ class Source < SourceBase
+ 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_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_feed(rss)
+ textInput = Rss::Channel::TextInput.new
+ set = setup_values(textInput)
+ if set
+ rss.channel.textInput = textInput
+ set_parent(textInput, rss.channel)
+ setup_other_elements(rss, textInput)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(title description name link)
+ end
+ end
+ end
+
+ add_maker("0.9", "0.92", RSS09)
+ add_maker("0.91", "0.91", RSS09)
+ add_maker("0.92", "0.92", RSS09)
+ add_maker("rss0.91", "0.91", RSS09)
+ add_maker("rss0.92", "0.92", RSS09)
+ end
+end
diff --git a/trunk/lib/rss/maker/1.0.rb b/trunk/lib/rss/maker/1.0.rb
new file mode 100644
index 0000000000..a1e2594f70
--- /dev/null
+++ b/trunk/lib/rss/maker/1.0.rb
@@ -0,0 +1,434 @@
+require "rss/1.0"
+
+require "rss/maker/base"
+
+module RSS
+ module Maker
+
+ class RSS10 < RSSBase
+
+ def initialize(feed_version="1.0")
+ super
+ @feed_type = "rss"
+ end
+
+ private
+ def make_feed
+ RDF.new(@version, @encoding, @standalone)
+ end
+
+ def setup_elements(rss)
+ setup_channel(rss)
+ setup_image(rss)
+ setup_items(rss)
+ setup_textinput(rss)
+ end
+
+ class Channel < ChannelBase
+
+ 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, channel)
+ else
+ raise NotSetError.new("maker.channel", _not_set_required_variables)
+ end
+ end
+ end
+
+ private
+ def setup_items(rss)
+ items = RDF::Channel::Items.new
+ seq = items.Seq
+ 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?
+ image = RDF::Channel::Image.new(@maker.image.url)
+ rss.channel.image = image
+ set_parent(image, rss.channel)
+ end
+ end
+
+ def setup_textinput(rss)
+ 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 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_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
+ 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_feed(rss)
+ if @url
+ image = RDF::Image.new(@url)
+ set = setup_values(image)
+ if set
+ rss.image = image
+ set_parent(image, rss)
+ setup_other_elements(rss, image)
+ end
+ end
+ end
+
+ def 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_feed(rss)
+ if rss.channel
+ normalize.each do |item|
+ item.to_feed(rss)
+ end
+ setup_other_elements(rss, rss.items)
+ end
+ end
+
+ class Item < ItemBase
+ 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
+ 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
+
+ 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_feed(*args)
+ end
+ end
+
+ class Enclosure < EnclosureBase
+ def to_feed(*args)
+ end
+ end
+
+ class Source < SourceBase
+ 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_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_feed(rss)
+ if @link
+ textinput = RDF::Textinput.new(@link)
+ set = setup_values(textinput)
+ if set
+ rss.textinput = textinput
+ set_parent(textinput, rss)
+ setup_other_elements(rss, textinput)
+ end
+ end
+ end
+
+ def 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("1.0", "1.0", RSS10)
+ add_maker("rss1.0", "1.0", RSS10)
+ end
+end
diff --git a/trunk/lib/rss/maker/2.0.rb b/trunk/lib/rss/maker/2.0.rb
new file mode 100644
index 0000000000..67d68126ac
--- /dev/null
+++ b/trunk/lib/rss/maker/2.0.rb
@@ -0,0 +1,223 @@
+require "rss/2.0"
+
+require "rss/maker/0.9"
+
+module RSS
+ module Maker
+
+ class RSS20 < RSS09
+
+ def initialize(feed_version="2.0")
+ super
+ end
+
+ class Channel < RSS09::Channel
+
+ private
+ def required_variable_names
+ %w(link)
+ end
+
+ class SkipDays < RSS09::Channel::SkipDays
+ class Day < RSS09::Channel::SkipDays::Day
+ end
+ end
+
+ class SkipHours < RSS09::Channel::SkipHours
+ class Hour < RSS09::Channel::SkipHours::Hour
+ end
+ end
+
+ class Cloud < RSS09::Channel::Cloud
+ def to_feed(rss, channel)
+ cloud = Rss::Channel::Cloud.new
+ set = setup_values(cloud)
+ if set
+ channel.cloud = cloud
+ set_parent(cloud, channel)
+ setup_other_elements(rss, cloud)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(domain port path registerProcedure protocol)
+ end
+ end
+
+ class Categories < RSS09::Channel::Categories
+ def to_feed(rss, channel)
+ @categories.each do |category|
+ category.to_feed(rss, channel)
+ end
+ end
+
+ class Category < RSS09::Channel::Categories::Category
+ def to_feed(rss, channel)
+ category = Rss::Channel::Category.new
+ set = setup_values(category)
+ if set
+ channel.categories << category
+ set_parent(category, channel)
+ setup_other_elements(rss, category)
+ end
+ end
+
+ 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
+ private
+ def required_variable_names
+ []
+ end
+
+ def not_set_required_variables
+ vars = super
+ if !title {|t| t.have_required_values?} and
+ !description {|d| d.have_required_values?}
+ vars << "title or description"
+ end
+ vars
+ end
+
+ def variables
+ super + ["pubDate"]
+ end
+
+ class Guid < RSS09::Items::Item::Guid
+ def to_feed(rss, item)
+ guid = Rss::Channel::Item::Guid.new
+ set = setup_values(guid)
+ if set
+ item.guid = guid
+ set_parent(guid, item)
+ setup_other_elements(rss, guid)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(content)
+ end
+ end
+
+ class Enclosure < RSS09::Items::Item::Enclosure
+ def to_feed(rss, item)
+ enclosure = Rss::Channel::Item::Enclosure.new
+ set = setup_values(enclosure)
+ if set
+ item.enclosure = enclosure
+ set_parent(enclosure, item)
+ setup_other_elements(rss, enclosure)
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(url length type)
+ end
+ end
+
+ class Source < RSS09::Items::Item::Source
+ def to_feed(rss, item)
+ source = Rss::Channel::Item::Source.new
+ set = setup_values(source)
+ if set
+ item.source = source
+ set_parent(source, item)
+ setup_other_elements(rss, source)
+ end
+ end
+
+ 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_feed(rss, item)
+ @categories.each do |category|
+ category.to_feed(rss, item)
+ end
+ end
+
+ class Category < RSS09::Items::Item::Categories::Category
+ 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
+
+ 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("2.0", "2.0", RSS20)
+ add_maker("rss2.0", "2.0", RSS20)
+ end
+end
diff --git a/trunk/lib/rss/maker/atom.rb b/trunk/lib/rss/maker/atom.rb
new file mode 100644
index 0000000000..fd3198cd9e
--- /dev/null
+++ b/trunk/lib/rss/maker/atom.rb
@@ -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
diff --git a/trunk/lib/rss/maker/base.rb b/trunk/lib/rss/maker/base.rb
new file mode 100644
index 0000000000..2262a764ec
--- /dev/null
+++ b/trunk/lib/rss/maker/base.rb
@@ -0,0 +1,880 @@
+require 'forwardable'
+
+require 'rss/rss'
+
+module RSS
+ module Maker
+ class Base
+ extend Utils::InheritedReader
+
+ OTHER_ELEMENTS = []
+ NEED_INITIALIZE_VARIABLES = []
+
+ class << self
+ def other_elements
+ inherited_array_reader("OTHER_ELEMENTS")
+ end
+ def need_initialize_variables
+ inherited_array_reader("NEED_INITIALIZE_VARIABLES")
+ end
+
+ def inherited_base
+ ::RSS::Maker::Base
+ end
+
+ def inherited(subclass)
+ subclass.const_set("OTHER_ELEMENTS", [])
+ subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
+ end
+
+ def add_other_element(variable_name)
+ self::OTHER_ELEMENTS << variable_name
+ end
+
+ def add_need_initialize_variable(variable_name, init_value=nil,
+ &init_block)
+ init_value ||= init_block
+ 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 to_feed(*args)
+ @#{plural}.each do |#{name}|
+ #{name}.to_feed(*args)
+ end
+ end
+
+ def replace(elements)
+ @#{plural}.replace(elements.to_a)
+ end
+ EOC
+ end
+
+ 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) do |object|
+ object.send("make_#{name}")
+ end
+ 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 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 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 def_other_element(name)
+ attr_accessor name
+ def_other_element_without_accessor(name)
+ end
+
+ 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 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
+ end
+
+ attr_reader :maker
+ def initialize(maker)
+ @maker = maker
+ @default_values_are_set = false
+ initialize_variables
+ end
+
+ def have_required_values?
+ 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|
+ if init_value.nil?
+ value = nil
+ else
+ if init_value.respond_to?(:call)
+ value = init_value.call(self)
+ elsif init_value.is_a?(String)
+ # just for backward compatibility
+ value = instance_eval(init_value, __FILE__, __LINE__)
+ else
+ value = init_value
+ end
+ end
+ instance_variable_set("@#{variable_name}", value)
+ end
+ end
+
+ def setup_other_elements(feed, current=nil)
+ current ||= current_element(feed)
+ self.class.other_elements.each do |element|
+ __send__("setup_#{element}", feed, current)
+ end
+ end
+
+ 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?
+ variables.each do |var|
+ setter = "#{var}="
+ if target.respond_to?(setter)
+ value = __send__(var)
+ if value
+ target.__send__(setter, value)
+ set = true
+ end
+ end
+ end
+ end
+ 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|
+ # init == "nil" is just for backward compatibility
+ init.nil? or init == "nil"
+ end.collect do |name, init|
+ name
+ end
+ end
+
+ def not_set_required_variables
+ required_variable_names.find_all do |var|
+ __send__(var).nil?
+ end
+ end
+
+ def required_variables_are_set?
+ required_variable_names.each do |var|
+ return false if __send__(var).nil?
+ end
+ true
+ end
+ end
+
+ 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(version, &block)
+ new(version).make(&block)
+ end
+ end
+
+ %w(xml_stylesheets channel image items textinput).each do |element|
+ attr_reader element
+ add_need_initialize_variable(element) do |object|
+ object.send("make_#{element}")
+ end
+ module_eval(<<-EOC, __FILE__, __LINE__)
+ private
+ def setup_#{element}(feed)
+ @#{element}.to_feed(feed)
+ end
+
+ def make_#{element}
+ self.class::#{Utils.to_class_name(element)}.new(self)
+ end
+ EOC
+ end
+
+ attr_reader :feed_version
+ alias_method(:rss_version, :feed_version)
+ attr_accessor :version, :encoding, :standalone
+
+ def initialize(feed_version)
+ super(self)
+ @feed_type = nil
+ @feed_subtype = nil
+ @feed_version = feed_version
+ @version = "1.0"
+ @encoding = "UTF-8"
+ @standalone = nil
+ end
+
+ def make
+ yield(self)
+ to_feed
+ end
+
+ def to_feed
+ feed = make_feed
+ setup_xml_stylesheets(feed)
+ setup_elements(feed)
+ setup_other_elements(feed)
+ feed.validate
+ feed
+ end
+
+ private
+ remove_method :make_xml_stylesheets
+ def make_xml_stylesheets
+ XMLStyleSheets.new(self)
+ end
+ end
+
+ class XMLStyleSheets < Base
+ def_array_element("xml_stylesheet", nil, "XMLStyleSheet")
+
+ class XMLStyleSheet < Base
+
+ ::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute|
+ attr_accessor attribute
+ add_need_initialize_variable(attribute)
+ end
+
+ def to_feed(feed)
+ xss = ::RSS::XMLStyleSheet.new
+ guess_type_if_need(xss)
+ set = setup_values(xss)
+ if set
+ feed.xml_stylesheets << xss
+ end
+ end
+
+ private
+ def guess_type_if_need(xss)
+ if @type.nil?
+ xss.href = @href
+ @type = xss.type
+ end
+ end
+
+ def required_variable_names
+ %w(href type)
+ end
+ end
+ end
+
+ class ChannelBase < Base
+ include SetupDefaultDate
+
+ %w(cloud categories skipDays skipHours).each do |name|
+ def_classed_element(name)
+ end
+
+ %w(generator copyright description title).each do |name|
+ def_classed_element(name, nil, "content")
+ end
+
+ [
+ ["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 ttl).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+
+ def pubDate
+ date
+ end
+
+ def pubDate=(date)
+ self.date = date
+ end
+
+ def updated
+ date
+ end
+
+ def updated=(date)
+ self.date = date
+ end
+
+ alias_method(:rights, :copyright)
+ alias_method(:rights=, :copyright=)
+
+ 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
+ end
+ end
+
+ class SkipHoursBase < Base
+ def_array_element("hour")
+
+ class HourBase < Base
+ %w(content).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+ end
+
+ class CloudBase < Base
+ %w(domain port path registerProcedure protocol).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ class CategoriesBase < Base
+ def_array_element("category", "categories")
+
+ 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 LinksBase < Base
+ def_array_element("link")
+
+ 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 < 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
+ end
+
+ class ItemsBase < Base
+ def_array_element("item")
+
+ attr_accessor :do_sort, :max_size
+
+ def initialize(maker)
+ super
+ @do_sort = false
+ @max_size = -1
+ end
+
+ def normalize
+ if @max_size >= 0
+ sort_if_need[0...@max_size]
+ else
+ sort_if_need[0..@max_size]
+ end
+ end
+
+ private
+ def sort_if_need
+ if @do_sort.respond_to?(:call)
+ @items.sort do |x, y|
+ @do_sort.call(x, y)
+ end
+ elsif @do_sort
+ @items.sort do |x, y|
+ y <=> x
+ end
+ else
+ @items
+ end
+ end
+
+ class ItemBase < Base
+ include SetupDefaultDate
+
+ %w(guid enclosure source categories content).each do |name|
+ def_classed_element(name)
+ end
+
+ %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
+
+ 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)
+ _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
+ -1
+ else
+ 0
+ end
+ end
+
+ class GuidBase < Base
+ %w(isPermaLink content).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ class EnclosureBase < Base
+ %w(url length type).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ 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 < Base
+ %w(title description name link).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+ end
+end
diff --git a/trunk/lib/rss/maker/content.rb b/trunk/lib/rss/maker/content.rb
new file mode 100644
index 0000000000..46c4911f73
--- /dev/null
+++ b/trunk/lib/rss/maker/content.rb
@@ -0,0 +1,21 @@
+require 'rss/content'
+require 'rss/maker/1.0'
+require 'rss/maker/2.0'
+
+module RSS
+ module Maker
+ module ContentModel
+ def self.append_features(klass)
+ super
+
+ ::RSS::ContentModel::ELEMENTS.each do |name|
+ klass.def_other_element(name)
+ end
+ end
+ end
+
+ class ItemsBase
+ class ItemBase; include ContentModel; end
+ end
+ end
+end
diff --git a/trunk/lib/rss/maker/dublincore.rb b/trunk/lib/rss/maker/dublincore.rb
new file mode 100644
index 0000000000..ff4813fe19
--- /dev/null
+++ b/trunk/lib/rss/maker/dublincore.rb
@@ -0,0 +1,124 @@
+require 'rss/dublincore'
+require 'rss/maker/1.0'
+
+module RSS
+ module Maker
+ module DublinCoreModel
+ def self.append_features(klass)
+ super
+
+ ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name|
+ plural_name ||= "#{name}s"
+ full_name = "#{RSS::DC_PREFIX}_#{name}"
+ full_plural_name = "#{RSS::DC_PREFIX}_#{plural_name}"
+ klass_name = Utils.to_class_name(name)
+ 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.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
+ 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__ + 1)
+ class #{plural_klass_name}Base < Base
+ def_array_element(#{name.dump}, #{full_plural_name.dump},
+ #{full_klass_name.dump})
+
+ class #{full_klass_name}Base < Base
+ attr_accessor :value
+ add_need_initialize_variable("value")
+ alias_method(:content, :value)
+ alias_method(:content=, :value=)
+
+ 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
+
+ def self.install_dublin_core(klass)
+ ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name|
+ plural_name ||= "#{name}s"
+ klass_name = Utils.to_class_name(name)
+ full_klass_name = "DublinCore#{klass_name}"
+ 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 #{full_klass_name} < #{full_klass_name}Base
+ end
+ #{klass_name} = #{full_klass_name}
+ end
+EOC
+ end
+ end
+ end
+
+ class ChannelBase
+ include DublinCoreModel
+ end
+
+ class ImageBase; include DublinCoreModel; end
+ class ItemsBase
+ class ItemBase
+ include DublinCoreModel
+ end
+ end
+ class TextinputBase; include DublinCoreModel; 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
+ DublinCoreModel.install_dublin_core(self)
+ end
+ end
+
+ class Textinput
+ DublinCoreModel.install_dublin_core(self)
+ end
+ EOC
+ end
+ end
+end
diff --git a/trunk/lib/rss/maker/entry.rb b/trunk/lib/rss/maker/entry.rb
new file mode 100644
index 0000000000..edaa31ec06
--- /dev/null
+++ b/trunk/lib/rss/maker/entry.rb
@@ -0,0 +1,163 @@
+require "rss/maker/atom"
+require "rss/maker/feed"
+
+module RSS
+ module Maker
+ module Atom
+ class Entry < RSSBase
+ def initialize(feed_version="1.0")
+ super
+ @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", "1.0", Atom::Entry)
+ add_maker("atom1.0:entry", "1.0", Atom::Entry)
+ end
+end
diff --git a/trunk/lib/rss/maker/feed.rb b/trunk/lib/rss/maker/feed.rb
new file mode 100644
index 0000000000..3a30ad4287
--- /dev/null
+++ b/trunk/lib/rss/maker/feed.rb
@@ -0,0 +1,429 @@
+require "rss/maker/atom"
+
+module RSS
+ module Maker
+ module Atom
+ class Feed < RSSBase
+ def initialize(feed_version="1.0")
+ super
+ @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", "1.0", Atom::Feed)
+ add_maker("atom:feed", "1.0", Atom::Feed)
+ add_maker("atom1.0", "1.0", Atom::Feed)
+ add_maker("atom1.0:feed", "1.0", Atom::Feed)
+ end
+end
diff --git a/trunk/lib/rss/maker/image.rb b/trunk/lib/rss/maker/image.rb
new file mode 100644
index 0000000000..b95cf4c714
--- /dev/null
+++ b/trunk/lib/rss/maker/image.rb
@@ -0,0 +1,111 @@
+require 'rss/image'
+require 'rss/maker/1.0'
+require 'rss/maker/dublincore'
+
+module RSS
+ module Maker
+ module ImageItemModel
+ def self.append_features(klass)
+ super
+
+ name = "#{RSS::IMAGE_PREFIX}_item"
+ klass.def_classed_element(name)
+ end
+
+ 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 < Base
+ include Maker::DublinCoreModel
+
+ attr_accessor :about, :resource, :image_width, :image_height
+ add_need_initialize_variable("about")
+ add_need_initialize_variable("resource")
+ add_need_initialize_variable("image_width")
+ add_need_initialize_variable("image_height")
+ alias width= image_width=
+ alias width image_width
+ alias height= image_height=
+ alias height image_height
+
+ 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
+
+ module ImageFaviconModel
+ def self.append_features(klass)
+ super
+
+ name = "#{RSS::IMAGE_PREFIX}_favicon"
+ klass.def_classed_element(name)
+ end
+
+ def self.install_image_favicon(klass)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ class ImageFavicon < ImageFaviconBase
+ DublinCoreModel.install_dublin_core(self)
+ end
+ EOC
+ end
+
+ class ImageFaviconBase < Base
+ include Maker::DublinCoreModel
+
+ attr_accessor :about, :image_size
+ add_need_initialize_variable("about")
+ add_need_initialize_variable("image_size")
+ alias size image_size
+ alias size= image_size=
+
+ 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
+
+ class ChannelBase; include Maker::ImageFaviconModel; end
+
+ class ItemsBase
+ class ItemBase; include Maker::ImageItemModel; end
+ end
+
+ makers.each do |maker|
+ maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ class Channel
+ ImageFaviconModel.install_image_favicon(self)
+ end
+
+ class Items
+ class Item
+ ImageItemModel.install_image_item(self)
+ end
+ end
+ EOC
+ end
+ end
+end
diff --git a/trunk/lib/rss/maker/itunes.rb b/trunk/lib/rss/maker/itunes.rb
new file mode 100644
index 0000000000..8b7420da3c
--- /dev/null
+++ b/trunk/lib/rss/maker/itunes.rb
@@ -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, name, 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, name, 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_#{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
diff --git a/trunk/lib/rss/maker/slash.rb b/trunk/lib/rss/maker/slash.rb
new file mode 100644
index 0000000000..27adef3832
--- /dev/null
+++ b/trunk/lib/rss/maker/slash.rb
@@ -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
diff --git a/trunk/lib/rss/maker/syndication.rb b/trunk/lib/rss/maker/syndication.rb
new file mode 100644
index 0000000000..b81230457c
--- /dev/null
+++ b/trunk/lib/rss/maker/syndication.rb
@@ -0,0 +1,18 @@
+require 'rss/syndication'
+require 'rss/maker/1.0'
+
+module RSS
+ module Maker
+ module SyndicationModel
+ def self.append_features(klass)
+ super
+
+ ::RSS::SyndicationModel::ELEMENTS.each do |name|
+ klass.def_other_element(name)
+ end
+ end
+ end
+
+ class ChannelBase; include SyndicationModel; end
+ end
+end
diff --git a/trunk/lib/rss/maker/taxonomy.rb b/trunk/lib/rss/maker/taxonomy.rb
new file mode 100644
index 0000000000..211603840f
--- /dev/null
+++ b/trunk/lib/rss/maker/taxonomy.rb
@@ -0,0 +1,118 @@
+require 'rss/taxonomy'
+require 'rss/maker/1.0'
+require 'rss/maker/dublincore'
+
+module RSS
+ module Maker
+ module TaxonomyTopicsModel
+ def self.append_features(klass)
+ super
+
+ klass.def_classed_element("#{RSS::TAXO_PREFIX}_topics",
+ "TaxonomyTopics")
+ end
+
+ def self.install_taxo_topics(klass)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ class TaxonomyTopics < TaxonomyTopicsBase
+ def to_feed(feed, current)
+ if current.respond_to?(:taxo_topics)
+ topics = current.class::TaxonomyTopics.new
+ bag = topics.Bag
+ @resources.each do |resource|
+ bag.lis << RDF::Bag::Li.new(resource)
+ end
+ current.taxo_topics = topics
+ end
+ end
+ end
+EOC
+ end
+
+ class TaxonomyTopicsBase < Base
+ attr_reader :resources
+ def_array_element("resource")
+ remove_method :new_resource
+ end
+ end
+
+ module TaxonomyTopicModel
+ def self.append_features(klass)
+ super
+
+ class_name = "TaxonomyTopics"
+ klass.def_classed_elements("#{TAXO_PREFIX}_topic", "value", class_name)
+ end
+
+ def self.install_taxo_topic(klass)
+ 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_feed(feed, current)
+ if current.respond_to?(:taxo_topics)
+ topic = current.class::TaxonomyTopic.new(value)
+ topic.taxo_link = value
+ taxo_topics.to_feed(feed, topic) if taxo_topics
+ current.taxo_topics << topic
+ setup_other_elements(feed, topic)
+ end
+ end
+ end
+ end
+EOC
+ end
+
+ class TaxonomyTopicsBase < Base
+ def_array_element("topic", nil, "TaxonomyTopic")
+ alias_method(:new_taxo_topic, :new_topic) # For backward compatibility
+
+ class TaxonomyTopicBase < Base
+ include DublinCoreModel
+ include TaxonomyTopicsModel
+
+ attr_accessor :value
+ add_need_initialize_variable("value")
+ alias_method(:taxo_link, :value)
+ alias_method(:taxo_link=, :value=)
+
+ def have_required_values?
+ @value
+ end
+ end
+ end
+ end
+
+ class RSSBase
+ include TaxonomyTopicModel
+ end
+
+ class ChannelBase
+ include TaxonomyTopicsModel
+ end
+
+ class ItemsBase
+ class ItemBase
+ include TaxonomyTopicsModel
+ end
+ end
+
+ makers.each do |maker|
+ maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ TaxonomyTopicModel.install_taxo_topic(self)
+
+ class Channel
+ TaxonomyTopicsModel.install_taxo_topics(self)
+ end
+
+ class Items
+ class Item
+ TaxonomyTopicsModel.install_taxo_topics(self)
+ end
+ end
+ EOC
+ end
+ end
+end
diff --git a/trunk/lib/rss/maker/trackback.rb b/trunk/lib/rss/maker/trackback.rb
new file mode 100644
index 0000000000..278fe53ebe
--- /dev/null
+++ b/trunk/lib/rss/maker/trackback.rb
@@ -0,0 +1,61 @@
+require 'rss/trackback'
+require 'rss/maker/1.0'
+require 'rss/maker/2.0'
+
+module RSS
+ module Maker
+ module TrackBackModel
+ def self.append_features(klass)
+ super
+
+ klass.def_other_element("#{RSS::TRACKBACK_PREFIX}_ping")
+ klass.def_classed_elements("#{RSS::TRACKBACK_PREFIX}_about", "value",
+ "TrackBackAbouts")
+ end
+
+ class TrackBackAboutsBase < Base
+ def_array_element("about", nil, "TrackBackAbout")
+
+ class TrackBackAboutBase < Base
+ attr_accessor :value
+ add_need_initialize_variable("value")
+
+ alias_method(:resource, :value)
+ alias_method(:resource=, :value=)
+ alias_method(:content, :value)
+ alias_method(:content=, :value=)
+
+ def have_required_values?
+ @value
+ end
+
+ 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
+
+ class ItemsBase
+ class ItemBase; include TrackBackModel; end
+ 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
+ EOC
+ end
+ end
+end