summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rss.rb3
-rw-r--r--lib/rss/atom.rb42
-rw-r--r--lib/rss/image.rb6
-rw-r--r--lib/rss/itunes.rb410
-rw-r--r--lib/rss/maker.rb1
-rw-r--r--lib/rss/maker/0.9.rb13
-rw-r--r--lib/rss/maker/1.0.rb6
-rw-r--r--lib/rss/maker/2.0.rb8
-rw-r--r--lib/rss/maker/atom.rb4
-rw-r--r--lib/rss/maker/base.rb518
-rw-r--r--lib/rss/maker/content.rb13
-rw-r--r--lib/rss/maker/dublincore.rb62
-rw-r--r--lib/rss/maker/entry.rb14
-rw-r--r--lib/rss/maker/feed.rb14
-rw-r--r--lib/rss/maker/image.rb38
-rw-r--r--lib/rss/maker/itunes.rb248
-rw-r--r--lib/rss/maker/syndication.rb13
-rw-r--r--lib/rss/maker/taxonomy.rb52
-rw-r--r--lib/rss/maker/trackback.rb38
-rw-r--r--lib/rss/parser.rb28
-rw-r--r--lib/rss/rss.rb387
-rw-r--r--lib/rss/utils.rb76
22 files changed, 1286 insertions, 708 deletions
diff --git a/lib/rss.rb b/lib/rss.rb
index bbe19ad95c..8eb8603581 100644
--- a/lib/rss.rb
+++ b/lib/rss.rb
@@ -1,4 +1,4 @@
-# Copyright (c) 2003-2006 Kouhei Sutou. You can redistribute it and/or
+# Copyright (c) 2003-2007 Kouhei Sutou. You can redistribute it and/or
# modify it under the same terms as Ruby.
#
# Author:: Kouhei Sutou <kou@cozmixng.org>
@@ -10,6 +10,7 @@ require 'rss/atom'
require 'rss/content'
require 'rss/dublincore'
require 'rss/image'
+require 'rss/itunes'
require 'rss/syndication'
require 'rss/taxonomy'
require 'rss/trackback'
diff --git a/lib/rss/atom.rb b/lib/rss/atom.rb
index 901e69a4b0..7cba934feb 100644
--- a/lib/rss/atom.rb
+++ b/lib/rss/atom.rb
@@ -131,7 +131,7 @@ module RSS
private
def maker_target(target)
- target.__send__(self.class.name.split(/::/).last.downcase)
+ target.__send__(self.class.name.split(/::/).last.downcase) {|x| x}
end
def setup_maker_attributes(target)
@@ -239,6 +239,11 @@ module RSS
alias_method :items, :entries
+ def have_author?
+ authors.any? {|author| !author.to_s.empty?} or
+ entries.any? {|entry| entry.have_author?(false)}
+ end
+
private
def atom_validate(ignore_unknown_element, tags, uri)
unless have_author?
@@ -251,11 +256,6 @@ module RSS
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
@@ -315,9 +315,10 @@ module RSS
private
def setup_maker_attributes(target)
- generator = target.generator
- generator.uri = uri if uri
- generator.version = version if version
+ target.generator do |generator|
+ generator.uri = uri if uri
+ generator.version = version if version
+ end
end
end
@@ -408,6 +409,12 @@ module RSS
tag, URI, occurs, tag, *args)
end
+ def have_author?(check_parent=true)
+ authors.any? {|author| !author.to_s.empty?} or
+ (check_parent and @parent and @parent.have_author?) or
+ (source and source.have_author?)
+ end
+
private
def atom_validate(ignore_unknown_element, tags, uri)
unless have_author?
@@ -420,12 +427,6 @@ module RSS
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
@@ -606,7 +607,6 @@ module RSS
tag, URI, occurs, tag, *args)
end
- private
def have_author?
!author.to_s.empty?
end
@@ -674,6 +674,11 @@ module RSS
super(maker)
end
+ def have_author?
+ authors.any? {|author| !author.to_s.empty?} or
+ (source and source.have_author?)
+ end
+
private
def atom_validate(ignore_unknown_element, tags, uri)
unless have_author?
@@ -686,11 +691,6 @@ module RSS
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
diff --git a/lib/rss/image.rb b/lib/rss/image.rb
index 02a8a0b6a7..c4714aea12 100644
--- a/lib/rss/image.rb
+++ b/lib/rss/image.rb
@@ -142,8 +142,8 @@ module RSS
end
AVAILABLE_SIZES = %w(small medium large)
- alias_method :_size=, :size=
- private :_size=
+ alias_method :set_size, :size=
+ private :set_size
def size=(new_value)
if @do_validate and !new_value.nil?
new_value = new_value.strip
@@ -152,7 +152,7 @@ module RSS
raise NotAvailableValueError.new(full_name, new_value, attr_name)
end
end
- __send!(:_size=, new_value)
+ set_size(new_value)
end
alias image_size= size=
diff --git a/lib/rss/itunes.rb b/lib/rss/itunes.rb
new file mode 100644
index 0000000000..7414bc511a
--- /dev/null
+++ b/lib/rss/itunes.rb
@@ -0,0 +1,410 @@
+require 'rss/2.0'
+
+module RSS
+ ITUNES_PREFIX = 'itunes'
+ ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
+
+ Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
+
+ module ITunesModelUtils
+ include Utils
+
+ def def_class_accessor(klass, name, type, *args)
+ normalized_name = name.gsub(/-/, "_")
+ full_name = "#{ITUNES_PREFIX}_#{normalized_name}"
+ klass_name = "ITunes#{Utils.to_class_name(normalized_name)}"
+
+ case type
+ when :element, :attribute
+ klass::ELEMENTS << full_name
+ def_element_class_accessor(klass, name, full_name, klass_name, *args)
+ when :elements
+ klass::ELEMENTS << full_name
+ def_elements_class_accessor(klass, name, full_name, klass_name, *args)
+ else
+ klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
+ klass.install_text_element(normalized_name, ITUNES_URI, "?",
+ full_name, type, name)
+ end
+ end
+
+ def def_element_class_accessor(klass, name, full_name, klass_name,
+ recommended_attribute_name=nil)
+ klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name)
+ end
+
+ def def_elements_class_accessor(klass, name, full_name, klass_name,
+ plural_name, recommended_attribute_name=nil)
+ full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}"
+ klass.install_have_children_element(name, ITUNES_PREFIX, "*",
+ full_name, full_plural_name)
+ end
+ end
+
+ module ITunesBaseModel
+ extend ITunesModelUtils
+
+ ELEMENTS = []
+
+ ELEMENT_INFOS = [["author"],
+ ["block", :yes_other],
+ ["explicit", :yes_clean_other],
+ ["keywords", :csv],
+ ["subtitle"],
+ ["summary"]]
+ end
+
+ module ITunesChannelModel
+ extend BaseModel
+ extend ITunesModelUtils
+ include ITunesBaseModel
+
+ ELEMENTS = []
+
+ class << self
+ def append_features(klass)
+ super
+
+ return if klass.instance_of?(Module)
+ ELEMENT_INFOS.each do |name, type, *additional_infos|
+ def_class_accessor(klass, name, type, *additional_infos)
+ end
+ end
+ end
+
+ ELEMENT_INFOS = [
+ ["category", :elements, "categories", "text"],
+ ["image", :attribute, "href"],
+ ["owner", :element],
+ ["new-feed-url"],
+ ] + ITunesBaseModel::ELEMENT_INFOS
+
+ class ITunesCategory < Element
+ include RSS09
+
+ @tag_name = "category"
+
+ class << self
+ def required_prefix
+ ITUNES_PREFIX
+ end
+
+ def required_uri
+ ITUNES_URI
+ end
+ end
+
+ [
+ ["text", "", true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ ITunesCategory = self
+ install_have_children_element("category", ITUNES_URI, "*",
+ "#{ITUNES_PREFIX}_category",
+ "#{ITUNES_PREFIX}_categories")
+
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.text = args[0]
+ end
+ end
+
+ def full_name
+ tag_name_with_prefix(ITUNES_PREFIX)
+ end
+
+ private
+ def maker_target(categories)
+ if text or !itunes_categories.empty?
+ categories.new_category
+ else
+ nil
+ end
+ end
+
+ def setup_maker_attributes(category)
+ category.text = text if text
+ end
+
+ def setup_maker_elements(category)
+ super(category)
+ itunes_categories.each do |sub_category|
+ sub_category.setup_maker(category)
+ end
+ end
+ end
+
+ class ITunesImage < Element
+ include RSS09
+
+ @tag_name = "image"
+
+ class << self
+ def required_prefix
+ ITUNES_PREFIX
+ end
+
+ def required_uri
+ ITUNES_URI
+ end
+ end
+
+ [
+ ["href", "", true]
+ ].each do |name, uri, required|
+ install_get_attribute(name, uri, required)
+ end
+
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.href = args[0]
+ end
+ end
+
+ def full_name
+ tag_name_with_prefix(ITUNES_PREFIX)
+ end
+
+ private
+ def maker_target(target)
+ if href
+ target.itunes_image {|image| image}
+ else
+ nil
+ end
+ end
+
+ def setup_maker_attributes(image)
+ image.href = href
+ end
+ end
+
+ class ITunesOwner < Element
+ include RSS09
+
+ @tag_name = "owner"
+
+ class << self
+ def required_prefix
+ ITUNES_PREFIX
+ end
+
+ def required_uri
+ ITUNES_URI
+ end
+ end
+
+ install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
+ [
+ ["name"],
+ ["email"],
+ ].each do |name,|
+ ITunesBaseModel::ELEMENT_INFOS << name
+ install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}")
+ end
+
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ self.itunes_name = args[0]
+ self.itunes_email = args[1]
+ end
+ end
+
+ def full_name
+ tag_name_with_prefix(ITUNES_PREFIX)
+ end
+
+ private
+ def maker_target(target)
+ target.itunes_owner
+ end
+
+ def setup_maker_element(owner)
+ super(owner)
+ owner.itunes_name = itunes_name
+ owner.itunes_email = itunes_email
+ end
+ end
+ end
+
+ module ITunesItemModel
+ extend BaseModel
+ extend ITunesModelUtils
+ include ITunesBaseModel
+
+ class << self
+ def append_features(klass)
+ super
+
+ return if klass.instance_of?(Module)
+ ELEMENT_INFOS.each do |name, type|
+ def_class_accessor(klass, name, type)
+ end
+ end
+ end
+
+ ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS +
+ [["duration", :element, "content"]]
+
+ class ITunesDuration < Element
+ include RSS09
+
+ @tag_name = "duration"
+
+ class << self
+ def required_prefix
+ ITUNES_PREFIX
+ end
+
+ def required_uri
+ ITUNES_URI
+ end
+
+ def parse(duration, do_validate=true)
+ if do_validate and /\A(?:
+ \d?\d:[0-5]\d:[0-5]\d|
+ [0-5]?\d:[0-5]\d
+ )\z/x !~ duration
+ raise ArgumentError,
+ "must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " +
+ duration.inspect
+ end
+
+ components = duration.split(':')
+ components[3..-1] = nil if components.size > 3
+
+ components.unshift("00") until components.size == 3
+
+ components.collect do |component|
+ component.to_i
+ end
+ end
+
+ def construct(hour, minute, second)
+ components = [minute, second]
+ if components.include?(nil)
+ nil
+ else
+ components.unshift(hour) if hour and hour > 0
+ components.collect do |component|
+ "%02d" % component
+ end.join(":")
+ end
+ end
+ end
+
+ content_setup
+ alias_method(:value, :content)
+ remove_method(:content=)
+
+ attr_reader :hour, :minute, :second
+ def initialize(*args)
+ if Utils.element_initialize_arguments?(args)
+ super
+ else
+ super()
+ args = args[0] if args.size == 1 and args[0].is_a?(Array)
+ if args.size == 1
+ self.content = args[0]
+ elsif args.size > 3
+ raise ArgumentError,
+ "must be (do_validate, params), (content), " +
+ "(minute, second), ([minute, second]), " +
+ "(hour, minute, second) or ([hour, minute, second]): " +
+ args.inspect
+ else
+ @second, @minute, @hour = args.reverse
+ update_content
+ end
+ end
+ end
+
+ def content=(value)
+ if value.nil?
+ @content = nil
+ elsif value.is_a?(self.class)
+ self.content = value.content
+ else
+ begin
+ @hour, @minute, @second = self.class.parse(value, @do_validate)
+ rescue ArgumentError
+ raise NotAvailableValueError.new(tag_name, value)
+ end
+ @content = value
+ end
+ end
+ alias_method(:value=, :content=)
+
+ def hour=(hour)
+ @hour = @do_validate ? Integer(hour) : hour.to_i
+ update_content
+ hour
+ end
+
+ def minute=(minute)
+ @minute = @do_validate ? Integer(minute) : minute.to_i
+ update_content
+ minute
+ end
+
+ def second=(second)
+ @second = @do_validate ? Integer(second) : second.to_i
+ update_content
+ second
+ end
+
+ def full_name
+ tag_name_with_prefix(ITUNES_PREFIX)
+ end
+
+ private
+ def update_content
+ @content = self.class.construct(hour, minute, second)
+ end
+
+ def maker_target(target)
+ if @content
+ target.itunes_duration {|duration| duration}
+ else
+ nil
+ end
+ end
+
+ def setup_maker_element(duration)
+ super(duration)
+ duration.content = @content
+ end
+ end
+ end
+
+ class Rss
+ class Channel
+ include ITunesChannelModel
+ class Item; include ITunesItemModel; end
+ end
+ end
+
+ element_infos =
+ ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS
+ element_infos.each do |name, type|
+ class_name = Utils.to_class_name(name)
+ case type
+ when :element, :elements, :attribute
+ BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}")
+ else
+ accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}"
+ BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base)
+ end
+ end
+end
diff --git a/lib/rss/maker.rb b/lib/rss/maker.rb
index a47b55b670..e362e785fa 100644
--- a/lib/rss/maker.rb
+++ b/lib/rss/maker.rb
@@ -40,3 +40,4 @@ require "rss/maker/syndication"
require "rss/maker/taxonomy"
require "rss/maker/trackback"
require "rss/maker/image"
+require "rss/maker/itunes"
diff --git a/lib/rss/maker/0.9.rb b/lib/rss/maker/0.9.rb
index dd75c9289b..c83597dfd5 100644
--- a/lib/rss/maker/0.9.rb
+++ b/lib/rss/maker/0.9.rb
@@ -22,7 +22,6 @@ module RSS
end
class Channel < ChannelBase
-
def to_feed(rss)
channel = Rss::Channel.new
set = setup_values(channel)
@@ -63,8 +62,8 @@ module RSS
def not_set_required_variables
vars = super
- vars << "description" unless description.have_required_values?
- vars << "title" unless title.have_required_values?
+ vars << "description" unless description {|d| d.have_required_values?}
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
@@ -259,7 +258,7 @@ module RSS
def to_feed(rss)
item = Rss::Channel::Item.new
set = setup_values(item)
- if set or title.have_required_values?
+ if set or title {|t| t.have_required_values?}
rss.items << item
set_parent(item, rss.channel)
setup_other_elements(rss, item)
@@ -268,10 +267,6 @@ module RSS
end
end
- def have_required_values?
- super and title.have_required_values?
- end
-
private
def required_variable_names
%w(link)
@@ -279,7 +274,7 @@ module RSS
def not_set_required_variables
vars = super
- vars << "title" unless title.have_required_values?
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
diff --git a/lib/rss/maker/1.0.rb b/lib/rss/maker/1.0.rb
index 12608ad94a..c4af6e9b2e 100644
--- a/lib/rss/maker/1.0.rb
+++ b/lib/rss/maker/1.0.rb
@@ -83,8 +83,8 @@ module RSS
def not_set_required_variables
vars = super
- vars << "description" unless description.have_required_values?
- vars << "title" unless title.have_required_values?
+ vars << "description" unless description {|d| d.have_required_values?}
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
@@ -256,7 +256,7 @@ module RSS
def not_set_required_variables
set_default_values do
vars = super
- vars << "title" unless title.have_required_values?
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
end
diff --git a/lib/rss/maker/2.0.rb b/lib/rss/maker/2.0.rb
index d93ba94d4a..9149c0e24b 100644
--- a/lib/rss/maker/2.0.rb
+++ b/lib/rss/maker/2.0.rb
@@ -15,7 +15,7 @@ module RSS
private
def required_variable_names
- %w(title link description)
+ %w(link)
end
class SkipDays < RSS09::Channel::SkipDays
@@ -90,13 +90,7 @@ module RSS
end
class Items < RSS09::Items
-
class Item < RSS09::Items::Item
-
- def have_required_values?
- @title or @description
- end
-
private
def required_variable_names
%w(title description)
diff --git a/lib/rss/maker/atom.rb b/lib/rss/maker/atom.rb
index 27d30c6d89..fd3198cd9e 100644
--- a/lib/rss/maker/atom.rb
+++ b/lib/rss/maker/atom.rb
@@ -147,11 +147,11 @@ EOC
def to_feed(feed, current)
logo = current.class::Logo.new
class << logo
- alias uri= content=
+ alias_method(:uri=, :content=)
end
set = setup_values(logo)
class << logo
- undef uri=
+ remove_method(:uri=)
end
if set
current.logo = logo
diff --git a/lib/rss/maker/base.rb b/lib/rss/maker/base.rb
index ad47ff29cc..752b2fa58f 100644
--- a/lib/rss/maker/base.rb
+++ b/lib/rss/maker/base.rb
@@ -4,85 +4,155 @@ require 'rss/rss'
module RSS
module Maker
- module Base
- def self.append_features(klass)
- super
-
- klass.module_eval(<<-EOC, __FILE__, __LINE__)
+ class Base
+ extend Utils::InheritedReader
- OTHER_ELEMENTS = []
- NEED_INITIALIZE_VARIABLES = []
+ OTHER_ELEMENTS = []
+ NEED_INITIALIZE_VARIABLES = []
- def self.inherited(subclass)
- subclass.const_set("OTHER_ELEMENTS", [])
- subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
-
- subclass.module_eval(<<-EOEOC, __FILE__, __LINE__)
- def self.other_elements
- OTHER_ELEMENTS + super
- end
-
- def self.need_initialize_variables
- NEED_INITIALIZE_VARIABLES + super
- end
- EOEOC
+ class << self
+ def other_elements
+ inherited_array_reader("OTHER_ELEMENTS")
+ end
+ def need_initialize_variables
+ inherited_array_reader("NEED_INITIALIZE_VARIABLES")
end
- def self.add_other_element(variable_name)
- OTHER_ELEMENTS << variable_name
+ def inherited_base
+ ::RSS::Maker::Base
end
- def self.other_elements
- OTHER_ELEMENTS
+ def inherited(subclass)
+ subclass.const_set("OTHER_ELEMENTS", [])
+ subclass.const_set("NEED_INITIALIZE_VARIABLES", [])
end
- def self.add_need_initialize_variable(variable_name, init_value="nil")
- NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
+ def add_other_element(variable_name)
+ self::OTHER_ELEMENTS << variable_name
end
- def self.need_initialize_variables
- NEED_INITIALIZE_VARIABLES
+ def add_need_initialize_variable(variable_name, init_value="nil")
+ self::NEED_INITIALIZE_VARIABLES << [variable_name, init_value]
end
- def self.def_array_element(name, plural=nil, klass=nil)
+ def def_array_element(name, plural=nil, klass_name=nil)
include Enumerable
extend Forwardable
- 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)
+ plural ||= "#{name}s"
+ klass_name ||= Utils.to_class_name(name)
+ def_delegators("@#{plural}", :<<, :[], :[]=, :first, :last)
+ def_delegators("@#{plural}", :push, :pop, :shift, :unshift)
+ def_delegators("@#{plural}", :each, :size, :empty?, :clear)
add_need_initialize_variable(plural, "[]")
- module_eval(<<-EOM, __FILE__, __LINE__ + 1)
- def new_\#{name}
- \#{name} = \#{klass}.new(@maker)
- @\#{plural} << \#{name}
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def new_#{name}
+ #{name} = self.class::#{klass_name}.new(@maker)
+ @#{plural} << #{name}
if block_given?
- yield \#{name}
+ yield #{name}
else
- \#{name}
+ #{name}
end
end
- alias new_child new_\#{name}
+ alias new_child new_#{name}
def to_feed(*args)
- @\#{plural}.each do |\#{name}|
- \#{name}.to_feed(*args)
+ @#{plural}.each do |#{name}|
+ #{name}.to_feed(*args)
end
end
def replace(elements)
- @\#{plural}.replace(elements.to_a)
+ @#{plural}.replace(elements.to_a)
end
-EOM
+ EOC
+ end
+
+ def def_classed_element_without_accessor(name, class_name=nil)
+ class_name ||= Utils.to_class_name(name)
+ add_other_element(name)
+ add_need_initialize_variable(name, "make_#{name}")
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ private
+ def setup_#{name}(feed, current)
+ @#{name}.to_feed(feed, current)
+ end
+
+ def make_#{name}
+ self.class::#{class_name}.new(@maker)
+ end
+ EOC
+ end
+
+ def def_classed_element(name, class_name=nil, attribute_name=nil)
+ def_classed_element_without_accessor(name, class_name)
+ if attribute_name
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{name}
+ if block_given?
+ yield(@#{name})
+ else
+ @#{name}.#{attribute_name}
+ end
+ end
+
+ def #{name}=(new_value)
+ @#{name}.#{attribute_name} = new_value
+ end
+ EOC
+ else
+ attr_reader name
+ end
+ end
+
+ def def_classed_elements(name, attribute, plural_class_name=nil,
+ plural_name=nil, new_name=nil)
+ plural_name ||= "#{name}s"
+ new_name ||= name
+ def_classed_element(plural_name, plural_class_name)
+ local_variable_name = "_#{name}"
+ new_value_variable_name = "new_value"
+ additional_setup_code = nil
+ if block_given?
+ additional_setup_code = yield(local_variable_name,
+ new_value_variable_name)
+ end
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{name}
+ #{local_variable_name} = #{plural_name}.first
+ #{local_variable_name} ? #{local_variable_name}.#{attribute} : nil
+ end
+
+ def #{name}=(#{new_value_variable_name})
+ #{local_variable_name} =
+ #{plural_name}.first || #{plural_name}.new_#{new_name}
+ #{additional_setup_code}
+ #{local_variable_name}.#{attribute} = #{new_value_variable_name}
+ end
+ EOC
+ end
+
+ def def_other_element(name)
+ attr_accessor name
+ def_other_element_without_accessor(name)
+ end
+
+ def def_other_element_without_accessor(name)
+ add_need_initialize_variable(name)
+ add_other_element(name)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def setup_#{name}(feed, current)
+ if !@#{name}.nil? and current.respond_to?(:#{name}=)
+ current.#{name} = @#{name}
+ end
+ end
+ EOC
end
- EOC
end
-
+
attr_reader :maker
def initialize(maker)
@maker = maker
@@ -183,12 +253,27 @@ EOM
attr_accessor element
add_need_initialize_variable(element)
end
-EOC
+ EOC
end
end
module AtomTextConstructBase
module EnsureXMLContent
+ class << self
+ def included(base)
+ super
+ base.class_eval do
+ %w(type content xml_content).each do |element|
+ attr_reader element
+ attr_writer element if element != "xml_content"
+ add_need_initialize_variable(element)
+ end
+
+ alias_method(:xhtml, :xml_content)
+ end
+ end
+ end
+
def ensure_xml_content(content)
xhtml_uri = ::RSS::Atom::XHTML_URI
unless content.is_a?(RSS::XML::Element) and
@@ -203,6 +288,14 @@ EOC
content
end
+ def xml_content=(content)
+ @xml_content = ensure_xml_content(content)
+ end
+
+ def xhtml=(content)
+ self.xml_content = content
+ end
+
private
def set_xhtml_uri_as_default_uri(children)
children.collect do |child|
@@ -221,21 +314,9 @@ EOC
def self.append_features(klass)
super
- klass.class_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ klass.class_eval do
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
end
@@ -248,7 +329,7 @@ EOC
}
_date = date
if _date and !dc_dates.any? {|dc_date| dc_date.value == _date}
- dc_date = self.class::DublinCoreDates::Date.new(self)
+ dc_date = self.class::DublinCoreDates::DublinCoreDate.new(self)
dc_date.value = _date.dup
dc_dates.unshift(dc_date)
end
@@ -260,9 +341,7 @@ EOC
end
end
- class RSSBase
- include Base
-
+ class RSSBase < Base
class << self
def make(&block)
new.make(&block)
@@ -281,7 +360,7 @@ EOC
def make_#{element}
self.class::#{Utils.to_class_name(element)}.new(self)
end
-EOC
+ EOC
end
attr_reader :feed_version
@@ -326,13 +405,10 @@ EOC
end
end
- class XMLStyleSheets
- include Base
-
+ class XMLStyleSheets < Base
def_array_element("xml_stylesheet", nil, "XMLStyleSheet")
- class XMLStyleSheet
- include Base
+ class XMLStyleSheet < Base
::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute|
attr_accessor attribute
@@ -362,26 +438,23 @@ EOC
end
end
- class ChannelBase
- include Base
+ class ChannelBase < Base
include SetupDefaultDate
- %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}(feed, current)
- @#{element}.to_feed(feed, current)
- end
+ %w(cloud categories skipDays skipHours).each do |name|
+ def_classed_element(name)
+ end
- def make_#{element}
- self.class::#{Utils.to_class_name(element)}.new(@maker)
- end
-EOC
+ %w(generator copyright description title).each do |name|
+ def_classed_element(name, nil, "content")
+ end
+
+ [
+ ["link", "href", Proc.new {|target,| "#{target}.href = 'self'"}],
+ ["author", "name"],
+ ["contributor", "name"],
+ ].each do |name, attribute, additional_setup_maker|
+ def_classed_elements(name, attribute, &additional_setup_maker)
end
%w(id about language
@@ -407,59 +480,12 @@ EOC
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 icon
image_favicon.about
end
@@ -476,14 +502,10 @@ EOC
maker.image.url = url
end
- class SkipDaysBase
- include Base
-
+ class SkipDaysBase < Base
def_array_element("day")
- class DayBase
- include Base
-
+ class DayBase < Base
%w(content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -491,14 +513,10 @@ EOC
end
end
- class SkipHoursBase
- include Base
-
+ class SkipHoursBase < Base
def_array_element("hour")
- class HourBase
- include Base
-
+ class HourBase < Base
%w(content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -506,23 +524,17 @@ EOC
end
end
- class CloudBase
- include Base
-
+ class CloudBase < Base
%w(domain port path registerProcedure protocol).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
- class CategoriesBase
- include Base
-
+ class CategoriesBase < Base
def_array_element("category", "categories")
- class CategoryBase
- include Base
-
+ class CategoryBase < Base
%w(domain content label).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -535,14 +547,10 @@ EOC
end
end
- class LinksBase
- include Base
-
+ class LinksBase < Base
def_array_element("link")
- class LinkBase
- include Base
-
+ class LinkBase < Base
%w(href rel type hreflang title length).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -550,56 +558,43 @@ EOC
end
end
- class AuthorsBase
- include Base
-
+ class AuthorsBase < Base
def_array_element("author")
- class AuthorBase
- include Base
+ class AuthorBase < Base
include AtomPersonConstructBase
end
end
- class ContributorsBase
- include Base
-
+ class ContributorsBase < Base
def_array_element("contributor")
- class ContributorBase
- include Base
+ class ContributorBase < Base
include AtomPersonConstructBase
end
end
- class GeneratorBase
- include Base
-
+ class GeneratorBase < Base
%w(uri version content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
- class CopyrightBase
- include Base
+ class CopyrightBase < Base
include AtomTextConstructBase
end
- class DescriptionBase
- include Base
+ class DescriptionBase < Base
include AtomTextConstructBase
end
- class TitleBase
- include Base
+ class TitleBase < Base
include AtomTextConstructBase
end
end
- class ImageBase
- include Base
-
+ class ImageBase < Base
%w(title url width height description).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -610,9 +605,7 @@ EOC
end
end
- class ItemsBase
- include Base
-
+ class ItemsBase < Base
def_array_element("item")
attr_accessor :do_sort, :max_size
@@ -646,27 +639,25 @@ EOC
end
end
- class ItemBase
- include Base
+ class ItemBase < Base
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}(feed, current)
- @#{element}.to_feed(feed, current)
- end
+ %w(guid enclosure source categories content).each do |name|
+ def_classed_element(name)
+ end
- def make_#{element}
- self.class::#{Utils.to_class_name(element)}.new(@maker)
- end
-EOC
+ %w(rights description title).each do |name|
+ def_classed_element(name, nil, "content")
end
+ [
+ ["author", "name"],
+ ["link", "href", Proc.new {|target,| "#{target}.href = 'alternate'"}],
+ ["contributor", "name"],
+ ].each do |name, attribute|
+ def_classed_elements(name, attribute)
+ end
+
%w(date comments id published).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -688,42 +679,9 @@ EOC
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)
_date = date || dc_date
_other_date = other.date || other.dc_date
@@ -738,42 +696,30 @@ EOC
end
end
- class GuidBase
- include Base
-
+ class GuidBase < Base
%w(isPermaLink content).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
- class EnclosureBase
- include Base
-
+ class EnclosureBase < Base
%w(url length type).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
- class SourceBase
- include Base
-
+ class SourceBase < Base
%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
+ logo rights subtitle title).each do |name|
+ def_classed_element(name)
+ end
- def make_#{element}
- self.class::#{Utils.to_class_name(element)}.new(@maker)
- end
- EOC
+ [
+ ["link", "href"],
+ ].each do |name, attribute|
+ def_classed_elements(name, attribute)
end
%w(id content date).each do |element|
@@ -781,15 +727,8 @@ EOC
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
+ alias_method(:url, :link)
+ alias_method(:url=, :link=)
def updated
date
@@ -805,9 +744,7 @@ EOC
ContributorsBase = ChannelBase::ContributorsBase
GeneratorBase = ChannelBase::GeneratorBase
- class IconBase
- include Base
-
+ class IconBase < Base
%w(url).each do |element|
attr_accessor element
add_need_initialize_variable(element)
@@ -816,27 +753,22 @@ EOC
LinksBase = ChannelBase::LinksBase
- class LogoBase
- include Base
-
+ class LogoBase < Base
%w(uri).each do |element|
attr_accessor element
add_need_initialize_variable(element)
end
end
- class RightsBase
- include Base
+ class RightsBase < Base
include AtomTextConstructBase
end
- class SubtitleBase
- include Base
+ class SubtitleBase < Base
include AtomTextConstructBase
end
- class TitleBase
- include Base
+ class TitleBase < Base
include AtomTextConstructBase
end
end
@@ -846,22 +778,19 @@ EOC
LinksBase = ChannelBase::LinksBase
ContributorsBase = ChannelBase::ContributorsBase
- class RightsBase
- include Base
+ class RightsBase < Base
include AtomTextConstructBase
end
- class DescriptionBase
- include Base
+ class DescriptionBase < Base
include AtomTextConstructBase
end
- class ContentBase
- include Base
+ class ContentBase < Base
include AtomTextConstructBase::EnsureXMLContent
- %w(type src content xml_content).each do |element|
- attr element, element != "xml_content"
+ %w(src).each do |element|
+ attr_accessor(element)
add_need_initialize_variable(element)
end
@@ -870,13 +799,9 @@ EOC
@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
@@ -913,16 +838,13 @@ EOC
end
end
- class TitleBase
- include Base
+ class TitleBase < Base
include AtomTextConstructBase
end
end
end
- class TextinputBase
- include Base
-
+ class TextinputBase < Base
%w(title description name link).each do |element|
attr_accessor element
add_need_initialize_variable(element)
diff --git a/lib/rss/maker/content.rb b/lib/rss/maker/content.rb
index 18590d0cf8..a1fd283116 100644
--- a/lib/rss/maker/content.rb
+++ b/lib/rss/maker/content.rb
@@ -7,17 +7,8 @@ module RSS
def self.append_features(klass)
super
- ::RSS::ContentModel::ELEMENTS.each do |element|
- klass.add_need_initialize_variable(element)
- klass.add_other_element(element)
- klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
- attr_accessor :#{element}
- def setup_#{element}(rss, current)
- if #{element} and current.respond_to?(:#{element}=)
- current.#{element} = @#{element} if @#{element}
- end
- end
- EOC
+ ::RSS::ContentModel::ELEMENTS.each do |name|
+ klass.def_other_element(name)
end
end
end
diff --git a/lib/rss/maker/dublincore.rb b/lib/rss/maker/dublincore.rb
index 088ae60942..ff4813fe19 100644
--- a/lib/rss/maker/dublincore.rb
+++ b/lib/rss/maker/dublincore.rb
@@ -15,61 +15,40 @@ module RSS
plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
full_plural_klass_name = "self.class::#{plural_klass_name}"
full_klass_name = "#{full_plural_klass_name}::#{klass_name}"
- klass.add_need_initialize_variable(full_plural_name,
- "make_#{full_plural_name}")
- klass.add_other_element(full_plural_name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
- attr_accessor :#{full_plural_name}
- def make_#{full_plural_name}
- #{full_plural_klass_name}.new(@maker)
- end
-
- def setup_#{full_plural_name}(feed, current)
- @#{full_plural_name}.to_feed(feed, current)
- end
-
- def #{full_name}
- @#{full_plural_name}[0] and @#{full_plural_name}[0].value
- end
-
- def #{full_name}=(new_value)
- @#{full_plural_name}[0] = #{full_klass_name}.new(self)
- @#{full_plural_name}[0].value = new_value
- end
-
+ klass.def_classed_elements(full_name, "value", plural_klass_name,
+ full_plural_name, name)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
def new_#{full_name}(value=nil)
- #{full_name} = #{full_klass_name}.new(self)
- #{full_name}.value = value
- @#{full_plural_name} << #{full_name}
+ _#{full_name} = #{full_plural_name}.new_#{name}
+ _#{full_name}.value = value
if block_given?
- yield #{full_name}
+ yield _#{full_name}
else
- #{full_name}
+ _#{full_name}
end
end
-EOC
+ EOC
end
klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
# For backward compatibility
alias #{DC_PREFIX}_rightses #{DC_PREFIX}_rights_list
-EOC
+ EOC
end
::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name|
plural_name ||= "#{name}s"
+ full_name ||= "#{DC_PREFIX}_#{name}"
+ full_plural_name ||= "#{DC_PREFIX}_#{plural_name}"
klass_name = Utils.to_class_name(name)
full_klass_name = "DublinCore#{klass_name}"
plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}"
- module_eval(<<-EOC, __FILE__, __LINE__)
- class #{plural_klass_name}Base
- include Base
-
- def_array_element(#{name.dump}, #{plural_name.dump})
-
- class #{klass_name}Base
- include Base
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ class #{plural_klass_name}Base < Base
+ def_array_element(#{name.dump}, #{full_plural_name.dump},
+ #{full_klass_name.dump})
+ class #{full_klass_name}Base < Base
attr_accessor :value
add_need_initialize_variable("value")
alias_method(:content, :value)
@@ -80,12 +59,13 @@ EOC
end
def to_feed(feed, current)
- if value and current.respond_to?(:dc_#{name})
+ if value and current.respond_to?(:#{full_name})
new_item = current.class::#{full_klass_name}.new(value)
- current.dc_#{plural_name} << new_item
+ current.#{full_plural_name} << new_item
end
end
end
+ #{klass_name}Base = #{full_klass_name}Base
end
EOC
end
@@ -94,11 +74,13 @@ 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)}"
klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
class #{plural_klass_name} < #{plural_klass_name}Base
- class #{klass_name} < #{klass_name}Base
+ class #{full_klass_name} < #{full_klass_name}Base
end
+ #{klass_name} = #{full_klass_name}
end
EOC
end
diff --git a/lib/rss/maker/entry.rb b/lib/rss/maker/entry.rb
index baa22c5bf1..be648832c3 100644
--- a/lib/rss/maker/entry.rb
+++ b/lib/rss/maker/entry.rb
@@ -75,12 +75,6 @@ module RSS
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)
@@ -100,7 +94,7 @@ module RSS
if authors.all? {|author| !author.have_required_values?}
vars << "author"
end
- vars << "title" unless title.have_required_values?
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
end
@@ -126,9 +120,11 @@ module RSS
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
+ @maker.channel.rights {|r| @rights = r}
+ end
+ unless keep[:title].variable_is_set?
+ @maker.channel.title {|t| @title = t}
end
- @title = @maker.channel.title unless keep[:title].variable_is_set?
self.updated ||= @maker.channel.updated
super(&block)
ensure
diff --git a/lib/rss/maker/feed.rb b/lib/rss/maker/feed.rb
index ac26788102..95ae735c6b 100644
--- a/lib/rss/maker/feed.rb
+++ b/lib/rss/maker/feed.rb
@@ -64,7 +64,7 @@ module RSS
@maker.items.all? {|item| item.author.to_s.empty?}
vars << "author"
end
- vars << "title" unless title.have_required_values?
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
@@ -148,11 +148,11 @@ module RSS
def to_feed(feed)
logo = feed.class::Logo.new
class << logo
- alias url= content=
+ alias_method(:url=, :content=)
end
set = setup_values(logo)
class << logo
- undef url=
+ remove_method(:url=)
end
if set
feed.logo = logo
@@ -194,7 +194,7 @@ module RSS
def have_required_values?
set_default_values do
- super and title.have_required_values?
+ super and title {|t| t.have_required_values?}
end
end
@@ -209,7 +209,7 @@ module RSS
def not_set_required_variables
vars = super
- vars << "title" unless title.have_required_values?
+ vars << "title" unless title {|t| t.have_required_values?}
vars
end
@@ -282,11 +282,11 @@ module RSS
def to_feed(feed, current)
icon = current.class::Icon.new
class << icon
- alias url= content=
+ alias_method(:url=, :content=)
end
set = setup_values(icon)
class << icon
- undef url=
+ remove_method(:url=)
end
if set
current.icon = icon
diff --git a/lib/rss/maker/image.rb b/lib/rss/maker/image.rb
index e3469d0597..b95cf4c714 100644
--- a/lib/rss/maker/image.rb
+++ b/lib/rss/maker/image.rb
@@ -9,20 +9,7 @@ module RSS
super
name = "#{RSS::IMAGE_PREFIX}_item"
- klass.add_need_initialize_variable(name, "make_#{name}")
- klass.add_other_element(name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
- attr_reader :#{name}
- def setup_#{name}(feed, current)
- if @#{name}
- @#{name}.to_feed(feed, current)
- end
- end
-
- def make_#{name}
- self.class::#{Utils.to_class_name(name)}.new(@maker)
- end
-EOC
+ klass.def_classed_element(name)
end
def self.install_image_item(klass)
@@ -33,8 +20,7 @@ EOC
EOC
end
- class ImageItemBase
- include Base
+ class ImageItemBase < Base
include Maker::DublinCoreModel
attr_accessor :about, :resource, :image_width, :image_height
@@ -67,20 +53,7 @@ EOC
super
name = "#{RSS::IMAGE_PREFIX}_favicon"
- klass.add_need_initialize_variable(name, "make_#{name}")
- klass.add_other_element(name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
- attr_reader :#{name}
- def setup_#{name}(feed, current)
- if @#{name}
- @#{name}.to_feed(feed, current)
- end
- end
-
- def make_#{name}
- self.class::#{Utils.to_class_name(name)}.new(@maker)
- end
-EOC
+ klass.def_classed_element(name)
end
def self.install_image_favicon(klass)
@@ -88,11 +61,10 @@ EOC
class ImageFavicon < ImageFaviconBase
DublinCoreModel.install_dublin_core(self)
end
-EOC
+ EOC
end
- class ImageFaviconBase
- include Base
+ class ImageFaviconBase < Base
include Maker::DublinCoreModel
attr_accessor :about, :image_size
diff --git a/lib/rss/maker/itunes.rb b/lib/rss/maker/itunes.rb
new file mode 100644
index 0000000000..86f41e2fd7
--- /dev/null
+++ b/lib/rss/maker/itunes.rb
@@ -0,0 +1,248 @@
+require 'rss/itunes'
+require 'rss/maker/2.0'
+
+module RSS
+ module Maker
+ module ITunesBaseModel
+ def def_class_accessor(klass, name, type, *args)
+ name = name.gsub(/-/, "_").gsub(/^itunes_/, '')
+ full_name = "#{RSS::ITUNES_PREFIX}_#{name}"
+ case type
+ when nil
+ klass.def_other_element(full_name)
+ when :yes_other
+ def_yes_other_accessor(klass, full_name)
+ when :yes_clean_other
+ def_yes_clean_other_accessor(klass, full_name)
+ when :csv
+ def_csv_accessor(klass, full_name)
+ when :element, :attribute
+ recommended_attribute_name, = *args
+ klass_name = "ITunes#{Utils.to_class_name(name)}"
+ klass.def_classed_element(full_name, klass_name,
+ recommended_attribute_name)
+ when :elements
+ plural_name, recommended_attribute_name = args
+ plural_name ||= "#{name}s"
+ full_plural_name = "#{RSS::ITUNES_PREFIX}_#{plural_name}"
+ klass_name = "ITunes#{Utils.to_class_name(name)}"
+ plural_klass_name = "ITunes#{Utils.to_class_name(plural_name)}"
+ def_elements_class_accessor(klass, full_name, full_plural_name,
+ klass_name, plural_klass_name,
+ recommended_attribute_name)
+ end
+ end
+
+ def def_yes_other_accessor(klass, full_name)
+ klass.def_other_element(full_name)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{full_name}?
+ Utils::YesOther.parse(@#{full_name})
+ end
+ EOC
+ end
+
+ def def_yes_clean_other_accessor(klass, full_name)
+ klass.def_other_element(full_name)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{full_name}?
+ Utils::YesCleanOther.parse(#{full_name})
+ end
+ EOC
+ end
+
+ def def_csv_accessor(klass, full_name)
+ klass.def_other_element_without_accessor(full_name)
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ attr_reader :#{full_name}
+ def #{full_name}=(value)
+ @#{full_name} = Utils::CSV.parse(value)
+ end
+ EOC
+ end
+
+ def def_elements_class_accessor(klass, full_name, full_plural_name,
+ klass_name, plural_klass_name,
+ recommended_attribute_name=nil)
+ if recommended_attribute_name
+ klass.def_classed_elements(full_name, recommended_attribute_name,
+ plural_klass_name, full_plural_name)
+ else
+ klass.def_classed_element(full_plural_name, plural_klass_name)
+ end
+ klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def new_#{full_name}(text=nil)
+ #{full_name} = @#{full_plural_name}.new_#{full_name}
+ #{full_name}.text = text
+ if block_given?
+ yield #{full_name}
+ else
+ #{full_name}
+ end
+ end
+ EOC
+ end
+ end
+
+ module ITunesChannelModel
+ extend ITunesBaseModel
+
+ class << self
+ def append_features(klass)
+ super
+
+ ::RSS::ITunesChannelModel::ELEMENT_INFOS.each do |name, type, *args|
+ def_class_accessor(klass, name, type, *args)
+ end
+ end
+ end
+
+ class ITunesCategoriesBase < Base
+ def_array_element("category", "itunes_categories",
+ "ITunesCategory")
+ class ITunesCategoryBase < Base
+ attr_accessor :text
+ add_need_initialize_variable("text")
+ def_array_element("category", "itunes_categories",
+ "ITunesCategory")
+
+ def have_required_values?
+ text
+ end
+
+ alias_method :to_feed_for_categories, :to_feed
+ def to_feed(feed, current)
+ if text and current.respond_to?(:itunes_category)
+ new_item = current.class::ITunesCategory.new(text)
+ to_feed_for_categories(feed, new_item)
+ current.itunes_categories << new_item
+ end
+ end
+ end
+ end
+
+ class ITunesImageBase < Base
+ add_need_initialize_variable("href")
+ attr_accessor("href")
+
+ def to_feed(feed, current)
+ if @href and current.respond_to?(:itunes_image)
+ current.itunes_image ||= current.class::ITunesImage.new
+ current.itunes_image.href = @href
+ end
+ end
+ end
+
+ class ITunesOwnerBase < Base
+ %w(itunes_name itunes_email).each do |name|
+ add_need_initialize_variable(name)
+ attr_accessor(name)
+ end
+
+ def to_feed(feed, current)
+ if current.respond_to?(:itunes_owner=)
+ _not_set_required_variables = not_set_required_variables
+ if (required_variable_names - _not_set_required_variables).empty?
+ return
+ end
+
+ unless have_required_values?
+ raise NotSetError.new("maker.channel.itunes_owner",
+ _not_set_required_variables)
+ end
+ current.itunes_owner ||= current.class::ITunesOwner.new
+ current.itunes_owner.itunes_name = @itunes_name
+ current.itunes_owner.itunes_email = @itunes_email
+ end
+ end
+
+ private
+ def required_variable_names
+ %w(itunes_name itunes_email)
+ end
+ end
+ end
+
+ module ITunesItemModel
+ extend ITunesBaseModel
+
+ class << self
+ def append_features(klass)
+ super
+
+ ::RSS::ITunesItemModel::ELEMENT_INFOS.each do |name, type, *args|
+ def_class_accessor(klass, name, type, *args)
+ end
+ end
+ end
+
+ class ITunesDurationBase < Base
+ attr_reader :content
+ add_need_initialize_variable("content")
+
+ %w(hour minute second).each do |name|
+ attr_reader(name)
+ add_need_initialize_variable(name, '0')
+ end
+
+ def content=(content)
+ if content.nil?
+ @hour, @minute, @second, @content = nil
+ else
+ @hour, @minute, @second =
+ ::RSS::ITunesItemModel::ITunesDuration.parse(content)
+ @content = content
+ end
+ end
+
+ def hour=(hour)
+ @hour = Integer(hour)
+ update_content
+ end
+
+ def minute=(minute)
+ @minute = Integer(minute)
+ update_content
+ end
+
+ def second=(second)
+ @second = Integer(second)
+ update_content
+ end
+
+ def to_feed(feed, current)
+ if @content and current.respond_to?(:itunes_duration=)
+ current.itunes_duration ||= current.class::ITunesDuration.new
+ current.itunes_duration.content = @content
+ end
+ end
+
+ private
+ def update_content
+ components = [@hour, @minute, @second]
+ @content =
+ ::RSS::ITunesItemModel::ITunesDuration.construct(*components)
+ end
+ end
+ end
+
+ class ChannelBase
+ include Maker::ITunesChannelModel
+ class ITunesCategories < ITunesCategoriesBase
+ class ITunesCategory < ITunesCategoryBase
+ ITunesCategory = self
+ end
+ end
+
+ class ITunesImage < ITunesImageBase; end
+ class ITunesOwner < ITunesOwnerBase; end
+ end
+
+ class ItemsBase
+ class ItemBase
+ include Maker::ITunesItemModel
+ class ITunesDuration < ITunesDurationBase; end
+ end
+ end
+ end
+end
diff --git a/lib/rss/maker/syndication.rb b/lib/rss/maker/syndication.rb
index 3717086257..b81230457c 100644
--- a/lib/rss/maker/syndication.rb
+++ b/lib/rss/maker/syndication.rb
@@ -7,17 +7,8 @@ module RSS
def self.append_features(klass)
super
- ::RSS::SyndicationModel::ELEMENTS.each do |element|
- klass.add_need_initialize_variable(element)
- klass.add_other_element(element)
- klass.module_eval(<<-EOC, __FILE__, __LINE__+1)
- attr_accessor :#{element}
- def setup_#{element}(rss, current)
- if #{element} and current.respond_to?(:#{element}=)
- current.#{element} = @#{element} if @#{element}
- end
- end
- EOC
+ ::RSS::SyndicationModel::ELEMENTS.each do |name|
+ klass.def_other_element(name)
end
end
end
diff --git a/lib/rss/maker/taxonomy.rb b/lib/rss/maker/taxonomy.rb
index 2e53a4e1f4..798b239df9 100644
--- a/lib/rss/maker/taxonomy.rb
+++ b/lib/rss/maker/taxonomy.rb
@@ -8,18 +8,8 @@ module RSS
def self.append_features(klass)
super
- klass.add_need_initialize_variable("taxo_topics", "make_taxo_topics")
- klass.add_other_element("taxo_topics")
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
- attr_reader :taxo_topics
- def make_taxo_topics
- self.class::TaxonomyTopics.new(@maker)
- end
-
- def setup_taxo_topics(feed, current)
- @taxo_topics.to_feed(feed, current)
- end
-EOC
+ klass.def_classed_element("#{RSS::TAXO_PREFIX}_topics",
+ "TaxonomyTopics")
end
def self.install_taxo_topics(klass)
@@ -39,9 +29,7 @@ EOC
EOC
end
- class TaxonomyTopicsBase
- include Base
-
+ class TaxonomyTopicsBase < Base
attr_reader :resources
def_array_element("resource")
remove_method :new_resource
@@ -52,29 +40,10 @@ EOC
def self.append_features(klass)
super
- klass.add_need_initialize_variable("taxo_topics", "make_taxo_topics")
- klass.add_other_element("taxo_topics")
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
- attr_reader :taxo_topics
- def make_taxo_topics
- self.class::TaxonomyTopics.new(@maker)
- end
-
- def setup_taxo_topics(feed, current)
- @taxo_topics.to_feed(feed, current)
- end
-
- def taxo_topic
- @taxo_topics[0] and @taxo_topics[0].value
- end
-
- def taxo_topic=(new_value)
- @taxo_topic[0] = self.class::TaxonomyTopic.new(self)
- @taxo_topic[0].value = new_value
- end
-EOC
+ class_name = "TaxonomyTopics"
+ klass.def_classed_elements("#{TAXO_PREFIX}_topic", "value", class_name)
end
-
+
def self.install_taxo_topic(klass)
klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
class TaxonomyTopics < TaxonomyTopicsBase
@@ -96,13 +65,10 @@ EOC
EOC
end
- class TaxonomyTopicsBase
- include Base
-
- def_array_element("taxo_topic", nil, "self.class::TaxonomyTopic")
+ class TaxonomyTopicsBase < Base
+ def_array_element("taxo_topic", nil, "TaxonomyTopic")
- class TaxonomyTopicBase
- include Base
+ class TaxonomyTopicBase < Base
include DublinCoreModel
include TaxonomyTopicsModel
diff --git a/lib/rss/maker/trackback.rb b/lib/rss/maker/trackback.rb
index 09a2fceb2d..278fe53ebe 100644
--- a/lib/rss/maker/trackback.rb
+++ b/lib/rss/maker/trackback.rb
@@ -8,41 +8,15 @@ module RSS
def self.append_features(klass)
super
- name = "#{RSS::TRACKBACK_PREFIX}_ping"
- klass.add_need_initialize_variable(name)
- klass.add_other_element(name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
- attr_accessor :#{name}
- def setup_#{name}(feed, current)
- if #{name} and current.respond_to?(:#{name}=)
- current.#{name} = #{name}
- end
- end
- EOC
-
- name = "#{RSS::TRACKBACK_PREFIX}_abouts"
- klass.add_need_initialize_variable(name, "make_#{name}")
- klass.add_other_element(name)
- klass.module_eval(<<-EOC, __FILE__, __LINE__ + 1)
- attr_accessor :#{name}
- def make_#{name}
- self.class::TrackBackAbouts.new(self)
- end
-
- def setup_#{name}(feed, current)
- @#{name}.to_feed(feed, current)
- end
- EOC
+ klass.def_other_element("#{RSS::TRACKBACK_PREFIX}_ping")
+ klass.def_classed_elements("#{RSS::TRACKBACK_PREFIX}_about", "value",
+ "TrackBackAbouts")
end
- class TrackBackAboutsBase
- include Base
-
- def_array_element("about", nil, "self.class::TrackBackAbout")
-
- class TrackBackAboutBase
- include Base
+ class TrackBackAboutsBase < Base
+ def_array_element("about", nil, "TrackBackAbout")
+ class TrackBackAboutBase < Base
attr_accessor :value
add_need_initialize_variable("value")
diff --git a/lib/rss/parser.rb b/lib/rss/parser.rb
index f5ea2bbc03..b7a76397b8 100644
--- a/lib/rss/parser.rb
+++ b/lib/rss/parser.rb
@@ -222,25 +222,22 @@ module RSS
@@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)
+ def def_get_text_element(uri, element_name, file, line)
+ register_uri(uri, element_name)
+ method_name = "start_#{element_name}"
+ unless private_method_defined?(method_name)
+ define_method(method_name) do |name, prefix, attrs, ns|
uri = _ns(ns, prefix)
- if self.class.uri_registered?(uri, #{name.inspect})
+ if self.class.uri_registered?(uri, element_name)
start_get_text_element(name, prefix, ns, uri)
else
start_else_element(name, prefix, attrs, ns)
end
end
- EOT
- __send!("private", "start_#{name}")
+ private(method_name)
end
end
-
end
-
end
module ListenerMixin
@@ -368,10 +365,10 @@ module RSS
def start_else_element(local, prefix, attrs, ns)
class_name = self.class.class_name(_ns(ns, prefix), local)
current_class = @last_element.class
- if current_class.const_defined?(class_name)
+ next_class = nil
+ begin
next_class = current_class.const_get(class_name)
- start_have_something_element(local, prefix, attrs, ns, next_class)
- else
+ rescue NameError
if !@do_validate or @ignore_unknown_element
@proc_stack.push(nil)
else
@@ -382,6 +379,9 @@ module RSS
raise NotExpectedTagError.new(local, _ns(ns, prefix), parent)
end
end
+ if next_class
+ start_have_something_element(local, prefix, attrs, ns, next_class)
+ end
end
NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/
@@ -460,7 +460,7 @@ module RSS
previous = @last_element
next_element = klass.new(@do_validate, attributes)
- previous.__send!(:set_next_element, tag_name, next_element)
+ previous.set_next_element(tag_name, next_element)
@last_element = next_element
@last_element.parent = previous if klass.need_parent?
@xml_child_mode = @last_element.have_xml_content?
diff --git a/lib/rss/rss.rb b/lib/rss/rss.rb
index c0ce96d6bf..fb777b1d53 100644
--- a/lib/rss/rss.rb
+++ b/lib/rss/rss.rb
@@ -53,7 +53,7 @@ require "rss/xml-stylesheet"
module RSS
- VERSION = "0.1.7"
+ VERSION = "0.1.8"
URI = "http://purl.org/rss/1.0/"
@@ -162,7 +162,6 @@ module RSS
end
module BaseModel
-
include Utils
def install_have_child_element(tag_name, uri, occurs, name=nil, type=nil)
@@ -190,7 +189,7 @@ EOC
plural_name ||= "#{name}s"
add_have_children_element(name, plural_name)
add_plural_form(name, plural_name)
- install_model(tag_name, uri, occurs, plural_name)
+ install_model(tag_name, uri, occurs, plural_name, true)
def_children_accessor(name, plural_name)
install_element(name, "s") do |n, elem_name|
@@ -205,20 +204,26 @@ EOC
end
end
- def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
+ def install_text_element(tag_name, uri, occurs, name=nil, type=nil,
+ disp_name=nil)
name ||= tag_name
disp_name ||= name
self::ELEMENTS << name
add_need_initialize_variable(name)
install_model(tag_name, uri, occurs, name)
- def_corresponded_attr_writer name, type, disp_name
- convert_attr_reader name
+ def_corresponded_attr_writer(name, type, disp_name)
+ def_corresponded_attr_reader(name, type || :convert)
install_element(name) do |n, elem_name|
<<-EOC
- if @#{n}
+ if respond_to?(:#{n}_content)
+ content = #{n}_content
+ else
+ content = @#{n}
+ end
+ if content
rv = "\#{indent}<#{elem_name}>"
- value = html_escape(@#{n})
+ value = html_escape(content)
if need_convert
rv << convert(value)
else
@@ -331,6 +336,46 @@ EOC
end
end
+ def yes_clean_other_attr_reader(*attrs)
+ attrs.each do |attr|
+ attr = attr.id2name if attr.kind_of?(Integer)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ attr_reader(:#{attr})
+ def #{attr}?
+ YesCleanOther.parse(@#{attr})
+ end
+ EOC
+ end
+ end
+
+ def yes_other_attr_reader(*attrs)
+ attrs.each do |attr|
+ attr = attr.id2name if attr.kind_of?(Integer)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ attr_reader(:#{attr})
+ def #{attr}?
+ Utils::YesOther.parse(@#{attr})
+ end
+ EOC
+ end
+ end
+
+ def csv_attr_reader(*attrs)
+ attrs.each do |attr|
+ attr = attr.id2name if attr.kind_of?(Integer)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ attr_reader(:#{attr})
+ def #{attr}_content
+ if @#{attr}.nil?
+ @#{attr}
+ else
+ @#{attr}.join(", ")
+ end
+ end
+ EOC
+ end
+ end
+
def date_writer(name, type, disp_name=name)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{name}=(new_value)
@@ -458,6 +503,34 @@ EOC
EOC
end
+ def yes_clean_other_writer(name, disp_name=name)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{name}=(value)
+ value = (value ? "yes" : "no") if [true, false].include?(value)
+ @#{name} = value
+ end
+ EOC
+ end
+
+ def yes_other_writer(name, disp_name=name)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{name}=(new_value)
+ if [true, false].include?(new_value)
+ new_value = new_value ? "yes" : "no"
+ end
+ @#{name} = new_value
+ end
+ EOC
+ end
+
+ def csv_writer(name, disp_name=name)
+ module_eval(<<-EOC, __FILE__, __LINE__ + 1)
+ def #{name}=(new_value)
+ @#{name} = Utils::CSV.parse(new_value)
+ end
+ EOC
+ end
+
def def_children_accessor(accessor_name, plural_name)
module_eval(<<-EOC, *get_file_and_line_from_caller(2))
def #{plural_name}
@@ -511,6 +584,7 @@ EOC
def setup_maker_element(target)
self.class.need_initialize_variables.each do |var|
value = __send__(var)
+ next if value.nil?
if value.respond_to?("setup_maker") and
!not_need_to_call_setup_maker_variables.include?(var)
value.setup_maker(target)
@@ -540,9 +614,9 @@ EOC
end
class Element
-
extend BaseModel
include Utils
+ extend Utils::InheritedReader
include SetupMaker
INDENT = " "
@@ -554,32 +628,34 @@ EOC
TO_ELEMENT_METHODS = []
NEED_INITIALIZE_VARIABLES = []
PLURAL_FORMS = {}
-
- class << self
+ class << self
def must_call_validators
- MUST_CALL_VALIDATORS
+ inherited_hash_reader("MUST_CALL_VALIDATORS")
end
def models
- MODELS
+ inherited_array_reader("MODELS")
end
def get_attributes
- GET_ATTRIBUTES
+ inherited_array_reader("GET_ATTRIBUTES")
end
def have_children_elements
- HAVE_CHILDREN_ELEMENTS
+ inherited_array_reader("HAVE_CHILDREN_ELEMENTS")
end
def to_element_methods
- TO_ELEMENT_METHODS
+ inherited_array_reader("TO_ELEMENT_METHODS")
end
def need_initialize_variables
- NEED_INITIALIZE_VARIABLES
+ inherited_array_reader("NEED_INITIALIZE_VARIABLES")
end
def plural_forms
- PLURAL_FORMS
+ inherited_hash_reader("PLURAL_FORMS")
+ end
+
+ def inherited_base
+ ::RSS::Element
end
-
def inherited(klass)
klass.const_set("MUST_CALL_VALIDATORS", {})
klass.const_set("MODELS", [])
@@ -589,123 +665,108 @@ EOC
klass.const_set("NEED_INITIALIZE_VARIABLES", [])
klass.const_set("PLURAL_FORMS", {})
- klass.module_eval(<<-EOC)
- public
-
- @tag_name = name.split(/::/).last
- @tag_name[0,1] = @tag_name[0,1].downcase
- @have_content = false
+ tag_name = klass.name.split(/::/).last
+ tag_name[0, 1] = tag_name[0, 1].downcase
+ klass.instance_variable_set("@tag_name", tag_name)
+ klass.instance_variable_set("@have_content", false)
+ end
- def self.must_call_validators
- super.merge(MUST_CALL_VALIDATORS)
- end
- def self.models
- MODELS + super
- end
- def self.get_attributes
- GET_ATTRIBUTES + super
- end
- def self.have_children_elements
- HAVE_CHILDREN_ELEMENTS + super
- end
- def self.to_element_methods
- TO_ELEMENT_METHODS + super
- end
- def self.need_initialize_variables
- NEED_INITIALIZE_VARIABLES + super
- end
- def self.plural_forms
- super.merge(PLURAL_FORMS)
+ def install_must_call_validator(prefix, uri)
+ self::MUST_CALL_VALIDATORS[uri] = prefix
+ end
+
+ def install_model(tag, uri, occurs=nil, getter=nil, plural=false)
+ getter ||= tag
+ if m = self::MODELS.find {|t, u, o, g, p| t == tag and u == uri}
+ m[2] = occurs
+ else
+ self::MODELS << [tag, uri, occurs, getter, plural]
end
+ end
-
- def self.install_must_call_validator(prefix, uri)
- MUST_CALL_VALIDATORS[uri] = prefix
+ def install_get_attribute(name, uri, required=true,
+ type=nil, disp_name=nil,
+ element_name=nil)
+ disp_name ||= name
+ element_name ||= name
+ writer_type, reader_type = type
+ def_corresponded_attr_writer name, writer_type, disp_name
+ def_corresponded_attr_reader name, reader_type
+ if type == :boolean and /^is/ =~ name
+ alias_method "#{$POSTMATCH}?", name
end
-
- def self.install_model(tag, uri, occurs=nil, getter=nil)
- getter ||= tag
- if m = MODELS.find {|t, u, o, g| t == tag and u == uri}
- m[2] = occurs
- else
- MODELS << [tag, uri, occurs, getter]
- end
+ self::GET_ATTRIBUTES << [name, uri, required, element_name]
+ add_need_initialize_variable(disp_name)
+ end
+
+ def def_corresponded_attr_writer(name, type=nil, disp_name=nil)
+ disp_name ||= name
+ case type
+ when :integer
+ integer_writer name, disp_name
+ when :positive_integer
+ positive_integer_writer name, disp_name
+ when :boolean
+ boolean_writer name, disp_name
+ when :w3cdtf, :rfc822, :rfc2822
+ date_writer name, type, disp_name
+ when :text_type
+ text_type_writer name, disp_name
+ when :content
+ content_writer name, disp_name
+ when :yes_clean_other
+ yes_clean_other_writer name, disp_name
+ when :yes_other
+ yes_other_writer name, disp_name
+ when :csv
+ csv_writer name
+ else
+ attr_writer name
end
+ end
- def self.install_get_attribute(name, uri, required=true,
- type=nil, disp_name=nil,
- element_name=nil)
- disp_name ||= name
- element_name ||= name
- 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, element_name]
- add_need_initialize_variable(disp_name)
+ def def_corresponded_attr_reader(name, type=nil)
+ case type
+ when :inherit
+ inherit_convert_attr_reader name
+ when :uri
+ uri_convert_attr_reader name
+ when :yes_clean_other
+ yes_clean_other_attr_reader name
+ when :yes_other
+ yes_other_attr_reader name
+ when :csv
+ csv_attr_reader name
+ else
+ convert_attr_reader name
end
+ end
- def self.def_corresponded_attr_writer(name, type=nil, disp_name=nil)
- disp_name ||= name
- case type
- when :integer
- integer_writer name, disp_name
- when :positive_integer
- positive_integer_writer name, disp_name
- when :boolean
- boolean_writer name, disp_name
- when :w3cdtf, :rfc822, :rfc2822
- date_writer name, type, disp_name
- when :text_type
- text_type_writer name, disp_name
- when :content
- content_writer name, disp_name
- else
- attr_writer name
- end
- end
+ def content_setup(type=nil, disp_name=nil)
+ writer_type, reader_type = type
+ def_corresponded_attr_writer :content, writer_type, disp_name
+ def_corresponded_attr_reader :content, reader_type
+ @have_content = true
+ end
- def self.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 have_content?
+ @have_content
+ 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
+ def add_have_children_element(variable_name, plural_name)
+ self::HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
+ end
- def self.have_content?
- @have_content
- end
+ def add_to_element_method(method_name)
+ self::TO_ELEMENT_METHODS << method_name
+ end
- def self.add_have_children_element(variable_name, plural_name)
- HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
- end
-
- def self.add_to_element_method(method_name)
- TO_ELEMENT_METHODS << method_name
- end
+ def add_need_initialize_variable(variable_name)
+ self::NEED_INITIALIZE_VARIABLES << variable_name
+ end
- def self.add_need_initialize_variable(variable_name)
- NEED_INITIALIZE_VARIABLES << variable_name
- end
-
- def self.add_plural_form(singular, plural)
- PLURAL_FORMS[singular] = plural
- end
-
- EOC
+ def add_plural_form(singular, plural)
+ self::PLURAL_FORMS[singular] = plural
end
def required_prefix
@@ -719,7 +780,7 @@ EOC
def need_parent?
false
end
-
+
def install_ns(prefix, uri)
if self::NSPOOL.has_key?(prefix)
raise OverlappedPrefixError.new(prefix)
@@ -821,6 +882,36 @@ EOC
false
end
+ def set_next_element(tag_name, next_element)
+ klass = next_element.class
+ prefix = ""
+ prefix << "#{klass.required_prefix}_" if klass.required_prefix
+ key = "#{prefix}#{tag_name.gsub(/-/, '_')}"
+ if self.class.plural_forms.has_key?(key)
+ ary = __send__("#{self.class.plural_forms[key]}")
+ ary << next_element
+ else
+ __send__("#{key}=", next_element)
+ end
+ end
+
+ protected
+ def have_required_elements?
+ self.class::MODELS.all? do |tag, uri, occurs, getter|
+ if occurs.nil? or occurs == "+"
+ child = __send__(getter)
+ if child.is_a?(Array)
+ children = child
+ children.any? {|c| c.have_required_elements?}
+ else
+ !child.to_s.empty?
+ end
+ else
+ true
+ end
+ end
+ end
+
private
def initialize_variables(attrs)
normalized_attrs = {}
@@ -832,7 +923,7 @@ EOC
if value
__send__("#{variable_name}=", value)
else
- instance_eval("@#{variable_name} = nil")
+ instance_variable_set("@#{variable_name}", nil)
end
end
initialize_have_children_elements
@@ -841,7 +932,7 @@ EOC
def initialize_have_children_elements
self.class.have_children_elements.each do |variable_name, plural_name|
- instance_eval("@#{variable_name} = []")
+ instance_variable_set("@#{variable_name}", [])
end
end
@@ -911,19 +1002,6 @@ EOC
''
end
- def set_next_element(tag_name, next_element)
- klass = next_element.class
- prefix = ""
- prefix << "#{klass.required_prefix}_" if klass.required_prefix
- key = "#{prefix}#{tag_name}"
- if self.class.plural_forms.has_key?(key)
- ary = __send__("#{self.class.plural_forms[key]}")
- ary << next_element
- else
- __send__("#{prefix}#{tag_name}=", next_element)
- end
- end
-
def children
rv = []
self.class.models.each do |name, uri, occurs, getter|
@@ -939,10 +1017,10 @@ EOC
def _tags
rv = []
- self.class.models.each do |name, uri, occurs, getter|
+ self.class.models.each do |name, uri, occurs, getter, plural|
value = __send__(getter)
next if value.nil?
- if value.is_a?(Array)
+ if plural and value.is_a?(Array)
rv.concat([[uri, name]] * value.size)
else
rv << [uri, name]
@@ -997,11 +1075,12 @@ EOC
tags = tags.sort_by {|x| element_names.index(x) || tags_size}
end
+ _tags = tags.dup if tags
models.each_with_index do |model, i|
name, model_uri, occurs, getter = model
if DEBUG
- p "before"
+ p "before"
p tags
p model
end
@@ -1095,7 +1174,7 @@ EOC
if have_xml_content?
__send__(self.class.xml_getter)
else
- @content
+ content
end
end
@@ -1103,25 +1182,9 @@ EOC
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
+ _content = content
+ _content = Base64.encode64(_content) if need_base64_encode?
+ h(_content)
end
end
end
diff --git a/lib/rss/utils.rb b/lib/rss/utils.rb
index 031ff3072b..0b53a19d3b 100644
--- a/lib/rss/utils.rb
+++ b/lib/rss/utils.rb
@@ -2,14 +2,16 @@ module RSS
module Utils
module_function
def to_class_name(name)
- name.split(/_/).collect do |part|
+ name.split(/[_\-]/).collect do |part|
"#{part[0, 1].upcase}#{part[1..-1]}"
end.join("")
end
def get_file_and_line_from_caller(i=0)
file, line, = caller[i].split(':')
- [file, line.to_i]
+ line = line.to_i
+ line += 1 if i.zero?
+ [file, line]
end
def html_escape(s)
@@ -28,5 +30,75 @@ module RSS
def element_initialize_arguments?(args)
[true, false].include?(args[0]) and args[1].is_a?(Hash)
end
+
+ module YesCleanOther
+ module_function
+ def parse(value)
+ if [true, false, nil].include?(value)
+ value
+ else
+ case value.to_s
+ when /\Ayes\z/i
+ true
+ when /\Aclean\z/i
+ false
+ else
+ nil
+ end
+ end
+ end
+ end
+
+ module YesOther
+ module_function
+ def parse(value)
+ if [true, false].include?(value)
+ value
+ else
+ /\Ayes\z/i.match(value.to_s) ? true : false
+ end
+ end
+ end
+
+ module CSV
+ module_function
+ def parse(value)
+ if value.is_a?(String)
+ value.strip.split(/\s*,\s*/)
+ else
+ value
+ end
+ end
+ end
+
+ module InheritedReader
+ def inherited_reader(constant_name)
+ base_class = inherited_base
+ result = base_class.const_get(constant_name)
+ found_base_class = false
+ ancestors.reverse_each do |klass|
+ if found_base_class
+ if klass.const_defined?(constant_name)
+ result = yield(result, klass.const_get(constant_name))
+ end
+ else
+ found_base_class = klass == base_class
+ end
+ end
+ result
+ end
+
+ def inherited_array_reader(constant_name)
+ inherited_reader(constant_name) do |result, current|
+ current + result
+ end
+ end
+
+ def inherited_hash_reader(constant_name)
+ inherited_reader(constant_name) do |result, current|
+ result.merge(current)
+ end
+ end
+ end
end
end