1require "time"
2
3class Time
4  class << self
5    unless respond_to?(:w3cdtf)
6      def w3cdtf(date)
7        if /\A\s*
8            (-?\d+)-(\d\d)-(\d\d)
9            (?:T
10            (\d\d):(\d\d)(?::(\d\d))?
11            (\.\d+)?
12            (Z|[+-]\d\d:\d\d)?)?
13            \s*\z/ix =~ date and (($5 and $8) or (!$5 and !$8))
14          datetime = [$1.to_i, $2.to_i, $3.to_i, $4.to_i, $5.to_i, $6.to_i]
15          usec = 0
16          usec = $7.to_f * 1000000 if $7
17          zone = $8
18          if zone
19            off = zone_offset(zone, datetime[0])
20            datetime = apply_offset(*(datetime + [off]))
21            datetime << usec
22            time = Time.utc(*datetime)
23            time.localtime unless zone_utc?(zone)
24            time
25          else
26            datetime << usec
27            Time.local(*datetime)
28          end
29        else
30          raise ArgumentError.new("invalid date: #{date.inspect}")
31        end
32      end
33    end
34  end
35
36  unless method_defined?(:w3cdtf)
37    def w3cdtf
38      if usec.zero?
39        fraction_digits = 0
40      else
41        fraction_digits = Math.log10(usec.to_s.sub(/0*$/, '').to_i).floor + 1
42      end
43      xmlschema(fraction_digits)
44    end
45  end
46end
47
48
49require "English"
50require "rss/utils"
51require "rss/converter"
52require "rss/xml-stylesheet"
53
54module RSS
55
56  VERSION = "0.2.7"
57
58  URI = "http://purl.org/rss/1.0/"
59
60  DEBUG = false
61
62  class Error < StandardError; end
63
64  class OverlappedPrefixError < Error
65    attr_reader :prefix
66    def initialize(prefix)
67      @prefix = prefix
68    end
69  end
70
71  class InvalidRSSError < Error; end
72
73  ##
74  # Raised if no matching tag is found.
75
76  class MissingTagError < InvalidRSSError
77    attr_reader :tag, :parent
78    def initialize(tag, parent)
79      @tag, @parent = tag, parent
80      super("tag <#{tag}> is missing in tag <#{parent}>")
81    end
82  end
83
84  ##
85  # Raised if there are more occurrences of the tag than expected.
86
87  class TooMuchTagError < InvalidRSSError
88    attr_reader :tag, :parent
89    def initialize(tag, parent)
90      @tag, @parent = tag, parent
91      super("tag <#{tag}> is too much in tag <#{parent}>")
92    end
93  end
94
95  ##
96  # Raised if a required attribute is missing.
97
98  class MissingAttributeError < InvalidRSSError
99    attr_reader :tag, :attribute
100    def initialize(tag, attribute)
101      @tag, @attribute = tag, attribute
102      super("attribute <#{attribute}> is missing in tag <#{tag}>")
103    end
104  end
105
106  ##
107  # Raised when an unknown tag is found.
108
109  class UnknownTagError < InvalidRSSError
110    attr_reader :tag, :uri
111    def initialize(tag, uri)
112      @tag, @uri = tag, uri
113      super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>")
114    end
115  end
116
117  ##
118  # Raised when an unexpected tag is encountered.
119
120  class NotExpectedTagError < InvalidRSSError
121    attr_reader :tag, :uri, :parent
122    def initialize(tag, uri, parent)
123      @tag, @uri, @parent = tag, uri, parent
124      super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>")
125    end
126  end
127  # For backward compatibility :X
128  NotExceptedTagError = NotExpectedTagError
129
130  ##
131  # Raised when an incorrect value is used.
132
133  class NotAvailableValueError < InvalidRSSError
134    attr_reader :tag, :value, :attribute
135    def initialize(tag, value, attribute=nil)
136      @tag, @value, @attribute = tag, value, attribute
137      message = "value <#{value}> of "
138      message << "attribute <#{attribute}> of " if attribute
139      message << "tag <#{tag}> is not available."
140      super(message)
141    end
142  end
143
144  ##
145  # Raised when an unknown conversion error occurs.
146
147  class UnknownConversionMethodError < Error
148    attr_reader :to, :from
149    def initialize(to, from)
150      @to = to
151      @from = from
152      super("can't convert to #{to} from #{from}.")
153    end
154  end
155  # for backward compatibility
156  UnknownConvertMethod = UnknownConversionMethodError
157
158  ##
159  # Raised when a conversion failure occurs.
160
161  class ConversionError < Error
162    attr_reader :string, :to, :from
163    def initialize(string, to, from)
164      @string = string
165      @to = to
166      @from = from
167      super("can't convert #{@string} to #{to} from #{from}.")
168    end
169  end
170
171  ##
172  # Raised when a required variable is not set.
173
174  class NotSetError < Error
175    attr_reader :name, :variables
176    def initialize(name, variables)
177      @name = name
178      @variables = variables
179      super("required variables of #{@name} are not set: #{@variables.join(', ')}")
180    end
181  end
182
183  ##
184  # Raised when a RSS::Maker attempts to use an unknown maker.
185
186  class UnsupportedMakerVersionError < Error
187    attr_reader :version
188    def initialize(version)
189      @version = version
190      super("Maker doesn't support version: #{@version}")
191    end
192  end
193
194  module BaseModel
195    include Utils
196
197    def install_have_child_element(tag_name, uri, occurs, name=nil, type=nil)
198      name ||= tag_name
199      add_need_initialize_variable(name)
200      install_model(tag_name, uri, occurs, name)
201
202      writer_type, reader_type = type
203      def_corresponded_attr_writer name, writer_type
204      def_corresponded_attr_reader name, reader_type
205      install_element(name) do |n, elem_name|
206        <<-EOC
207        if @#{n}
208          "\#{@#{n}.to_s(need_convert, indent)}"
209        else
210          ''
211        end
212EOC
213      end
214    end
215    alias_method(:install_have_attribute_element, :install_have_child_element)
216
217    def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil)
218      name ||= tag_name
219      plural_name ||= "#{name}s"
220      add_have_children_element(name, plural_name)
221      add_plural_form(name, plural_name)
222      install_model(tag_name, uri, occurs, plural_name, true)
223
224      def_children_accessor(name, plural_name)
225      install_element(name, "s") do |n, elem_name|
226        <<-EOC
227        rv = []
228        @#{n}.each do |x|
229          value = "\#{x.to_s(need_convert, indent)}"
230          rv << value if /\\A\\s*\\z/ !~ value
231        end
232        rv.join("\n")
233EOC
234      end
235    end
236
237    def install_text_element(tag_name, uri, occurs, name=nil, type=nil,
238                             disp_name=nil)
239      name ||= tag_name
240      disp_name ||= name
241      self::ELEMENTS << name unless self::ELEMENTS.include?(name)
242      add_need_initialize_variable(name)
243      install_model(tag_name, uri, occurs, name)
244
245      def_corresponded_attr_writer(name, type, disp_name)
246      def_corresponded_attr_reader(name, type || :convert)
247      install_element(name) do |n, elem_name|
248        <<-EOC
249        if respond_to?(:#{n}_content)
250          content = #{n}_content
251        else
252          content = @#{n}
253        end
254        if content
255          rv = "\#{indent}<#{elem_name}>"
256          value = html_escape(content)
257          if need_convert
258            rv << convert(value)
259          else
260            rv << value
261          end
262            rv << "</#{elem_name}>"
263          rv
264        else
265          ''
266        end
267EOC
268      end
269    end
270
271    def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
272      name ||= tag_name
273      type ||= :w3cdtf
274      disp_name ||= name
275      self::ELEMENTS << name
276      add_need_initialize_variable(name)
277      install_model(tag_name, uri, occurs, name)
278
279      # accessor
280      convert_attr_reader name
281      date_writer(name, type, disp_name)
282
283      install_element(name) do |n, elem_name|
284        <<-EOC
285        if @#{n}
286          rv = "\#{indent}<#{elem_name}>"
287          value = html_escape(@#{n}.#{type})
288          if need_convert
289            rv << convert(value)
290          else
291            rv << value
292          end
293            rv << "</#{elem_name}>"
294          rv
295        else
296          ''
297        end
298EOC
299      end
300
301    end
302
303    private
304    def install_element(name, postfix="")
305      elem_name = name.sub('_', ':')
306      method_name = "#{name}_element#{postfix}"
307      add_to_element_method(method_name)
308      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
309      def #{method_name}(need_convert=true, indent='')
310        #{yield(name, elem_name)}
311      end
312      private :#{method_name}
313EOC
314    end
315
316    def inherit_convert_attr_reader(*attrs)
317      attrs.each do |attr|
318        attr = attr.id2name if attr.kind_of?(Integer)
319        module_eval(<<-EOC, *get_file_and_line_from_caller(2))
320        def #{attr}_without_inherit
321          convert(@#{attr})
322        end
323
324        def #{attr}
325          if @#{attr}
326            #{attr}_without_inherit
327          elsif @parent
328            @parent.#{attr}
329          else
330            nil
331          end
332        end
333EOC
334      end
335    end
336
337    def uri_convert_attr_reader(*attrs)
338      attrs.each do |attr|
339        attr = attr.id2name if attr.kind_of?(Integer)
340        module_eval(<<-EOC, *get_file_and_line_from_caller(2))
341        def #{attr}_without_base
342          convert(@#{attr})
343        end
344
345        def #{attr}
346          value = #{attr}_without_base
347          return nil if value.nil?
348          if /\\A[a-z][a-z0-9+.\\-]*:/i =~ value
349            value
350          else
351            "\#{base}\#{value}"
352          end
353        end
354EOC
355      end
356    end
357
358    def convert_attr_reader(*attrs)
359      attrs.each do |attr|
360        attr = attr.id2name if attr.kind_of?(Integer)
361        module_eval(<<-EOC, *get_file_and_line_from_caller(2))
362        def #{attr}
363          convert(@#{attr})
364        end
365EOC
366      end
367    end
368
369    def yes_clean_other_attr_reader(*attrs)
370      attrs.each do |attr|
371        attr = attr.id2name if attr.kind_of?(Integer)
372        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
373          attr_reader(:#{attr})
374          def #{attr}?
375            YesCleanOther.parse(@#{attr})
376          end
377        EOC
378      end
379    end
380
381    def yes_other_attr_reader(*attrs)
382      attrs.each do |attr|
383        attr = attr.id2name if attr.kind_of?(Integer)
384        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
385          attr_reader(:#{attr})
386          def #{attr}?
387            Utils::YesOther.parse(@#{attr})
388          end
389        EOC
390      end
391    end
392
393    def csv_attr_reader(*attrs)
394      separator = nil
395      if attrs.last.is_a?(Hash)
396        options = attrs.pop
397        separator = options[:separator]
398      end
399      separator ||= ", "
400      attrs.each do |attr|
401        attr = attr.id2name if attr.kind_of?(Integer)
402        module_eval(<<-EOC, __FILE__, __LINE__ + 1)
403          attr_reader(:#{attr})
404          def #{attr}_content
405            if @#{attr}.nil?
406              @#{attr}
407            else
408              @#{attr}.join(#{separator.dump})
409            end
410          end
411        EOC
412      end
413    end
414
415    def date_writer(name, type, disp_name=name)
416      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
417      def #{name}=(new_value)
418        if new_value.nil?
419          @#{name} = new_value
420        elsif new_value.kind_of?(Time)
421          @#{name} = new_value.dup
422        else
423          if @do_validate
424            begin
425              @#{name} = Time.__send__('#{type}', new_value)
426            rescue ArgumentError
427              raise NotAvailableValueError.new('#{disp_name}', new_value)
428            end
429          else
430            @#{name} = nil
431            if /\\A\\s*\\z/ !~ new_value.to_s
432              begin
433                unless Date._parse(new_value, false).empty?
434                  @#{name} = Time.parse(new_value)
435                end
436              rescue ArgumentError
437              end
438            end
439          end
440        end
441
442        # Is it need?
443        if @#{name}
444          class << @#{name}
445            undef_method(:to_s)
446            alias_method(:to_s, :#{type})
447          end
448        end
449
450      end
451EOC
452    end
453
454    def integer_writer(name, disp_name=name)
455      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
456      def #{name}=(new_value)
457        if new_value.nil?
458          @#{name} = new_value
459        else
460          if @do_validate
461            begin
462              @#{name} = Integer(new_value)
463            rescue ArgumentError
464              raise NotAvailableValueError.new('#{disp_name}', new_value)
465            end
466          else
467            @#{name} = new_value.to_i
468          end
469        end
470      end
471EOC
472    end
473
474    def positive_integer_writer(name, disp_name=name)
475      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
476      def #{name}=(new_value)
477        if new_value.nil?
478          @#{name} = new_value
479        else
480          if @do_validate
481            begin
482              tmp = Integer(new_value)
483              raise ArgumentError if tmp <= 0
484              @#{name} = tmp
485            rescue ArgumentError
486              raise NotAvailableValueError.new('#{disp_name}', new_value)
487            end
488          else
489            @#{name} = new_value.to_i
490          end
491        end
492      end
493EOC
494    end
495
496    def boolean_writer(name, disp_name=name)
497      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
498      def #{name}=(new_value)
499        if new_value.nil?
500          @#{name} = new_value
501        else
502          if @do_validate and
503              ![true, false, "true", "false"].include?(new_value)
504            raise NotAvailableValueError.new('#{disp_name}', new_value)
505          end
506          if [true, false].include?(new_value)
507            @#{name} = new_value
508          else
509            @#{name} = new_value == "true"
510          end
511        end
512      end
513EOC
514    end
515
516    def text_type_writer(name, disp_name=name)
517      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
518      def #{name}=(new_value)
519        if @do_validate and
520            !["text", "html", "xhtml", nil].include?(new_value)
521          raise NotAvailableValueError.new('#{disp_name}', new_value)
522        end
523        @#{name} = new_value
524      end
525EOC
526    end
527
528    def content_writer(name, disp_name=name)
529      klass_name = "self.class::#{Utils.to_class_name(name)}"
530      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
531      def #{name}=(new_value)
532        if new_value.is_a?(#{klass_name})
533          @#{name} = new_value
534        else
535          @#{name} = #{klass_name}.new
536          @#{name}.content = new_value
537        end
538      end
539EOC
540    end
541
542    def yes_clean_other_writer(name, disp_name=name)
543      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
544        def #{name}=(value)
545          value = (value ? "yes" : "no") if [true, false].include?(value)
546          @#{name} = value
547        end
548      EOC
549    end
550
551    def yes_other_writer(name, disp_name=name)
552      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
553        def #{name}=(new_value)
554          if [true, false].include?(new_value)
555            new_value = new_value ? "yes" : "no"
556          end
557          @#{name} = new_value
558        end
559      EOC
560    end
561
562    def csv_writer(name, disp_name=name)
563      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
564        def #{name}=(new_value)
565          @#{name} = Utils::CSV.parse(new_value)
566        end
567      EOC
568    end
569
570    def csv_integer_writer(name, disp_name=name)
571      module_eval(<<-EOC, __FILE__, __LINE__ + 1)
572        def #{name}=(new_value)
573          @#{name} = Utils::CSV.parse(new_value) {|v| Integer(v)}
574        end
575      EOC
576    end
577
578    def def_children_accessor(accessor_name, plural_name)
579      module_eval(<<-EOC, *get_file_and_line_from_caller(2))
580      def #{plural_name}
581        @#{accessor_name}
582      end
583
584      def #{accessor_name}(*args)
585        if args.empty?
586          @#{accessor_name}.first
587        else
588          @#{accessor_name}[*args]
589        end
590      end
591
592      def #{accessor_name}=(*args)
593        receiver = self.class.name
594        warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \
595             "Don't use `\#{receiver}\##{accessor_name} = XXX'/" \
596             "`\#{receiver}\#set_#{accessor_name}(XXX)'. " \
597             "Those APIs are not sense of Ruby. " \
598             "Use `\#{receiver}\##{plural_name} << XXX' instead of them.")
599        if args.size == 1
600          @#{accessor_name}.push(args[0])
601        else
602          @#{accessor_name}.__send__("[]=", *args)
603        end
604      end
605      alias_method(:set_#{accessor_name}, :#{accessor_name}=)
606EOC
607    end
608  end
609
610  module SetupMaker
611    def setup_maker(maker)
612      target = maker_target(maker)
613      unless target.nil?
614        setup_maker_attributes(target)
615        setup_maker_element(target)
616        setup_maker_elements(target)
617      end
618    end
619
620    private
621    def maker_target(maker)
622      nil
623    end
624
625    def setup_maker_attributes(target)
626    end
627
628    def setup_maker_element(target)
629      self.class.need_initialize_variables.each do |var|
630        value = __send__(var)
631        next if value.nil?
632        if value.respond_to?("setup_maker") and
633            !not_need_to_call_setup_maker_variables.include?(var)
634          value.setup_maker(target)
635        else
636          setter = "#{var}="
637          if target.respond_to?(setter)
638            target.__send__(setter, value)
639          end
640        end
641      end
642    end
643
644    def not_need_to_call_setup_maker_variables
645      []
646    end
647
648    def setup_maker_elements(parent)
649      self.class.have_children_elements.each do |name, plural_name|
650        if parent.respond_to?(plural_name)
651          target = parent.__send__(plural_name)
652          __send__(plural_name).each do |elem|
653            elem.setup_maker(target)
654          end
655        end
656      end
657    end
658  end
659
660  class Element
661    extend BaseModel
662    include Utils
663    extend Utils::InheritedReader
664    include SetupMaker
665
666    INDENT = "  "
667
668    MUST_CALL_VALIDATORS = {}
669    MODELS = []
670    GET_ATTRIBUTES = []
671    HAVE_CHILDREN_ELEMENTS = []
672    TO_ELEMENT_METHODS = []
673    NEED_INITIALIZE_VARIABLES = []
674    PLURAL_FORMS = {}
675
676    class << self
677      def must_call_validators
678        inherited_hash_reader("MUST_CALL_VALIDATORS")
679      end
680      def models
681        inherited_array_reader("MODELS")
682      end
683      def get_attributes
684        inherited_array_reader("GET_ATTRIBUTES")
685      end
686      def have_children_elements
687        inherited_array_reader("HAVE_CHILDREN_ELEMENTS")
688      end
689      def to_element_methods
690        inherited_array_reader("TO_ELEMENT_METHODS")
691      end
692      def need_initialize_variables
693        inherited_array_reader("NEED_INITIALIZE_VARIABLES")
694      end
695      def plural_forms
696        inherited_hash_reader("PLURAL_FORMS")
697      end
698
699      def inherited_base
700        ::RSS::Element
701      end
702
703      def inherited(klass)
704        klass.const_set(:MUST_CALL_VALIDATORS, {})
705        klass.const_set(:MODELS, [])
706        klass.const_set(:GET_ATTRIBUTES, [])
707        klass.const_set(:HAVE_CHILDREN_ELEMENTS, [])
708        klass.const_set(:TO_ELEMENT_METHODS, [])
709        klass.const_set(:NEED_INITIALIZE_VARIABLES, [])
710        klass.const_set(:PLURAL_FORMS, {})
711
712        tag_name = klass.name.split(/::/).last
713        tag_name[0, 1] = tag_name[0, 1].downcase
714        klass.instance_variable_set(:@tag_name, tag_name)
715        klass.instance_variable_set(:@have_content, false)
716      end
717
718      def install_must_call_validator(prefix, uri)
719        self::MUST_CALL_VALIDATORS[uri] = prefix
720      end
721
722      def install_model(tag, uri, occurs=nil, getter=nil, plural=false)
723        getter ||= tag
724        if m = self::MODELS.find {|t, u, o, g, p| t == tag and u == uri}
725          m[2] = occurs
726        else
727          self::MODELS << [tag, uri, occurs, getter, plural]
728        end
729      end
730
731      def install_get_attribute(name, uri, required=true,
732                                type=nil, disp_name=nil,
733                                element_name=nil)
734        disp_name ||= name
735        element_name ||= name
736        writer_type, reader_type = type
737        def_corresponded_attr_writer name, writer_type, disp_name
738        def_corresponded_attr_reader name, reader_type
739        if type == :boolean and /^is/ =~ name
740          alias_method "#{$POSTMATCH}?", name
741        end
742        self::GET_ATTRIBUTES << [name, uri, required, element_name]
743        add_need_initialize_variable(disp_name)
744      end
745
746      def def_corresponded_attr_writer(name, type=nil, disp_name=nil)
747        disp_name ||= name
748        case type
749        when :integer
750          integer_writer name, disp_name
751        when :positive_integer
752          positive_integer_writer name, disp_name
753        when :boolean
754          boolean_writer name, disp_name
755        when :w3cdtf, :rfc822, :rfc2822
756          date_writer name, type, disp_name
757        when :text_type
758          text_type_writer name, disp_name
759        when :content
760          content_writer name, disp_name
761        when :yes_clean_other
762          yes_clean_other_writer name, disp_name
763        when :yes_other
764          yes_other_writer name, disp_name
765        when :csv
766          csv_writer name
767        when :csv_integer
768          csv_integer_writer name
769        else
770          attr_writer name
771        end
772      end
773
774      def def_corresponded_attr_reader(name, type=nil)
775        case type
776        when :inherit
777          inherit_convert_attr_reader name
778        when :uri
779          uri_convert_attr_reader name
780        when :yes_clean_other
781          yes_clean_other_attr_reader name
782        when :yes_other
783          yes_other_attr_reader name
784        when :csv
785          csv_attr_reader name
786        when :csv_integer
787          csv_attr_reader name, :separator => ","
788        else
789          convert_attr_reader name
790        end
791      end
792
793      def content_setup(type=nil, disp_name=nil)
794        writer_type, reader_type = type
795        def_corresponded_attr_writer :content, writer_type, disp_name
796        def_corresponded_attr_reader :content, reader_type
797        @have_content = true
798      end
799
800      def have_content?
801        @have_content
802      end
803
804      def add_have_children_element(variable_name, plural_name)
805        self::HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
806      end
807
808      def add_to_element_method(method_name)
809        self::TO_ELEMENT_METHODS << method_name
810      end
811
812      def add_need_initialize_variable(variable_name)
813        self::NEED_INITIALIZE_VARIABLES << variable_name
814      end
815
816      def add_plural_form(singular, plural)
817        self::PLURAL_FORMS[singular] = plural
818      end
819
820      def required_prefix
821        nil
822      end
823
824      def required_uri
825        ""
826      end
827
828      def need_parent?
829        false
830      end
831
832      def install_ns(prefix, uri)
833        if self::NSPOOL.has_key?(prefix)
834          raise OverlappedPrefixError.new(prefix)
835        end
836        self::NSPOOL[prefix] = uri
837      end
838
839      def tag_name
840        @tag_name
841      end
842    end
843
844    attr_accessor :parent, :do_validate
845
846    def initialize(do_validate=true, attrs=nil)
847      @parent = nil
848      @converter = nil
849      if attrs.nil? and (do_validate.is_a?(Hash) or do_validate.is_a?(Array))
850        do_validate, attrs = true, do_validate
851      end
852      @do_validate = do_validate
853      initialize_variables(attrs || {})
854    end
855
856    def tag_name
857      self.class.tag_name
858    end
859
860    def full_name
861      tag_name
862    end
863
864    def converter=(converter)
865      @converter = converter
866      targets = children.dup
867      self.class.have_children_elements.each do |variable_name, plural_name|
868        targets.concat(__send__(plural_name))
869      end
870      targets.each do |target|
871        target.converter = converter unless target.nil?
872      end
873    end
874
875    def convert(value)
876      if @converter
877        @converter.convert(value)
878      else
879        value
880      end
881    end
882
883    def valid?(ignore_unknown_element=true)
884      validate(ignore_unknown_element)
885      true
886    rescue RSS::Error
887      false
888    end
889
890    def validate(ignore_unknown_element=true)
891      do_validate = @do_validate
892      @do_validate = true
893      validate_attribute
894      __validate(ignore_unknown_element)
895    ensure
896      @do_validate = do_validate
897    end
898
899    def validate_for_stream(tags, ignore_unknown_element=true)
900      validate_attribute
901      __validate(ignore_unknown_element, tags, false)
902    end
903
904    def to_s(need_convert=true, indent='')
905      if self.class.have_content?
906        return "" if !empty_content? and !content_is_set?
907        rv = tag(indent) do |next_indent|
908          if empty_content?
909            ""
910          else
911            xmled_content
912          end
913        end
914      else
915        rv = tag(indent) do |next_indent|
916          self.class.to_element_methods.collect do |method_name|
917            __send__(method_name, false, next_indent)
918          end
919        end
920      end
921      rv = convert(rv) if need_convert
922      rv
923    end
924
925    def have_xml_content?
926      false
927    end
928
929    def need_base64_encode?
930      false
931    end
932
933    def set_next_element(tag_name, next_element)
934      klass = next_element.class
935      prefix = ""
936      prefix << "#{klass.required_prefix}_" if klass.required_prefix
937      key = "#{prefix}#{tag_name.gsub(/-/, '_')}"
938      if self.class.plural_forms.has_key?(key)
939        ary = __send__("#{self.class.plural_forms[key]}")
940        ary << next_element
941      else
942        __send__("#{key}=", next_element)
943      end
944    end
945
946    protected
947    def have_required_elements?
948      self.class::MODELS.all? do |tag, uri, occurs, getter|
949        if occurs.nil? or occurs == "+"
950          child = __send__(getter)
951          if child.is_a?(Array)
952            children = child
953            children.any? {|c| c.have_required_elements?}
954          else
955            !child.to_s.empty?
956          end
957        else
958          true
959        end
960      end
961    end
962
963    private
964    def initialize_variables(attrs)
965      normalized_attrs = {}
966      attrs.each do |key, value|
967        normalized_attrs[key.to_s] = value
968      end
969      self.class.need_initialize_variables.each do |variable_name|
970        value = normalized_attrs[variable_name.to_s]
971        if value
972          __send__("#{variable_name}=", value)
973        else
974          instance_variable_set("@#{variable_name}", nil)
975        end
976      end
977      initialize_have_children_elements
978      @content = normalized_attrs["content"] if self.class.have_content?
979    end
980
981    def initialize_have_children_elements
982      self.class.have_children_elements.each do |variable_name, plural_name|
983        instance_variable_set("@#{variable_name}", [])
984      end
985    end
986
987    def tag(indent, additional_attrs={}, &block)
988      next_indent = indent + INDENT
989
990      attrs = collect_attrs
991      return "" if attrs.nil?
992
993      return "" unless have_required_elements?
994
995      attrs.update(additional_attrs)
996      start_tag = make_start_tag(indent, next_indent, attrs.dup)
997
998      if block
999        content = block.call(next_indent)
1000      else
1001        content = []
1002      end
1003
1004      if content.is_a?(String)
1005        content = [content]
1006        start_tag << ">"
1007        end_tag = "</#{full_name}>"
1008      else
1009        content = content.reject{|x| x.empty?}
1010        if content.empty?
1011          return "" if attrs.empty?
1012          end_tag = "/>"
1013        else
1014          start_tag << ">\n"
1015          end_tag = "\n#{indent}</#{full_name}>"
1016        end
1017      end
1018
1019      start_tag + content.join("\n") + end_tag
1020    end
1021
1022    def make_start_tag(indent, next_indent, attrs)
1023      start_tag = ["#{indent}<#{full_name}"]
1024      unless attrs.empty?
1025        start_tag << attrs.collect do |key, value|
1026          %Q[#{h key}="#{h value}"]
1027        end.join("\n#{next_indent}")
1028      end
1029      start_tag.join(" ")
1030    end
1031
1032    def collect_attrs
1033      attrs = {}
1034      _attrs.each do |name, required, alias_name|
1035        value = __send__(alias_name || name)
1036        return nil if required and value.nil?
1037        next if value.nil?
1038        return nil if attrs.has_key?(name)
1039        attrs[name] = value
1040      end
1041      attrs
1042    end
1043
1044    def tag_name_with_prefix(prefix)
1045      "#{prefix}:#{tag_name}"
1046    end
1047
1048    # For backward compatibility
1049    def calc_indent
1050      ''
1051    end
1052
1053    def children
1054      rv = []
1055      self.class.models.each do |name, uri, occurs, getter|
1056        value = __send__(getter)
1057        next if value.nil?
1058        value = [value] unless value.is_a?(Array)
1059        value.each do |v|
1060          rv << v if v.is_a?(Element)
1061        end
1062      end
1063      rv
1064    end
1065
1066    def _tags
1067      rv = []
1068      self.class.models.each do |name, uri, occurs, getter, plural|
1069        value = __send__(getter)
1070        next if value.nil?
1071        if plural and value.is_a?(Array)
1072          rv.concat([[uri, name]] * value.size)
1073        else
1074          rv << [uri, name]
1075        end
1076      end
1077      rv
1078    end
1079
1080    def _attrs
1081      self.class.get_attributes.collect do |name, uri, required, element_name|
1082        [element_name, required, name]
1083      end
1084    end
1085
1086    def __validate(ignore_unknown_element, tags=_tags, recursive=true)
1087      if recursive
1088        children.compact.each do |child|
1089          child.validate
1090        end
1091      end
1092      must_call_validators = self.class.must_call_validators
1093      tags = tag_filter(tags.dup)
1094      p tags if DEBUG
1095      must_call_validators.each do |uri, prefix|
1096        _validate(ignore_unknown_element, tags[uri], uri)
1097        meth = "#{prefix}_validate"
1098        if !prefix.empty? and respond_to?(meth, true)
1099          __send__(meth, ignore_unknown_element, tags[uri], uri)
1100        end
1101      end
1102    end
1103
1104    def validate_attribute
1105      _attrs.each do |a_name, required, alias_name|
1106        value = instance_variable_get("@#{alias_name || a_name}")
1107        if required and value.nil?
1108          raise MissingAttributeError.new(tag_name, a_name)
1109        end
1110        __send__("#{alias_name || a_name}=", value)
1111      end
1112    end
1113
1114    def _validate(ignore_unknown_element, tags, uri, models=self.class.models)
1115      count = 1
1116      do_redo = false
1117      not_shift = false
1118      tag = nil
1119      models = models.find_all {|model| model[1] == uri}
1120      element_names = models.collect {|model| model[0]}
1121      if tags
1122        tags_size = tags.size
1123        tags = tags.sort_by {|x| element_names.index(x) || tags_size}
1124      end
1125
1126      models.each_with_index do |model, i|
1127        name, _, occurs, = model
1128
1129        if DEBUG
1130          p "before"
1131          p tags
1132          p model
1133        end
1134
1135        if not_shift
1136          not_shift = false
1137        elsif tags
1138          tag = tags.shift
1139        end
1140
1141        if DEBUG
1142          p "mid"
1143          p count
1144        end
1145
1146        case occurs
1147        when '?'
1148          if count > 2
1149            raise TooMuchTagError.new(name, tag_name)
1150          else
1151            if name == tag
1152              do_redo = true
1153            else
1154              not_shift = true
1155            end
1156          end
1157        when '*'
1158          if name == tag
1159            do_redo = true
1160          else
1161            not_shift = true
1162          end
1163        when '+'
1164          if name == tag
1165            do_redo = true
1166          else
1167            if count > 1
1168              not_shift = true
1169            else
1170              raise MissingTagError.new(name, tag_name)
1171            end
1172          end
1173        else
1174          if name == tag
1175            if models[i+1] and models[i+1][0] != name and
1176                tags and tags.first == name
1177              raise TooMuchTagError.new(name, tag_name)
1178            end
1179          else
1180            raise MissingTagError.new(name, tag_name)
1181          end
1182        end
1183
1184        if DEBUG
1185          p "after"
1186          p not_shift
1187          p do_redo
1188          p tag
1189        end
1190
1191        if do_redo
1192          do_redo = false
1193          count += 1
1194          redo
1195        else
1196          count = 1
1197        end
1198
1199      end
1200
1201      if !ignore_unknown_element and !tags.nil? and !tags.empty?
1202        raise NotExpectedTagError.new(tags.first, uri, tag_name)
1203      end
1204
1205    end
1206
1207    def tag_filter(tags)
1208      rv = {}
1209      tags.each do |tag|
1210        rv[tag[0]] = [] unless rv.has_key?(tag[0])
1211        rv[tag[0]].push(tag[1])
1212      end
1213      rv
1214    end
1215
1216    def empty_content?
1217      false
1218    end
1219
1220    def content_is_set?
1221      if have_xml_content?
1222        __send__(self.class.xml_getter)
1223      else
1224        content
1225      end
1226    end
1227
1228    def xmled_content
1229      if have_xml_content?
1230        __send__(self.class.xml_getter).to_s
1231      else
1232        _content = content
1233        _content = [_content].pack("m").delete("\n") if need_base64_encode?
1234        h(_content)
1235      end
1236    end
1237  end
1238
1239  module RootElementMixin
1240
1241    include XMLStyleSheetMixin
1242
1243    attr_reader :output_encoding
1244    attr_reader :feed_type, :feed_subtype, :feed_version
1245    attr_accessor :version, :encoding, :standalone
1246    def initialize(feed_version, version=nil, encoding=nil, standalone=nil)
1247      super()
1248      @feed_type = nil
1249      @feed_subtype = nil
1250      @feed_version = feed_version
1251      @version = version || '1.0'
1252      @encoding = encoding
1253      @standalone = standalone
1254      @output_encoding = nil
1255    end
1256
1257    def feed_info
1258      [@feed_type, @feed_version, @feed_subtype]
1259    end
1260
1261    def output_encoding=(enc)
1262      @output_encoding = enc
1263      self.converter = Converter.new(@output_encoding, @encoding)
1264    end
1265
1266    def setup_maker(maker)
1267      maker.version = version
1268      maker.encoding = encoding
1269      maker.standalone = standalone
1270
1271      xml_stylesheets.each do |xss|
1272        xss.setup_maker(maker)
1273      end
1274
1275      super
1276    end
1277
1278    def to_feed(type, &block)
1279      Maker.make(type) do |maker|
1280        setup_maker(maker)
1281        block.call(maker) if block
1282      end
1283    end
1284
1285    def to_rss(type, &block)
1286      to_feed("rss#{type}", &block)
1287    end
1288
1289    def to_atom(type, &block)
1290      to_feed("atom:#{type}", &block)
1291    end
1292
1293    def to_xml(type=nil, &block)
1294      if type.nil? or same_feed_type?(type)
1295        to_s
1296      else
1297        to_feed(type, &block).to_s
1298      end
1299    end
1300
1301    private
1302    def same_feed_type?(type)
1303      if /^(atom|rss)?(\d+\.\d+)?(?::(.+))?$/i =~ type
1304        feed_type = ($1 || @feed_type).downcase
1305        feed_version = $2 || @feed_version
1306        feed_subtype = $3 || @feed_subtype
1307        [feed_type, feed_version, feed_subtype] == feed_info
1308      else
1309        false
1310      end
1311    end
1312
1313    def tag(indent, attrs={}, &block)
1314      rv = super(indent, ns_declarations.merge(attrs), &block)
1315      return rv if rv.empty?
1316      "#{xmldecl}#{xml_stylesheet_pi}#{rv}"
1317    end
1318
1319    def xmldecl
1320      rv = %Q[<?xml version="#{@version}"]
1321      if @output_encoding or @encoding
1322        rv << %Q[ encoding="#{@output_encoding or @encoding}"]
1323      end
1324      rv << %Q[ standalone="yes"] if @standalone
1325      rv << "?>\n"
1326      rv
1327    end
1328
1329    def ns_declarations
1330      decls = {}
1331      self.class::NSPOOL.collect do |prefix, uri|
1332        prefix = ":#{prefix}" unless prefix.empty?
1333        decls["xmlns#{prefix}"] = uri
1334      end
1335      decls
1336    end
1337
1338    def maker_target(target)
1339      target
1340    end
1341  end
1342end
1343