source: extensions/gsdl-video/trunk/installed/cmdline/lib/ruby/1.8/rss/rss.rb@ 18425

Last change on this file since 18425 was 18425, checked in by davidb, 15 years ago

Video extension to Greenstone

File size: 25.1 KB
Line 
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 datetime << $7.to_f * 1000000 if $7
16 if $8
17 Time.utc(*datetime) - zone_offset($8)
18 else
19 Time.local(*datetime)
20 end
21 else
22 raise ArgumentError.new("invalid date: #{date.inspect}")
23 end
24 end
25 end
26 end
27
28 unless instance_methods.include?("w3cdtf")
29 alias w3cdtf iso8601
30 end
31end
32
33require "English"
34require "rss/utils"
35require "rss/converter"
36require "rss/xml-stylesheet"
37
38module RSS
39
40 VERSION = "0.1.6"
41
42 URI = "http://purl.org/rss/1.0/"
43
44 DEBUG = false
45
46 class Error < StandardError; end
47
48 class OverlappedPrefixError < Error
49 attr_reader :prefix
50 def initialize(prefix)
51 @prefix = prefix
52 end
53 end
54
55 class InvalidRSSError < Error; end
56
57 class MissingTagError < InvalidRSSError
58 attr_reader :tag, :parent
59 def initialize(tag, parent)
60 @tag, @parent = tag, parent
61 super("tag <#{tag}> is missing in tag <#{parent}>")
62 end
63 end
64
65 class TooMuchTagError < InvalidRSSError
66 attr_reader :tag, :parent
67 def initialize(tag, parent)
68 @tag, @parent = tag, parent
69 super("tag <#{tag}> is too much in tag <#{parent}>")
70 end
71 end
72
73 class MissingAttributeError < InvalidRSSError
74 attr_reader :tag, :attribute
75 def initialize(tag, attribute)
76 @tag, @attribute = tag, attribute
77 super("attribute <#{attribute}> is missing in tag <#{tag}>")
78 end
79 end
80
81 class UnknownTagError < InvalidRSSError
82 attr_reader :tag, :uri
83 def initialize(tag, uri)
84 @tag, @uri = tag, uri
85 super("tag <#{tag}> is unknown in namespace specified by uri <#{uri}>")
86 end
87 end
88
89 class NotExpectedTagError < InvalidRSSError
90 attr_reader :tag, :uri, :parent
91 def initialize(tag, uri, parent)
92 @tag, @uri, @parent = tag, uri, parent
93 super("tag <{#{uri}}#{tag}> is not expected in tag <#{parent}>")
94 end
95 end
96 # For backward compatibility :X
97 NotExceptedTagError = NotExpectedTagError
98
99 class NotAvailableValueError < InvalidRSSError
100 attr_reader :tag, :value, :attribute
101 def initialize(tag, value, attribute=nil)
102 @tag, @value, @attribute = tag, value, attribute
103 message = "value <#{value}> of "
104 message << "attribute <#{attribute}> of " if attribute
105 message << "tag <#{tag}> is not available."
106 super(message)
107 end
108 end
109
110 class UnknownConversionMethodError < Error
111 attr_reader :to, :from
112 def initialize(to, from)
113 @to = to
114 @from = from
115 super("can't convert to #{to} from #{from}.")
116 end
117 end
118 # for backward compatibility
119 UnknownConvertMethod = UnknownConversionMethodError
120
121 class ConversionError < Error
122 attr_reader :string, :to, :from
123 def initialize(string, to, from)
124 @string = string
125 @to = to
126 @from = from
127 super("can't convert #{@string} to #{to} from #{from}.")
128 end
129 end
130
131 class NotSetError < Error
132 attr_reader :name, :variables
133 def initialize(name, variables)
134 @name = name
135 @variables = variables
136 super("required variables of #{@name} are not set: #{@variables.join(', ')}")
137 end
138 end
139
140 module BaseModel
141
142 include Utils
143
144 def install_have_child_element(tag_name, uri, occurs, name=nil)
145 name ||= tag_name
146 add_need_initialize_variable(name)
147 install_model(tag_name, uri, occurs, name)
148
149 attr_accessor name
150 install_element(name) do |n, elem_name|
151 <<-EOC
152 if @#{n}
153 "\#{@#{n}.to_s(need_convert, indent)}"
154 else
155 ''
156 end
157EOC
158 end
159 end
160 alias_method(:install_have_attribute_element, :install_have_child_element)
161
162 def install_have_children_element(tag_name, uri, occurs, name=nil, plural_name=nil)
163 name ||= tag_name
164 plural_name ||= "#{name}s"
165 add_have_children_element(name, plural_name)
166 add_plural_form(name, plural_name)
167 install_model(tag_name, uri, occurs, plural_name)
168
169 def_children_accessor(name, plural_name)
170 install_element(name, "s") do |n, elem_name|
171 <<-EOC
172 rv = []
173 @#{n}.each do |x|
174 value = "\#{x.to_s(need_convert, indent)}"
175 rv << value if /\\A\\s*\\z/ !~ value
176 end
177 rv.join("\n")
178EOC
179 end
180 end
181
182 def install_text_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
183 name ||= tag_name
184 disp_name ||= name
185 self::ELEMENTS << name
186 add_need_initialize_variable(name)
187 install_model(tag_name, uri, occurs, name)
188
189 def_corresponded_attr_writer name, type, disp_name
190 convert_attr_reader name
191 install_element(name) do |n, elem_name|
192 <<-EOC
193 if @#{n}
194 rv = "\#{indent}<#{elem_name}>"
195 value = html_escape(@#{n})
196 if need_convert
197 rv << convert(value)
198 else
199 rv << value
200 end
201 rv << "</#{elem_name}>"
202 rv
203 else
204 ''
205 end
206EOC
207 end
208 end
209
210 def install_date_element(tag_name, uri, occurs, name=nil, type=nil, disp_name=nil)
211 name ||= tag_name
212 type ||= :w3cdtf
213 disp_name ||= name
214 self::ELEMENTS << name
215 add_need_initialize_variable(name)
216 install_model(tag_name, uri, occurs, name)
217
218 # accessor
219 convert_attr_reader name
220 date_writer(name, type, disp_name)
221
222 install_element(name) do |n, elem_name|
223 <<-EOC
224 if @#{n}
225 rv = "\#{indent}<#{elem_name}>"
226 value = html_escape(@#{n}.#{type})
227 if need_convert
228 rv << convert(value)
229 else
230 rv << value
231 end
232 rv << "</#{elem_name}>"
233 rv
234 else
235 ''
236 end
237EOC
238 end
239
240 end
241
242 private
243 def install_element(name, postfix="")
244 elem_name = name.sub('_', ':')
245 method_name = "#{name}_element#{postfix}"
246 add_to_element_method(method_name)
247 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
248 def #{method_name}(need_convert=true, indent='')
249 #{yield(name, elem_name)}
250 end
251 private :#{method_name}
252EOC
253 end
254
255 def convert_attr_reader(*attrs)
256 attrs.each do |attr|
257 attr = attr.id2name if attr.kind_of?(Integer)
258 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
259 def #{attr}
260 if @converter
261 @converter.convert(@#{attr})
262 else
263 @#{attr}
264 end
265 end
266EOC
267 end
268 end
269
270 def date_writer(name, type, disp_name=name)
271 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
272 def #{name}=(new_value)
273 if new_value.nil? or new_value.kind_of?(Time)
274 @#{name} = new_value
275 else
276 if @do_validate
277 begin
278 @#{name} = Time.__send__('#{type}', new_value)
279 rescue ArgumentError
280 raise NotAvailableValueError.new('#{disp_name}', new_value)
281 end
282 else
283 @#{name} = nil
284 if /\\A\\s*\\z/ !~ new_value.to_s
285 begin
286 @#{name} = Time.parse(new_value)
287 rescue ArgumentError
288 end
289 end
290 end
291 end
292
293 # Is it need?
294 if @#{name}
295 class << @#{name}
296 undef_method(:to_s)
297 alias_method(:to_s, :#{type})
298 end
299 end
300
301 end
302EOC
303 end
304
305 def integer_writer(name, disp_name=name)
306 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
307 def #{name}=(new_value)
308 if new_value.nil?
309 @#{name} = new_value
310 else
311 if @do_validate
312 begin
313 @#{name} = Integer(new_value)
314 rescue ArgumentError
315 raise NotAvailableValueError.new('#{disp_name}', new_value)
316 end
317 else
318 @#{name} = new_value.to_i
319 end
320 end
321 end
322EOC
323 end
324
325 def positive_integer_writer(name, disp_name=name)
326 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
327 def #{name}=(new_value)
328 if new_value.nil?
329 @#{name} = new_value
330 else
331 if @do_validate
332 begin
333 tmp = Integer(new_value)
334 raise ArgumentError if tmp <= 0
335 @#{name} = tmp
336 rescue ArgumentError
337 raise NotAvailableValueError.new('#{disp_name}', new_value)
338 end
339 else
340 @#{name} = new_value.to_i
341 end
342 end
343 end
344EOC
345 end
346
347 def boolean_writer(name, disp_name=name)
348 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
349 def #{name}=(new_value)
350 if new_value.nil?
351 @#{name} = new_value
352 else
353 if @do_validate and
354 ![true, false, "true", "false"].include?(new_value)
355 raise NotAvailableValueError.new('#{disp_name}', new_value)
356 end
357 if [true, false].include?(new_value)
358 @#{name} = new_value
359 else
360 @#{name} = new_value == "true"
361 end
362 end
363 end
364EOC
365 end
366
367 def def_children_accessor(accessor_name, plural_name)
368 module_eval(<<-EOC, *get_file_and_line_from_caller(2))
369 def #{plural_name}
370 @#{accessor_name}
371 end
372
373 def #{accessor_name}(*args)
374 if args.empty?
375 @#{accessor_name}.first
376 else
377 @#{accessor_name}[*args]
378 end
379 end
380
381 def #{accessor_name}=(*args)
382 warn("Warning:\#{caller.first.sub(/:in `.*'\z/, '')}: " \
383 "Don't use `#{accessor_name} = XXX'/`set_#{accessor_name}(XXX)'. " \
384 "Those APIs are not sense of Ruby. " \
385 "Use `#{plural_name} << XXX' instead of them.")
386 if args.size == 1
387 @#{accessor_name}.push(args[0])
388 else
389 @#{accessor_name}.__send__("[]=", *args)
390 end
391 end
392 alias_method(:set_#{accessor_name}, :#{accessor_name}=)
393EOC
394 end
395 end
396
397 class Element
398
399 extend BaseModel
400 include Utils
401
402 INDENT = " "
403
404 MUST_CALL_VALIDATORS = {}
405 MODELS = []
406 GET_ATTRIBUTES = []
407 HAVE_CHILDREN_ELEMENTS = []
408 TO_ELEMENT_METHODS = []
409 NEED_INITIALIZE_VARIABLES = []
410 PLURAL_FORMS = {}
411
412 class << self
413
414 def must_call_validators
415 MUST_CALL_VALIDATORS
416 end
417 def models
418 MODELS
419 end
420 def get_attributes
421 GET_ATTRIBUTES
422 end
423 def have_children_elements
424 HAVE_CHILDREN_ELEMENTS
425 end
426 def to_element_methods
427 TO_ELEMENT_METHODS
428 end
429 def need_initialize_variables
430 NEED_INITIALIZE_VARIABLES
431 end
432 def plural_forms
433 PLURAL_FORMS
434 end
435
436
437 def inherited(klass)
438 klass.const_set("MUST_CALL_VALIDATORS", {})
439 klass.const_set("MODELS", [])
440 klass.const_set("GET_ATTRIBUTES", [])
441 klass.const_set("HAVE_CHILDREN_ELEMENTS", [])
442 klass.const_set("TO_ELEMENT_METHODS", [])
443 klass.const_set("NEED_INITIALIZE_VARIABLES", [])
444 klass.const_set("PLURAL_FORMS", {})
445
446 klass.module_eval(<<-EOC)
447 public
448
449 @tag_name = name.split(/::/).last
450 @tag_name[0,1] = @tag_name[0,1].downcase
451 @have_content = false
452
453 def self.must_call_validators
454 super.merge(MUST_CALL_VALIDATORS)
455 end
456 def self.models
457 MODELS + super
458 end
459 def self.get_attributes
460 GET_ATTRIBUTES + super
461 end
462 def self.have_children_elements
463 HAVE_CHILDREN_ELEMENTS + super
464 end
465 def self.to_element_methods
466 TO_ELEMENT_METHODS + super
467 end
468 def self.need_initialize_variables
469 NEED_INITIALIZE_VARIABLES + super
470 end
471 def self.plural_forms
472 super.merge(PLURAL_FORMS)
473 end
474
475
476 def self.install_must_call_validator(prefix, uri)
477 MUST_CALL_VALIDATORS[uri] = prefix
478 end
479
480 def self.install_model(tag, uri, occurs=nil, getter=nil)
481 getter ||= tag
482 if m = MODELS.find {|t, u, o, g| t == tag and u == uri}
483 m[2] = occurs
484 else
485 MODELS << [tag, uri, occurs, getter]
486 end
487 end
488
489 def self.install_get_attribute(name, uri, required=true,
490 type=nil, disp_name=nil,
491 element_name=nil)
492 disp_name ||= name
493 element_name ||= name
494 def_corresponded_attr_writer name, type, disp_name
495 convert_attr_reader name
496 if type == :boolean and /^is/ =~ name
497 alias_method "\#{$POSTMATCH}?", name
498 end
499 GET_ATTRIBUTES << [name, uri, required, element_name]
500 add_need_initialize_variable(disp_name)
501 end
502
503 def self.def_corresponded_attr_writer(name, type=nil, disp_name=name)
504 case type
505 when :integer
506 integer_writer name, disp_name
507 when :positive_integer
508 positive_integer_writer name, disp_name
509 when :boolean
510 boolean_writer name, disp_name
511 when :w3cdtf, :rfc822, :rfc2822
512 date_writer name, type, disp_name
513 else
514 attr_writer name
515 end
516 end
517
518 def self.content_setup(type=nil)
519 def_corresponded_attr_writer "content", type
520 convert_attr_reader :content
521 @have_content = true
522 end
523
524 def self.have_content?
525 @have_content
526 end
527
528 def self.add_have_children_element(variable_name, plural_name)
529 HAVE_CHILDREN_ELEMENTS << [variable_name, plural_name]
530 end
531
532 def self.add_to_element_method(method_name)
533 TO_ELEMENT_METHODS << method_name
534 end
535
536 def self.add_need_initialize_variable(variable_name)
537 NEED_INITIALIZE_VARIABLES << variable_name
538 end
539
540 def self.add_plural_form(singular, plural)
541 PLURAL_FORMS[singular] = plural
542 end
543
544 EOC
545 end
546
547 def required_prefix
548 nil
549 end
550
551 def required_uri
552 ""
553 end
554
555 def install_ns(prefix, uri)
556 if self::NSPOOL.has_key?(prefix)
557 raise OverlappedPrefixError.new(prefix)
558 end
559 self::NSPOOL[prefix] = uri
560 end
561
562 def tag_name
563 @tag_name
564 end
565 end
566
567 attr_accessor :do_validate
568
569 def initialize(do_validate=true, attrs={})
570 @converter = nil
571 @do_validate = do_validate
572 initialize_variables(attrs)
573 end
574
575 def tag_name
576 self.class.tag_name
577 end
578
579 def full_name
580 tag_name
581 end
582
583 def converter=(converter)
584 @converter = converter
585 targets = children.dup
586 self.class.have_children_elements.each do |variable_name, plural_name|
587 targets.concat(__send__(plural_name))
588 end
589 targets.each do |target|
590 target.converter = converter unless target.nil?
591 end
592 end
593
594 def convert(value)
595 if @converter
596 @converter.convert(value)
597 else
598 value
599 end
600 end
601
602 def validate(ignore_unknown_element=true)
603 validate_attribute
604 __validate(ignore_unknown_element)
605 end
606
607 def validate_for_stream(tags, ignore_unknown_element=true)
608 validate_attribute
609 __validate(ignore_unknown_element, tags, false)
610 end
611
612 def setup_maker(maker)
613 target = maker_target(maker)
614 unless target.nil?
615 setup_maker_attributes(target)
616 setup_maker_element(target)
617 setup_maker_elements(target)
618 end
619 end
620
621 def to_s(need_convert=true, indent='')
622 if self.class.have_content?
623 return "" unless @content
624 rv = tag(indent) do |next_indent|
625 h(@content)
626 end
627 else
628 rv = tag(indent) do |next_indent|
629 self.class.to_element_methods.collect do |method_name|
630 __send__(method_name, false, next_indent)
631 end
632 end
633 end
634 rv = convert(rv) if need_convert
635 rv
636 end
637
638 private
639 def initialize_variables(attrs)
640 normalized_attrs = {}
641 attrs.each do |key, value|
642 normalized_attrs[key.to_s] = value
643 end
644 self.class.need_initialize_variables.each do |variable_name|
645 value = normalized_attrs[variable_name.to_s]
646 if value
647 __send__("#{variable_name}=", value)
648 else
649 instance_eval("@#{variable_name} = nil")
650 end
651 end
652 initialize_have_children_elements
653 @content = "" if self.class.have_content?
654 end
655
656 def initialize_have_children_elements
657 self.class.have_children_elements.each do |variable_name, plural_name|
658 instance_eval("@#{variable_name} = []")
659 end
660 end
661
662 def tag(indent, additional_attrs={}, &block)
663 next_indent = indent + INDENT
664
665 attrs = collect_attrs
666 return "" if attrs.nil?
667
668 attrs.update(additional_attrs)
669 start_tag = make_start_tag(indent, next_indent, attrs)
670
671 if block
672 content = block.call(next_indent)
673 else
674 content = []
675 end
676
677 if content.is_a?(String)
678 content = [content]
679 start_tag << ">"
680 end_tag = "</#{full_name}>"
681 else
682 content = content.reject{|x| x.empty?}
683 if content.empty?
684 end_tag = "/>"
685 else
686 start_tag << ">\n"
687 end_tag = "\n#{indent}</#{full_name}>"
688 end
689 end
690
691 start_tag + content.join("\n") + end_tag
692 end
693
694 def make_start_tag(indent, next_indent, attrs)
695 start_tag = ["#{indent}<#{full_name}"]
696 unless attrs.empty?
697 start_tag << attrs.collect do |key, value|
698 %Q[#{h key}="#{h value}"]
699 end.join("\n#{next_indent}")
700 end
701 start_tag.join(" ")
702 end
703
704 def collect_attrs
705 attrs = {}
706 _attrs.each do |name, required, alias_name|
707 value = __send__(alias_name || name)
708 return nil if required and value.nil?
709 next if value.nil?
710 return nil if attrs.has_key?(name)
711 attrs[name] = value
712 end
713 attrs
714 end
715
716 def tag_name_with_prefix(prefix)
717 "#{prefix}:#{tag_name}"
718 end
719
720 # For backward compatibility
721 def calc_indent
722 ''
723 end
724
725 def maker_target(maker)
726 nil
727 end
728
729 def setup_maker_attributes(target)
730 end
731
732 def setup_maker_element(target)
733 self.class.need_initialize_variables.each do |var|
734 value = __send__(var)
735 if value.respond_to?("setup_maker") and
736 !not_need_to_call_setup_maker_variables.include?(var)
737 value.setup_maker(target)
738 else
739 setter = "#{var}="
740 if target.respond_to?(setter)
741 target.__send__(setter, value)
742 end
743 end
744 end
745 end
746
747 def not_need_to_call_setup_maker_variables
748 []
749 end
750
751 def setup_maker_elements(parent)
752 self.class.have_children_elements.each do |name, plural_name|
753 if parent.respond_to?(plural_name)
754 target = parent.__send__(plural_name)
755 __send__(plural_name).each do |elem|
756 elem.setup_maker(target)
757 end
758 end
759 end
760 end
761
762 def set_next_element(tag_name, next_element)
763 klass = next_element.class
764 prefix = ""
765 prefix << "#{klass.required_prefix}_" if klass.required_prefix
766 key = "#{prefix}#{tag_name}"
767 if self.class.plural_forms.has_key?(key)
768 ary = __send__("#{self.class.plural_forms[key]}")
769 ary << next_element
770 else
771 __send__("#{prefix}#{tag_name}=", next_element)
772 end
773 end
774
775 def children
776 rv = []
777 self.class.models.each do |name, uri, occurs, getter|
778 value = __send__(getter)
779 next if value.nil?
780 value = [value] unless value.is_a?(Array)
781 value.each do |v|
782 rv << v if v.is_a?(Element)
783 end
784 end
785 rv
786 end
787
788 def _tags
789 rv = []
790 self.class.models.each do |name, uri, occurs, getter|
791 value = __send__(getter)
792 next if value.nil?
793 if value.is_a?(Array)
794 rv.concat([[uri, name]] * value.size)
795 else
796 rv << [uri, name]
797 end
798 end
799 rv
800 end
801
802 def _attrs
803 self.class.get_attributes.collect do |name, uri, required, element_name|
804 [element_name, required, name]
805 end
806 end
807
808 def __validate(ignore_unknown_element, tags=_tags, recursive=true)
809 if recursive
810 children.compact.each do |child|
811 child.validate
812 end
813 end
814 must_call_validators = self.class.must_call_validators
815 tags = tag_filter(tags.dup)
816 p tags if DEBUG
817 must_call_validators.each do |uri, prefix|
818 _validate(ignore_unknown_element, tags[uri], uri)
819 meth = "#{prefix}_validate"
820 if respond_to?(meth, true)
821 __send__(meth, ignore_unknown_element, tags[uri], uri)
822 end
823 end
824 end
825
826 def validate_attribute
827 _attrs.each do |a_name, required, alias_name|
828 if required and __send__(alias_name || a_name).nil?
829 raise MissingAttributeError.new(tag_name, a_name)
830 end
831 end
832 end
833
834 def _validate(ignore_unknown_element, tags, uri, models=self.class.models)
835 count = 1
836 do_redo = false
837 not_shift = false
838 tag = nil
839 models = models.find_all {|model| model[1] == uri}
840 element_names = models.collect {|model| model[0]}
841 if tags
842 tags_size = tags.size
843 tags = tags.sort_by {|x| element_names.index(x) || tags_size}
844 end
845
846 models.each_with_index do |model, i|
847 name, model_uri, occurs, getter = model
848
849 if DEBUG
850 p "before"
851 p tags
852 p model
853 end
854
855 if not_shift
856 not_shift = false
857 elsif tags
858 tag = tags.shift
859 end
860
861 if DEBUG
862 p "mid"
863 p count
864 end
865
866 case occurs
867 when '?'
868 if count > 2
869 raise TooMuchTagError.new(name, tag_name)
870 else
871 if name == tag
872 do_redo = true
873 else
874 not_shift = true
875 end
876 end
877 when '*'
878 if name == tag
879 do_redo = true
880 else
881 not_shift = true
882 end
883 when '+'
884 if name == tag
885 do_redo = true
886 else
887 if count > 1
888 not_shift = true
889 else
890 raise MissingTagError.new(name, tag_name)
891 end
892 end
893 else
894 if name == tag
895 if models[i+1] and models[i+1][0] != name and
896 tags and tags.first == name
897 raise TooMuchTagError.new(name, tag_name)
898 end
899 else
900 raise MissingTagError.new(name, tag_name)
901 end
902 end
903
904 if DEBUG
905 p "after"
906 p not_shift
907 p do_redo
908 p tag
909 end
910
911 if do_redo
912 do_redo = false
913 count += 1
914 redo
915 else
916 count = 1
917 end
918
919 end
920
921 if !ignore_unknown_element and !tags.nil? and !tags.empty?
922 raise NotExpectedTagError.new(tags.first, uri, tag_name)
923 end
924
925 end
926
927 def tag_filter(tags)
928 rv = {}
929 tags.each do |tag|
930 rv[tag[0]] = [] unless rv.has_key?(tag[0])
931 rv[tag[0]].push(tag[1])
932 end
933 rv
934 end
935
936 end
937
938 module RootElementMixin
939
940 include XMLStyleSheetMixin
941
942 attr_reader :output_encoding
943
944 def initialize(rss_version, version=nil, encoding=nil, standalone=nil)
945 super()
946 @rss_version = rss_version
947 @version = version || '1.0'
948 @encoding = encoding
949 @standalone = standalone
950 @output_encoding = nil
951 end
952
953 def output_encoding=(enc)
954 @output_encoding = enc
955 self.converter = Converter.new(@output_encoding, @encoding)
956 end
957
958 def setup_maker(maker)
959 maker.version = version
960 maker.encoding = encoding
961 maker.standalone = standalone
962
963 xml_stylesheets.each do |xss|
964 xss.setup_maker(maker)
965 end
966
967 setup_maker_elements(maker)
968 end
969
970 def to_xml(version=nil, &block)
971 if version.nil? or version == @rss_version
972 to_s
973 else
974 RSS::Maker.make(version) do |maker|
975 setup_maker(maker)
976 block.call(maker) if block
977 end.to_s
978 end
979 end
980
981 private
982 def tag(indent, attrs={}, &block)
983 rv = xmldecl + xml_stylesheet_pi
984 rv << super(indent, ns_declarations.merge(attrs), &block)
985 rv
986 end
987
988 def xmldecl
989 rv = %Q[<?xml version="#{@version}"]
990 if @output_encoding or @encoding
991 rv << %Q[ encoding="#{@output_encoding or @encoding}"]
992 end
993 rv << %Q[ standalone="yes"] if @standalone
994 rv << "?>\n"
995 rv
996 end
997
998 def ns_declarations
999 decls = {}
1000 self.class::NSPOOL.collect do |prefix, uri|
1001 prefix = ":#{prefix}" unless prefix.empty?
1002 decls["xmlns#{prefix}"] = uri
1003 end
1004 decls
1005 end
1006
1007 def setup_maker_elements(maker)
1008 channel.setup_maker(maker) if channel
1009 image.setup_maker(maker) if image
1010 textinput.setup_maker(maker) if textinput
1011 super(maker)
1012 end
1013 end
1014
1015end
Note: See TracBrowser for help on using the repository browser.