diff options
Diffstat (limited to 'ruby_1_8_6/lib/rss')
28 files changed, 5782 insertions, 0 deletions
diff --git a/ruby_1_8_6/lib/rss/0.9.rb b/ruby_1_8_6/lib/rss/0.9.rb new file mode 100644 index 0000000000..69e01ddd57 --- /dev/null +++ b/ruby_1_8_6/lib/rss/0.9.rb @@ -0,0 +1,422 @@ +require "rss/parser" + +module RSS + + module RSS09 + NSPOOL = {} + ELEMENTS = [] + + def self.append_features(klass) + super + + klass.install_must_call_validator('', "") + end + end + + class Rss < Element + + include RSS09 + include RootElementMixin + + %w(channel).each do |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) + super + end + + def items + if @channel + @channel.items + else + [] + end + end + + def image + if @channel + @channel.image + else + nil + end + end + + def textinput + if @channel + @channel.textInput + else + nil + end + end + + def setup_maker_elements(maker) + super + items.each do |item| + item.setup_maker(maker.items) + end + end + + private + def _attrs + [ + ["version", true, "rss_version"], + ] + end + + class Channel < Element + + include RSS09 + + [ + ["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= + + private + def maker_target(maker) + maker.channel + end + + def setup_maker_elements(channel) + super + [ + [skipDays, "day"], + [skipHours, "hour"], + ].each do |skip, key| + if skip + skip.__send__("#{key}s").each do |val| + target_skips = channel.__send__("skip#{key.capitalize}s") + new_target = target_skips.__send__("new_#{key}") + new_target.content = val.content + end + end + end + end + + def not_need_to_call_setup_maker_variables + %w(image textInput) + end + + class SkipDays < Element + include RSS09 + + [ + ["day", "*"] + ].each do |name, occurs| + install_have_children_element(name, "", occurs) + end + + class Day < Element + include RSS09 + + content_setup + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.content = args[0] + end + end + + end + + end + + class SkipHours < Element + include RSS09 + + [ + ["hour", "*"] + ].each do |name, occurs| + install_have_children_element(name, "", occurs) + end + + class Hour < Element + include RSS09 + + content_setup(:integer) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.content = args[0] + end + end + end + + end + + class Image < Element + + include RSS09 + + %w(url title link).each do |name| + install_text_element(name, "", nil) + end + [ + ["width", :integer], + ["height", :integer], + ["description"], + ].each do |name, type| + install_text_element(name, "", "?", name, type) + end + + 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 + end + + private + def maker_target(maker) + maker.image + end + end + + class Cloud < Element + + include RSS09 + + [ + ["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(*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 + + [ + ["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 maker_target(items) + if items.respond_to?("items") + # For backward compatibility + items = items.items + end + items.new_item + end + + def setup_maker_element(item) + super + @enclosure.setup_maker(item) if @enclosure + @source.setup_maker(item) if @source + end + + class Source < Element + + include RSS09 + + [ + ["url", "", true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required) + end + + content_setup + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.url = args[0] + self.content = args[1] + end + end + + private + def maker_target(item) + item.source + end + + def setup_maker_attributes(source) + source.url = url + source.content = content + end + end + + class Enclosure < Element + + include RSS09 + + [ + ["url", "", true], + ["length", "", true, :integer], + ["type", "", true], + ].each do |name, uri, required, type| + install_get_attribute(name, uri, required, type) + end + + 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 maker_target(item) + item.enclosure + end + + def setup_maker_attributes(enclosure) + enclosure.url = url + enclosure.length = length + enclosure.type = type + end + end + + class Category < Element + + include RSS09 + + [ + ["domain", "", false] + ].each do |name, uri, required| + install_get_attribute(name, uri, required) + end + + content_setup + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.domain = args[0] + self.content = args[1] + end + end + + private + def maker_target(item) + item.new_category + end + + def setup_maker_attributes(category) + category.domain = domain + category.content = content + end + + end + + end + + class TextInput < Element + + include RSS09 + + %w(title description name link).each do |name| + install_text_element(name, "", nil) + end + + 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 + end + + private + def maker_target(maker) + maker.textinput + end + end + + end + + end + + RSS09::ELEMENTS.each do |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, "") + + @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, @ignore_unknown_element) if @do_validate + } + end + + end + +end diff --git a/ruby_1_8_6/lib/rss/1.0.rb b/ruby_1_8_6/lib/rss/1.0.rb new file mode 100644 index 0000000000..a945434fbf --- /dev/null +++ b/ruby_1_8_6/lib/rss/1.0.rb @@ -0,0 +1,451 @@ +require "rss/parser" + +module RSS + + module RSS10 + NSPOOL = {} + ELEMENTS = [] + + def self.append_features(klass) + super + + klass.install_must_call_validator('', ::RSS::URI) + end + + end + + class RDF < Element + + include RSS10 + include RootElementMixin + + class << self + + def required_uri + URI + end + + end + + @tag_name = 'RDF' + + PREFIX = 'rdf' + URI = "http://www.w3.org/1999/02/22-rdf-syntax-ns#" + + install_ns('', ::RSS::URI) + install_ns(PREFIX, URI) + + [ + ["channel", nil], + ["image", "?"], + ["item", "+", :children], + ["textinput", "?"], + ].each do |tag, occurs, type| + type ||= :child + __send__("install_have_#{type}_element", tag, ::RSS::URI, occurs) + end + + attr_accessor :rss_version, :version, :encoding, :standalone + + def initialize(version=nil, encoding=nil, standalone=nil) + super('1.0', version, encoding, standalone) + end + + def full_name + tag_name_with_prefix(PREFIX) + end + + class Li < Element + + include RSS10 + + class << self + def required_uri + URI + end + end + + [ + ["resource", [URI, ""], 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.resource = args[0] + end + end + + def full_name + tag_name_with_prefix(PREFIX) + end + end + + class Seq < Element + + include RSS10 + + Li = ::RSS::RDF::Li + + class << self + def required_uri + URI + end + end + + @tag_name = 'Seq' + + install_have_children_element("li", URI, "*") + install_must_call_validator('rdf', ::RSS::RDF::URI) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + @li = args[0] if args[0] + end + end + + def full_name + tag_name_with_prefix(PREFIX) + end + + def setup_maker(target) + lis.each do |li| + target << li.resource + end + end + end + + class Bag < Element + + include RSS10 + + Li = ::RSS::RDF::Li + + class << self + def required_uri + URI + end + end + + @tag_name = 'Bag' + + install_have_children_element("li", URI, "*") + install_must_call_validator('rdf', URI) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + @li = args[0] if args[0] + end + end + + def full_name + tag_name_with_prefix(PREFIX) + end + + def setup_maker(target) + lis.each do |li| + target << li.resource + end + end + end + + class Channel < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + [ + ["about", URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required, nil, nil, + "#{PREFIX}:#{name}") + end + + [ + ['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 + end + + private + def maker_target(maker) + maker.channel + end + + def setup_maker_attributes(channel) + channel.about = about + end + + class Image < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + [ + ["resource", URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required, nil, nil, + "#{PREFIX}:#{name}") + end + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.resource = args[0] + end + end + end + + class Textinput < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + [ + ["resource", URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required, nil, nil, + "#{PREFIX}:#{name}") + end + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.resource = args[0] + end + end + end + + class Items < Element + + include RSS10 + + Seq = ::RSS::RDF::Seq + + class << self + + def required_uri + ::RSS::URI + end + + end + + install_have_child_element("Seq", URI, nil) + install_must_call_validator('rdf', URI) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.Seq = args[0] + end + self.Seq ||= Seq.new + end + + def resources + if @Seq + @Seq.lis.collect do |li| + li.resource + end + else + [] + end + end + end + end + + class Image < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + [ + ["about", URI, true] + ].each do |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, ::RSS::URI, nil) + end + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.about = args[0] + end + end + + private + def maker_target(maker) + maker.image + end + end + + class Item < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + + [ + ["about", URI, true] + ].each do |name, uri, required| + install_get_attribute(name, uri, required, nil, nil, + "#{PREFIX}:#{name}") + end + + [ + ["title", nil], + ["link", nil], + ["description", "?"], + ].each do |tag, occurs| + install_text_element(tag, ::RSS::URI, occurs) + end + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.about = args[0] + end + end + + private + def maker_target(items) + if items.respond_to?("items") + # For backward compatibility + items = items.items + end + items.new_item + end + end + + class Textinput < Element + + include RSS10 + + class << self + + def required_uri + ::RSS::URI + end + + end + + [ + ["about", URI, true] + ].each do |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, ::RSS::URI, nil) + end + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.about = args[0] + end + end + + private + def maker_target(maker) + maker.textinput + end + end + + end + + RSS10::ELEMENTS.each do |name| + BaseListener.install_get_text_element(URI, name, "#{name}=") + end + + module ListenerMixin + private + def 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, @ignore_unknown_element) if @do_validate + } + end + end + +end diff --git a/ruby_1_8_6/lib/rss/2.0.rb b/ruby_1_8_6/lib/rss/2.0.rb new file mode 100644 index 0000000000..44bdb4f1ae --- /dev/null +++ b/ruby_1_8_6/lib/rss/2.0.rb @@ -0,0 +1,111 @@ +require "rss/0.9" + +module RSS + + class Rss + + class Channel + + [ + ["generator"], + ["ttl", :integer], + ].each do |name, type| + install_text_element(name, "", "?", name, type) + end + + [ + %w(category categories), + ].each do |name, plural_name| + install_have_children_element(name, "", "*", name, plural_name) + end + + [ + ["image", "?"], + ["language", "?"], + ].each do |name, occurs| + install_model(name, "", occurs) + end + + Category = Item::Category + + class Item + + [ + ["comments", "?"], + ["author", "?"], + ].each do |name, occurs| + install_text_element(name, "", occurs) + end + + [ + ["pubDate", '?'], + ].each do |name, occurs| + install_date_element(name, "", occurs, name, 'rfc822') + end + alias date pubDate + alias date= pubDate= + + [ + ["guid", '?'], + ].each do |name, occurs| + install_have_child_element(name, "", occurs) + end + + private + alias _setup_maker_element setup_maker_element + def setup_maker_element(item) + _setup_maker_element(item) + @guid.setup_maker(item) if @guid + end + + class Guid < Element + + include RSS09 + + [ + ["isPermaLink", "", false, :boolean] + ].each do |name, uri, required, type| + install_get_attribute(name, uri, required, type) + end + + content_setup + + 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? + private :_PermaLink? + def PermaLink? + perma = _PermaLink? + perma or perma.nil? + end + + private + def maker_target(item) + item.guid + end + + def setup_maker_attributes(guid) + guid.isPermaLink = isPermaLink + guid.content = content + end + end + + end + + end + + end + + RSS09::ELEMENTS.each do |name| + BaseListener.install_get_text_element("", name, "#{name}=") + end + +end diff --git a/ruby_1_8_6/lib/rss/content.rb b/ruby_1_8_6/lib/rss/content.rb new file mode 100644 index 0000000000..1b13f39fcf --- /dev/null +++ b/ruby_1_8_6/lib/rss/content.rb @@ -0,0 +1,38 @@ +require "rss/1.0" + +module RSS + + CONTENT_PREFIX = 'content' + CONTENT_URI = "http://purl.org/rss/1.0/modules/content/" + + RDF.install_ns(CONTENT_PREFIX, CONTENT_URI) + + module ContentModel + + extend BaseModel + + ELEMENTS = [] + + def self.append_features(klass) + super + + 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 + class Item; include ContentModel; end + end + + prefix_size = CONTENT_PREFIX.size + 1 + 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}=") + end + +end diff --git a/ruby_1_8_6/lib/rss/converter.rb b/ruby_1_8_6/lib/rss/converter.rb new file mode 100644 index 0000000000..d928c48223 --- /dev/null +++ b/ruby_1_8_6/lib/rss/converter.rb @@ -0,0 +1,158 @@ +require "rss/utils" + +module RSS + + class Converter + + include Utils + + def initialize(to_enc, from_enc=nil) + normalized_to_enc = to_enc.downcase.gsub(/-/, '_') + from_enc ||= 'utf-8' + normalized_from_enc = from_enc.downcase.gsub(/-/, '_') + if normalized_to_enc == normalized_from_enc + def_same_enc() + else + def_diff_enc = "def_to_#{normalized_to_enc}_from_#{normalized_from_enc}" + if respond_to?(def_diff_enc) + __send__(def_diff_enc) + else + def_else_enc(to_enc, from_enc) + end + end + end + + def convert(value) + value + end + + def def_convert(depth=0) + instance_eval(<<-EOC, *get_file_and_line_from_caller(depth)) + def convert(value) + if value.kind_of?(String) + #{yield('value')} + else + value + end + end + EOC + end + + def def_iconv_convert(to_enc, from_enc, depth=0) + begin + require "iconv" + @iconv = Iconv.new(to_enc, from_enc) + def_convert(depth+1) do |value| + <<-EOC + begin + @iconv.iconv(#{value}) + rescue Iconv::Failure + raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") + end + EOC + end + rescue LoadError, ArgumentError, SystemCallError + raise UnknownConversionMethodError.new(to_enc, from_enc) + end + end + + def def_else_enc(to_enc, from_enc) + def_iconv_convert(to_enc, from_enc, 0) + end + + def def_same_enc() + def_convert do |value| + value + end + end + + def def_uconv_convert_if_can(meth, to_enc, from_enc, nkf_arg) + begin + require "uconv" + def_convert(1) do |value| + <<-EOC + begin + Uconv.#{meth}(#{value}) + rescue Uconv::Error + raise ConversionError.new(#{value}, "#{to_enc}", "#{from_enc}") + end + EOC + end + rescue LoadError + require 'nkf' + def_convert(1) do |value| + "NKF.nkf(#{nkf_arg.dump}, #{value})" + end + end + end + + def def_to_euc_jp_from_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', '-Ew') + end + + def def_to_shift_jis_from_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', '-Sw') + end + + def def_to_euc_jp_from_shift_jis + require "nkf" + def_convert do |value| + "NKF.nkf('-Se', #{value})" + end + end + + def def_to_shift_jis_from_euc_jp + require "nkf" + def_convert do |value| + "NKF.nkf('-Es', #{value})" + end + end + + def def_to_euc_jp_from_iso_2022_jp + require "nkf" + def_convert do |value| + "NKF.nkf('-Je', #{value})" + end + end + + def def_to_iso_2022_jp_from_euc_jp + require "nkf" + def_convert do |value| + "NKF.nkf('-Ej', #{value})" + end + end + + def def_to_utf_8_from_iso_8859_1 + def_convert do |value| + "#{value}.unpack('C*').pack('U*')" + end + end + + def def_to_iso_8859_1_from_utf_8 + def_convert do |value| + <<-EOC + array_utf8 = #{value}.unpack('U*') + array_enc = [] + array_utf8.each do |num| + if num <= 0xFF + array_enc << num + else + array_enc.concat "&\#\#{num};".unpack('C*') + end + end + array_enc.pack('C*') + EOC + end + end + + end + +end diff --git a/ruby_1_8_6/lib/rss/dublincore.rb b/ruby_1_8_6/lib/rss/dublincore.rb new file mode 100644 index 0000000000..8a4afd4dd9 --- /dev/null +++ b/ruby_1_8_6/lib/rss/dublincore.rb @@ -0,0 +1,154 @@ +require "rss/1.0" + +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) + super + + return if klass.instance_of?(Module) + DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| + plural = plural_name || "#{name}s" + 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)) + remove_method :#{full_name} + remove_method :#{full_name}= + remove_method :set_#{full_name} + + def #{full_name} + @#{full_name}.first and @#{full_name}.first.value + end + + def #{full_name}=(new_value) + @#{full_name}[0] = Utils.new_with_value_if_need(#{klass_name}, new_value) + end + alias set_#{full_name} #{full_name}= + EOC + end + klass.module_eval(<<-EOC, *get_file_and_line_from_caller(0)) + alias date #{DC_PREFIX}_date + alias date= #{DC_PREFIX}_date= + EOC + end + end + + module DublinCoreModel + + extend BaseModel + extend BaseDublinCoreModel + + TEXT_ELEMENTS = { + "title" => nil, + "description" => nil, + "creator" => nil, + "subject" => nil, + "publisher" => nil, + "contributor" => nil, + "type" => nil, + "format" => nil, + "identifier" => nil, + "source" => nil, + "language" => nil, + "relation" => nil, + "coverage" => nil, + "rights" => "rightses" # FIXME + } + + DATE_ELEMENTS = { + "date" => "w3cdtf", + } + + ELEMENT_NAME_INFOS = DublinCoreModel::TEXT_ELEMENTS.to_a + DublinCoreModel::DATE_ELEMENTS.each do |name, | + ELEMENT_NAME_INFOS << [name, nil] + end + + ELEMENTS = TEXT_ELEMENTS.keys + DATE_ELEMENTS.keys + + ELEMENTS.each do |name, plural_name| + module_eval(<<-EOC, *get_file_and_line_from_caller(0)) + class DublinCore#{Utils.to_class_name(name)} < Element + include RSS10 + + content_setup + + class << self + def required_prefix + DC_PREFIX + end + + def required_uri + DC_URI + end + end + + @tag_name = #{name.dump} + + alias_method(:value, :content) + alias_method(:value=, :content=) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.content = args[0] + end + end + + def full_name + tag_name_with_prefix(DC_PREFIX) + end + + def maker_target(target) + target.new_#{name} + end + + def setup_maker_attributes(#{name}) + #{name}.content = content + end + end + EOC + end + + DATE_ELEMENTS.each do |name, type| + 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}) + + alias_method(:value=, :content=) + end + EOC + 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}") + end + + DublinCoreModel::ELEMENTS.collect! {|name| "#{DC_PREFIX}_#{name}"} +end diff --git a/ruby_1_8_6/lib/rss/image.rb b/ruby_1_8_6/lib/rss/image.rb new file mode 100644 index 0000000000..a9e9e9094e --- /dev/null +++ b/ruby_1_8_6/lib/rss/image.rb @@ -0,0 +1,193 @@ +require 'rss/1.0' +require 'rss/dublincore' + +module RSS + + IMAGE_PREFIX = 'image' + IMAGE_URI = 'http://web.resource.org/rss/1.0/modules/image/' + + RDF.install_ns(IMAGE_PREFIX, IMAGE_URI) + + IMAGE_ELEMENTS = [] + + %w(item favicon).each do |name| + class_name = Utils.to_class_name(name) + BaseListener.install_class_name(IMAGE_URI, name, "Image#{class_name}") + IMAGE_ELEMENTS << "#{IMAGE_PREFIX}_#{name}" + end + + module ImageModelUtils + 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 + + module ImageItemModel + include ImageModelUtils + extend BaseModel + + def self.append_features(klass) + super + + klass.install_have_child_element("item", IMAGE_URI, "?", + "#{IMAGE_PREFIX}_item") + klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) + end + + class ImageItem < Element + include RSS10 + include DublinCoreModel + + @tag_name = "item" + + class << self + def required_prefix + IMAGE_PREFIX + end + + def required_uri + 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, 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(tag, IMAGE_URI, "?", + full_name, :integer, disp_name) + BaseListener.install_get_text_element(IMAGE_URI, tag, "#{full_name}=") + end + + alias width= image_width= + alias width image_width + alias height= image_height= + alias height image_height + + 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 + + private + def maker_target(target) + target.image_item + end + + def setup_maker_attributes(item) + item.about = self.about + item.resource = self.resource + end + end + end + + module ImageFaviconModel + include ImageModelUtils + extend BaseModel + + def self.append_features(klass) + super + + unless klass.class == Module + klass.install_have_child_element("favicon", IMAGE_URI, "?", + "#{IMAGE_PREFIX}_favicon") + klass.install_must_call_validator(IMAGE_PREFIX, IMAGE_URI) + end + end + + class ImageFavicon < Element + include RSS10 + include DublinCoreModel + + @tag_name = "favicon" + + class << self + def required_prefix + IMAGE_PREFIX + end + + def required_uri + IMAGE_URI + end + end + + [ + ["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) + alias_method :_size=, :size= + private :_size= + def size=(new_value) + if @do_validate and !new_value.nil? + new_value = new_value.strip + unless AVAILABLE_SIZES.include?(new_value) + attr_name = "#{IMAGE_PREFIX}:size" + raise NotAvailableValueError.new(full_name, new_value, attr_name) + end + end + __send__(:_size=, new_value) + end + + alias image_size= size= + alias image_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 + + private + def maker_target(target) + target.image_favicon + end + + def setup_maker_attributes(favicon) + favicon.about = self.about + favicon.size = self.size + end + end + + end + + class RDF + class Channel; include ImageFaviconModel; end + class Item; include ImageItemModel; end + end + +end diff --git a/ruby_1_8_6/lib/rss/maker.rb b/ruby_1_8_6/lib/rss/maker.rb new file mode 100644 index 0000000000..9ed799ac7f --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker.rb @@ -0,0 +1,37 @@ +require "rss/rss" + +module RSS + + module Maker + + MAKERS = {} + + class << self + def make(version, &block) + maker(version).make(&block) + end + + def maker(version) + MAKERS[version] + end + + def add_maker(version, maker) + MAKERS[version] = maker + end + + def filename_to_version(filename) + File.basename(filename, ".*") + end + end + end + +end + +require "rss/maker/1.0" +require "rss/maker/2.0" +require "rss/maker/content" +require "rss/maker/dublincore" +require "rss/maker/syndication" +require "rss/maker/taxonomy" +require "rss/maker/trackback" +require "rss/maker/image" diff --git a/ruby_1_8_6/lib/rss/maker/0.9.rb b/ruby_1_8_6/lib/rss/maker/0.9.rb new file mode 100644 index 0000000000..b82585fb96 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/0.9.rb @@ -0,0 +1,224 @@ +require "rss/0.9" + +require "rss/maker/base" + +module RSS + module Maker + + class RSS09 < RSSBase + + def initialize(rss_version="0.91") + super + end + + private + def make_rss + Rss.new(@rss_version, @version, @encoding, @standalone) + end + + def setup_elements(rss) + setup_channel(rss) + end + + class Channel < ChannelBase + + def to_rss(rss) + channel = Rss::Channel.new + set = setup_values(channel) + if set + rss.channel = channel + 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) + end + end + + def have_required_values? + @title and @link and @description and @language + end + + private + def setup_items(rss) + @maker.items.to_rss(rss) + end + + def setup_image(rss) + @maker.image.to_rss(rss) + end + + def setup_textinput(rss) + @maker.textinput.to_rss(rss) + end + + def variables + super + ["pubDate"] + end + + def required_variable_names + %w(title link description language) + end + + class SkipDays < SkipDaysBase + def to_rss(rss, channel) + unless @days.empty? + skipDays = Rss::Channel::SkipDays.new + channel.skipDays = skipDays + @days.each do |day| + day.to_rss(rss, skipDays.days) + end + end + end + + class Day < DayBase + def to_rss(rss, days) + day = Rss::Channel::SkipDays::Day.new + set = setup_values(day) + if set + days << day + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + + class SkipHours < SkipHoursBase + def to_rss(rss, channel) + unless @hours.empty? + skipHours = Rss::Channel::SkipHours.new + channel.skipHours = skipHours + @hours.each do |hour| + hour.to_rss(rss, skipHours.hours) + end + end + end + + class Hour < HourBase + def to_rss(rss, hours) + hour = Rss::Channel::SkipHours::Hour.new + set = setup_values(hour) + if set + hours << hour + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + + class Cloud < CloudBase + def to_rss(*args) + end + end + + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end + end + end + + class Image < ImageBase + def to_rss(rss) + image = Rss::Channel::Image.new + set = setup_values(image) + if set + image.link = link + rss.channel.image = image + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @title and link + end + end + + class Items < ItemsBase + def to_rss(rss) + if rss.channel + normalize.each do |item| + item.to_rss(rss) + end + setup_other_elements(rss) + end + end + + class Item < ItemBase + def to_rss(rss) + item = Rss::Channel::Item.new + set = setup_values(item) + if set + rss.items << item + setup_other_elements(rss) + end + end + + private + def have_required_values? + @title and @link + end + + class Guid < GuidBase + def to_rss(*args) + end + end + + class Enclosure < EnclosureBase + def to_rss(*args) + end + end + + class Source < SourceBase + def to_rss(*args) + end + end + + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end + end + + end + end + + class Textinput < TextinputBase + def to_rss(rss) + textInput = Rss::Channel::TextInput.new + set = setup_values(textInput) + if set + rss.channel.textInput = textInput + setup_other_elements(rss) + end + end + + private + def have_required_values? + @title and @description and @name and @link + end + end + end + + add_maker(filename_to_version(__FILE__), RSS09) + add_maker(filename_to_version(__FILE__) + "1", RSS09) + end +end diff --git a/ruby_1_8_6/lib/rss/maker/1.0.rb b/ruby_1_8_6/lib/rss/maker/1.0.rb new file mode 100644 index 0000000000..3e6542a007 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/1.0.rb @@ -0,0 +1,204 @@ +require "rss/1.0" + +require "rss/maker/base" + +module RSS + module Maker + + class RSS10 < RSSBase + + def initialize + super("1.0") + end + + private + def make_rss + RDF.new(@version, @encoding, @standalone) + end + + def setup_elements(rss) + setup_channel(rss) + setup_image(rss) + setup_items(rss) + setup_textinput(rss) + end + + class Channel < ChannelBase + + def to_rss(rss) + set = false + if @about + channel = RDF::Channel.new(@about) + set = setup_values(channel) + if set + channel.dc_dates.clear + rss.channel = channel + setup_items(rss) + setup_image(rss) + setup_textinput(rss) + setup_other_elements(rss) + 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) + end + rss.channel.items = items + end + + def setup_image(rss) + if @maker.image.have_required_values? + rss.channel.image = RDF::Channel::Image.new(@maker.image.url) + end + end + + def setup_textinput(rss) + if @maker.textinput.have_required_values? + textinput = RDF::Channel::Textinput.new(@maker.textinput.link) + rss.channel.textinput = textinput + end + end + + def required_variable_names + %w(about title link description) + end + + class SkipDays < SkipDaysBase + def to_rss(*args) + end + + class Day < DayBase + end + end + + class SkipHours < SkipHoursBase + def to_rss(*args) + end + + class Hour < HourBase + end + end + + class Cloud < CloudBase + def to_rss(*args) + end + end + + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end + end + end + + class Image < ImageBase + def to_rss(rss) + if @url + image = RDF::Image.new(@url) + set = setup_values(image) + if set + rss.image = image + setup_other_elements(rss) + end + end + end + + def have_required_values? + @url and @title and link and @maker.channel.have_required_values? + end + + private + def variables + super + ["link"] + end + end + + class Items < ItemsBase + def to_rss(rss) + if rss.channel + normalize.each do |item| + item.to_rss(rss) + end + setup_other_elements(rss) + end + end + + class Item < ItemBase + def to_rss(rss) + if @link + item = RDF::Item.new(@link) + set = setup_values(item) + if set + item.dc_dates.clear + rss.items << item + setup_other_elements(rss) + end + end + end + + def have_required_values? + @title and @link + end + + class Guid < GuidBase + def to_rss(*args) + end + end + + class Enclosure < EnclosureBase + def to_rss(*args) + end + end + + class Source < SourceBase + def to_rss(*args) + end + end + + class Categories < CategoriesBase + def to_rss(*args) + end + + class Category < CategoryBase + end + end + end + end + + class Textinput < TextinputBase + def to_rss(rss) + if @link + textinput = RDF::Textinput.new(@link) + set = setup_values(textinput) + if set + rss.textinput = textinput + setup_other_elements(rss) + end + end + end + + def have_required_values? + @title and @description and @name and @link and + @maker.channel.have_required_values? + end + end + end + + add_maker(filename_to_version(__FILE__), RSS10) + end +end diff --git a/ruby_1_8_6/lib/rss/maker/2.0.rb b/ruby_1_8_6/lib/rss/maker/2.0.rb new file mode 100644 index 0000000000..a958661614 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/2.0.rb @@ -0,0 +1,168 @@ +require "rss/2.0" + +require "rss/maker/0.9" + +module RSS + module Maker + + class RSS20 < RSS09 + + def initialize(rss_version="2.0") + super + end + + class Channel < RSS09::Channel + + def have_required_values? + @title and @link and @description + end + + def required_variable_names + %w(title link description) + end + + class SkipDays < RSS09::Channel::SkipDays + class Day < RSS09::Channel::SkipDays::Day + end + end + + class SkipHours < RSS09::Channel::SkipHours + class Hour < RSS09::Channel::SkipHours::Hour + end + end + + class Cloud < RSS09::Channel::Cloud + def to_rss(rss, channel) + cloud = Rss::Channel::Cloud.new + set = setup_values(cloud) + if set + channel.cloud = cloud + setup_other_elements(rss) + end + end + + def have_required_values? + @domain and @port and @path and + @registerProcedure and @protocol + end + end + + class Categories < RSS09::Channel::Categories + def to_rss(rss, channel) + @categories.each do |category| + category.to_rss(rss, channel) + end + end + + class Category < RSS09::Channel::Categories::Category + def to_rss(rss, channel) + category = Rss::Channel::Category.new + set = setup_values(category) + if set + channel.categories << category + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + + end + + class Image < RSS09::Image + end + + class Items < RSS09::Items + + class Item < RSS09::Items::Item + + def have_required_values? + @title or @description + end + + private + def variables + super + ["pubDate"] + end + + class Guid < RSS09::Items::Item::Guid + def to_rss(rss, item) + guid = Rss::Channel::Item::Guid.new + set = setup_values(guid) + if set + item.guid = guid + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + + class Enclosure < RSS09::Items::Item::Enclosure + def to_rss(rss, item) + enclosure = Rss::Channel::Item::Enclosure.new + set = setup_values(enclosure) + if set + item.enclosure = enclosure + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @length and @type + end + end + + class Source < RSS09::Items::Item::Source + def to_rss(rss, item) + source = Rss::Channel::Item::Source.new + set = setup_values(source) + if set + item.source = source + setup_other_elements(rss) + end + end + + def have_required_values? + @url and @content + end + end + + class Categories < RSS09::Items::Item::Categories + def to_rss(rss, item) + @categories.each do |category| + category.to_rss(rss, item) + end + end + + class Category < RSS09::Items::Item::Categories::Category + def to_rss(rss, item) + category = Rss::Channel::Item::Category.new + set = setup_values(category) + if set + item.categories << category + setup_other_elements(rss) + end + end + + def have_required_values? + @content + end + end + end + end + + end + + class Textinput < RSS09::Textinput + end + end + + add_maker(filename_to_version(__FILE__), RSS20) + end +end diff --git a/ruby_1_8_6/lib/rss/maker/base.rb b/ruby_1_8_6/lib/rss/maker/base.rb new file mode 100644 index 0000000000..2327dd98e4 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/base.rb @@ -0,0 +1,546 @@ +require 'forwardable' + +require 'rss/rss' + +module RSS + module Maker + + module Base + + def self.append_features(klass) + super + + klass.module_eval(<<-EOC, __FILE__, __LINE__) + + 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 + end + + def self.add_other_element(variable_name) + OTHER_ELEMENTS << variable_name + end + + def self.other_elements + OTHER_ELEMENTS + end + + def self.add_need_initialize_variable(variable_name, init_value="nil") + NEED_INITIALIZE_VARIABLES << [variable_name, init_value] + end + + def self.need_initialize_variables + NEED_INITIALIZE_VARIABLES + end + + def self.def_array_element(name) + 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, "[]") + end + EOC + end + + def initialize(maker) + @maker = maker + initialize_variables + end + + def have_required_values? + true + end + + private + def initialize_variables + self.class.need_initialize_variables.each do |variable_name, init_value| + instance_eval("@#{variable_name} = #{init_value}", __FILE__, __LINE__) + end + end + + def setup_other_elements(rss) + self.class.other_elements.each do |element| + __send__("setup_#{element}", rss, current_element(rss)) + end + end + + def current_element(rss) + rss + end + + def setup_values(target) + set = false + if have_required_values? + variables.each do |var| + setter = "#{var}=" + if target.respond_to?(setter) + value = __send__(var) + if value + target.__send__(setter, value) + set = true + end + end + end + end + set + end + + def variables + self.class.need_initialize_variables.find_all do |name, init| + "nil" == init + end.collect do |name, init| + name + 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? + end + end + + def required_variables_are_set? + required_variable_names.each do |var| + return false if __send__(var).nil? + end + true + end + + end + + class RSSBase + include Base + + class << self + def make(&block) + new.make(&block) + end + end + + %w(xml_stylesheets channel image items textinput).each do |element| + attr_reader element + add_need_initialize_variable(element, "make_#{element}") + module_eval(<<-EOC, __FILE__, __LINE__) + private + def setup_#{element}(rss) + @#{element}.to_rss(rss) + end + + def make_#{element} + self.class::#{Utils.to_class_name(element)}.new(self) + end +EOC + end + + attr_reader :rss_version + attr_accessor :version, :encoding, :standalone + + def initialize(rss_version) + super(self) + @rss_version = rss_version + @version = "1.0" + @encoding = "UTF-8" + @standalone = nil + end + + def make + if block_given? + yield(self) + to_rss + 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 + else + nil + end + end + + private + remove_method :make_xml_stylesheets + 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 + if block_given? + yield xss + else + xss + end + end + + class XMLStyleSheet + include Base + + ::RSS::XMLStyleSheet::ATTRIBUTES.each do |attribute| + attr_accessor attribute + add_need_initialize_variable(attribute) + end + + def to_rss(rss) + xss = ::RSS::XMLStyleSheet.new + guess_type_if_need(xss) + set = setup_values(xss) + if set + rss.xml_stylesheets << xss + end + end + + def have_required_values? + @href and @type + end + + private + def guess_type_if_need(xss) + if @type.nil? + xss.href = @href + @type = xss.type + end + end + end + end + + class ChannelBase + include Base + + %w(cloud categories skipDays skipHours).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) + end + + def make_#{element} + self.class::#{Utils.to_class_name(element)}.new(@maker) + end +EOC + end + + %w(about title link description language copyright + managingEditor webMaster rating docs date + lastBuildDate generator ttl).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + alias_method(:pubDate, :date) + alias_method(:pubDate=, :date=) + + def current_element(rss) + rss.channel + end + + class SkipDaysBase + include Base + + def_array_element("days") + + def new_day + day = self.class::Day.new(@maker) + @days << day + if block_given? + yield day + else + day + end + end + + def current_element(rss) + rss.channel.skipDays + end + + class DayBase + include Base + + %w(content).each do |element| + 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 + if block_given? + yield hour + else + hour + end + end + + def current_element(rss) + rss.channel.skipHours + end + + class HourBase + include Base + + %w(content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def current_element(rss) + rss.channel.skipHours.last + end + + end + end + + class CloudBase + include Base + + %w(domain port path registerProcedure protocol).each do |element| + 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 + if block_given? + yield category + else + category + end + end + + class CategoryBase + include Base + + %w(domain content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + end + end + + class ImageBase + include Base + + %w(title url width height description).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def link + @maker.channel.link + end + + def current_element(rss) + rss.image + end + end + + class ItemsBase + include Base + + def_array_element("items") + + attr_accessor :do_sort, :max_size + + def initialize(maker) + super + @do_sort = false + @max_size = -1 + end + + def normalize + if @max_size >= 0 + sort_if_need[0...@max_size] + else + sort_if_need[0..@max_size] + end + end + + def current_element(rss) + rss.items + end + + def new_item + item = self.class::Item.new(@maker) + @items << item + if block_given? + yield item + else + item + end + end + + private + def sort_if_need + if @do_sort.respond_to?(:call) + @items.sort do |x, y| + @do_sort.call(x, y) + end + elsif @do_sort + @items.sort do |x, y| + y <=> x + end + else + @items + end + end + + class ItemBase + include Base + + %w(guid enclosure source categories).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) + end + + def make_#{element} + self.class::#{Utils.to_class_name(element)}.new(@maker) + end +EOC + end + + %w(title link description date author comments).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + alias_method(:pubDate, :date) + alias_method(:pubDate=, :date=) + + def <=>(other) + if date and other.date + date <=> other.date + elsif date + 1 + elsif other.date + -1 + else + 0 + end + end + + def current_element(rss) + rss.items.last + end + + class GuidBase + include Base + + %w(isPermaLink content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + + class EnclosureBase + include Base + + %w(url length type).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + + class SourceBase + include Base + + %w(url content).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + end + + CategoriesBase = ChannelBase::CategoriesBase + + end + end + + class TextinputBase + include Base + + %w(title description name link).each do |element| + attr_accessor element + add_need_initialize_variable(element) + end + + def current_element(rss) + rss.textinput + end + + end + + end +end diff --git a/ruby_1_8_6/lib/rss/maker/content.rb b/ruby_1_8_6/lib/rss/maker/content.rb new file mode 100644 index 0000000000..18590d0cf8 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/content.rb @@ -0,0 +1,29 @@ +require 'rss/content' +require 'rss/maker/1.0' + +module RSS + module Maker + module ContentModel + 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 + end + end + end + + class ItemsBase + class ItemBase; include ContentModel; end + end + end +end diff --git a/ruby_1_8_6/lib/rss/maker/dublincore.rb b/ruby_1_8_6/lib/rss/maker/dublincore.rb new file mode 100644 index 0000000000..0cf1255e82 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/dublincore.rb @@ -0,0 +1,169 @@ +require 'rss/dublincore' +require 'rss/maker/1.0' + +module RSS + module Maker + module DublinCoreModel + def self.append_features(klass) + super + + ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| + plural_name ||= "#{name}s" + full_name = "#{RSS::DC_PREFIX}_#{name}" + full_plural_name = "#{RSS::DC_PREFIX}_#{plural_name}" + klass_name = Utils.to_class_name(name) + plural_klass_name = "DublinCore#{Utils.to_class_name(plural_name)}" + full_plural_klass_name = "self.class::#{plural_klass_name}" + full_klass_name = "#{full_plural_klass_name}::#{klass_name}" + klass.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}(rss, current) + @#{full_plural_name}.to_rss(rss, 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 +EOC + end + end + + ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| + plural_name ||= "#{name}s" + klass_name = Utils.to_class_name(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} + if block_given? + yield #{name} + else + #{name} + end + end + + def to_rss(rss, current) + @#{plural_name}.each do |#{name}| + #{name}.to_rss(rss, current) + end + end + + class #{klass_name}Base + include Base + + attr_accessor :value + add_need_initialize_variable("value") + alias_method(:content, :value) + alias_method(:content=, :value=) + + def have_required_values? + @value + end + end + end + EOC + end + + def self.install_dublin_core(klass) + ::RSS::DublinCoreModel::ELEMENT_NAME_INFOS.each do |name, plural_name| + plural_name ||= "#{name}s" + klass_name = Utils.to_class_name(name) + 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)) + 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 + end + end + end + + 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 + 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 Items + class Item + DublinCoreModel.install_dublin_core(self) + end + end + + class Textinput + DublinCoreModel.install_dublin_core(self) + end + end + end +end diff --git a/ruby_1_8_6/lib/rss/maker/image.rb b/ruby_1_8_6/lib/rss/maker/image.rb new file mode 100644 index 0000000000..ed51c8ecba --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/image.rb @@ -0,0 +1,145 @@ +require 'rss/image' +require 'rss/maker/1.0' +require 'rss/maker/dublincore' + +module RSS + module Maker + module ImageItemModel + def self.append_features(klass) + super + + name = "#{RSS::IMAGE_PREFIX}_item" + klass.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}(rss, current) + if @#{name} + @#{name}.to_rss(rss, current) + end + end + + def make_#{name} + self.class::#{Utils.to_class_name(name)}.new(@maker) + end +EOC + end + + class ImageItemBase + include Base + include Maker::DublinCoreModel + + attr_accessor :about, :resource, :image_width, :image_height + add_need_initialize_variable("about") + add_need_initialize_variable("resource") + add_need_initialize_variable("image_width") + add_need_initialize_variable("image_height") + alias width= image_width= + alias width image_width + alias height= image_height= + alias height image_height + + def have_required_values? + @about + end + end + end + + module ImageFaviconModel + def self.append_features(klass) + 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}(rss, current) + if @#{name} + @#{name}.to_rss(rss, current) + end + end + + def make_#{name} + self.class::#{Utils.to_class_name(name)}.new(@maker) + end +EOC + end + + class ImageFaviconBase + include Base + include Maker::DublinCoreModel + + attr_accessor :about, :image_size + add_need_initialize_variable("about") + add_need_initialize_variable("image_size") + alias size image_size + alias size= image_size= + + def have_required_values? + @about and @image_size + end + end + end + + class ChannelBase; include Maker::ImageFaviconModel; end + + class ItemsBase + 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 + 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 + end + end + end + + class Channel + class ImageFavicon < ImageFaviconBase + DublinCoreModel.install_dublin_core(self) + def to_rss(*args) + end + end + end + end + + end +end diff --git a/ruby_1_8_6/lib/rss/maker/syndication.rb b/ruby_1_8_6/lib/rss/maker/syndication.rb new file mode 100644 index 0000000000..3717086257 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/syndication.rb @@ -0,0 +1,27 @@ +require 'rss/syndication' +require 'rss/maker/1.0' + +module RSS + module Maker + module SyndicationModel + def self.append_features(klass) + super + + ::RSS::SyndicationModel::ELEMENTS.each do |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 + end + end + end + + class ChannelBase; include SyndicationModel; end + end +end diff --git a/ruby_1_8_6/lib/rss/maker/taxonomy.rb b/ruby_1_8_6/lib/rss/maker/taxonomy.rb new file mode 100644 index 0000000000..f272996581 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/taxonomy.rb @@ -0,0 +1,182 @@ +require 'rss/taxonomy' +require 'rss/maker/1.0' +require 'rss/maker/dublincore' + +module RSS + module Maker + module TaxonomyTopicsModel + def self.append_features(klass) + super + + klass.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(rss, current) + @taxo_topics.to_rss(rss, current) + end +EOC + end + + def self.install_taxo_topics(klass) + klass.module_eval(<<-EOC, *Utils.get_file_and_line_from_caller(1)) + class TaxonomyTopics < TaxonomyTopicsBase + def to_rss(rss, current) + if current.respond_to?(:taxo_topics) + topics = current.class::TaxonomyTopics.new + bag = topics.Bag + @resources.each do |resource| + bag.lis << RDF::Bag::Li.new(resource) + end + current.taxo_topics = topics + end + end + end +EOC + end + + class TaxonomyTopicsBase + include Base + + attr_reader :resources + def_array_element("resources") + end + end + + module TaxonomyTopicModel + 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(rss, current) + @taxo_topics.to_rss(rss, 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 + end + + def self.install_taxo_topic(klass) + klass.module_eval(<<-EOC, *Utils.get_file_and_line_from_caller(1)) + class TaxonomyTopics < TaxonomyTopicsBase + class TaxonomyTopic < TaxonomyTopicBase + DublinCoreModel.install_dublin_core(self) + TaxonomyTopicsModel.install_taxo_topics(self) + + def to_rss(rss, 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 + current.taxo_topics << topic + setup_other_elements(rss) + end + end + + def current_element(rss) + super.taxo_topics.last + end + end + end +EOC + end + + class TaxonomyTopicsBase + include Base + + def_array_element("taxo_topics") + + def new_taxo_topic + taxo_topic = self.class::TaxonomyTopic.new(self) + @taxo_topics << taxo_topic + if block_given? + yield taxo_topic + else + taxo_topic + end + end + + 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 + include TaxonomyTopicsModel + + attr_accessor :value + add_need_initialize_variable("value") + alias_method(:taxo_link, :value) + alias_method(:taxo_link=, :value=) + + def have_required_values? + @value + end + end + end + end + + class RSSBase + include TaxonomyTopicModel + end + + class ChannelBase + include TaxonomyTopicsModel + end + + class ItemsBase + class ItemBase + include TaxonomyTopicsModel + end + end + + class RSS10 + TaxonomyTopicModel.install_taxo_topic(self) + + class Channel + TaxonomyTopicsModel.install_taxo_topics(self) + end + + class Items + class Item + 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) + end + end + end + end +end diff --git a/ruby_1_8_6/lib/rss/maker/trackback.rb b/ruby_1_8_6/lib/rss/maker/trackback.rb new file mode 100644 index 0000000000..4ae6164f68 --- /dev/null +++ b/ruby_1_8_6/lib/rss/maker/trackback.rb @@ -0,0 +1,130 @@ +require 'rss/trackback' +require 'rss/maker/1.0' +require 'rss/maker/2.0' + +module RSS + module Maker + module TrackBackModel + def self.append_features(klass) + super + + 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}(rss, 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}(rss, current) + @#{name}.to_rss(rss, current) + end + EOC + end + + class TrackBackAboutsBase + include Base + + def_array_element("abouts") + + def new_about + about = self.class::TrackBackAbout.new(@maker) + @abouts << about + if block_given? + yield about + else + about + end + end + + def to_rss(rss, current) + @abouts.each do |about| + about.to_rss(rss, current) + end + end + + class TrackBackAboutBase + include Base + + attr_accessor :value + add_need_initialize_variable("value") + + alias_method(:resource, :value) + alias_method(:resource=, :value=) + alias_method(:content, :value) + alias_method(:content=, :value=) + + def have_required_values? + @value + end + + 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 + 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 + 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 + end + end + end + end + end + end + + end +end diff --git a/ruby_1_8_6/lib/rss/parser.rb b/ruby_1_8_6/lib/rss/parser.rb new file mode 100644 index 0000000000..033bc123aa --- /dev/null +++ b/ruby_1_8_6/lib/rss/parser.rb @@ -0,0 +1,476 @@ +require "forwardable" +require "open-uri" + +require "rss/rss" + +module RSS + + class NotWellFormedError < Error + attr_reader :line, :element + + # Create a new NotWellFormedError for an error at +line+ + # in +element+. If a block is given the return value of + # the block ends up in the error message. + def initialize(line=nil, element=nil) + message = "This is not well formed XML" + if element or line + message << "\nerror occurred" + message << " in #{element}" if element + message << " at about #{line} line" if line + end + message << "\n#{yield}" if block_given? + super(message) + end + end + + class XMLParserNotFound < Error + def initialize + super("available XML parser was not found in " << + "#{AVAILABLE_PARSER_LIBRARIES.inspect}.") + end + end + + class NotValidXMLParser < Error + def initialize(parser) + super("#{parser} is not an available XML parser. " << + "Available XML parser"<< + (AVAILABLE_PARSERS.size > 1 ? "s are ": " is ") << + "#{AVAILABLE_PARSERS.inspect}.") + end + end + + class NSError < InvalidRSSError + attr_reader :tag, :prefix, :uri + def initialize(tag, prefix, require_uri) + @tag, @prefix, @uri = tag, prefix, require_uri + super("prefix <#{prefix}> doesn't associate uri " << + "<#{require_uri}> in tag <#{tag}>") + end + end + + class Parser + + extend Forwardable + + class << self + + @@default_parser = nil + + def default_parser + @@default_parser || AVAILABLE_PARSERS.first + end + + # Set @@default_parser to new_value if it is one of the + # available parsers. Else raise NotValidXMLParser error. + def default_parser=(new_value) + if AVAILABLE_PARSERS.include?(new_value) + @@default_parser = new_value + else + raise NotValidXMLParser.new(new_value) + end + end + + 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 + parser.parse + end + end + + def_delegators(:@parser, :parse, :rss, + :ignore_unknown_element, + :ignore_unknown_element=, :do_validate, + :do_validate=) + + def initialize(rss, parser_class=self.class.default_parser) + @parser = parser_class.new(normalize_rss(rss)) + end + + private + + # Try to get the XML associated with +rss+. + # Return +rss+ if it already looks like XML, or treat it as a URI, + # or a file to get the XML, + def normalize_rss(rss) + return rss if maybe_xml?(rss) + + uri = to_uri(rss) + + if uri.respond_to?(:read) + uri.read + elsif !rss.tainted? and File.readable?(rss) + File.open(rss) {|f| f.read} + else + rss + end + end + + # maybe_xml? tests if source is a string that looks like XML. + def maybe_xml?(source) + source.is_a?(String) and /</ =~ source + end + + # Attempt to convert rss to a URI, but just return it if + # there's a ::URI::Error + def to_uri(rss) + return rss if rss.is_a?(::URI::Generic) + + begin + URI(rss) + rescue ::URI::Error + rss + end + end + end + + class BaseParser + + class << self + def raise_for_undefined_entity? + listener.raise_for_undefined_entity? + end + end + + def initialize(rss) + @listener = self.class.listener.new + @rss = rss + end + + def rss + @listener.rss + end + + def ignore_unknown_element + @listener.ignore_unknown_element + end + + def ignore_unknown_element=(new_value) + @listener.ignore_unknown_element = new_value + end + + def do_validate + @listener.do_validate + end + + def do_validate=(new_value) + @listener.do_validate = new_value + end + + def parse + if @listener.rss.nil? + _parse + end + @listener.rss + end + + end + + class BaseListener + + extend Utils + + class << self + + @@setters = {} + @@registered_uris = {} + @@class_names = {} + + # return the setter for the uri, tag_name pair, or nil. + def setter(uri, tag_name) + begin + @@setters[uri][tag_name] + rescue NameError + nil + end + end + + + # return the tag_names for setters associated with uri + def available_tags(uri) + begin + @@setters[uri].keys + rescue NameError + [] + end + end + + # register uri against this name. + def register_uri(uri, name) + @@registered_uris[name] ||= {} + @@registered_uris[name][uri] = nil + end + + # test if this uri is registered against this name + def uri_registered?(uri, name) + @@registered_uris[name].has_key?(uri) + end + + # record class_name for the supplied uri and tag_name + def install_class_name(uri, tag_name, class_name) + @@class_names[uri] ||= {} + @@class_names[uri][tag_name] = class_name + end + + # retrieve class_name for the supplied uri and tag_name + # If it doesn't exist, capitalize the tag_name + def class_name(uri, tag_name) + begin + @@class_names[uri][tag_name] + rescue NameError + tag_name[0,1].upcase + tag_name[1..-1] + end + end + + def install_get_text_element(uri, name, setter) + install_setter(uri, name, setter) + def_get_text_element(uri, name, *get_file_and_line_from_caller(1)) + end + + def raise_for_undefined_entity? + true + end + + private + # set the setter for the uri, tag_name pair + def install_setter(uri, tag_name, setter) + @@setters[uri] ||= {} + @@setters[uri][tag_name] = setter + end + + def def_get_text_element(uri, name, file, line) + register_uri(uri, name) + unless private_instance_methods(false).include?("start_#{name}") + module_eval(<<-EOT, file, line) + def start_#{name}(name, prefix, attrs, ns) + uri = _ns(ns, prefix) + if self.class.uri_registered?(uri, #{name.inspect}) + start_get_text_element(name, prefix, ns, uri) + else + start_else_element(name, prefix, attrs, ns) + end + end + EOT + __send__("private", "start_#{name}") + end + end + + end + + end + + module ListenerMixin + + attr_reader :rss + + attr_accessor :ignore_unknown_element + attr_accessor :do_validate + + def initialize + @rss = nil + @ignore_unknown_element = true + @do_validate = true + @ns_stack = [{}] + @tag_stack = [[]] + @text_stack = [''] + @proc_stack = [] + @last_element = nil + @version = @encoding = @standalone = nil + @xml_stylesheets = [] + end + + # set instance vars for version, encoding, standalone + def xmldecl(version, encoding, standalone) + @version, @encoding, @standalone = version, encoding, standalone + end + + def instruction(name, content) + if name == "xml-stylesheet" + params = parse_pi_content(content) + if params.has_key?("href") + @xml_stylesheets << XMLStyleSheet.new(*params) + end + end + end + + def tag_start(name, attributes) + @text_stack.push('') + + ns = @ns_stack.last.dup + attrs = {} + attributes.each do |n, v| + if /\Axmlns(?:\z|:)/ =~ n + ns[$POSTMATCH] = v + else + attrs[n] = v + end + end + @ns_stack.push(ns) + + prefix, local = split_name(name) + @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) + else + start_else_element(local, prefix, attrs, ns.dup) + end + end + + def tag_end(name) + if DEBUG + p "end tag #{name}" + p @tag_stack + end + text = @text_stack.pop + tags = @tag_stack.pop + pr = @proc_stack.pop + pr.call(text, tags) unless pr.nil? + @ns_stack.pop + end + + def text(data) + @text_stack.last << data + end + + private + def _ns(ns, prefix) + ns.fetch(prefix, "") + end + + CONTENT_PATTERN = /\s*([^=]+)=(["'])([^\2]+?)\2/ + # Extract the first name="value" pair from content. + # Works with single quotes according to the constant + # CONTENT_PATTERN. Return a Hash. + def parse_pi_content(content) + params = {} + content.scan(CONTENT_PATTERN) do |name, quote, value| + params[name] = value + end + params + end + + 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.constants.include?(class_name) + next_class = current_class.const_get(class_name) + start_have_something_element(local, prefix, attrs, ns, next_class) + else + 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 NotExpectedTagError.new(local, _ns(ns, prefix), parent) + end + end + end + + NAMESPLIT = /^(?:([\w:][-\w\d.]*):)?([\w:][-\w\d.]*)/ + def split_name(name) + name =~ NAMESPLIT + [$1 || '', $2] + end + + def check_ns(tag_name, prefix, ns, require_uri) + if @do_validate + if _ns(ns, prefix) == require_uri + #ns.delete(prefix) + else + raise NSError.new(tag_name, prefix, require_uri) + end + end + end + + def start_get_text_element(tag_name, prefix, ns, required_uri) + @proc_stack.push Proc.new {|text, tags| + setter = self.class.setter(required_uri, tag_name) + if @last_element.respond_to?(setter) + @last_element.__send__(setter, text.to_s) + else + if @do_validate and !@ignore_unknown_element + raise NotExpectedTagError.new(tag_name, _ns(ns, prefix), + @last_element.tag_name) + end + end + } + end + + def start_have_something_element(tag_name, prefix, attrs, ns, klass) + + check_ns(tag_name, prefix, ns, klass.required_uri) + + 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 == [""] + for prefix, uri in ns + if a_uri.include?(uri) + val = attrs["#{prefix}:#{a_name}"] + break if val + end + end + end + if val.nil? and a_uri.include?("") + val = attrs[a_name] + end + + if @do_validate and required and val.nil? + unless a_uri.include?("") + for prefix, uri in ns + if a_uri.include?(uri) + a_name = "#{prefix}:#{a_name}" + end + end + end + raise MissingAttributeError.new(tag_name, a_name) + end + + attributes[a_name] = val + end + + previous = @last_element + next_element = klass.new(@do_validate, attributes) + previous.instance_eval {set_next_element(tag_name, next_element)} + @last_element = next_element + @proc_stack.push Proc.new { |text, tags| + p(@last_element.class) if DEBUG + @last_element.content = text if klass.have_content? + if @do_validate + @last_element.validate_for_stream(tags, @ignore_unknown_element) + end + @last_element = previous + } + end + + end + + unless const_defined? :AVAILABLE_PARSER_LIBRARIES + AVAILABLE_PARSER_LIBRARIES = [ + ["rss/xmlparser", :XMLParserParser], + ["rss/xmlscanner", :XMLScanParser], + ["rss/rexmlparser", :REXMLParser], + ] + end + + AVAILABLE_PARSERS = [] + + AVAILABLE_PARSER_LIBRARIES.each do |lib, parser| + begin + require lib + AVAILABLE_PARSERS.push(const_get(parser)) + rescue LoadError + end + end + + if AVAILABLE_PARSERS.empty? + raise XMLParserNotFound + end +end diff --git a/ruby_1_8_6/lib/rss/rexmlparser.rb b/ruby_1_8_6/lib/rss/rexmlparser.rb new file mode 100644 index 0000000000..4dabf59199 --- /dev/null +++ b/ruby_1_8_6/lib/rss/rexmlparser.rb @@ -0,0 +1,54 @@ +require "rexml/document" +require "rexml/streamlistener" + +/\A(\d+)\.(\d+)(?:\.\d+)+\z/ =~ REXML::Version +if ([$1.to_i, $2.to_i] <=> [2, 5]) < 0 + raise LoadError, "needs REXML 2.5 or later (#{REXML::Version})" +end + +module RSS + + class REXMLParser < BaseParser + + class << self + def listener + REXMLListener + end + end + + private + def _parse + begin + REXML::Document.parse_stream(@rss, @listener) + rescue RuntimeError => e + raise NotWellFormedError.new{e.message} + rescue REXML::ParseException => e + context = e.context + line = context[0] if context + raise NotWellFormedError.new(line){e.message} + end + end + + end + + class REXMLListener < BaseListener + + include REXML::StreamListener + include ListenerMixin + + class << self + def raise_for_undefined_entity? + false + end + end + + def xmldecl(version, encoding, standalone) + super(version, encoding, standalone == "yes") + # Encoding is converted to UTF-8 when REXML parse XML. + @encoding = 'UTF-8' + end + + alias_method(:cdata, :text) + end + +end diff --git a/ruby_1_8_6/lib/rss/rss.rb b/ruby_1_8_6/lib/rss/rss.rb new file mode 100644 index 0000000000..a06985af94 --- /dev/null +++ b/ruby_1_8_6/lib/rss/rss.rb @@ -0,0 +1,1015 @@ +require "time" + +class Time + class << self + unless respond_to?(:w3cdtf) + def w3cdtf(date) + if /\A\s* + (-?\d+)-(\d\d)-(\d\d) + (?:T + (\d\d):(\d\d)(?::(\d\d))? + (\.\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) + else + Time.local(*datetime) + end + else + raise ArgumentError.new("invalid date: #{date.inspect}") + end + end + end + end + + unless instance_methods.include?("w3cdtf") + alias w3cdtf iso8601 + end +end + +require "English" +require "rss/utils" +require "rss/converter" +require "rss/xml-stylesheet" + +module RSS + + VERSION = "0.1.6" + + URI = "http://purl.org/rss/1.0/" + + DEBUG = false + + class Error < StandardError; end + + class OverlappedPrefixError < Error + attr_reader :prefix + def initialize(prefix) + @prefix = prefix + end + end + + class InvalidRSSError < Error; end + + class MissingTagError < InvalidRSSError + attr_reader :tag, :parent + def initialize(tag, parent) + @tag, @parent = tag, parent + super("tag <#{tag}> is missing in tag <#{parent}>") + end + end + + class TooMuchTagError < InvalidRSSError + attr_reader :tag, :parent + def initialize(tag, parent) + @tag, @parent = tag, parent + super("tag <#{tag}> is too much in tag <#{parent}>") + end + end + + class MissingAttributeError < InvalidRSSError + attr_reader :tag, :attribute + def initialize(tag, attribute) + @tag, @attribute = tag, attribute + super("attribute <#{attribute}> is missing in tag <#{tag}>") + end + end + + class UnknownTagError < InvalidRSSError + attr_reader :tag, :uri + def initialize(tag, uri) + @tag, @uri = tag, uri + super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>") + end + end + + 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 + def initialize(tag, value, attribute=nil) + @tag, @value, @attribute = tag, value, attribute + message = "value <#{value}> of " + message << "attribute <#{attribute}> of " if attribute + message << "tag <#{tag}> is not available." + super(message) + end + end + + class UnknownConversionMethodError < Error + attr_reader :to, :from + def initialize(to, from) + @to = to + @from = from + super("can't convert to #{to} from #{from}.") + end + end + # for backward compatibility + UnknownConvertMethod = UnknownConversionMethodError + + class ConversionError < Error + attr_reader :string, :to, :from + def initialize(string, to, from) + @string = string + @to = to + @from = from + super("can't convert #{@string} to #{to} from #{from}.") + end + end + + class NotSetError < Error + attr_reader :name, :variables + def initialize(name, variables) + @name = name + @variables = variables + super("required variables of #{@name} are not set: #{@variables.join(', ')}") + end + end + + module BaseModel + + include Utils + + def install_have_child_element(tag_name, uri, occurs, name=nil) + name ||= tag_name + add_need_initialize_variable(name) + install_model(tag_name, uri, occurs, name) + + attr_accessor name + install_element(name) do |n, elem_name| + <<-EOC + if @#{n} + "\#{@#{n}.to_s(need_convert, indent)}" + else + '' + end +EOC + end + end + alias_method(:install_have_attribute_element, :install_have_child_element) + + 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 + rv = [] + @#{n}.each do |x| + value = "\#{x.to_s(need_convert, indent)}" + rv << value if /\\A\\s*\\z/ !~ value + end + rv.join("\n") +EOC + end + end + + 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 + install_element(name) do |n, elem_name| + <<-EOC + if @#{n} + rv = "\#{indent}<#{elem_name}>" + value = html_escape(@#{n}) + if need_convert + rv << convert(value) + else + rv << value + end + rv << "</#{elem_name}>" + rv + else + '' + end +EOC + end + end + + 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 + date_writer(name, type, disp_name) + + install_element(name) do |n, elem_name| + <<-EOC + if @#{n} + rv = "\#{indent}<#{elem_name}>" + value = html_escape(@#{n}.#{type}) + if need_convert + rv << convert(value) + else + rv << value + end + rv << "</#{elem_name}>" + rv + else + '' + end +EOC + end + + end + + 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 #{method_name}(need_convert=true, indent='') + #{yield(name, elem_name)} + end + private :#{method_name} +EOC + 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} + if @converter + @converter.convert(@#{attr}) + else + @#{attr} + 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) + if new_value.nil? or new_value.kind_of?(Time) + @#{name} = new_value + else + if @do_validate + begin + @#{name} = Time.__send__('#{type}', new_value) + rescue ArgumentError + raise NotAvailableValueError.new('#{disp_name}', new_value) + end + else + @#{name} = nil + if /\\A\\s*\\z/ !~ new_value.to_s + begin + @#{name} = Time.parse(new_value) + rescue ArgumentError + end + end + end + end + + # Is it need? + if @#{name} + class << @#{name} + undef_method(:to_s) + alias_method(:to_s, :#{type}) + end + end + + end +EOC + end + + def integer_writer(name, disp_name=name) + module_eval(<<-EOC, *get_file_and_line_from_caller(2)) + def #{name}=(new_value) + if new_value.nil? + @#{name} = new_value + else + if @do_validate + begin + @#{name} = Integer(new_value) + rescue ArgumentError + raise NotAvailableValueError.new('#{disp_name}', new_value) + end + else + @#{name} = new_value.to_i + end + end + end +EOC + end + + def positive_integer_writer(name, disp_name=name) + module_eval(<<-EOC, *get_file_and_line_from_caller(2)) + def #{name}=(new_value) + if new_value.nil? + @#{name} = new_value + else + if @do_validate + begin + tmp = Integer(new_value) + raise ArgumentError if tmp <= 0 + @#{name} = tmp + rescue ArgumentError + raise NotAvailableValueError.new('#{disp_name}', new_value) + end + else + @#{name} = new_value.to_i + end + end + end +EOC + end + + def boolean_writer(name, disp_name=name) + module_eval(<<-EOC, *get_file_and_line_from_caller(2)) + def #{name}=(new_value) + if new_value.nil? + @#{name} = new_value + else + if @do_validate and + ![true, false, "true", "false"].include?(new_value) + raise NotAvailableValueError.new('#{disp_name}', new_value) + end + if [true, false].include?(new_value) + @#{name} = new_value + else + @#{name} = new_value == "true" + end + 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} + @#{accessor_name} + end + + def #{accessor_name}(*args) + if args.empty? + @#{accessor_name}.first + else + @#{accessor_name}[*args] + end + end + + def #{accessor_name}=(*args) + warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \ + "Don't use `#{accessor_name} = XXX'/`set_#{accessor_name}(XXX)'. " \ + "Those APIs are not sense of Ruby. " \ + "Use `#{plural_name} << XXX' instead of them.") + if args.size == 1 + @#{accessor_name}.push(args[0]) + else + @#{accessor_name}.__send__("[]=", *args) + end + end + alias_method(:set_#{accessor_name}, :#{accessor_name}=) +EOC + end + end + + class Element + + extend BaseModel + include Utils + + INDENT = " " + + MUST_CALL_VALIDATORS = {} + MODELS = [] + GET_ATTRIBUTES = [] + HAVE_CHILDREN_ELEMENTS = [] + TO_ELEMENT_METHODS = [] + NEED_INITIALIZE_VARIABLES = [] + PLURAL_FORMS = {} + + class << self + + def must_call_validators + MUST_CALL_VALIDATORS + end + def models + MODELS + end + def get_attributes + GET_ATTRIBUTES + end + def have_children_elements + HAVE_CHILDREN_ELEMENTS + end + def to_element_methods + TO_ELEMENT_METHODS + end + def need_initialize_variables + NEED_INITIALIZE_VARIABLES + end + def plural_forms + PLURAL_FORMS + end + + + def inherited(klass) + klass.const_set("MUST_CALL_VALIDATORS", {}) + 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", {}) + + klass.module_eval(<<-EOC) + public + + @tag_name = name.split(/::/).last + @tag_name[0,1] = @tag_name[0,1].downcase + @have_content = false + + 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) + end + + + def self.install_must_call_validator(prefix, uri) + MUST_CALL_VALIDATORS[uri] = prefix + 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 + end + + def self.install_get_attribute(name, uri, required=true, + type=nil, disp_name=nil, + element_name=nil) + disp_name ||= name + element_name ||= name + def_corresponded_attr_writer name, type, disp_name + convert_attr_reader name + if type == :boolean and /^is/ =~ name + alias_method "\#{$POSTMATCH}?", name + end + 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) + 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 + else + attr_writer name + end + end + + def self.content_setup(type=nil) + def_corresponded_attr_writer "content", type + convert_attr_reader :content + @have_content = true + end + + def self.have_content? + @have_content + 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 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 + end + + def required_prefix + nil + end + + def required_uri + "" + end + + def install_ns(prefix, uri) + if self::NSPOOL.has_key?(prefix) + raise OverlappedPrefixError.new(prefix) + end + self::NSPOOL[prefix] = uri + end + + def tag_name + @tag_name + end + end + + attr_accessor :do_validate + + def initialize(do_validate=true, attrs={}) + @converter = nil + @do_validate = do_validate + initialize_variables(attrs) + end + + def tag_name + self.class.tag_name + end + + def full_name + tag_name + end + + def converter=(converter) + @converter = converter + targets = children.dup + self.class.have_children_elements.each do |variable_name, plural_name| + targets.concat(__send__(plural_name)) + end + targets.each do |target| + target.converter = converter unless target.nil? + end + end + + def convert(value) + if @converter + @converter.convert(value) + else + value + end + end + + def validate(ignore_unknown_element=true) + validate_attribute + __validate(ignore_unknown_element) + end + + def validate_for_stream(tags, ignore_unknown_element=true) + validate_attribute + __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) + end + end + + def to_s(need_convert=true, indent='') + if self.class.have_content? + return "" unless @content + rv = tag(indent) do |next_indent| + h(@content) + 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 + + private + 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| + 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? + end + + def initialize_have_children_elements + self.class.have_children_elements.each do |variable_name, plural_name| + instance_eval("@#{variable_name} = []") + end + end + + def tag(indent, additional_attrs={}, &block) + next_indent = indent + INDENT + + attrs = collect_attrs + return "" if attrs.nil? + + attrs.update(additional_attrs) + start_tag = make_start_tag(indent, next_indent, attrs) + + if block + content = block.call(next_indent) + else + content = [] + end + + if content.is_a?(String) + content = [content] + start_tag << ">" + end_tag = "</#{full_name}>" + else + content = content.reject{|x| x.empty?} + if content.empty? + end_tag = "/>" + else + start_tag << ">\n" + end_tag = "\n#{indent}</#{full_name}>" + end + end + + start_tag + content.join("\n") + end_tag + end + + def make_start_tag(indent, next_indent, attrs) + start_tag = ["#{indent}<#{full_name}"] + unless attrs.empty? + start_tag << attrs.collect do |key, value| + %Q[#{h key}="#{h value}"] + end.join("\n#{next_indent}") + end + start_tag.join(" ") + end + + def collect_attrs + attrs = {} + _attrs.each do |name, required, alias_name| + value = __send__(alias_name || name) + return nil if required and 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 + + # For backward compatibility + def calc_indent + '' + 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 + 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| + 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 + + 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(ignore_unknown_element, tags=_tags, recursive=true) + if recursive + children.compact.each do |child| + child.validate + end + end + must_call_validators = self.class.must_call_validators + tags = tag_filter(tags.dup) + p tags if DEBUG + must_call_validators.each do |uri, prefix| + _validate(ignore_unknown_element, tags[uri], uri) + meth = "#{prefix}_validate" + if 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? + raise MissingAttributeError.new(tag_name, a_name) + end + end + end + + def _validate(ignore_unknown_element, tags, uri, models=self.class.models) + count = 1 + do_redo = false + not_shift = false + tag = nil + 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 + + models.each_with_index do |model, i| + name, model_uri, occurs, getter = model + + if DEBUG + p "before" + p tags + p model + end + + if not_shift + not_shift = false + elsif tags + tag = tags.shift + end + + if DEBUG + p "mid" + p count + end + + case occurs + when '?' + if count > 2 + raise TooMuchTagError.new(name, tag_name) + else + if name == tag + do_redo = true + else + not_shift = true + end + end + when '*' + if name == tag + do_redo = true + else + not_shift = true + end + when '+' + if name == tag + do_redo = true + else + if count > 1 + not_shift = true + else + raise MissingTagError.new(name, tag_name) + end + end + else + 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(name, tag_name) + end + end + + if DEBUG + p "after" + p not_shift + p do_redo + p tag + end + + if do_redo + do_redo = false + count += 1 + redo + else + count = 1 + end + + end + + if !ignore_unknown_element and !tags.nil? and !tags.empty? + raise NotExpectedTagError.new(tags.first, uri, tag_name) + end + + end + + def tag_filter(tags) + rv = {} + tags.each do |tag| + rv[tag[0]] = [] unless rv.has_key?(tag[0]) + rv[tag[0]].push(tag[1]) + end + rv + end + + end + + module RootElementMixin + + include XMLStyleSheetMixin + + attr_reader :output_encoding + + def initialize(rss_version, version=nil, encoding=nil, standalone=nil) + super() + @rss_version = rss_version + @version = version || '1.0' + @encoding = encoding + @standalone = standalone + @output_encoding = nil + end + + def output_encoding=(enc) + @output_encoding = enc + self.converter = Converter.new(@output_encoding, @encoding) + end + + def setup_maker(maker) + maker.version = version + maker.encoding = encoding + maker.standalone = standalone + + xml_stylesheets.each do |xss| + xss.setup_maker(maker) + end + + setup_maker_elements(maker) + end + + def to_xml(version=nil, &block) + if version.nil? or version == @rss_version + to_s + else + RSS::Maker.make(version) do |maker| + setup_maker(maker) + block.call(maker) if block + end.to_s + end + end + + private + def tag(indent, attrs={}, &block) + rv = xmldecl + xml_stylesheet_pi + rv << super(indent, ns_declarations.merge(attrs), &block) + rv + end + + def xmldecl + rv = %Q[<?xml version="#{@version}"] + if @output_encoding or @encoding + rv << %Q[ encoding="#{@output_encoding or @encoding}"] + end + rv << %Q[ standalone="yes"] if @standalone + rv << "?>\n" + rv + end + + def ns_declarations + decls = {} + self.class::NSPOOL.collect do |prefix, uri| + prefix = ":#{prefix}" unless prefix.empty? + 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) + end + end + +end diff --git a/ruby_1_8_6/lib/rss/syndication.rb b/ruby_1_8_6/lib/rss/syndication.rb new file mode 100644 index 0000000000..93d35c89a7 --- /dev/null +++ b/ruby_1_8_6/lib/rss/syndication.rb @@ -0,0 +1,64 @@ +require "rss/1.0" + +module RSS + + SY_PREFIX = 'sy' + SY_URI = "http://purl.org/rss/1.0/modules/syndication/" + + RDF.install_ns(SY_PREFIX, SY_URI) + + module SyndicationModel + + extend BaseModel + + ELEMENTS = [] + + def self.append_features(klass) + super + + klass.install_must_call_validator(SY_PREFIX, SY_URI) + klass.module_eval do + [ + ["updatePeriod"], + ["updateFrequency", :positive_integer] + ].each do |name, type| + install_text_element(name, SY_URI, "?", + "#{SY_PREFIX}_#{name}", type, + "#{SY_PREFIX}:#{name}") + end + + %w(updateBase).each do |name| + install_date_element(name, SY_URI, "?", + "#{SY_PREFIX}_#{name}", 'w3cdtf', name) + end + + alias_method(:_sy_updatePeriod=, :sy_updatePeriod=) + def sy_updatePeriod=(new_value) + new_value = new_value.strip + validate_sy_updatePeriod(new_value) if @do_validate + self._sy_updatePeriod = new_value + end + end + end + + private + SY_UPDATEPERIOD_AVAILABLE_VALUES = %w(hourly daily weekly monthly yearly) + def validate_sy_updatePeriod(value) + unless SY_UPDATEPERIOD_AVAILABLE_VALUES.include?(value) + raise NotAvailableValueError.new("updatePeriod", value) + end + end + end + + class RDF + class Channel; include SyndicationModel; end + end + + prefix_size = SY_PREFIX.size + 1 + 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}=") + end + +end diff --git a/ruby_1_8_6/lib/rss/taxonomy.rb b/ruby_1_8_6/lib/rss/taxonomy.rb new file mode 100644 index 0000000000..8caa25e2a4 --- /dev/null +++ b/ruby_1_8_6/lib/rss/taxonomy.rb @@ -0,0 +1,145 @@ +require "rss/1.0" +require "rss/dublincore" + +module RSS + + TAXO_PREFIX = "taxo" + TAXO_URI = "http://purl.org/rss/1.0/modules/taxonomy/" + + RDF.install_ns(TAXO_PREFIX, TAXO_URI) + + TAXO_ELEMENTS = [] + + %w(link).each do |name| + full_name = "#{TAXO_PREFIX}_#{name}" + BaseListener.install_get_text_element(TAXO_URI, name, "#{full_name}=") + TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" + end + + %w(topic topics).each do |name| + class_name = Utils.to_class_name(name) + BaseListener.install_class_name(TAXO_URI, name, "Taxonomy#{class_name}") + TAXO_ELEMENTS << "#{TAXO_PREFIX}_#{name}" + end + + module TaxonomyTopicsModel + extend BaseModel + + def self.append_features(klass) + super + + 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 + + class TaxonomyTopics < Element + include RSS10 + + Bag = ::RSS::RDF::Bag + + class << self + def required_prefix + TAXO_PREFIX + end + + def required_uri + TAXO_URI + end + end + + @tag_name = "topics" + + install_have_child_element("Bag", RDF::URI, nil) + install_must_call_validator('rdf', RDF::URI) + + 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 + tag_name_with_prefix(TAXO_PREFIX) + end + + def maker_target(target) + target.taxo_topics + end + + def resources + if @Bag + @Bag.lis.collect do |li| + li.resource + end + else + [] + end + end + end + end + + module TaxonomyTopicModel + extend BaseModel + + def self.append_features(klass) + super + var_name = "#{TAXO_PREFIX}_topic" + klass.install_have_children_element("topic", TAXO_URI, "*", var_name) + end + + class TaxonomyTopic < Element + include RSS10 + + include DublinCoreModel + include TaxonomyTopicsModel + + class << self + def required_prefix + TAXO_PREFIX + end + + def required_uri + TAXO_URI + end + end + + @tag_name = "topic" + + install_get_attribute("about", ::RSS::RDF::URI, true, nil, nil, + "#{RDF::PREFIX}:about") + install_text_element("link", TAXO_URI, "?", "#{TAXO_PREFIX}_link") + + 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 maker_target(target) + target.new_taxo_topic + end + end + end + + class RDF + include TaxonomyTopicModel + class Channel + include TaxonomyTopicsModel + end + class Item; include TaxonomyTopicsModel; end + end +end diff --git a/ruby_1_8_6/lib/rss/trackback.rb b/ruby_1_8_6/lib/rss/trackback.rb new file mode 100644 index 0000000000..ee2491f332 --- /dev/null +++ b/ruby_1_8_6/lib/rss/trackback.rb @@ -0,0 +1,288 @@ +require 'rss/1.0' +require 'rss/2.0' + +module RSS + + TRACKBACK_PREFIX = 'trackback' + TRACKBACK_URI = 'http://madskills.com/public/xml/rss/module/trackback/' + + RDF.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) + Rss.install_ns(TRACKBACK_PREFIX, TRACKBACK_URI) + + module TrackBackUtils + private + 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) + + def append_features(klass) + super + + 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(name, TRACKBACK_URI, "?", var_name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + remove_method :#{var_name} + def #{var_name} + @#{var_name} and @#{var_name}.value + end + + remove_method :#{var_name}= + def #{var_name}=(value) + @#{var_name} = Utils.new_with_value_if_need(#{klass_name}, value) + end + EOC + end + + [%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(name, TRACKBACK_URI, "*", + var_name) + klass.module_eval(<<-EOC, __FILE__, __LINE__) + remove_method :#{var_name} + def #{var_name}(*args) + if args.empty? + @#{var_name}.first and @#{var_name}.first.value + else + ret = @#{var_name}.__send__("[]", *args) + if ret.is_a?(Array) + ret.collect {|x| x.value} + else + ret.value + end + end + end + + remove_method :#{var_name}= + remove_method :set_#{var_name} + def #{var_name}=(*args) + if args.size == 1 + item = Utils.new_with_value_if_need(#{klass_name}, args[0]) + @#{var_name}.push(item) + else + new_val = args.last + if new_val.is_a?(Array) + new_val = new_value.collect do |val| + Utils.new_with_value_if_need(#{klass_name}, val) + end + else + new_val = Utils.new_with_value_if_need(#{klass_name}, new_val) + end + @#{var_name}.__send__("[]=", *(args[0..-2] + [new_val])) + end + end + alias set_#{var_name} #{var_name}= + EOC + end + end + end + end + + module TrackBackModel10 + extend BaseModel + extend BaseTrackBackModel + + class TrackBackPing < Element + include RSS10 + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end + + end + + @tag_name = "ping" + + [ + ["resource", ::RSS::RDF::URI, true] + ].each do |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(*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 + end + + class TrackBackAbout < Element + include RSS10 + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end + + end + + @tag_name = "about" + + [ + ["resource", ::RSS::RDF::URI, true] + ].each do |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(*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 + + private + def maker_target(abouts) + abouts.new_about + end + + def setup_maker_attributes(about) + about.resource = self.resource + end + + end + end + + module TrackBackModel20 + extend BaseModel + extend BaseTrackBackModel + + class TrackBackPing < Element + include RSS09 + + @tag_name = "ping" + + content_setup + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end + + end + + alias_method(:value, :content) + alias_method(:value=, :content=) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.content = args[0] + end + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + + end + + class TrackBackAbout < Element + include RSS09 + + @tag_name = "about" + + content_setup + + class << self + + def required_prefix + TRACKBACK_PREFIX + end + + def required_uri + TRACKBACK_URI + end + + end + + alias_method(:value, :content) + alias_method(:value=, :content=) + + def initialize(*args) + if Utils.element_initialize_arguments?(args) + super + else + super() + self.content = args[0] + end + end + + def full_name + tag_name_with_prefix(TRACKBACK_PREFIX) + end + + end + end + + class RDF + class Item; include TrackBackModel10; end + end + + class Rss + class Channel + class Item; include TrackBackModel20; end + end + end + + BaseTrackBackModel::ELEMENTS.each do |name| + class_name = Utils.to_class_name(name) + BaseListener.install_class_name(TRACKBACK_URI, name, + "TrackBack#{class_name}") + end + + BaseTrackBackModel::ELEMENTS.collect! {|name| "#{TRACKBACK_PREFIX}_#{name}"} +end diff --git a/ruby_1_8_6/lib/rss/utils.rb b/ruby_1_8_6/lib/rss/utils.rb new file mode 100644 index 0000000000..b242a72292 --- /dev/null +++ b/ruby_1_8_6/lib/rss/utils.rb @@ -0,0 +1,37 @@ +module RSS + module Utils + module_function + + # Convert a name_with_underscores to CamelCase. + def to_class_name(name) + 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] + end + + # escape '&', '"', '<' and '>' for use in HTML. + def html_escape(s) + s.to_s.gsub(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<") + end + alias h html_escape + + # If +value+ is an instance of class +klass+, return it, else + # create a new instance of +klass+ with value +value+. + def new_with_value_if_need(klass, value) + if value.is_a?(klass) + value + else + klass.new(value) + end + end + + def element_initialize_arguments?(args) + [true, false].include?(args[0]) and args[1].is_a?(Hash) + end + end +end diff --git a/ruby_1_8_6/lib/rss/xml-stylesheet.rb b/ruby_1_8_6/lib/rss/xml-stylesheet.rb new file mode 100644 index 0000000000..66e3161dd0 --- /dev/null +++ b/ruby_1_8_6/lib/rss/xml-stylesheet.rb @@ -0,0 +1,101 @@ +require "rss/utils" + +module RSS + + module XMLStyleSheetMixin + attr_accessor :xml_stylesheets + def initialize(*args) + super + @xml_stylesheets = [] + end + + private + def xml_stylesheet_pi + xsss = @xml_stylesheets.collect do |xss| + pi = xss.to_s + pi = nil if /\A\s*\z/ =~ pi + pi + end.compact + xsss.push("") unless xsss.empty? + xsss.join("\n") + end + end + + class XMLStyleSheet + + include Utils + + ATTRIBUTES = %w(href type title media charset alternate) + + GUESS_TABLE = { + "xsl" => "text/xsl", + "css" => "text/css", + } + + attr_accessor(*ATTRIBUTES) + attr_accessor(:do_validate) + def initialize(*attrs) + @do_validate = true + ATTRIBUTES.each do |attr| + __send__("#{attr}=", nil) + end + vars = ATTRIBUTES.dup + vars.unshift(:do_validate) + attrs.each do |name, value| + if vars.include?(name.to_s) + __send__("#{name}=", value) + end + end + end + + def to_s + rv = "" + if @href + rv << %Q[<?xml-stylesheet] + ATTRIBUTES.each do |name| + if __send__(name) + rv << %Q[ #{name}="#{h __send__(name)}"] + end + end + rv << %Q[?>] + end + rv + end + + remove_method(:href=) + def href=(value) + @href = value + if @href and @type.nil? + @type = guess_type(@href) + end + @href + end + + remove_method(:alternate=) + def alternate=(value) + if value.nil? or /\A(?:yes|no)\z/ =~ value + @alternate = value + else + if @do_validate + args = ["?xml-stylesheet?", %Q[alternate="#{value}"]] + raise NotAvailableValueError.new(*args) + end + end + @alternate + end + + def setup_maker(maker) + xss = maker.xml_stylesheets.new_xml_stylesheet + ATTRIBUTES.each do |attr| + xss.__send__("#{attr}=", __send__(attr)) + end + end + + private + def guess_type(filename) + /\.([^.]+)$/ =~ filename + GUESS_TABLE[$1] + end + + end +end diff --git a/ruby_1_8_6/lib/rss/xmlparser.rb b/ruby_1_8_6/lib/rss/xmlparser.rb new file mode 100644 index 0000000000..3dfe7d461a --- /dev/null +++ b/ruby_1_8_6/lib/rss/xmlparser.rb @@ -0,0 +1,93 @@ +begin + require "xml/parser" +rescue LoadError + require "xmlparser" +end + +begin + require "xml/encoding-ja" +rescue LoadError + require "xmlencoding-ja" + if defined?(Kconv) + module XMLEncoding_ja + class SJISHandler + include Kconv + end + end + end +end + +module XML + class Parser + unless defined?(Error) + Error = ::XMLParserError + end + end +end + +module RSS + + class REXMLLikeXMLParser < ::XML::Parser + + include ::XML::Encoding_ja + + def listener=(listener) + @listener = listener + end + + def startElement(name, attrs) + @listener.tag_start(name, attrs) + end + + def endElement(name) + @listener.tag_end(name) + end + + def character(data) + @listener.text(data) + end + + def xmlDecl(version, encoding, standalone) + @listener.xmldecl(version, encoding, standalone == 1) + end + + def processingInstruction(target, content) + @listener.instruction(target, content) + end + + end + + class XMLParserParser < BaseParser + + class << self + def listener + XMLParserListener + end + end + + private + def _parse + begin + parser = REXMLLikeXMLParser.new + parser.listener = @listener + parser.parse(@rss) + rescue ::XML::Parser::Error => e + raise NotWellFormedError.new(parser.line){e.message} + end + end + + end + + class XMLParserListener < BaseListener + + include ListenerMixin + + def xmldecl(version, encoding, standalone) + super + # Encoding is converted to UTF-8 when XMLParser parses XML. + @encoding = 'UTF-8' + end + + end + +end diff --git a/ruby_1_8_6/lib/rss/xmlscanner.rb b/ruby_1_8_6/lib/rss/xmlscanner.rb new file mode 100644 index 0000000000..61b9fa6bf4 --- /dev/null +++ b/ruby_1_8_6/lib/rss/xmlscanner.rb @@ -0,0 +1,121 @@ +require 'xmlscan/scanner' +require 'stringio' + +module RSS + + class XMLScanParser < BaseParser + + class << self + def listener + XMLScanListener + end + end + + private + def _parse + begin + if @rss.is_a?(String) + input = StringIO.new(@rss) + else + input = @rss + end + scanner = XMLScan::XMLScanner.new(@listener) + scanner.parse(input) + rescue XMLScan::Error => e + lineno = e.lineno || scanner.lineno || input.lineno + raise NotWellFormedError.new(lineno){e.message} + end + end + + end + + class XMLScanListener < BaseListener + + include XMLScan::Visitor + include ListenerMixin + + ENTITIES = { + 'lt' => '<', + 'gt' => '>', + 'amp' => '&', + 'quot' => '"', + 'apos' => '\'' + } + + def on_xmldecl_version(str) + @version = str + end + + def on_xmldecl_encoding(str) + @encoding = str + end + + def on_xmldecl_standalone(str) + @standalone = str + end + + def on_xmldecl_end + xmldecl(@version, @encoding, @standalone == "yes") + end + + alias_method(:on_pi, :instruction) + alias_method(:on_chardata, :text) + alias_method(:on_cdata, :text) + + def on_etag(name) + tag_end(name) + end + + def on_entityref(ref) + text(entity(ref)) + end + + def on_charref(code) + text([code].pack('U')) + end + + alias_method(:on_charref_hex, :on_charref) + + def on_stag(name) + @attrs = {} + end + + def on_attribute(name) + @attrs[name] = @current_attr = '' + end + + def on_attr_value(str) + @current_attr << str + end + + def on_attr_entityref(ref) + @current_attr << entity(ref) + end + + def on_attr_charref(code) + @current_attr << [code].pack('U') + end + + alias_method(:on_attr_charref_hex, :on_attr_charref) + + def on_stag_end(name) + tag_start(name, @attrs) + end + + def on_stag_end_empty(name) + tag_start(name, @attrs) + tag_end(name) + end + + private + def entity(ref) + ent = ENTITIES[ref] + if ent + ent + else + wellformed_error("undefined entity: #{ref}") + end + end + end + +end |