ruby/lib/rss/itunes.rb

411 строки
10 KiB
Ruby

require 'rss/2.0'
module RSS
ITUNES_PREFIX = 'itunes'
ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
module ITunesModelUtils
include Utils
def def_class_accessor(klass, name, type, *args)
normalized_name = name.gsub(/-/, "_")
full_name = "#{ITUNES_PREFIX}_#{normalized_name}"
klass_name = "ITunes#{Utils.to_class_name(normalized_name)}"
case type
when :element, :attribute
klass::ELEMENTS << full_name
def_element_class_accessor(klass, name, full_name, klass_name, *args)
when :elements
klass::ELEMENTS << full_name
def_elements_class_accessor(klass, name, full_name, klass_name, *args)
else
klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
klass.install_text_element(normalized_name, ITUNES_URI, "?",
full_name, type, name)
end
end
def def_element_class_accessor(klass, name, full_name, klass_name,
recommended_attribute_name=nil)
klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name)
end
def def_elements_class_accessor(klass, name, full_name, klass_name,
plural_name, recommended_attribute_name=nil)
full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}"
klass.install_have_children_element(name, ITUNES_PREFIX, "*",
full_name, full_plural_name)
end
end
module ITunesBaseModel
extend ITunesModelUtils
ELEMENTS = []
ELEMENT_INFOS = [["author"],
["block", :yes_other],
["explicit", :yes_clean_other],
["keywords", :csv],
["subtitle"],
["summary"]]
end
module ITunesChannelModel
extend BaseModel
extend ITunesModelUtils
include ITunesBaseModel
ELEMENTS = []
class << self
def append_features(klass)
super
return if klass.instance_of?(Module)
ELEMENT_INFOS.each do |name, type, *additional_infos|
def_class_accessor(klass, name, type, *additional_infos)
end
end
end
ELEMENT_INFOS = [
["category", :elements, "categories", "text"],
["image", :attribute, "href"],
["owner", :element],
["new-feed-url"],
] + ITunesBaseModel::ELEMENT_INFOS
class ITunesCategory < Element
include RSS09
@tag_name = "category"
class << self
def required_prefix
ITUNES_PREFIX
end
def required_uri
ITUNES_URI
end
end
[
["text", "", true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
ITunesCategory = self
install_have_children_element("category", ITUNES_URI, "*",
"#{ITUNES_PREFIX}_category",
"#{ITUNES_PREFIX}_categories")
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
else
super()
self.text = args[0]
end
end
def full_name
tag_name_with_prefix(ITUNES_PREFIX)
end
private
def maker_target(categories)
if text or !itunes_categories.empty?
categories.new_category
else
nil
end
end
def setup_maker_attributes(category)
category.text = text if text
end
def setup_maker_elements(category)
super(category)
itunes_categories.each do |sub_category|
sub_category.setup_maker(category)
end
end
end
class ITunesImage < Element
include RSS09
@tag_name = "image"
class << self
def required_prefix
ITUNES_PREFIX
end
def required_uri
ITUNES_URI
end
end
[
["href", "", true]
].each do |name, uri, required|
install_get_attribute(name, uri, required)
end
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
else
super()
self.href = args[0]
end
end
def full_name
tag_name_with_prefix(ITUNES_PREFIX)
end
private
def maker_target(target)
if href
target.itunes_image {|image| image}
else
nil
end
end
def setup_maker_attributes(image)
image.href = href
end
end
class ITunesOwner < Element
include RSS09
@tag_name = "owner"
class << self
def required_prefix
ITUNES_PREFIX
end
def required_uri
ITUNES_URI
end
end
install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
[
["name"],
["email"],
].each do |name,|
ITunesBaseModel::ELEMENT_INFOS << name
install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}")
end
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
else
super()
self.itunes_name = args[0]
self.itunes_email = args[1]
end
end
def full_name
tag_name_with_prefix(ITUNES_PREFIX)
end
private
def maker_target(target)
target.itunes_owner
end
def setup_maker_element(owner)
super(owner)
owner.itunes_name = itunes_name
owner.itunes_email = itunes_email
end
end
end
module ITunesItemModel
extend BaseModel
extend ITunesModelUtils
include ITunesBaseModel
class << self
def append_features(klass)
super
return if klass.instance_of?(Module)
ELEMENT_INFOS.each do |name, type|
def_class_accessor(klass, name, type)
end
end
end
ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS +
[["duration", :element, "content"]]
class ITunesDuration < Element
include RSS09
@tag_name = "duration"
class << self
def required_prefix
ITUNES_PREFIX
end
def required_uri
ITUNES_URI
end
def parse(duration, do_validate=true)
if do_validate and /\A(?:
\d?\d:[0-5]\d:[0-5]\d|
[0-5]?\d:[0-5]\d
)\z/x !~ duration
raise ArgumentError,
"must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " +
duration.inspect
end
components = duration.split(':')
components[3..-1] = nil if components.size > 3
components.unshift("00") until components.size == 3
components.collect do |component|
component.to_i
end
end
def construct(hour, minute, second)
components = [minute, second]
if components.include?(nil)
nil
else
components.unshift(hour) if hour and hour > 0
components.collect do |component|
"%02d" % component
end.join(":")
end
end
end
content_setup
alias_method(:value, :content)
remove_method(:content=)
attr_reader :hour, :minute, :second
def initialize(*args)
if Utils.element_initialize_arguments?(args)
super
else
super()
args = args[0] if args.size == 1 and args[0].is_a?(Array)
if args.size == 1
self.content = args[0]
elsif args.size > 3
raise ArgumentError,
"must be (do_validate, params), (content), " +
"(minute, second), ([minute, second]), " +
"(hour, minute, second) or ([hour, minute, second]): " +
args.inspect
else
@second, @minute, @hour = args.reverse
update_content
end
end
end
def content=(value)
if value.nil?
@content = nil
elsif value.is_a?(self.class)
self.content = value.content
else
begin
@hour, @minute, @second = self.class.parse(value, @do_validate)
rescue ArgumentError
raise NotAvailableValueError.new(tag_name, value)
end
@content = value
end
end
alias_method(:value=, :content=)
def hour=(hour)
@hour = @do_validate ? Integer(hour) : hour.to_i
update_content
hour
end
def minute=(minute)
@minute = @do_validate ? Integer(minute) : minute.to_i
update_content
minute
end
def second=(second)
@second = @do_validate ? Integer(second) : second.to_i
update_content
second
end
def full_name
tag_name_with_prefix(ITUNES_PREFIX)
end
private
def update_content
@content = self.class.construct(hour, minute, second)
end
def maker_target(target)
if @content
target.itunes_duration {|duration| duration}
else
nil
end
end
def setup_maker_element(duration)
super(duration)
duration.content = @content
end
end
end
class Rss
class Channel
include ITunesChannelModel
class Item; include ITunesItemModel; end
end
end
element_infos =
ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS
element_infos.each do |name, type|
case type
when :element, :elements, :attribute
class_name = Utils.to_class_name(name)
BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}")
else
accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}"
BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base)
end
end
end