/tools/Ruby/lib/ruby/1.8/rss/itunes.rb

http://github.com/agross/netopenspace · Ruby · 410 lines · 341 code · 69 blank · 0 comment · 20 complexity · 6f012364b67f3552bf2a71945932e3fc MD5 · raw file

  1. require 'rss/2.0'
  2. module RSS
  3. ITUNES_PREFIX = 'itunes'
  4. ITUNES_URI = 'http://www.itunes.com/dtds/podcast-1.0.dtd'
  5. Rss.install_ns(ITUNES_PREFIX, ITUNES_URI)
  6. module ITunesModelUtils
  7. include Utils
  8. def def_class_accessor(klass, name, type, *args)
  9. normalized_name = name.gsub(/-/, "_")
  10. full_name = "#{ITUNES_PREFIX}_#{normalized_name}"
  11. klass_name = "ITunes#{Utils.to_class_name(normalized_name)}"
  12. case type
  13. when :element, :attribute
  14. klass::ELEMENTS << full_name
  15. def_element_class_accessor(klass, name, full_name, klass_name, *args)
  16. when :elements
  17. klass::ELEMENTS << full_name
  18. def_elements_class_accessor(klass, name, full_name, klass_name, *args)
  19. else
  20. klass.install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
  21. klass.install_text_element(normalized_name, ITUNES_URI, "?",
  22. full_name, type, name)
  23. end
  24. end
  25. def def_element_class_accessor(klass, name, full_name, klass_name,
  26. recommended_attribute_name=nil)
  27. klass.install_have_child_element(name, ITUNES_PREFIX, "?", full_name)
  28. end
  29. def def_elements_class_accessor(klass, name, full_name, klass_name,
  30. plural_name, recommended_attribute_name=nil)
  31. full_plural_name = "#{ITUNES_PREFIX}_#{plural_name}"
  32. klass.install_have_children_element(name, ITUNES_PREFIX, "*",
  33. full_name, full_plural_name)
  34. end
  35. end
  36. module ITunesBaseModel
  37. extend ITunesModelUtils
  38. ELEMENTS = []
  39. ELEMENT_INFOS = [["author"],
  40. ["block", :yes_other],
  41. ["explicit", :yes_clean_other],
  42. ["keywords", :csv],
  43. ["subtitle"],
  44. ["summary"]]
  45. end
  46. module ITunesChannelModel
  47. extend BaseModel
  48. extend ITunesModelUtils
  49. include ITunesBaseModel
  50. ELEMENTS = []
  51. class << self
  52. def append_features(klass)
  53. super
  54. return if klass.instance_of?(Module)
  55. ELEMENT_INFOS.each do |name, type, *additional_infos|
  56. def_class_accessor(klass, name, type, *additional_infos)
  57. end
  58. end
  59. end
  60. ELEMENT_INFOS = [
  61. ["category", :elements, "categories", "text"],
  62. ["image", :attribute, "href"],
  63. ["owner", :element],
  64. ["new-feed-url"],
  65. ] + ITunesBaseModel::ELEMENT_INFOS
  66. class ITunesCategory < Element
  67. include RSS09
  68. @tag_name = "category"
  69. class << self
  70. def required_prefix
  71. ITUNES_PREFIX
  72. end
  73. def required_uri
  74. ITUNES_URI
  75. end
  76. end
  77. [
  78. ["text", "", true]
  79. ].each do |name, uri, required|
  80. install_get_attribute(name, uri, required)
  81. end
  82. ITunesCategory = self
  83. install_have_children_element("category", ITUNES_URI, "*",
  84. "#{ITUNES_PREFIX}_category",
  85. "#{ITUNES_PREFIX}_categories")
  86. def initialize(*args)
  87. if Utils.element_initialize_arguments?(args)
  88. super
  89. else
  90. super()
  91. self.text = args[0]
  92. end
  93. end
  94. def full_name
  95. tag_name_with_prefix(ITUNES_PREFIX)
  96. end
  97. private
  98. def maker_target(categories)
  99. if text or !itunes_categories.empty?
  100. categories.new_category
  101. else
  102. nil
  103. end
  104. end
  105. def setup_maker_attributes(category)
  106. category.text = text if text
  107. end
  108. def setup_maker_elements(category)
  109. super(category)
  110. itunes_categories.each do |sub_category|
  111. sub_category.setup_maker(category)
  112. end
  113. end
  114. end
  115. class ITunesImage < Element
  116. include RSS09
  117. @tag_name = "image"
  118. class << self
  119. def required_prefix
  120. ITUNES_PREFIX
  121. end
  122. def required_uri
  123. ITUNES_URI
  124. end
  125. end
  126. [
  127. ["href", "", true]
  128. ].each do |name, uri, required|
  129. install_get_attribute(name, uri, required)
  130. end
  131. def initialize(*args)
  132. if Utils.element_initialize_arguments?(args)
  133. super
  134. else
  135. super()
  136. self.href = args[0]
  137. end
  138. end
  139. def full_name
  140. tag_name_with_prefix(ITUNES_PREFIX)
  141. end
  142. private
  143. def maker_target(target)
  144. if href
  145. target.itunes_image {|image| image}
  146. else
  147. nil
  148. end
  149. end
  150. def setup_maker_attributes(image)
  151. image.href = href
  152. end
  153. end
  154. class ITunesOwner < Element
  155. include RSS09
  156. @tag_name = "owner"
  157. class << self
  158. def required_prefix
  159. ITUNES_PREFIX
  160. end
  161. def required_uri
  162. ITUNES_URI
  163. end
  164. end
  165. install_must_call_validator(ITUNES_PREFIX, ITUNES_URI)
  166. [
  167. ["name"],
  168. ["email"],
  169. ].each do |name,|
  170. ITunesBaseModel::ELEMENT_INFOS << name
  171. install_text_element(name, ITUNES_URI, nil, "#{ITUNES_PREFIX}_#{name}")
  172. end
  173. def initialize(*args)
  174. if Utils.element_initialize_arguments?(args)
  175. super
  176. else
  177. super()
  178. self.itunes_name = args[0]
  179. self.itunes_email = args[1]
  180. end
  181. end
  182. def full_name
  183. tag_name_with_prefix(ITUNES_PREFIX)
  184. end
  185. private
  186. def maker_target(target)
  187. target.itunes_owner
  188. end
  189. def setup_maker_element(owner)
  190. super(owner)
  191. owner.itunes_name = itunes_name
  192. owner.itunes_email = itunes_email
  193. end
  194. end
  195. end
  196. module ITunesItemModel
  197. extend BaseModel
  198. extend ITunesModelUtils
  199. include ITunesBaseModel
  200. class << self
  201. def append_features(klass)
  202. super
  203. return if klass.instance_of?(Module)
  204. ELEMENT_INFOS.each do |name, type|
  205. def_class_accessor(klass, name, type)
  206. end
  207. end
  208. end
  209. ELEMENT_INFOS = ITunesBaseModel::ELEMENT_INFOS +
  210. [["duration", :element, "content"]]
  211. class ITunesDuration < Element
  212. include RSS09
  213. @tag_name = "duration"
  214. class << self
  215. def required_prefix
  216. ITUNES_PREFIX
  217. end
  218. def required_uri
  219. ITUNES_URI
  220. end
  221. def parse(duration, do_validate=true)
  222. if do_validate and /\A(?:
  223. \d?\d:[0-5]\d:[0-5]\d|
  224. [0-5]?\d:[0-5]\d
  225. )\z/x !~ duration
  226. raise ArgumentError,
  227. "must be one of HH:MM:SS, H:MM:SS, MM::SS, M:SS: " +
  228. duration.inspect
  229. end
  230. components = duration.split(':')
  231. components[3..-1] = nil if components.size > 3
  232. components.unshift("00") until components.size == 3
  233. components.collect do |component|
  234. component.to_i
  235. end
  236. end
  237. def construct(hour, minute, second)
  238. components = [minute, second]
  239. if components.include?(nil)
  240. nil
  241. else
  242. components.unshift(hour) if hour and hour > 0
  243. components.collect do |component|
  244. "%02d" % component
  245. end.join(":")
  246. end
  247. end
  248. end
  249. content_setup
  250. alias_method(:value, :content)
  251. remove_method(:content=)
  252. attr_reader :hour, :minute, :second
  253. def initialize(*args)
  254. if Utils.element_initialize_arguments?(args)
  255. super
  256. else
  257. super()
  258. args = args[0] if args.size == 1 and args[0].is_a?(Array)
  259. if args.size == 1
  260. self.content = args[0]
  261. elsif args.size > 3
  262. raise ArgumentError,
  263. "must be (do_validate, params), (content), " +
  264. "(minute, second), ([minute, second]), " +
  265. "(hour, minute, second) or ([hour, minute, second]): " +
  266. args.inspect
  267. else
  268. @second, @minute, @hour = args.reverse
  269. update_content
  270. end
  271. end
  272. end
  273. def content=(value)
  274. if value.nil?
  275. @content = nil
  276. elsif value.is_a?(self.class)
  277. self.content = value.content
  278. else
  279. begin
  280. @hour, @minute, @second = self.class.parse(value, @do_validate)
  281. rescue ArgumentError
  282. raise NotAvailableValueError.new(tag_name, value)
  283. end
  284. @content = value
  285. end
  286. end
  287. alias_method(:value=, :content=)
  288. def hour=(hour)
  289. @hour = @do_validate ? Integer(hour) : hour.to_i
  290. update_content
  291. hour
  292. end
  293. def minute=(minute)
  294. @minute = @do_validate ? Integer(minute) : minute.to_i
  295. update_content
  296. minute
  297. end
  298. def second=(second)
  299. @second = @do_validate ? Integer(second) : second.to_i
  300. update_content
  301. second
  302. end
  303. def full_name
  304. tag_name_with_prefix(ITUNES_PREFIX)
  305. end
  306. private
  307. def update_content
  308. @content = self.class.construct(hour, minute, second)
  309. end
  310. def maker_target(target)
  311. if @content
  312. target.itunes_duration {|duration| duration}
  313. else
  314. nil
  315. end
  316. end
  317. def setup_maker_element(duration)
  318. super(duration)
  319. duration.content = @content
  320. end
  321. end
  322. end
  323. class Rss
  324. class Channel
  325. include ITunesChannelModel
  326. class Item; include ITunesItemModel; end
  327. end
  328. end
  329. element_infos =
  330. ITunesChannelModel::ELEMENT_INFOS + ITunesItemModel::ELEMENT_INFOS
  331. element_infos.each do |name, type|
  332. case type
  333. when :element, :elements, :attribute
  334. class_name = Utils.to_class_name(name)
  335. BaseListener.install_class_name(ITUNES_URI, name, "ITunes#{class_name}")
  336. else
  337. accessor_base = "#{ITUNES_PREFIX}_#{name.gsub(/-/, '_')}"
  338. BaseListener.install_get_text_element(ITUNES_URI, name, accessor_base)
  339. end
  340. end
  341. end