summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorkou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-03-17 10:13:25 +0000
committerkou <kou@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2007-03-17 10:13:25 +0000
commit966a25465aab5c2972e6c453f631a15fc2223256 (patch)
tree847090e856c9901ab2cc19251c179b9b0985e65b /lib
parent53cbab048452742b537ac8bccf494630d1c184c8 (diff)
* lib/rss, test/rss:
- supported Atom. - bumped version 0.1.6 to 0.1.7. * sample/rss/convert.rb: added new sample. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@12087 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib')
-rw-r--r--lib/rss.rb5
-rw-r--r--lib/rss/0.9.rb532
-rw-r--r--lib/rss/1.0.rb486
-rw-r--r--lib/rss/2.0.rb97
-rw-r--r--lib/rss/atom.rb749
-rw-r--r--lib/rss/content.rb25
-rw-r--r--lib/rss/converter.rb19
-rw-r--r--lib/rss/dublincore.rb62
-rw-r--r--lib/rss/dublincore/1.0.rb13
-rw-r--r--lib/rss/dublincore/2.0.rb13
-rw-r--r--lib/rss/dublincore/atom.rb17
-rw-r--r--lib/rss/image.rb116
-rw-r--r--lib/rss/maker.rb19
-rw-r--r--lib/rss/maker/0.9.rb372
-rw-r--r--lib/rss/maker/1.0.rb328
-rw-r--r--lib/rss/maker/2.0.rb134
-rw-r--r--lib/rss/maker/atom.rb172
-rw-r--r--lib/rss/maker/base.rb710
-rw-r--r--lib/rss/maker/dublincore.rb100
-rw-r--r--lib/rss/maker/entry.rb167
-rw-r--r--lib/rss/maker/feed.rb429
-rw-r--r--lib/rss/maker/image.rb100
-rw-r--r--lib/rss/maker/taxonomy.rb73
-rw-r--r--lib/rss/maker/trackback.rb85
-rw-r--r--lib/rss/parser.rb172
-rw-r--r--lib/rss/rss.rb661
-rw-r--r--lib/rss/syndication.rb32
-rw-r--r--lib/rss/taxonomy.rb128
-rw-r--r--lib/rss/trackback.rb106
-rw-r--r--lib/rss/utils.rb7
-rw-r--r--lib/rss/xml.rb71
31 files changed, 4032 insertions, 1968 deletions
diff --git a/lib/rss.rb b/lib/rss.rb
index 495edb1b98..bbe19ad95c 100644
--- a/lib/rss.rb
+++ b/lib/rss.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2003-2005 Kouhei Sutou. You can redistribute it and/or
+# Copyright (c) 2003-2006 Kouhei Sutou. You can redistribute it and/or
# modify it under the same terms as Ruby.
#
# Author:: Kouhei Sutou <kou@cozmixng.org>
@@ -6,11 +6,12 @@
require 'rss/1.0'
require 'rss/2.0'
+require 'rss/atom'
require 'rss/content'
require 'rss/dublincore'
require 'rss/image'
require 'rss/syndication'
-#require 'rss/taxonomy'
+require 'rss/taxonomy'
require 'rss/trackback'
require "rss/maker"
diff --git a/lib/rss/0.9.rb b/lib/rss/0.9.rb
index 900536869d..7b24e7596d 100644
--- a/lib/rss/0.9.rb
+++ b/lib/rss/0.9.rb
@@ -9,7 +9,7 @@ module RSS
def self.append_features(klass)
super
- klass.install_must_call_validator('', nil)
+ klass.install_must_call_validator('', "")
end
end
@@ -17,22 +17,18 @@ module RSS
include RSS09
include RootElementMixin
- # include XMLStyleSheetMixin
-
- [
- ["channel", nil],
- ].each do |tag, occurs|
- install_model(tag, occurs)
- end
%w(channel).each do |name|
- install_have_child_element(name)
+ 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
@@ -58,34 +54,20 @@ module RSS
nil
end
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent, ns_declarations) do |next_indent|
- [
- channel_element(false, next_indent),
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
- private
- def children
- [@channel]
- end
-
- def _tags
- [
- [nil, 'channel'],
- ].delete_if do |uri, name|
- __send__(name).nil?
+ def setup_maker_elements(maker)
+ super
+ 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
@@ -94,119 +76,30 @@ module RSS
include RSS09
[
- ["title", nil],
- ["link", nil],
- ["description", nil],
- ["language", nil],
- ["copyright", "?"],
- ["managingEditor", "?"],
- ["webMaster", "?"],
- ["rating", "?"],
- ["docs", "?"],
- ].each do |name, occurs|
- install_text_element(name)
- install_model(name, occurs)
- end
-
- [
- ["pubDate", "?"],
- ["lastBuildDate", "?"],
- ].each do |name, occurs|
- install_date_element(name, 'rfc822')
- install_model(name, occurs)
+ ["title", nil, :text],
+ ["link", nil, :text],
+ ["description", nil, :text],
+ ["language", nil, :text],
+ ["copyright", "?", :text],
+ ["managingEditor", "?", :text],
+ ["webMaster", "?", :text],
+ ["rating", "?", :text],
+ ["pubDate", "?", :date, :rfc822],
+ ["lastBuildDate", "?", :date, :rfc822],
+ ["docs", "?", :text],
+ ["cloud", "?", :have_attribute],
+ ["skipDays", "?", :have_child],
+ ["skipHours", "?", :have_child],
+ ["image", nil, :have_child],
+ ["item", "*", :have_children],
+ ["textInput", "?", :have_child],
+ ].each do |name, occurs, type, *args|
+ __send__("install_#{type}_element", name, "", occurs, name, *args)
end
alias date pubDate
alias date= pubDate=
- [
- ["skipDays", "?"],
- ["skipHours", "?"],
- ["image", nil],
- ["textInput", "?"],
- ].each do |name, occurs|
- install_have_child_element(name)
- install_model(name, occurs)
- end
-
- [
- ["cloud", "?"]
- ].each do |name, occurs|
- install_have_attribute_element(name)
- install_model(name, occurs)
- end
-
- [
- ["item", "*"]
- ].each do |name, occurs|
- install_have_children_element(name)
- install_model(name, occurs)
- end
-
- def initialize()
- super()
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- link_element(false, next_indent),
- description_element(false, next_indent),
- language_element(false, next_indent),
- copyright_element(false, next_indent),
- managingEditor_element(false, next_indent),
- webMaster_element(false, next_indent),
- rating_element(false, next_indent),
- pubDate_element(false, next_indent),
- lastBuildDate_element(false, next_indent),
- docs_element(false, next_indent),
- cloud_element(false, next_indent),
- skipDays_element(false, next_indent),
- skipHours_element(false, next_indent),
- image_element(false, next_indent),
- item_elements(false, next_indent),
- textInput_element(false, next_indent),
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
-
private
- def children
- [@skipDays, @skipHours, @image, @textInput, @cloud, *@item]
- end
-
- def _tags
- rv = [
- "title",
- "link",
- "description",
- "language",
- "copyright",
- "managingEditor",
- "webMaster",
- "rating",
- "docs",
- "skipDays",
- "skipHours",
- "image",
- "textInput",
- "cloud",
- ].delete_if do |name|
- __send__(name).nil?
- end.collect do |elem|
- [nil, elem]
- end
-
- @item.each do
- rv << [nil, "item"]
- end
-
- rv
- end
-
def maker_target(maker)
maker.channel
end
@@ -237,29 +130,7 @@ module RSS
[
["day", "*"]
].each do |name, occurs|
- install_have_children_element(name)
- install_model(name, occurs)
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- day_elements(false, next_indent)
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def children
- @day
- end
-
- def _tags
- @day.compact.collect do
- [nil, "day"]
- end
+ install_have_children_element(name, "", occurs)
end
class Day < Element
@@ -267,9 +138,13 @@ module RSS
content_setup
- def initialize(content=nil)
- super()
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.content = args[0]
+ end
end
end
@@ -282,29 +157,7 @@ module RSS
[
["hour", "*"]
].each do |name, occurs|
- install_have_children_element(name)
- install_model(name, occurs)
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- hour_elements(false, next_indent)
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def children
- @hour
- end
-
- def _tags
- @hour.compact.collect do
- [nil, "hour"]
- end
+ install_have_children_element(name, "", occurs)
end
class Hour < Element
@@ -312,9 +165,13 @@ module RSS
content_setup(:integer)
- def initialize(content=nil)
- super()
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.content = args[0]
+ end
end
end
@@ -325,54 +182,31 @@ module RSS
include RSS09
%w(url title link).each do |name|
- install_text_element(name)
- install_model(name, nil)
+ install_text_element(name, "", nil)
end
[
["width", :integer],
["height", :integer],
["description"],
].each do |name, type|
- install_text_element(name, type)
- install_model(name, "?")
- end
-
- def initialize(url=nil, title=nil, link=nil, width=nil, height=nil,
- description=nil)
- super()
- self.url = url
- self.title = title
- self.link = link
- self.width = width
- self.height = height
- self.description = description
+ install_text_element(name, "", "?", name, type)
end
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- url_element(false, next_indent),
- title_element(false, next_indent),
- link_element(false, next_indent),
- width_element(false, next_indent),
- height_element(false, next_indent),
- description_element(false, next_indent),
- other_element(false, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.url = args[0]
+ self.title = args[1]
+ self.link = args[2]
+ self.width = args[3]
+ self.height = args[4]
+ self.description = args[5]
end
- rv = convert(rv) if need_convert
- rv
end
private
- def _tags
- %w(url title link width height description).delete_if do |name|
- __send__(name).nil?
- end.collect do |elem|
- [nil, elem]
- end
- end
-
def maker_target(maker)
maker.image
end
@@ -381,106 +215,47 @@ module RSS
class Cloud < Element
include RSS09
-
+
[
- ["domain", nil, true],
- ["port", nil, true, :integer],
- ["path", nil, true],
- ["registerProcedure", nil, true],
- ["protocol", nil, true],
+ ["domain", "", true],
+ ["port", "", true, :integer],
+ ["path", "", true],
+ ["registerProcedure", "", true],
+ ["protocol", "", true],
].each do |name, uri, required, type|
install_get_attribute(name, uri, required, type)
end
- def initialize(domain=nil, port=nil, path=nil, rp=nil, protocol=nil)
- super()
- self.domain = domain
- self.port = port
- self.path = path
- self.registerProcedure = rp
- self.protocol = protocol
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _attrs
- %w(domain port path registerProcedure protocol).collect do |attr|
- [attr, true]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.domain = args[0]
+ self.port = args[1]
+ self.path = args[2]
+ self.registerProcedure = args[3]
+ self.protocol = args[4]
end
end
-
end
class Item < Element
include RSS09
- %w(title link description).each do |name|
- install_text_element(name)
- end
-
- %w(source enclosure).each do |name|
- install_have_child_element(name)
- end
-
[
- %w(category categories),
- ].each do |name, plural_name|
- install_have_children_element(name, plural_name)
- end
-
- [
- ["title", '?'],
- ["link", '?'],
- ["description", '?'],
- ["category", '*'],
- ["source", '?'],
- ["enclosure", '?'],
- ].each do |tag, occurs|
- install_model(tag, occurs)
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- link_element(false, next_indent),
- description_element(false, next_indent),
- category_elements(false, next_indent),
- source_element(false, next_indent),
- enclosure_element(false, next_indent),
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
+ ["title", '?', :text],
+ ["link", '?', :text],
+ ["description", '?', :text],
+ ["category", '*', :have_children, "categories"],
+ ["source", '?', :have_child],
+ ["enclosure", '?', :have_child],
+ ].each do |tag, occurs, type, *args|
+ __send__("install_#{type}_element", tag, "", occurs, tag, *args)
end
private
- def children
- [@source, @enclosure, *@category].compact
- end
-
- def _tags
- rv = %w(title link description author comments
- source enclosure).delete_if do |name|
- __send__(name).nil?
- end.collect do |name|
- [nil, name]
- end
-
- @category.each do
- rv << [nil, "category"]
- end
-
- rv
- end
-
def maker_target(items)
if items.respond_to?("items")
# For backward compatibility
@@ -500,31 +275,24 @@ module RSS
include RSS09
[
- ["url", nil, true]
+ ["url", "", true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
content_setup
- def initialize(url=nil, content=nil)
- super()
- self.url = url
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.url = args[0]
+ self.content = args[1]
+ end
end
private
- def _tags
- []
- end
-
- def _attrs
- [
- ["url", true]
- ]
- end
-
-
def maker_target(item)
item.source
end
@@ -540,35 +308,25 @@ module RSS
include RSS09
[
- ["url", nil, true],
- ["length", nil, true, :integer],
- ["type", nil, true],
+ ["url", "", true],
+ ["length", "", true, :integer],
+ ["type", "", true],
].each do |name, uri, required, type|
install_get_attribute(name, uri, required, type)
end
- def initialize(url=nil, length=nil, type=nil)
- super()
- self.url = url
- self.length = length
- self.type = type
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.url = args[0]
+ self.length = args[1]
+ self.type = args[2]
+ end
end
private
- def _attrs
- [
- ["url", true],
- ["length", true],
- ["type", true],
- ]
- end
-
def maker_target(item)
item.enclosure
end
@@ -585,26 +343,24 @@ module RSS
include RSS09
[
- ["domain", nil, false]
+ ["domain", "", false]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
content_setup
- def initialize(domain=nil, content=nil)
- super()
- self.domain = domain
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.domain = args[0]
+ self.content = args[1]
+ end
end
private
- def _attrs
- [
- ["domain", false]
- ]
- end
-
def maker_target(item)
item.new_category
end
@@ -623,41 +379,22 @@ module RSS
include RSS09
%w(title description name link).each do |name|
- install_text_element(name)
- install_model(name, nil)
+ install_text_element(name, "", nil)
end
- def initialize(title=nil, description=nil, name=nil, link=nil)
- super()
- self.title = title
- self.description = description
- self.name = name
- self.link = link
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- description_element(false, next_indent),
- name_element(false, next_indent),
- link_element(false, next_indent),
- other_element(false, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.title = args[0]
+ self.description = args[1]
+ self.name = args[2]
+ self.link = args[3]
end
- rv = convert(rv) if need_convert
- rv
end
private
- def _tags
- %w(title description name link).each do |name|
- __send__(name).nil?
- end.collect do |elem|
- [nil, elem]
- end
- end
-
def maker_target(maker)
maker.textinput
end
@@ -668,21 +405,22 @@ module RSS
end
RSS09::ELEMENTS.each do |name|
- BaseListener.install_get_text_element(nil, name, "#{name}=")
+ BaseListener.install_get_text_element("", name, name)
end
module ListenerMixin
private
- def start_rss(tag_name, prefix, attrs, ns)
- check_ns(tag_name, prefix, ns, nil)
+ 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|
- @rss.validate_for_stream(tags) if @do_validate
- }
+ pr = Proc.new do |text, tags|
+ @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate
+ end
+ @proc_stack.push(pr)
end
end
diff --git a/lib/rss/1.0.rb b/lib/rss/1.0.rb
index 36d6f5df87..f04e61c5eb 100644
--- a/lib/rss/1.0.rb
+++ b/lib/rss/1.0.rb
@@ -38,62 +38,22 @@ module RSS
[
["channel", nil],
["image", "?"],
- ["item", "+"],
+ ["item", "+", :children],
["textinput", "?"],
- ].each do |tag, occurs|
- install_model(tag, occurs)
+ ].each do |tag, occurs, type|
+ type ||= :child
+ __send__("install_have_#{type}_element", tag, ::RSS::URI, occurs)
end
- %w(channel image textinput).each do |name|
- install_have_child_element(name)
- end
-
- install_have_children_element("item")
-
- 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
tag_name_with_prefix(PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent, ns_declarations) do |next_indent|
- [
- channel_element(false, next_indent),
- image_element(false, next_indent),
- item_elements(false, next_indent),
- textinput_element(false, next_indent),
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def rdf_validate(tags)
- _validate(tags, [])
- end
-
- def children
- [@channel, @image, @textinput, *@item]
- end
-
- def _tags
- rv = [
- [::RSS::URI, "channel"],
- [::RSS::URI, "image"],
- ].delete_if {|uri, name| __send__(name).nil?}
- @item.each do |item|
- rv << [::RSS::URI, "item"]
- end
- rv << [::RSS::URI, "textinput"] if @textinput
- rv
- end
class Li < Element
@@ -106,32 +66,23 @@ module RSS
end
[
- ["resource", [URI, nil], true]
+ ["resource", [URI, ""], true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
- def initialize(resource=nil)
- super()
- self.resource = resource
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.resource = args[0]
+ end
end
def full_name
tag_name_with_prefix(PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _attrs
- [
- ["resource", true]
- ]
- end
end
class Seq < Element
@@ -148,21 +99,15 @@ module RSS
@tag_name = 'Seq'
- install_have_children_element("li")
-
+ install_have_children_element("li", URI, "*")
install_must_call_validator('rdf', ::RSS::RDF::URI)
- def initialize(li=[])
- super()
- @li = li
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- tag(indent) do |next_indent|
- [
- li_elements(need_convert, next_indent),
- other_element(need_convert, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ @li = args[0] if args[0]
end
end
@@ -175,23 +120,6 @@ module RSS
target << li.resource
end
end
-
- private
- def children
- @li
- end
-
- def rdf_validate(tags)
- _validate(tags, [["li", '*']])
- end
-
- def _tags
- rv = []
- @li.each do |li|
- rv << [URI, "li"]
- end
- rv
- end
end
class Bag < Element
@@ -208,21 +136,15 @@ module RSS
@tag_name = 'Bag'
- install_have_children_element("li")
-
- install_must_call_validator('rdf', ::RSS::RDF::URI)
-
- def initialize(li=[])
- super()
- @li = li
- end
+ install_have_children_element("li", URI, "*")
+ install_must_call_validator('rdf', URI)
- def to_s(need_convert=true, indent=calc_indent)
- tag(indent) do |next_indent|
- [
- li_elements(need_convert, next_indent),
- other_element(need_convert, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ @li = args[0] if args[0]
end
end
@@ -235,23 +157,6 @@ module RSS
target << li.resource
end
end
-
- private
- def children
- @li
- end
-
- def rdf_validate(tags)
- _validate(tags, [["li", '*']])
- end
-
- def _tags
- rv = []
- @li.each do |li|
- rv << [URI, "li"]
- end
- rv
- end
end
class Channel < Element
@@ -269,73 +174,31 @@ module RSS
[
["about", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
- end
-
- %w(title link description).each do |name|
- install_text_element(name)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
- %w(image items textinput).each do |name|
- install_have_child_element(name)
- end
-
[
- ['title', nil],
- ['link', nil],
- ['description', nil],
- ['image', '?'],
- ['items', nil],
- ['textinput', '?'],
- ].each do |tag, occurs|
- install_model(tag, occurs)
- end
-
- def initialize(about=nil)
- super()
- self.about = about
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- link_element(false, next_indent),
- description_element(false, next_indent),
- image_element(false, next_indent),
- items_element(false, next_indent),
- textinput_element(false, next_indent),
- other_element(false, next_indent),
- ]
+ ['title', nil, :text],
+ ['link', nil, :text],
+ ['description', nil, :text],
+ ['image', '?', :have_child],
+ ['items', nil, :have_child],
+ ['textinput', '?', :have_child],
+ ].each do |tag, occurs, type|
+ __send__("install_#{type}_element", tag, ::RSS::URI, occurs)
+ end
+
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
end
- rv = convert(rv) if need_convert
- rv
end
private
- def children
- [@image, @items, @textinput]
- end
-
- def _tags
- [
- [::RSS::URI, 'title'],
- [::RSS::URI, 'link'],
- [::RSS::URI, 'description'],
- [::RSS::URI, 'image'],
- [::RSS::URI, 'items'],
- [::RSS::URI, 'textinput'],
- ].delete_if do |uri, name|
- __send__(name).nil?
- end
- end
-
- def _attrs
- [
- ["#{PREFIX}:about", true, "about"]
- ]
- end
-
def maker_target(maker)
maker.channel
end
@@ -359,25 +222,17 @@ module RSS
[
["resource", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
- def initialize(resource=nil)
- super()
- self.resource = resource
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _attrs
- [
- ["#{PREFIX}:resource", true, "resource"]
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.resource = args[0]
+ end
end
end
@@ -396,25 +251,17 @@ module RSS
[
["resource", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
- def initialize(resource=nil)
- super()
- self.resource = resource
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _attrs
- [
- ["#{PREFIX}:resource", true, "resource"]
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.resource = args[0]
+ end
end
end
@@ -432,22 +279,17 @@ module RSS
end
- install_have_child_element("Seq")
-
- install_must_call_validator('rdf', ::RSS::RDF::URI)
+ install_have_child_element("Seq", URI, nil)
+ install_must_call_validator('rdf', URI)
- def initialize(seq=Seq.new)
- super()
- @Seq = seq
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- Seq_element(need_convert, next_indent),
- other_element(need_convert, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.Seq = args[0]
end
+ self.Seq ||= Seq.new
end
def resources
@@ -459,21 +301,6 @@ module RSS
[]
end
end
-
- private
- def children
- [@Seq]
- end
-
- def _tags
- rv = []
- rv << [URI, 'Seq'] unless @Seq.nil?
- rv
- end
-
- def rdf_validate(tags)
- _validate(tags, [["Seq", nil]])
- end
end
end
@@ -488,60 +315,28 @@ module RSS
end
end
-
+
[
["about", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
%w(title url link).each do |name|
- install_text_element(name)
- end
-
- [
- ['title', nil],
- ['url', nil],
- ['link', nil],
- ].each do |tag, occurs|
- install_model(tag, occurs)
+ install_text_element(name, ::RSS::URI, nil)
end
- def initialize(about=nil)
- super()
- self.about = about
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- url_element(false, next_indent),
- link_element(false, next_indent),
- other_element(false, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
end
- rv = convert(rv) if need_convert
- rv
end
private
- def _tags
- [
- [::RSS::URI, 'title'],
- [::RSS::URI, 'url'],
- [::RSS::URI, 'link'],
- ].delete_if do |uri, name|
- __send__(name).nil?
- end
- end
-
- def _attrs
- [
- ["#{PREFIX}:about", true, "about"]
- ]
- end
-
def maker_target(maker)
maker.image
end
@@ -559,14 +354,12 @@ module RSS
end
+
[
["about", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
- end
-
- %w(title link description).each do |name|
- install_text_element(name)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
[
@@ -574,44 +367,19 @@ module RSS
["link", nil],
["description", "?"],
].each do |tag, occurs|
- install_model(tag, occurs)
+ install_text_element(tag, ::RSS::URI, occurs)
end
- def initialize(about=nil)
- super()
- self.about = about
- end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- link_element(false, next_indent),
- description_element(false, next_indent),
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _tags
- [
- [::RSS::URI, 'title'],
- [::RSS::URI, 'link'],
- [::RSS::URI, 'description'],
- ].delete_if do |uri, name|
- __send__(name).nil?
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
end
end
- def _attrs
- [
- ["#{PREFIX}:about", true, "about"]
- ]
- end
-
+ private
def maker_target(items)
if items.respond_to?("items")
# For backward compatibility
@@ -636,59 +404,24 @@ module RSS
[
["about", URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{PREFIX}:#{name}")
end
%w(title description name link).each do |name|
- install_text_element(name)
- end
-
- [
- ["title", nil],
- ["description", nil],
- ["name", nil],
- ["link", nil],
- ].each do |tag, occurs|
- install_model(tag, occurs)
- end
-
- def initialize(about=nil)
- super()
- self.about = about
+ install_text_element(name, ::RSS::URI, nil)
end
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- title_element(false, next_indent),
- description_element(false, next_indent),
- name_element(false, next_indent),
- link_element(false, next_indent),
- other_element(false, next_indent),
- ]
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
end
- rv = convert(rv) if need_convert
- rv
end
private
- def _tags
- [
- [::RSS::URI, 'title'],
- [::RSS::URI, 'description'],
- [::RSS::URI, 'name'],
- [::RSS::URI, 'link'],
- ].delete_if do |uri, name|
- __send__(name).nil?
- end
- end
-
- def _attrs
- [
- ["#{PREFIX}:about", true, "about"]
- ]
- end
-
def maker_target(maker)
maker.textinput
end
@@ -697,21 +430,22 @@ module RSS
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|
- @rss.validate_for_stream(tags) if @do_validate
- }
+ pr = Proc.new do |text, tags|
+ @rss.validate_for_stream(tags, @ignore_unknown_element) if @do_validate
+ end
+ @proc_stack.push(pr)
end
end
diff --git a/lib/rss/2.0.rb b/lib/rss/2.0.rb
index 1c3c22ee70..3798da4eb7 100644
--- a/lib/rss/2.0.rb
+++ b/lib/rss/2.0.rb
@@ -10,52 +10,20 @@ module RSS
["generator"],
["ttl", :integer],
].each do |name, type|
- install_text_element(name, type)
- install_model(name, '?')
+ install_text_element(name, "", "?", name, type)
end
[
%w(category categories),
].each do |name, plural_name|
- install_have_children_element(name, plural_name)
- install_model(name, '*')
+ install_have_children_element(name, "", "*", name, plural_name)
end
-
+
[
["image", "?"],
["language", "?"],
].each do |name, occurs|
- install_model(name, occurs)
- end
-
- def other_element(need_convert, indent)
- rv = <<-EOT
-#{category_elements(need_convert, indent)}
-#{generator_element(need_convert, indent)}
-#{ttl_element(need_convert, indent)}
-EOT
- rv << super
- end
-
- private
- alias children09 children
- def children
- children09 + @category.compact
- end
-
- alias _tags09 _tags
- def _tags
- rv = %w(generator ttl).delete_if do |name|
- __send__(name).nil?
- end.collect do |elem|
- [nil, elem]
- end + _tags09
-
- @category.each do
- rv << [nil, "category"]
- end
-
- rv
+ install_model(name, "", occurs)
end
Category = Item::Category
@@ -66,15 +34,13 @@ EOT
["comments", "?"],
["author", "?"],
].each do |name, occurs|
- install_text_element(name)
- install_model(name, occurs)
+ install_text_element(name, "", occurs)
end
[
["pubDate", '?'],
].each do |name, occurs|
- install_date_element(name, 'rfc822')
- install_model(name, occurs)
+ install_date_element(name, "", occurs, name, 'rfc822')
end
alias date pubDate
alias date= pubDate=
@@ -82,37 +48,10 @@ EOT
[
["guid", '?'],
].each do |name, occurs|
- install_have_child_element(name)
- install_model(name, occurs)
- end
-
- def other_element(need_convert, indent)
- rv = [
- super,
- *%w(author comments pubDate guid).collect do |name|
- __send__("#{name}_element", false, indent)
- end
- ].reject do |value|
- /\A\s*\z/.match(value)
- end
- rv.join("\n")
+ install_have_child_element(name, "", occurs)
end
private
- alias children09 children
- def children
- children09 + [@guid].compact
- end
-
- alias _tags09 _tags
- def _tags
- %w(comments author pubDate guid).delete_if do |name|
- __send__(name).nil?
- end.collect do |elem|
- [nil, elem]
- end + _tags09
- end
-
alias _setup_maker_element setup_maker_element
def setup_maker_element(item)
_setup_maker_element(item)
@@ -124,17 +63,21 @@ EOT
include RSS09
[
- ["isPermaLink", nil, false, :boolean]
+ ["isPermaLink", "", false, :boolean]
].each do |name, uri, required, type|
install_get_attribute(name, uri, required, type)
end
content_setup
- def initialize(isPermaLink=nil, content=nil)
- super()
- self.isPermaLink = isPermaLink
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.isPermaLink = args[0]
+ self.content = args[1]
+ end
end
alias_method :_PermaLink?, :PermaLink?
@@ -145,12 +88,6 @@ EOT
end
private
- def _attrs
- [
- ["isPermaLink", false]
- ]
- end
-
def maker_target(item)
item.guid
end
@@ -168,7 +105,7 @@ EOT
end
RSS09::ELEMENTS.each do |name|
- BaseListener.install_get_text_element(nil, name, "#{name}=")
+ BaseListener.install_get_text_element("", name, name)
end
end
diff --git a/lib/rss/atom.rb b/lib/rss/atom.rb
new file mode 100644
index 0000000000..901e69a4b0
--- /dev/null
+++ b/lib/rss/atom.rb
@@ -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)
+ 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
+
+ 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 have_author?
+ authors.any? {|author| !author.to_s.empty?} or
+ entries.any? {|entry| entry.__send!(:have_author?, false)}
+ 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)
+ generator = target.generator
+ generator.uri = uri if uri
+ generator.version = version if version
+ 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
+
+ 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 have_author?(check_parent=true)
+ authors.any? {|author| !author.to_s.empty?} or
+ (check_parent and @parent and @parent.__send!(:have_author?)) or
+ (source and source.__send!(: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
+
+ private
+ 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
+
+ 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 have_author?
+ authors.any? {|author| !author.to_s.empty?} or
+ (source and source.__send!(: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
diff --git a/lib/rss/content.rb b/lib/rss/content.rb
index a732cec973..bb61d9ebc5 100644
--- a/lib/rss/content.rb
+++ b/lib/rss/content.rb
@@ -15,28 +15,13 @@ module RSS
def self.append_features(klass)
super
-
- klass.module_eval(<<-EOC, *get_file_and_line_from_caller(1))
- %w(encoded).each do |name|
- install_text_element("\#{CONTENT_PREFIX}_\#{name}")
- end
- EOC
- end
-
- def content_validate(tags)
- counter = {}
- ELEMENTS.each do |name|
- counter[name] = 0
- end
- tags.each do |tag|
- key = "#{CONTENT_PREFIX}_#{tag}"
- raise UnknownTagError.new(tag, CONTENT_URI) unless counter.has_key?(key)
- counter[key] += 1
- raise TooMuchTagError.new(tag, tag_name) if counter[key] > 1
+ klass.install_must_call_validator(CONTENT_PREFIX, CONTENT_URI)
+ %w(encoded).each do |name|
+ klass.install_text_element(name, CONTENT_URI, "?",
+ "#{CONTENT_PREFIX}_#{name}")
end
end
-
end
class RDF
@@ -47,7 +32,7 @@ module RSS
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
diff --git a/lib/rss/converter.rb b/lib/rss/converter.rb
index 7ad79db318..415a319188 100644
--- a/lib/rss/converter.rb
+++ b/lib/rss/converter.rb
@@ -66,7 +66,7 @@ module RSS
end
end
- def def_uconv_convert_if_can(meth, to_enc, from_enc)
+ def def_uconv_convert_if_can(meth, to_enc, from_enc, nkf_arg)
begin
require "uconv"
def_convert(1) do |value|
@@ -79,24 +79,31 @@ module RSS
EOC
end
rescue LoadError
- def_iconv_convert(to_enc, from_enc, 1)
+ require 'nkf'
+ 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
def def_to_euc_jp_from_utf_8
- def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8')
+ def_uconv_convert_if_can('u8toeuc', 'EUC-JP', 'UTF-8', '-We')
end
def def_to_utf_8_from_euc_jp
- def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP')
+ def_uconv_convert_if_can('euctou8', 'UTF-8', 'EUC-JP', '-Ew')
end
def def_to_shift_jis_from_utf_8
- def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8')
+ def_uconv_convert_if_can('u8tosjis', 'Shift_JIS', 'UTF-8', '-Ws')
end
def def_to_utf_8_from_shift_jis
- def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS')
+ def_uconv_convert_if_can('sjistou8', 'UTF-8', 'Shift_JIS', '-Sw')
end
def def_to_euc_jp_from_shift_jis
diff --git a/lib/rss/dublincore.rb b/lib/rss/dublincore.rb
index 79d2ca561c..7ba239f8f1 100644
--- a/lib/rss/dublincore.rb
+++ b/lib/rss/dublincore.rb
@@ -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)
@@ -17,10 +14,10 @@ module RSS
full_name = "#{DC_PREFIX}_#{name}"
full_plural_name = "#{DC_PREFIX}_#{plural}"
klass_name = "DublinCore#{Utils.to_class_name(name)}"
+ klass.install_must_call_validator(DC_PREFIX, DC_URI)
+ klass.install_have_children_element(name, DC_URI, "*",
+ full_name, full_plural_name)
klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0))
- install_have_children_element(#{full_name.dump},
- #{full_plural_name.dump})
-
remove_method :#{full_name}
remove_method :#{full_name}=
remove_method :set_#{full_name}
@@ -36,8 +33,17 @@ module RSS
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
@@ -72,7 +78,7 @@ module RSS
}
ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a
- DublinCoreModel::DATE_ELEMENTS.each do |name, _|
+ DublinCoreModel::DATE_ELEMENTS.each do |name, |
ELEMENT_NAME_INFOS << [name, nil]
end
@@ -100,9 +106,13 @@ module RSS
alias_method(:value, :content)
alias_method(:value=, :content=)
- def initialize(content=nil)
- super()
- self.content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.content = args[0]
+ end
end
def full_name
@@ -121,39 +131,23 @@ module RSS
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
end
-
- def dc_validate(tags)
- tags.each do |tag|
- key = "#{DC_PREFIX}_#{tag}"
- unless DublinCoreModel::ELEMENTS.include?(key)
- raise UnknownTagError.new(tag, DC_URI)
- end
- end
- end
-
end
# 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}")
@@ -161,3 +155,7 @@ module RSS
DublinCoreModel::ELEMENTS.collect! {|name| "#{DC_PREFIX}_#{name}"}
end
+
+require 'rss/dublincore/1.0'
+require 'rss/dublincore/2.0'
+require 'rss/dublincore/atom'
diff --git a/lib/rss/dublincore/1.0.rb b/lib/rss/dublincore/1.0.rb
new file mode 100644
index 0000000000..e193c6d2c2
--- /dev/null
+++ b/lib/rss/dublincore/1.0.rb
@@ -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
diff --git a/lib/rss/dublincore/2.0.rb b/lib/rss/dublincore/2.0.rb
new file mode 100644
index 0000000000..82ed1888c5
--- /dev/null
+++ b/lib/rss/dublincore/2.0.rb
@@ -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
diff --git a/lib/rss/dublincore/atom.rb b/lib/rss/dublincore/atom.rb
new file mode 100644
index 0000000000..e78df4821b
--- /dev/null
+++ b/lib/rss/dublincore/atom.rb
@@ -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
diff --git a/lib/rss/image.rb b/lib/rss/image.rb
index 9d3326efca..44ee3dd41b 100644
--- a/lib/rss/image.rb
+++ b/lib/rss/image.rb
@@ -17,9 +17,11 @@ module RSS
end
module ImageModelUtils
- def validate_one_tag_name(name, tags)
- invalid = tags.find {|tag| tag != name}
- raise UnknownTagError.new(invalid, IMAGE_URI) if invalid
+ def validate_one_tag_name(ignore_unknown_element, name, tags)
+ if !ignore_unknown_element
+ invalid = tags.find {|tag| tag != name}
+ raise UnknownTagError.new(invalid, IMAGE_URI) if invalid
+ end
raise TooMuchTagError.new(name, tag_name) if tags.size > 1
end
end
@@ -31,13 +33,11 @@ module RSS
def self.append_features(klass)
super
- klass.install_have_child_element("#{IMAGE_PREFIX}_item")
+ klass.install_have_child_element("item", IMAGE_URI, "?",
+ "#{IMAGE_PREFIX}_item")
+ klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI)
end
- def image_validate(tags)
- validate_one_tag_name("item", tags)
- end
-
class ImageItem < Element
include RSS10
include DublinCoreModel
@@ -53,19 +53,23 @@ module RSS
IMAGE_URI
end
end
-
+
+ install_must_call_validator(IMAGE_PREFIX, IMAGE_URI)
+
[
["about", ::RSS::RDF::URI, true],
["resource", ::RSS::RDF::URI, false],
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{::RSS::RDF::PREFIX}:#{name}")
end
%w(width height).each do |tag|
full_name = "#{IMAGE_PREFIX}_#{tag}"
disp_name = "#{IMAGE_PREFIX}:#{tag}"
- install_text_element(full_name, :integer, disp_name)
- BaseListener.install_get_text_element(IMAGE_URI, tag, "#{full_name}=")
+ install_text_element(tag, IMAGE_URI, "?",
+ full_name, :integer, disp_name)
+ BaseListener.install_get_text_element(IMAGE_URI, tag, full_name)
end
alias width= image_width=
@@ -73,43 +77,21 @@ module RSS
alias height= image_height=
alias height image_height
- def initialize(about=nil, resource=nil)
- super()
- self.about = about
- self.resource = resource
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
+ self.resource = args[1]
+ end
end
def full_name
tag_name_with_prefix(IMAGE_PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
private
- def _tags
- [
- [IMAGE_URI, 'width'],
- [IMAGE_URI, 'height'],
- ].delete_if do |uri, name|
- __send__(name).nil?
- end
- end
-
- def _attrs
- [
- ["#{::RSS::RDF::PREFIX}:about", true, "about"],
- ["#{::RSS::RDF::PREFIX}:resource", false, "resource"],
- ]
- end
-
def maker_target(target)
target.image_item
end
@@ -129,14 +111,12 @@ module RSS
super
unless klass.class == Module
- klass.install_have_child_element("#{IMAGE_PREFIX}_favicon")
+ klass.install_have_child_element("favicon", IMAGE_URI, "?",
+ "#{IMAGE_PREFIX}_favicon")
+ klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI)
end
end
- def image_validate(tags)
- validate_one_tag_name("favicon", tags)
- end
-
class ImageFavicon < Element
include RSS10
include DublinCoreModel
@@ -152,12 +132,13 @@ module RSS
IMAGE_URI
end
end
-
+
[
- ["about", ::RSS::RDF::URI, true],
- ["size", IMAGE_URI, true],
- ].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ ["about", ::RSS::RDF::URI, true, ::RSS::RDF::PREFIX],
+ ["size", IMAGE_URI, true, IMAGE_PREFIX],
+ ].each do |name, uri, required, prefix|
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{prefix}:#{name}")
end
AVAILABLE_SIZES = %w(small medium large)
@@ -171,40 +152,27 @@ module RSS
raise NotAvailableValueError.new(full_name, new_value, attr_name)
end
end
- funcall(:_size=, new_value)
+ __send!(:_size=, new_value)
end
alias image_size= size=
alias image_size size
- def initialize(about=nil, size=nil)
- super()
- self.about = about
- self.size = size
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
+ self.size = args[1]
+ end
end
def full_name
tag_name_with_prefix(IMAGE_PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- other_element(false, next_indent),
- ]
- end
- rv = convert(rv) if need_convert
- rv
- end
private
- def _attrs
- [
- ["#{::RSS::RDF::PREFIX}:about", true, "about"],
- ["#{IMAGE_PREFIX}:size", true, "size"],
- ]
- end
-
def maker_target(target)
target.image_favicon
end
diff --git a/lib/rss/maker.rb b/lib/rss/maker.rb
index 9ed799ac7f..a47b55b670 100644
--- a/lib/rss/maker.rb
+++ b/lib/rss/maker.rb
@@ -1,14 +1,14 @@
require "rss/rss"
module RSS
-
module Maker
-
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,16 +19,21 @@ module RSS
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/syndication"
diff --git a/lib/rss/maker/0.9.rb b/lib/rss/maker/0.9.rb
index b82585fb96..dd75c9289b 100644
--- a/lib/rss/maker/0.9.rb
+++ b/lib/rss/maker/0.9.rb
@@ -7,13 +7,14 @@ module RSS
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)
@@ -22,40 +23,34 @@ module RSS
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 +58,409 @@ module RSS
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.have_required_values?
+ vars << "title" unless title.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.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
+ super and title.have_required_values?
+ end
+
+ private
+ def required_variable_names
+ %w(link)
+ end
+
+ def not_set_required_variables
+ vars = super
+ vars << "title" unless title.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
diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb
index 3e6542a007..12608ad94a 100644
--- a/lib/rss/maker/1.0.rb
+++ b/lib/rss/maker/1.0.rb
@@ -9,10 +9,11 @@ module RSS
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 @@ module RSS
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 @@ module 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 title link description)
+ %w(about link)
end
-
+
+ def not_set_required_variables
+ vars = super
+ vars << "description" unless description.have_required_values?
+ vars << "title" unless title.have_required_values?
+ vars
+ end
+
class SkipDays < SkipDaysBase
- def to_rss(*args)
+ def to_feed(*args)
end
class Day < DayBase
@@ -85,7 +97,7 @@ module RSS
end
class SkipHours < SkipHoursBase
- def to_rss(*args)
+ def to_feed(*args)
end
class Hour < HourBase
@@ -93,112 +105,330 @@ module RSS
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.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
diff --git a/lib/rss/maker/2.0.rb b/lib/rss/maker/2.0.rb
index a958661614..d93ba94d4a 100644
--- a/lib/rss/maker/2.0.rb
+++ b/lib/rss/maker/2.0.rb
@@ -7,16 +7,13 @@ module RSS
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)
end
@@ -32,47 +29,64 @@ module RSS
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
@@ -84,85 +98,123 @@ module RSS
end
private
+ def required_variable_names
+ %w(title description)
+ end
+
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
diff --git a/lib/rss/maker/atom.rb b/lib/rss/maker/atom.rb
new file mode 100644
index 0000000000..27d30c6d89
--- /dev/null
+++ b/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 uri= content=
+ end
+ set = setup_values(logo)
+ class << logo
+ undef 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/lib/rss/maker/base.rb b/lib/rss/maker/base.rb
index 6d7dd557bf..ad47ff29cc 100644
--- a/lib/rss/maker/base.rb
+++ b/lib/rss/maker/base.rb
@@ -4,9 +4,7 @@ require 'rss/rss'
module RSS
module Maker
-
module Base
-
def self.append_features(klass)
super
@@ -46,28 +44,60 @@ module RSS
NEED_INITIALIZE_VARIABLES
end
- def self.def_array_element(name)
+ def self.def_array_element(name, plural=nil, klass=nil)
include Enumerable
extend Forwardable
- def_delegators("@\#{name}", :<<, :[], :[]=, :first, :last)
- def_delegators("@\#{name}", :push, :pop, :shift, :unshift)
- def_delegators("@\#{name}", :each, :size)
-
- add_need_initialize_variable(name, "[]")
+ plural ||= "\#{name}s"
+ klass ||= "self.class::\#{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(<<-EOM, __FILE__, __LINE__ + 1)
+ def new_\#{name}
+ \#{name} = \#{klass}.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
+EOM
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 +105,32 @@ module RSS
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 +148,10 @@ module RSS
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 +160,6 @@ module RSS
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,7 +172,92 @@ module RSS
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
+ 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
+
+ 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(<<-EOC, __FILE__, __LINE__ + 1)
+ include EnsureXMLContent
+
+ %w(type content xml_content).each do |element|
+ attr element, element != "xml_content"
+ add_need_initialize_variable(element)
+ end
+
+ def xml_content=(content)
+ @xml_content = ensure_xml_content(content)
+ end
+
+ alias_method(:xhtml, :xml_content)
+ alias_method(:xhtml=, :xml_content=)
+EOC
+ 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::Date.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
@@ -143,8 +274,8 @@ module RSS
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}
@@ -153,12 +284,15 @@ module RSS
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 +301,19 @@ EOC
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,25 +324,12 @@ EOC
def make_xml_stylesheets
XMLStyleSheets.new(self)
end
-
end
class XMLStyleSheets
include Base
- def_array_element("xml_stylesheets")
-
- 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
- xss
- end
+ def_array_element("xml_stylesheet", nil, "XMLStyleSheet")
class XMLStyleSheet
include Base
@@ -218,19 +339,15 @@ EOC
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?
@@ -238,20 +355,27 @@ EOC
@type = xss.type
end
end
+
+ def required_variable_names
+ %w(href type)
+ end
end
end
class ChannelBase
include Base
+ include SetupDefaultDate
- %w(cloud categories skipDays skipHours).each do |element|
+ %w(cloud categories skipDays skipHours links authors
+ contributors generator copyright description
+ title).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)
+ def setup_#{element}(feed, current)
+ @#{element}.to_feed(feed, current)
end
def make_#{element}
@@ -260,34 +384,102 @@ EOC
EOC
end
- %w(about title link description language copyright
+ %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 pubDate=(date)
+ self.date = date
+ end
+
+ def updated
+ date
+ end
+
+ def updated=(date)
+ self.date = date
+ end
+
+ def link
+ _link = links.first
+ _link ? _link.href : nil
+ end
+
+ def link=(href)
+ _link = links.first || links.new_link
+ _link.rel = "self"
+ _link.href = href
+ end
+
+ def author
+ _author = authors.first
+ _author ? _author.name : nil
+ end
+
+ def author=(name)
+ _author = authors.first || authors.new_author
+ _author.name = name
+ end
+
+ def contributor
+ _contributor = contributors.first
+ _contributor ? _contributor.name : nil
+ end
+
+ def contributor=(name)
+ _contributor = contributors.first || contributors.new_contributor
+ _contributor.name = name
+ end
+
+ def generator=(content)
+ @generator.content = content
+ end
+
+ def copyright=(content)
+ @copyright.content = content
+ end
+
+ alias_method(:rights, :copyright)
+ alias_method(:rights=, :copyright=)
+
+ def description=(content)
+ @description.content = content
+ end
+
+ alias_method(:subtitle, :description)
+ alias_method(:subtitle=, :description=)
+
+ def title=(content)
+ @title.content = content
+ end
- def current_element(rss)
- rss.channel
+ 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
include Base
- def_array_element("days")
-
- def new_day
- day = self.class::Day.new(@maker)
- @days << day
- day
- end
-
- def current_element(rss)
- rss.channel.skipDays
- end
+ def_array_element("day")
class DayBase
include Base
@@ -296,28 +488,13 @@ EOC
attr_accessor element
add_need_initialize_variable(element)
end
-
- def current_element(rss)
- rss.channel.skipDays.last
- end
-
end
end
class SkipHoursBase
include Base
- def_array_element("hours")
-
- def new_hour
- hour = self.class::Hour.new(@maker)
- @hours << hour
- hour
- end
-
- def current_element(rss)
- rss.channel.skipHours
- end
+ def_array_element("hour")
class HourBase
include Base
@@ -326,11 +503,6 @@ EOC
attr_accessor element
add_need_initialize_variable(element)
end
-
- def current_element(rss)
- rss.channel.skipHours.last
- end
-
end
end
@@ -341,33 +513,88 @@ EOC
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")
- def new_category
- category = self.class::Category.new(@maker)
- @categories << category
- category
- end
+ def_array_element("category", "categories")
class CategoryBase
include Base
- %w(domain content).each do |element|
+ %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
+ include Base
+
+ def_array_element("link")
+
+ class LinkBase
+ include Base
+
+ %w(href rel type hreflang title length).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+ end
+
+ class AuthorsBase
+ include Base
+
+ def_array_element("author")
+
+ class AuthorBase
+ include Base
+ include AtomPersonConstructBase
+ end
+ end
+
+ class ContributorsBase
+ include Base
+
+ def_array_element("contributor")
+
+ class ContributorBase
+ include Base
+ include AtomPersonConstructBase
+ end
+ end
+
+ class GeneratorBase
+ include Base
+
+ %w(uri version content).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ class CopyrightBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class DescriptionBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class TitleBase
+ include Base
+ include AtomTextConstructBase
+ end
end
class ImageBase
@@ -377,21 +604,17 @@ EOC
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
- def_array_element("items")
-
+ def_array_element("item")
+
attr_accessor :do_sort, :max_size
def initialize(maker)
@@ -407,17 +630,7 @@ EOC
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
- item
- end
-
private
def sort_if_need
if @do_sort.respond_to?(:call)
@@ -435,15 +648,17 @@ EOC
class ItemBase
include Base
-
- %w(guid enclosure source categories).each do |element|
+ include SetupDefaultDate
+
+ %w(guid enclosure source categories authors links
+ contributors rights description content title).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)
+ def setup_#{element}(feed, current)
+ @#{element}.to_feed(feed, current)
end
def make_#{element}
@@ -451,30 +666,77 @@ EOC
end
EOC
end
-
- %w(title link description date author comments).each do |element|
+
+ %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
+
+ def author
+ _link = authors.first
+ _link ? _author.name : nil
+ end
+
+ def author=(name)
+ _author = authors.first || authors.new_author
+ _author.name = name
+ end
+
+ def link
+ _link = links.first
+ _link ? _link.href : nil
+ end
+
+ def link=(href)
+ _link = links.first || links.new_link
+ _link.rel = "alternate"
+ _link.href = href
+ end
+
+ def rights=(content)
+ @rights.content = content
+ end
+
+ def description=(content)
+ @description.content = content
+ end
+
+ alias_method(:summary, :description)
+ alias_method(:summary=, :description=)
+
+ def title=(content)
+ @title.content = content
+ end
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
@@ -484,7 +746,7 @@ EOC
add_need_initialize_variable(element)
end
end
-
+
class EnclosureBase
include Base
@@ -493,18 +755,168 @@ EOC
add_need_initialize_variable(element)
end
end
-
+
class SourceBase
include Base
- %w(url content).each do |element|
+ %w(authors categories contributors generator icon
+ links logo rights subtitle title).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}(feed, current)
+ @#{element}.to_feed(feed, current)
+ end
+
+ def make_#{element}
+ self.class::#{Utils.to_class_name(element)}.new(@maker)
+ end
+ EOC
+ end
+
+ %w(id content date).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
+
+ def url
+ link = links.first
+ link ? link.href : nil
+ end
+
+ def url=(value)
+ link = links.first || links.new_link
+ link.href = value
+ end
+
+ 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
+ include Base
+
+ %w(url).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ LinksBase = ChannelBase::LinksBase
+
+ class LogoBase
+ include Base
+
+ %w(uri).each do |element|
+ attr_accessor element
+ add_need_initialize_variable(element)
+ end
+ end
+
+ class RightsBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class SubtitleBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class TitleBase
+ include Base
+ include AtomTextConstructBase
+ end
end
-
+
CategoriesBase = ChannelBase::CategoriesBase
-
+ AuthorsBase = ChannelBase::AuthorsBase
+ LinksBase = ChannelBase::LinksBase
+ ContributorsBase = ChannelBase::ContributorsBase
+
+ class RightsBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class DescriptionBase
+ include Base
+ include AtomTextConstructBase
+ end
+
+ class ContentBase
+ include Base
+ include AtomTextConstructBase::EnsureXMLContent
+
+ %w(type src content xml_content).each do |element|
+ attr element, element != "xml_content"
+ add_need_initialize_variable(element)
+ end
+
+ def xml_content=(content)
+ content = ensure_xml_content(content) if inline_xhtml?
+ @xml_content = content
+ end
+
+ alias_method(:xhtml, :xml_content)
+ alias_method(:xhtml=, :xml_content=)
+
+ alias_method(:xml, :xml_content)
+ alias_method(:xml=, :xml_content=)
+
+ private
+ 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
+ include Base
+ include AtomTextConstructBase
+ end
end
end
@@ -515,12 +927,6 @@ EOC
attr_accessor element
add_need_initialize_variable(element)
end
-
- def current_element(rss)
- rss.textinput
- end
-
end
-
end
end
diff --git a/lib/rss/maker/dublincore.rb b/lib/rss/maker/dublincore.rb
index b208d5fcb2..088ae60942 100644
--- a/lib/rss/maker/dublincore.rb
+++ b/lib/rss/maker/dublincore.rb
@@ -24,8 +24,8 @@ module RSS
#{full_plural_klass_name}.new(@maker)
end
- def setup_#{full_plural_name}(rss, current)
- @#{full_plural_name}.to_rss(rss, current)
+ def setup_#{full_plural_name}(feed, current)
+ @#{full_plural_name}.to_feed(feed, current)
end
def #{full_name}
@@ -36,6 +36,17 @@ module RSS
@#{full_plural_name}[0] = #{full_klass_name}.new(self)
@#{full_plural_name}[0].value = new_value
end
+
+ def new_#{full_name}(value=nil)
+ #{full_name} = #{full_klass_name}.new(self)
+ #{full_name}.value = value
+ @#{full_plural_name} << #{full_name}
+ if block_given?
+ yield #{full_name}
+ else
+ #{full_name}
+ end
+ end
EOC
end
@@ -48,25 +59,14 @@ EOC
::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)}"
module_eval(<<-EOC, __FILE__, __LINE__)
class #{plural_klass_name}Base
include Base
- def_array_element(#{plural_name.dump})
-
- def new_#{name}
- #{name} = self.class::#{klass_name}.new(self)
- @#{plural_name} << #{name}
- #{name}
- end
+ def_array_element(#{name.dump}, #{plural_name.dump})
- def to_rss(rss, current)
- @#{plural_name}.each do |#{name}|
- #{name}.to_rss(rss, current)
- end
- end
-
class #{klass_name}Base
include Base
@@ -78,6 +78,13 @@ EOC
def have_required_values?
@value
end
+
+ def to_feed(feed, 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
end
end
EOC
@@ -88,16 +95,9 @@ EOC
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))
+ 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
end
end
EOC
@@ -107,64 +107,36 @@ EOC
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
-
- class Image
- DublinCoreModel.install_dublin_core(self)
- end
-
- class Items
- class Item
+ makers.each do |maker|
+ maker.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ class Channel
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 Image
+ 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 Items
- class Item
+ class Textinput
DublinCoreModel.install_dublin_core(self)
end
- end
-
- class Textinput
- DublinCoreModel.install_dublin_core(self)
- end
+ EOC
end
end
end
diff --git a/lib/rss/maker/entry.rb b/lib/rss/maker/entry.rb
new file mode 100644
index 0000000000..baa22c5bf1
--- /dev/null
+++ b/lib/rss/maker/entry.rb
@@ -0,0 +1,167 @@
+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
+
+ def have_required_values?
+ set_default_values do
+ super and title.have_required_values?
+ 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.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?
+ @rights = @maker.channel.rights
+ end
+ @title = @maker.channel.title unless keep[:title].variable_is_set?
+ 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
diff --git a/lib/rss/maker/feed.rb b/lib/rss/maker/feed.rb
new file mode 100644
index 0000000000..ac26788102
--- /dev/null
+++ b/lib/rss/maker/feed.rb
@@ -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.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 url= content=
+ end
+ set = setup_values(logo)
+ class << logo
+ undef 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.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.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 url= content=
+ end
+ set = setup_values(icon)
+ class << icon
+ undef 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
diff --git a/lib/rss/maker/image.rb b/lib/rss/maker/image.rb
index ed51c8ecba..e3469d0597 100644
--- a/lib/rss/maker/image.rb
+++ b/lib/rss/maker/image.rb
@@ -11,11 +11,11 @@ module RSS
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)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
attr_reader :#{name}
- def setup_#{name}(rss, current)
+ def setup_#{name}(feed, current)
if @#{name}
- @#{name}.to_rss(rss, current)
+ @#{name}.to_feed(feed, current)
end
end
@@ -25,6 +25,14 @@ module RSS
EOC
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
include Base
include Maker::DublinCoreModel
@@ -42,6 +50,15 @@ EOC
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
@@ -54,9 +71,9 @@ EOC
klass.add_other_element(name)
klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
attr_reader :#{name}
- def setup_#{name}(rss, current)
+ def setup_#{name}(feed, current)
if @#{name}
- @#{name}.to_rss(rss, current)
+ @#{name}.to_feed(feed, current)
end
end
@@ -66,6 +83,14 @@ EOC
EOC
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
include Base
include Maker::DublinCoreModel
@@ -79,6 +104,15 @@ EOC
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 +122,18 @@ EOC
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
diff --git a/lib/rss/maker/taxonomy.rb b/lib/rss/maker/taxonomy.rb
index 2e54ea66eb..2e53a4e1f4 100644
--- a/lib/rss/maker/taxonomy.rb
+++ b/lib/rss/maker/taxonomy.rb
@@ -15,17 +15,17 @@ module RSS
def make_taxo_topics
self.class::TaxonomyTopics.new(@maker)
end
-
- def setup_taxo_topics(rss, current)
- @taxo_topics.to_rss(rss, current)
+
+ def setup_taxo_topics(feed, current)
+ @taxo_topics.to_feed(feed, current)
end
EOC
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
@@ -43,7 +43,8 @@ EOC
include Base
attr_reader :resources
- def_array_element("resources")
+ def_array_element("resource")
+ remove_method :new_resource
end
end
@@ -59,8 +60,8 @@ EOC
self.class::TaxonomyTopics.new(@maker)
end
- def setup_taxo_topics(rss, current)
- @taxo_topics.to_rss(rss, current)
+ def setup_taxo_topics(feed, current)
+ @taxo_topics.to_feed(feed, current)
end
def taxo_topic
@@ -75,25 +76,21 @@ EOC
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
@@ -102,20 +99,8 @@ EOC
class TaxonomyTopicsBase
include Base
- def_array_element("taxo_topics")
-
- def new_taxo_topic
- taxo_topic = self.class::TaxonomyTopic.new(self)
- @taxo_topics << taxo_topic
- taxo_topic
- end
+ def_array_element("taxo_topic", nil, "self.class::TaxonomyTopic")
- def to_rss(rss, current)
- @taxo_topics.each do |taxo_topic|
- taxo_topic.to_rss(rss, current)
- end
- end
-
class TaxonomyTopicBase
include Base
include DublinCoreModel
@@ -147,32 +132,20 @@ EOC
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
diff --git a/lib/rss/maker/trackback.rb b/lib/rss/maker/trackback.rb
index 32254a040c..09a2fceb2d 100644
--- a/lib/rss/maker/trackback.rb
+++ b/lib/rss/maker/trackback.rb
@@ -11,9 +11,9 @@ module RSS
name = "#{RSS::TRACKBACK_PREFIX}_ping"
klass.add_need_initialize_variable(name)
klass.add_other_element(name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
attr_accessor :#{name}
- def setup_#{name}(rss, current)
+ def setup_#{name}(feed, current)
if #{name} and current.respond_to?(:#{name}=)
current.#{name} = #{name}
end
@@ -23,14 +23,14 @@ module RSS
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)
+ 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)
+ def setup_#{name}(feed, current)
+ @#{name}.to_feed(feed, current)
end
EOC
end
@@ -38,20 +38,8 @@ module RSS
class TrackBackAboutsBase
include Base
- def_array_element("abouts")
-
- def new_about
- about = self.class::TrackBackAbout.new(@maker)
- @abouts << about
- about
- end
+ def_array_element("about", nil, "self.class::TrackBackAbout")
- def to_rss(rss, current)
- @abouts.each do |about|
- about.to_rss(rss, current)
- end
- end
-
class TrackBackAboutBase
include Base
@@ -62,65 +50,38 @@ module RSS
alias_method(:resource=, :value=)
alias_method(:content, :value)
alias_method(:content=, :value=)
-
+
def have_required_values?
@value
end
-
- end
- end
- end
-
- class ItemsBase
- 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
- 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 RSS09
- class Items
- class Item
- class TrackBackAbouts < TrackBackAboutsBase
- def to_rss(*args)
- end
- class TrackBackAbout < TrackBackAboutBase
- end
- end
- end
- end
+ class ItemsBase
+ class ItemBase; include TrackBackModel; 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
+
+ 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
-
end
end
diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb
index babf15f52c..f5ea2bbc03 100644
--- a/lib/rss/parser.rb
+++ b/lib/rss/parser.rb
@@ -2,6 +2,7 @@ require "forwardable"
require "open-uri"
require "rss/rss"
+require "rss/xml"
module RSS
@@ -63,7 +64,8 @@ module RSS
end
end
- def parse(rss, do_validate=true, ignore_unknown_element=true, parser_class=default_parser)
+ def parse(rss, do_validate=true, ignore_unknown_element=true,
+ parser_class=default_parser)
parser = new(rss, parser_class)
parser.do_validate = do_validate
parser.ignore_unknown_element = ignore_unknown_element
@@ -103,7 +105,7 @@ module RSS
return rss if rss.is_a?(::URI::Generic)
begin
- URI(rss)
+ ::URI.parse(rss)
rescue ::URI::Error
rss
end
@@ -158,26 +160,26 @@ module RSS
class << self
- @@setters = {}
+ @@accessor_bases = {}
@@registered_uris = {}
@@class_names = {}
- def install_setter(uri, tag_name, setter)
- @@setters[uri] ||= {}
- @@setters[uri][tag_name] = setter
- end
-
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
+
def available_tags(uri)
begin
- @@setters[uri].keys
+ @@accessor_bases[uri].keys
rescue NameError
[]
end
@@ -205,8 +207,8 @@ module RSS
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
@@ -215,20 +217,18 @@ module RSS
end
private
+ 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}".to_sym)
module_eval(<<-EOT, file, line)
def start_#{name}(name, prefix, attrs, ns)
- uri = ns[prefix]
+ uri = _ns(ns, prefix)
if self.class.uri_registered?(uri, #{name.inspect})
- if @do_validate
- tags = self.class.available_tags(uri)
- unless tags.include?(name)
- raise UnknownTagError.new(name, uri)
- end
- end
start_get_text_element(name, prefix, ns, uri)
else
start_else_element(name, prefix, attrs, ns)
@@ -244,7 +244,6 @@ module RSS
end
module ListenerMixin
-
attr_reader :rss
attr_accessor :ignore_unknown_element
@@ -254,13 +253,16 @@ module RSS
@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
def xmldecl(version, encoding, standalone)
@@ -271,7 +273,7 @@ module RSS
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
@@ -291,12 +293,41 @@ module RSS
@ns_stack.push(ns)
prefix, local = split_name(name)
- @tag_stack.last.push([ns[prefix], local])
+ @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
@@ -313,10 +344,17 @@ module RSS
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
+ def _ns(ns, prefix)
+ ns.fetch(prefix, "")
+ end
CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/
def parse_pi_content(content)
@@ -328,20 +366,20 @@ module RSS
end
def start_else_element(local, prefix, attrs, ns)
- class_name = self.class.class_name(ns[prefix], local)
+ class_name = self.class.class_name(_ns(ns, prefix), local)
current_class = @last_element.class
if current_class.const_defined?(class_name)
next_class = current_class.const_get(class_name)
start_have_something_element(local, prefix, attrs, ns, next_class)
else
- if @ignore_unknown_element
+ if !@do_validate or @ignore_unknown_element
@proc_stack.push(nil)
else
parent = "ROOT ELEMENT???"
if current_class.tag_name
parent = current_class.tag_name
end
- raise NotExceptedTagError.new(local, parent)
+ raise NotExpectedTagError.new(local, _ns(ns, prefix), parent)
end
end
end
@@ -353,41 +391,48 @@ module RSS
end
def check_ns(tag_name, prefix, ns, require_uri)
- if @do_validate
- if ns[prefix] == require_uri
- #ns.delete(prefix)
- else
+ unless _ns(ns, prefix) == require_uri
+ if @do_validate
raise NSError.new(tag_name, prefix, require_uri)
+ else
+ # 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)
- setter ||= "#{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 not @ignore_unknown_element
- raise NotExceptedTagError.new(tag_name, @last_element.tag_name)
+ if @do_validate and !@ignore_unknown_element
+ raise NotExpectedTagError.new(tag_name, _ns(ns, prefix),
+ @last_element.tag_name)
end
end
- }
+ end
+ @proc_stack.push(pr)
end
def start_have_something_element(tag_name, prefix, attrs, ns, klass)
check_ns(tag_name, prefix, ns, klass.required_uri)
- args = []
-
- klass.get_attributes.each do |a_name, a_uri, required|
+ attributes = {}
+ klass.get_attributes.each do |a_name, a_uri, required, element_name|
if a_uri.is_a?(String) or !a_uri.respond_to?(:include?)
a_uri = [a_uri]
end
- unless a_uri == [nil]
+ unless a_uri == [""]
for prefix, uri in ns
if a_uri.include?(uri)
val = attrs["#{prefix}:#{a_name}"]
@@ -395,12 +440,12 @@ module RSS
end
end
end
- if val.nil? and a_uri.include?(nil)
+ if val.nil? and a_uri.include?("")
val = attrs[a_name]
end
if @do_validate and required and val.nil?
- unless a_uri.include?(nil)
+ unless a_uri.include?("")
for prefix, uri in ns
if a_uri.include?(uri)
a_name = "#{prefix}:#{a_name}"
@@ -410,20 +455,37 @@ module RSS
raise MissingAttributeError.new(tag_name, a_name)
end
- args << val
+ attributes[a_name] = val
end
previous = @last_element
- next_element = klass.new(*args)
- next_element.do_validate = @do_validate
- previous.funcall(:set_next_element, tag_name, next_element)
+ next_element = klass.new(@do_validate, attributes)
+ previous.__send!(: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?
- @last_element.validate_for_stream(tags) if @do_validate
+ 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
diff --git a/lib/rss/rss.rb b/lib/rss/rss.rb
index 52ca4db890..c0ce96d6bf 100644
--- a/lib/rss/rss.rb
+++ b/lib/rss/rss.rb
@@ -11,11 +11,19 @@ class Time
(\.\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
@@ -26,7 +34,14 @@ class Time
end
unless method_defined?(:w3cdtf)
- alias w3cdtf iso8601
+ 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
@@ -38,7 +53,7 @@ require "rss/xml-stylesheet"
module RSS
- VERSION = "0.1.6"
+ VERSION = "0.1.7"
URI = "http://purl.org/rss/1.0/"
@@ -87,13 +102,15 @@ module RSS
end
end
- class NotExceptedTagError < InvalidRSSError
- attr_reader :tag, :parent
- def initialize(tag, parent)
- @tag, @parent = tag, parent
- super("tag <#{tag}> is not expected in tag <#{parent}>")
+ class NotExpectedTagError < InvalidRSSError
+ attr_reader :tag, :uri, :parent
+ def initialize(tag, uri, parent)
+ @tag, @uri, @parent = tag, uri, parent
+ super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>")
end
end
+ # For backward compatibility :X
+ NotExceptedTagError = NotExpectedTagError
class NotAvailableValueError < InvalidRSSError
attr_reader :tag, :value, :attribute
@@ -135,15 +152,27 @@ module RSS
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(name)
+ 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}
@@ -156,11 +185,13 @@ EOC
end
alias_method(:install_have_attribute_element, :install_have_child_element)
- def install_have_children_element(name, plural_name=nil)
+ def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil)
+ name ||= tag_name
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)
+
def_children_accessor(name, plural_name)
install_element(name, "s") do |n, elem_name|
<<-EOC
@@ -174,9 +205,12 @@ EOC
end
end
- def install_text_element(name, type=nil, disp_name=name)
+ 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
@@ -199,9 +233,13 @@ EOC
end
end
- def install_date_element(name, type, disp_name=name)
+ def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
+ name ||= tag_name
+ type ||= :w3cdtf
+ disp_name ||= name
self::ELEMENTS << name
add_need_initialize_variable(name)
+ install_model(tag_name, uri, occurs, name)
# accessor
convert_attr_reader name
@@ -230,34 +268,76 @@ EOC
private
def install_element(name, postfix="")
elem_name = name.sub('_', ':')
+ method_name = "#{name}_element#{postfix}"
+ add_to_element_method(method_name)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
- def #{name}_element#{postfix}(need_convert=true, indent='')
+ def #{method_name}(need_convert=true, indent='')
#{yield(name, elem_name)}
end
- private :#{name}_element#{postfix}
+ private :#{method_name}
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 @#{attr}
+ #{attr}_without_inherit
+ elsif @parent
+ @parent.#{attr}
+ else
+ 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}
- if @converter
- @converter.convert(@#{attr})
+ value = #{attr}_without_base
+ return nil if value.nil?
+ if /\\A[a-z][a-z0-9+.\\-]*:/i =~ value
+ value
else
- @#{attr}
+ "\#{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 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
@@ -269,7 +349,9 @@ EOC
@#{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
@@ -350,6 +432,32 @@ EOC
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 def_children_accessor(accessor_name, plural_name)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{plural_name}
@@ -365,10 +473,12 @@ EOC
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
@@ -378,36 +488,70 @@ EOC
alias_method(:set_#{accessor_name}, :#{accessor_name}=)
EOC
end
+ end
- def def_content_only_to_s
- module_eval(<<-EOC, *get_file_and_line_from_caller(2))
- def to_s(need_convert=true, indent=calc_indent)
- if @content
- rv = tag(indent) do |next_indent|
- h(@content)
- end
- rv = convert(rv) if need_convert
- rv
+ 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)
+ 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
-EOC
end
-
end
class Element
extend BaseModel
include Utils
+ include SetupMaker
INDENT = " "
MUST_CALL_VALIDATORS = {}
- MODEL = []
+ MODELS = []
GET_ATTRIBUTES = []
HAVE_CHILDREN_ELEMENTS = []
+ TO_ELEMENT_METHODS = []
NEED_INITIALIZE_VARIABLES = []
PLURAL_FORMS = {}
@@ -416,8 +560,8 @@ EOC
def must_call_validators
MUST_CALL_VALIDATORS
end
- def model
- MODEL
+ def models
+ MODELS
end
def get_attributes
GET_ATTRIBUTES
@@ -425,6 +569,9 @@ EOC
def have_children_elements
HAVE_CHILDREN_ELEMENTS
end
+ def to_element_methods
+ TO_ELEMENT_METHODS
+ end
def need_initialize_variables
NEED_INITIALIZE_VARIABLES
end
@@ -435,9 +582,10 @@ EOC
def inherited(klass)
klass.const_set("MUST_CALL_VALIDATORS", {})
- klass.const_set("MODEL", [])
+ klass.const_set("MODELS", [])
klass.const_set("GET_ATTRIBUTES", [])
klass.const_set("HAVE_CHILDREN_ELEMENTS", [])
+ klass.const_set("TO_ELEMENT_METHODS", [])
klass.const_set("NEED_INITIALIZE_VARIABLES", [])
klass.const_set("PLURAL_FORMS", {})
@@ -446,14 +594,13 @@ EOC
@tag_name = name.split(/::/).last
@tag_name[0,1] = @tag_name[0,1].downcase
- @indent_size = name.split(/::/).size - 2
@have_content = false
def self.must_call_validators
super.merge(MUST_CALL_VALIDATORS)
end
- def self.model
- MODEL + super
+ def self.models
+ MODELS + super
end
def self.get_attributes
GET_ATTRIBUTES + super
@@ -461,6 +608,9 @@ EOC
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
@@ -473,25 +623,32 @@ EOC
MUST_CALL_VALIDATORS[uri] = prefix
end
- def self.install_model(tag, occurs=nil)
- if m = MODEL.find {|t, o| t == tag}
- m[1] = occurs
+ 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
- MODEL << [tag, occurs]
+ MODELS << [tag, uri, occurs, getter]
end
end
def self.install_get_attribute(name, uri, required=true,
- type=nil, disp_name=name)
- def_corresponded_attr_writer name, type, disp_name
- convert_attr_reader name
+ 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
- GET_ATTRIBUTES << [name, uri, required]
+ GET_ATTRIBUTES << [name, uri, required, element_name]
+ add_need_initialize_variable(disp_name)
end
- def self.def_corresponded_attr_writer(name, type=nil, disp_name=name)
+ def self.def_corresponded_attr_writer(name, type=nil, disp_name=nil)
+ disp_name ||= name
case type
when :integer
integer_writer name, disp_name
@@ -499,15 +656,32 @@ EOC
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
else
attr_writer name
end
end
- def self.content_setup(type=nil)
- def_corresponded_attr_writer "content", type
- convert_attr_reader :content
- def_content_only_to_s
+ def self.def_corresponded_attr_reader(name, type=nil)
+ case type
+ when :inherit
+ inherit_convert_attr_reader name
+ when :uri
+ uri_convert_attr_reader name
+ else
+ convert_attr_reader name
+ end
+ end
+
+ def self.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
@@ -519,6 +693,10 @@ EOC
HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
end
+ def self.add_to_element_method(method_name)
+ TO_ELEMENT_METHODS << method_name
+ end
+
def self.add_need_initialize_variable(variable_name)
NEED_INITIALIZE_VARIABLES << variable_name
end
@@ -535,7 +713,11 @@ EOC
end
def required_uri
- nil
+ ""
+ end
+
+ def need_parent?
+ false
end
def install_ns(prefix, uri)
@@ -548,19 +730,18 @@ EOC
def tag_name
@tag_name
end
-
- def indent_size
- @indent_size
- end
-
end
- attr_accessor :do_validate
+ attr_accessor :parent, :do_validate
- def initialize(do_validate=true)
+ 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
+ initialize_variables(attrs || {})
end
def tag_name
@@ -571,10 +752,6 @@ EOC
tag_name
end
- def indent_size
- self.class.indent_size
- end
-
def converter=(converter)
@converter = converter
targets = children.dup
@@ -593,33 +770,73 @@ EOC
value
end
end
-
- def validate
+
+ 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
+ __validate(ignore_unknown_element)
+ ensure
+ @do_validate = do_validate
end
- def validate_for_stream(tags)
+ def validate_for_stream(tags, ignore_unknown_element=true)
validate_attribute
- __validate(tags, false)
+ __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)
+ def to_s(need_convert=true, indent='')
+ if self.class.have_content?
+ return "" if !empty_content? and !content_is_set?
+ rv = tag(indent) do |next_indent|
+ if empty_content?
+ ""
+ else
+ xmled_content
+ end
+ end
+ else
+ rv = tag(indent) do |next_indent|
+ self.class.to_element_methods.collect do |method_name|
+ __send__(method_name, false, next_indent)
+ end
+ end
end
+ rv = convert(rv) if need_convert
+ rv
end
-
+
+ def have_xml_content?
+ false
+ end
+
+ def need_base64_encode?
+ false
+ end
+
private
- def initialize_variables
+ def initialize_variables(attrs)
+ normalized_attrs = {}
+ attrs.each do |key, value|
+ normalized_attrs[key.to_s] = value
+ end
self.class.need_initialize_variables.each do |variable_name|
- instance_eval("@#{variable_name} = nil")
+ value = normalized_attrs[variable_name.to_s]
+ if value
+ __send__("#{variable_name}=", value)
+ else
+ instance_eval("@#{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
@@ -628,14 +845,16 @@ EOC
end
end
- def tag(indent, additional_attrs=[], &block)
+ def tag(indent, additional_attrs={}, &block)
next_indent = indent + INDENT
attrs = collect_attrs
return "" if attrs.nil?
- attrs += additional_attrs
- start_tag = make_start_tag(indent, next_indent, attrs)
+ return "" unless have_required_elements?
+
+ attrs.update(additional_attrs)
+ start_tag = make_start_tag(indent, next_indent, attrs.dup)
if block
content = block.call(next_indent)
@@ -650,6 +869,7 @@ EOC
else
content = content.reject{|x| x.empty?}
if content.empty?
+ return "" if attrs.empty?
end_tag = "/>"
else
start_tag << ">\n"
@@ -671,58 +891,24 @@ EOC
end
def collect_attrs
- _attrs.collect do |name, required, alias_name|
+ attrs = {}
+ _attrs.each do |name, required, alias_name|
value = __send__(alias_name || name)
return nil if required and value.nil?
- [name, value]
- end.reject do |name, value|
- value.nil?
+ next if value.nil?
+ return nil if attrs.has_key?(name)
+ attrs[name] = value
end
+ attrs
end
def tag_name_with_prefix(prefix)
"#{prefix}:#{tag_name}"
end
-
- def calc_indent
- INDENT * (self.class.indent_size)
- end
- def maker_target(maker)
- nil
- end
-
- def setup_maker_attributes(target)
- end
-
- def setup_maker_element(target)
- self.class.need_initialize_variables.each do |var|
- 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
+ # For backward compatibility
+ def calc_indent
+ ''
end
def set_next_element(tag_name, next_element)
@@ -737,22 +923,41 @@ EOC
__send__("#{prefix}#{tag_name}=", next_element)
end
end
-
- # not String class children.
+
def children
- []
+ rv = []
+ self.class.models.each do |name, uri, occurs, getter|
+ value = __send__(getter)
+ next if value.nil?
+ value = [value] unless value.is_a?(Array)
+ value.each do |v|
+ rv << v if v.is_a?(Element)
+ end
+ end
+ rv
end
- # default #validate() argument.
def _tags
- []
+ rv = []
+ self.class.models.each do |name, uri, occurs, getter|
+ value = __send__(getter)
+ next if value.nil?
+ if value.is_a?(Array)
+ rv.concat([[uri, name]] * value.size)
+ else
+ rv << [uri, name]
+ end
+ end
+ rv
end
def _attrs
- []
+ self.class.get_attributes.collect do |name, uri, required, element_name|
+ [element_name, required, name]
+ end
end
- def __validate(tags=_tags, recursive=true)
+ def __validate(ignore_unknown_element, tags=_tags, recursive=true)
if recursive
children.compact.each do |child|
child.validate
@@ -761,54 +966,44 @@ EOC
must_call_validators = self.class.must_call_validators
tags = tag_filter(tags.dup)
p tags if DEBUG
- self.class::NSPOOL.each do |prefix, uri|
- if tags.has_key?(uri) and !must_call_validators.has_key?(uri)
- meth = "#{prefix}_validate"
- __send__(meth, tags[uri]) if respond_to?(meth, true)
- end
- end
must_call_validators.each do |uri, prefix|
- __send__("#{prefix}_validate", tags[uri])
+ _validate(ignore_unknown_element, tags[uri], uri)
+ meth = "#{prefix}_validate"
+ if !prefix.empty? and respond_to?(meth, true)
+ __send__(meth, ignore_unknown_element, tags[uri], uri)
+ end
end
end
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
- def other_element(need_convert, indent='')
- rv = []
- private_methods.each do |meth|
- if /\A([^_]+)_[^_]+_elements?\z/ =~ meth.to_s and
- self.class::NSPOOL.has_key?($1)
- res = __send__(meth, need_convert, indent)
- rv << res if /\A\s*\z/ !~ res
- end
- end
- rv.join("\n")
- end
-
- def _validate(tags, model=self.class.model)
+ def _validate(ignore_unknown_element, tags, uri, models=self.class.models)
count = 1
do_redo = false
not_shift = false
tag = nil
- element_names = model.collect {|elem| elem[0]}
+ models = models.find_all {|model| model[1] == uri}
+ element_names = models.collect {|model| model[0]}
if tags
tags_size = tags.size
tags = tags.sort_by {|x| element_names.index(x) || tags_size}
end
- model.each_with_index do |elem, i|
+ models.each_with_index do |model, i|
+ name, model_uri, occurs, getter = model
if DEBUG
p "before"
p tags
- p elem
+ p model
end
if not_shift
@@ -822,41 +1017,41 @@ EOC
p count
end
- case elem[1]
+ case occurs
when '?'
if count > 2
- raise TooMuchTagError.new(elem[0], tag_name)
+ raise TooMuchTagError.new(name, tag_name)
else
- if elem[0] == tag
+ if name == tag
do_redo = true
else
not_shift = true
end
end
when '*'
- if elem[0] == tag
+ if name == tag
do_redo = true
else
not_shift = true
end
when '+'
- if elem[0] == tag
+ if name == tag
do_redo = true
else
if count > 1
not_shift = true
else
- raise MissingTagError.new(elem[0], tag_name)
+ raise MissingTagError.new(name, tag_name)
end
end
else
- if elem[0] == tag
- if model[i+1] and model[i+1][0] != elem[0] and
- tags and tags.first == elem[0]
- raise TooMuchTagError.new(elem[0], tag_name)
+ if name == tag
+ if models[i+1] and models[i+1][0] != name and
+ tags and tags.first == name
+ raise TooMuchTagError.new(name, tag_name)
end
else
- raise MissingTagError.new(elem[0], tag_name)
+ raise MissingTagError.new(name, tag_name)
end
end
@@ -877,8 +1072,8 @@ EOC
end
- if !tags.nil? and !tags.empty?
- raise NotExceptedTagError.new(tag, tag_name)
+ if !ignore_unknown_element and !tags.nil? and !tags.empty?
+ raise NotExpectedTagError.new(tags.first, uri, tag_name)
end
end
@@ -892,6 +1087,43 @@ EOC
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
+
+ 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? {|child| child.__send!(:have_required_elements?)}
+ else
+ !child.to_s.empty?
+ end
+ else
+ true
+ end
+ end
+ end
end
module RootElementMixin
@@ -899,16 +1131,23 @@ EOC
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)
@@ -923,14 +1162,48 @@ EOC
xss.setup_maker(maker)
end
- setup_maker_elements(maker)
+ super
end
-
+
+ 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
+ to_feed(type, &block).to_s
+ end
+ end
+
private
- def tag(indent, attrs, &block)
- rv = xmldecl + xml_stylesheet_pi
- rv << super(indent, attrs, &block)
- rv
+ 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 = super(indent, ns_declarations.merge(attrs), &block)
+ return rv if rv.empty?
+ "#{xmldecl}#{xml_stylesheet_pi}#{rv}"
end
def xmldecl
@@ -944,18 +1217,16 @@ EOC
end
def ns_declarations
+ decls = {}
self.class::NSPOOL.collect do |prefix, uri|
prefix = ":#{prefix}" unless prefix.empty?
- ["xmlns#{prefix}", uri]
+ decls["xmlns#{prefix}"] = uri
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
diff --git a/lib/rss/syndication.rb b/lib/rss/syndication.rb
index 8791ec24fc..3eb15429f6 100644
--- a/lib/rss/syndication.rb
+++ b/lib/rss/syndication.rb
@@ -15,20 +15,26 @@ module RSS
def self.append_features(klass)
super
-
- klass.module_eval(<<-EOC, *get_file_and_line_from_caller(1))
+
+ klass.install_must_call_validator(SY_PREFIX, SY_URI)
+ klass.module_eval do
[
["updatePeriod"],
["updateFrequency", :positive_integer]
].each do |name, type|
- install_text_element("\#{SY_PREFIX}_\#{name}", type,
- "\#{SY_PREFIX}:\#{name}")
+ install_text_element(name, SY_URI, "?",
+ "#{SY_PREFIX}_#{name}", type,
+ "#{SY_PREFIX}:#{name}")
end
%w(updateBase).each do |name|
- install_date_element("\#{SY_PREFIX}_\#{name}", 'w3cdtf', name)
+ install_date_element(name, SY_URI, "?",
+ "#{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
@@ -38,20 +44,6 @@ module RSS
EOC
end
- def sy_validate(tags)
- counter = {}
- ELEMENTS.each do |name|
- counter[name] = 0
- end
-
- tags.each do |tag|
- key = "#{SY_PREFIX}_#{tag}"
- raise UnknownTagError.new(tag, SY_URI) unless counter.has_key?(key)
- counter[key] += 1
- raise TooMuchTagError.new(tag, tag_name) if counter[key] > 1
- end
- end
-
private
SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly)
def validate_sy_updatePeriod(value)
@@ -69,7 +61,7 @@ module RSS
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
diff --git a/lib/rss/taxonomy.rb b/lib/rss/taxonomy.rb
index 52267133ff..276f63b05d 100644
--- a/lib/rss/taxonomy.rb
+++ b/lib/rss/taxonomy.rb
@@ -12,7 +12,7 @@ module RSS
%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
@@ -28,22 +28,10 @@ module RSS
def self.append_features(klass)
super
- var_name = "#{TAXO_PREFIX}_topics"
- klass.install_have_child_element(var_name)
- end
-
- def taxo_validate(tags)
- found_topics = false
- tags.each do |tag|
- if tag == "topics"
- if found_topics
- raise TooMuchTagError.new(tag, tag_name)
- else
- found_topics = true
- end
- else
- raise UnknownTagError.new(tag, TAXO_URI)
- end
+ klass.install_must_call_validator(TAXO_PREFIX, TAXO_URI)
+ %w(topics).each do |name|
+ klass.install_have_child_element(name, TAXO_URI, "?",
+ "#{TAXO_PREFIX}_#{name}")
end
end
@@ -64,13 +52,17 @@ module RSS
@tag_name = "topics"
- install_have_child_element("Bag")
-
- install_must_call_validator('rdf', ::RSS::RDF::URI)
+ install_have_child_element("Bag", RDF::URI, nil)
+ install_must_call_validator('rdf', RDF::URI)
- def initialize(bag=Bag.new)
- super()
- @Bag = bag
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.Bag = args[0]
+ end
+ self.Bag ||= Bag.new
end
def full_name
@@ -80,15 +72,6 @@ module RSS
def maker_target(target)
target.taxo_topics
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- Bag_element(need_convert, next_indent),
- other_element(need_convert, next_indent),
- ]
- end
- end
def resources
if @Bag
@@ -99,21 +82,6 @@ module RSS
[]
end
end
-
- private
- def children
- [@Bag]
- end
-
- def _tags
- rv = []
- rv << [::RSS::RDF::URI, 'Bag'] unless @Bag.nil?
- rv
- end
-
- def rdf_validate(tags)
- _validate(tags, [["Bag", nil]])
- end
end
end
@@ -123,15 +91,7 @@ module RSS
def self.append_features(klass)
super
var_name = "#{TAXO_PREFIX}_topic"
- klass.install_have_children_element(var_name)
- end
-
- def taxo_validate(tags)
- tags.each do |tag|
- if tag != "topic"
- raise UnknownTagError.new(tag, TAXO_URI)
- end
- end
+ klass.install_have_children_element("topic", TAXO_URI, "*", var_name)
end
class TaxonomyTopic < Element
@@ -152,62 +112,26 @@ module RSS
@tag_name = "topic"
- install_get_attribute("about", ::RSS::RDF::URI, true)
- install_text_element("#{TAXO_PREFIX}_link")
+ install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil,
+ "#{RDF::PREFIX}:about")
+ install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link")
- def initialize(about=nil)
- super()
- @about = about
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.about = args[0]
+ end
end
def full_name
tag_name_with_prefix(TAXO_PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent) do |next_indent|
- [
- other_element(need_convert, next_indent),
- ]
- end
- end
-
- def taxo_validate(tags)
- elements = %w(link topics)
- counter = {}
-
- tags.each do |tag|
- if elements.include?(tag)
- counter[tag] ||= 0
- counter[tag] += 1
- raise TooMuchTagError.new(tag, tag_name) if counter[tag] > 1
- else
- raise UnknownTagError.new(tag, TAXO_URI)
- end
- end
- end
def maker_target(target)
target.new_taxo_topic
end
-
- private
- def children
- [@taxo_link, @taxo_topics]
- end
-
- def _attrs
- [
- ["#{RDF::PREFIX}:about", true, "about"]
- ]
- end
-
- def _tags
- rv = []
- rv << [TAXO_URI, "link"] unless @taxo_link.nil?
- rv << [TAXO_URI, "topics"] unless @taxo_topics.nil?
- rv
- end
end
end
diff --git a/lib/rss/trackback.rb b/lib/rss/trackback.rb
index ad6954f3f5..ee2491f332 100644
--- a/lib/rss/trackback.rb
+++ b/lib/rss/trackback.rb
@@ -11,28 +11,15 @@ module RSS
module TrackBackUtils
private
- def trackback_validate(tags)
- counter = {}
- %w(ping about).each do |name|
- counter["#{TRACKBACK_PREFIX}_#{name}"] = 0
- end
-
- tags.each do |tag|
- key = "#{TRACKBACK_PREFIX}_#{tag}"
- raise UnknownTagError.new(tag, TRACKBACK_URI) unless counter.has_key?(key)
- counter[key] += 1
- if tag != "about" and counter[key] > 1
- raise TooMuchTagError.new(tag, tag_name)
- end
- end
-
- if counter["#{TRACKBACK_PREFIX}_ping"].zero? and
- counter["#{TRACKBACK_PREFIX}_about"].nonzero?
+ def trackback_validate(ignore_unknown_element, tags, uri)
+ return if tags.nil?
+ if tags.find {|tag| tag == "about"} and
+ !tags.find {|tag| tag == "ping"}
raise MissingTagError.new("#{TRACKBACK_PREFIX}:ping", tag_name)
end
end
end
-
+
module BaseTrackBackModel
ELEMENTS = %w(ping about)
@@ -43,10 +30,11 @@ module RSS
unless klass.class == Module
klass.module_eval {include TrackBackUtils}
+ klass.install_must_call_validator(TRACKBACK_PREFIX, TRACKBACK_URI)
%w(ping).each do |name|
var_name = "#{TRACKBACK_PREFIX}_#{name}"
klass_name = "TrackBack#{Utils.to_class_name(name)}"
- klass.install_have_child_element(var_name)
+ klass.install_have_child_element(name, TRACKBACK_URI, "?", var_name)
klass.module_eval(<<-EOC, __FILE__, __LINE__)
remove_method :#{var_name}
def #{var_name}
@@ -63,7 +51,8 @@ module RSS
[%w(about s)].each do |name, postfix|
var_name = "#{TRACKBACK_PREFIX}_#{name}"
klass_name = "TrackBack#{Utils.to_class_name(name)}"
- klass.install_have_children_element(var_name)
+ klass.install_have_children_element(name, TRACKBACK_URI, "*",
+ var_name)
klass.module_eval(<<-EOC, __FILE__, __LINE__)
remove_method :#{var_name}
def #{var_name}(*args)
@@ -124,38 +113,28 @@ module RSS
end
@tag_name = "ping"
-
+
[
["resource", ::RSS::RDF::URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{::RSS::RDF::PREFIX}:#{name}")
end
alias_method(:value, :resource)
alias_method(:value=, :resource=)
-
- def initialize(resource=nil)
- super()
- @resource = resource
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.resource = args[0]
+ end
end
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
-
- private
- def _attrs
- [
- ["#{::RSS::RDF::PREFIX}:resource", true, "resource"],
- ]
- end
-
end
class TrackBackAbout < Element
@@ -174,38 +153,31 @@ module RSS
end
@tag_name = "about"
-
+
[
["resource", ::RSS::RDF::URI, true]
].each do |name, uri, required|
- install_get_attribute(name, uri, required)
+ install_get_attribute(name, uri, required, nil, nil,
+ "#{::RSS::RDF::PREFIX}:#{name}")
end
alias_method(:value, :resource)
alias_method(:value=, :resource=)
- def initialize(resource=nil)
- super()
- @resource = resource
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.resource = args[0]
+ end
end
def full_name
tag_name_with_prefix(TRACKBACK_PREFIX)
end
-
- def to_s(need_convert=true, indent=calc_indent)
- rv = tag(indent)
- rv = convert(rv) if need_convert
- rv
- end
private
- def _attrs
- [
- ["#{::RSS::RDF::PREFIX}:resource", true, "resource"],
- ]
- end
-
def maker_target(abouts)
abouts.new_about
end
@@ -243,9 +215,13 @@ module RSS
alias_method(:value, :content)
alias_method(:value=, :content=)
- def initialize(content=nil)
- super()
- @content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.content = args[0]
+ end
end
def full_name
@@ -276,9 +252,13 @@ module RSS
alias_method(:value, :content)
alias_method(:value=, :content=)
- def initialize(content=nil)
- super()
- @content = content
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.content = args[0]
+ end
end
def full_name
diff --git a/lib/rss/utils.rb b/lib/rss/utils.rb
index 0286becf00..031ff3072b 100644
--- a/lib/rss/utils.rb
+++ b/lib/rss/utils.rb
@@ -1,7 +1,5 @@
module RSS
-
module Utils
-
module_function
def to_class_name(name)
name.split(/_/).collect do |part|
@@ -26,6 +24,9 @@ module RSS
klass.new(value)
end
end
- end
+ def element_initialize_arguments?(args)
+ [true, false].include?(args[0]) and args[1].is_a?(Hash)
+ end
+ end
end
diff --git a/lib/rss/xml.rb b/lib/rss/xml.rb
new file mode 100644
index 0000000000..1ae878b772
--- /dev/null
+++ b/lib/rss/xml.rb
@@ -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