feedtools 0.2.26 → 0.2.27

Sign up to get free protection for your applications and to get access to all the features.
Files changed (166) hide show
  1. data/CHANGELOG +232 -216
  2. data/db/migration.rb +2 -0
  3. data/db/schema.mysql.sql +2 -0
  4. data/db/schema.postgresql.sql +3 -1
  5. data/db/schema.sqlite.sql +3 -1
  6. data/lib/feed_tools.rb +37 -14
  7. data/lib/feed_tools/database_feed_cache.rb +13 -2
  8. data/lib/feed_tools/feed.rb +430 -104
  9. data/lib/feed_tools/feed_item.rb +533 -268
  10. data/lib/feed_tools/helpers/generic_helper.rb +1 -1
  11. data/lib/feed_tools/helpers/html_helper.rb +78 -116
  12. data/lib/feed_tools/helpers/retrieval_helper.rb +33 -3
  13. data/lib/feed_tools/helpers/uri_helper.rb +46 -54
  14. data/lib/feed_tools/monkey_patch.rb +27 -1
  15. data/lib/feed_tools/vendor/html5/History.txt +10 -0
  16. data/lib/feed_tools/vendor/html5/Manifest.txt +117 -0
  17. data/lib/feed_tools/vendor/html5/README +45 -0
  18. data/lib/feed_tools/vendor/html5/Rakefile.rb +33 -0
  19. data/lib/feed_tools/vendor/html5/bin/html5 +217 -0
  20. data/lib/feed_tools/vendor/html5/lib/core_ext/string.rb +17 -0
  21. data/lib/feed_tools/vendor/html5/lib/html5.rb +13 -0
  22. data/lib/feed_tools/vendor/html5/lib/html5/constants.rb +1046 -0
  23. data/lib/feed_tools/vendor/html5/lib/html5/filters/base.rb +10 -0
  24. data/lib/feed_tools/vendor/html5/lib/html5/filters/inject_meta_charset.rb +82 -0
  25. data/lib/feed_tools/vendor/html5/lib/html5/filters/iso639codes.rb +752 -0
  26. data/lib/feed_tools/vendor/html5/lib/html5/filters/optionaltags.rb +198 -0
  27. data/lib/feed_tools/vendor/html5/lib/html5/filters/rfc2046.rb +30 -0
  28. data/lib/feed_tools/vendor/html5/lib/html5/filters/rfc3987.rb +89 -0
  29. data/lib/feed_tools/vendor/html5/lib/html5/filters/sanitizer.rb +15 -0
  30. data/lib/feed_tools/vendor/html5/lib/html5/filters/validator.rb +830 -0
  31. data/lib/feed_tools/vendor/html5/lib/html5/filters/whitespace.rb +36 -0
  32. data/lib/feed_tools/vendor/html5/lib/html5/html5parser.rb +248 -0
  33. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_body_phase.rb +46 -0
  34. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_frameset_phase.rb +33 -0
  35. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_head_phase.rb +50 -0
  36. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/before_head_phase.rb +41 -0
  37. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_body_phase.rb +613 -0
  38. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_caption_phase.rb +69 -0
  39. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_cell_phase.rb +78 -0
  40. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_column_group_phase.rb +55 -0
  41. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_frameset_phase.rb +57 -0
  42. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_head_phase.rb +138 -0
  43. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_row_phase.rb +89 -0
  44. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_select_phase.rb +85 -0
  45. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_table_body_phase.rb +86 -0
  46. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_table_phase.rb +115 -0
  47. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/initial_phase.rb +133 -0
  48. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/phase.rb +154 -0
  49. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/root_element_phase.rb +41 -0
  50. data/lib/feed_tools/vendor/html5/lib/html5/html5parser/trailing_end_phase.rb +35 -0
  51. data/lib/feed_tools/vendor/html5/lib/html5/inputstream.rb +648 -0
  52. data/lib/feed_tools/vendor/html5/lib/html5/liberalxmlparser.rb +158 -0
  53. data/lib/feed_tools/vendor/html5/lib/html5/sanitizer.rb +188 -0
  54. data/lib/feed_tools/vendor/html5/lib/html5/serializer.rb +2 -0
  55. data/lib/feed_tools/vendor/html5/lib/html5/serializer/htmlserializer.rb +179 -0
  56. data/lib/feed_tools/vendor/html5/lib/html5/serializer/xhtmlserializer.rb +20 -0
  57. data/lib/feed_tools/vendor/html5/lib/html5/sniffer.rb +45 -0
  58. data/lib/feed_tools/vendor/html5/lib/html5/tokenizer.rb +966 -0
  59. data/lib/feed_tools/vendor/html5/lib/html5/treebuilders.rb +24 -0
  60. data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/base.rb +334 -0
  61. data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/hpricot.rb +231 -0
  62. data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/rexml.rb +209 -0
  63. data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/simpletree.rb +185 -0
  64. data/lib/feed_tools/vendor/html5/lib/html5/treewalkers.rb +26 -0
  65. data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/base.rb +162 -0
  66. data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/hpricot.rb +48 -0
  67. data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/rexml.rb +48 -0
  68. data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/simpletree.rb +48 -0
  69. data/lib/feed_tools/vendor/html5/lib/html5/version.rb +3 -0
  70. data/lib/feed_tools/vendor/html5/testdata/encoding/chardet/test_big5.txt +51 -0
  71. data/lib/feed_tools/vendor/html5/testdata/encoding/test-yahoo-jp.dat +10 -0
  72. data/lib/feed_tools/vendor/html5/testdata/encoding/tests1.dat +394 -0
  73. data/lib/feed_tools/vendor/html5/testdata/encoding/tests2.dat +81 -0
  74. data/lib/feed_tools/vendor/html5/testdata/sanitizer/tests1.dat +416 -0
  75. data/lib/feed_tools/vendor/html5/testdata/serializer/core.test +104 -0
  76. data/lib/feed_tools/vendor/html5/testdata/serializer/injectmeta.test +65 -0
  77. data/lib/feed_tools/vendor/html5/testdata/serializer/optionaltags.test +900 -0
  78. data/lib/feed_tools/vendor/html5/testdata/serializer/options.test +60 -0
  79. data/lib/feed_tools/vendor/html5/testdata/serializer/whitespace.test +51 -0
  80. data/lib/feed_tools/vendor/html5/testdata/sites/google-results.htm +1 -0
  81. data/lib/feed_tools/vendor/html5/testdata/sites/python-ref-import.htm +1 -0
  82. data/lib/feed_tools/vendor/html5/testdata/sites/web-apps-old.htm +1 -0
  83. data/lib/feed_tools/vendor/html5/testdata/sites/web-apps.htm +34275 -0
  84. data/lib/feed_tools/vendor/html5/testdata/sniffer/htmlOrFeed.json +43 -0
  85. data/lib/feed_tools/vendor/html5/testdata/tokenizer/contentModelFlags.test +48 -0
  86. data/lib/feed_tools/vendor/html5/testdata/tokenizer/entities.test +2339 -0
  87. data/lib/feed_tools/vendor/html5/testdata/tokenizer/escapeFlag.test +21 -0
  88. data/lib/feed_tools/vendor/html5/testdata/tokenizer/test1.test +172 -0
  89. data/lib/feed_tools/vendor/html5/testdata/tokenizer/test2.test +129 -0
  90. data/lib/feed_tools/vendor/html5/testdata/tokenizer/test3.test +367 -0
  91. data/lib/feed_tools/vendor/html5/testdata/tokenizer/test4.test +198 -0
  92. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests1.dat +1950 -0
  93. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests2.dat +773 -0
  94. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests3.dat +270 -0
  95. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests4.dat +60 -0
  96. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests5.dat +175 -0
  97. data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests6.dat +196 -0
  98. data/lib/feed_tools/vendor/html5/testdata/validator/attributes.test +1035 -0
  99. data/lib/feed_tools/vendor/html5/testdata/validator/base-href-attribute.test +787 -0
  100. data/lib/feed_tools/vendor/html5/testdata/validator/base-target-attribute.test +35 -0
  101. data/lib/feed_tools/vendor/html5/testdata/validator/blockquote-cite-attribute.test +7 -0
  102. data/lib/feed_tools/vendor/html5/testdata/validator/classattribute.test +152 -0
  103. data/lib/feed_tools/vendor/html5/testdata/validator/contenteditableattribute.test +59 -0
  104. data/lib/feed_tools/vendor/html5/testdata/validator/contextmenuattribute.test +115 -0
  105. data/lib/feed_tools/vendor/html5/testdata/validator/dirattribute.test +59 -0
  106. data/lib/feed_tools/vendor/html5/testdata/validator/draggableattribute.test +63 -0
  107. data/lib/feed_tools/vendor/html5/testdata/validator/html-xmlns-attribute.test +23 -0
  108. data/lib/feed_tools/vendor/html5/testdata/validator/idattribute.test +115 -0
  109. data/lib/feed_tools/vendor/html5/testdata/validator/inputattributes.test +2795 -0
  110. data/lib/feed_tools/vendor/html5/testdata/validator/irrelevantattribute.test +63 -0
  111. data/lib/feed_tools/vendor/html5/testdata/validator/langattribute.test +5579 -0
  112. data/lib/feed_tools/vendor/html5/testdata/validator/li-value-attribute.test +7 -0
  113. data/lib/feed_tools/vendor/html5/testdata/validator/link-href-attribute.test +7 -0
  114. data/lib/feed_tools/vendor/html5/testdata/validator/link-hreflang-attribute.test +7 -0
  115. data/lib/feed_tools/vendor/html5/testdata/validator/link-rel-attribute.test +271 -0
  116. data/lib/feed_tools/vendor/html5/testdata/validator/ol-start-attribute.test +7 -0
  117. data/lib/feed_tools/vendor/html5/testdata/validator/starttags.test +375 -0
  118. data/lib/feed_tools/vendor/html5/testdata/validator/style-scoped-attribute.test +7 -0
  119. data/lib/feed_tools/vendor/html5/testdata/validator/tabindexattribute.test +79 -0
  120. data/lib/feed_tools/vendor/html5/tests/preamble.rb +72 -0
  121. data/lib/feed_tools/vendor/html5/tests/test_encoding.rb +35 -0
  122. data/lib/feed_tools/vendor/html5/tests/test_lxp.rb +279 -0
  123. data/lib/feed_tools/vendor/html5/tests/test_parser.rb +68 -0
  124. data/lib/feed_tools/vendor/html5/tests/test_sanitizer.rb +142 -0
  125. data/lib/feed_tools/vendor/html5/tests/test_serializer.rb +68 -0
  126. data/lib/feed_tools/vendor/html5/tests/test_sniffer.rb +27 -0
  127. data/lib/feed_tools/vendor/html5/tests/test_stream.rb +62 -0
  128. data/lib/feed_tools/vendor/html5/tests/test_tokenizer.rb +94 -0
  129. data/lib/feed_tools/vendor/html5/tests/test_treewalkers.rb +135 -0
  130. data/lib/feed_tools/vendor/html5/tests/test_validator.rb +31 -0
  131. data/lib/feed_tools/vendor/html5/tests/tokenizer_test_parser.rb +63 -0
  132. data/lib/feed_tools/vendor/uri.rb +781 -0
  133. data/lib/feed_tools/version.rb +1 -1
  134. data/rakefile +27 -6
  135. data/test/unit/atom_test.rb +298 -210
  136. data/test/unit/helper_test.rb +7 -12
  137. data/test/unit/rdf_test.rb +51 -1
  138. data/test/unit/rss_test.rb +13 -3
  139. metadata +239 -116
  140. data/lib/feed_tools/vendor/htree.rb +0 -97
  141. data/lib/feed_tools/vendor/htree/container.rb +0 -10
  142. data/lib/feed_tools/vendor/htree/context.rb +0 -67
  143. data/lib/feed_tools/vendor/htree/display.rb +0 -27
  144. data/lib/feed_tools/vendor/htree/doc.rb +0 -149
  145. data/lib/feed_tools/vendor/htree/elem.rb +0 -262
  146. data/lib/feed_tools/vendor/htree/encoder.rb +0 -163
  147. data/lib/feed_tools/vendor/htree/equality.rb +0 -218
  148. data/lib/feed_tools/vendor/htree/extract_text.rb +0 -37
  149. data/lib/feed_tools/vendor/htree/fstr.rb +0 -33
  150. data/lib/feed_tools/vendor/htree/gencode.rb +0 -97
  151. data/lib/feed_tools/vendor/htree/htmlinfo.rb +0 -672
  152. data/lib/feed_tools/vendor/htree/inspect.rb +0 -108
  153. data/lib/feed_tools/vendor/htree/leaf.rb +0 -94
  154. data/lib/feed_tools/vendor/htree/loc.rb +0 -367
  155. data/lib/feed_tools/vendor/htree/modules.rb +0 -48
  156. data/lib/feed_tools/vendor/htree/name.rb +0 -124
  157. data/lib/feed_tools/vendor/htree/output.rb +0 -207
  158. data/lib/feed_tools/vendor/htree/parse.rb +0 -409
  159. data/lib/feed_tools/vendor/htree/raw_string.rb +0 -124
  160. data/lib/feed_tools/vendor/htree/regexp-util.rb +0 -15
  161. data/lib/feed_tools/vendor/htree/rexml.rb +0 -130
  162. data/lib/feed_tools/vendor/htree/scan.rb +0 -166
  163. data/lib/feed_tools/vendor/htree/tag.rb +0 -111
  164. data/lib/feed_tools/vendor/htree/template.rb +0 -909
  165. data/lib/feed_tools/vendor/htree/text.rb +0 -115
  166. data/lib/feed_tools/vendor/htree/traverse.rb +0 -465
@@ -1,97 +0,0 @@
1
- #
2
- # = htree.rb
3
- #
4
- # HTML/XML document tree
5
- #
6
- # Author:: Tanaka Akira <akr@m17n.org>
7
- #
8
- # == Features
9
- #
10
- # - Permissive unified HTML/XML parser
11
- # - byte-to-byte round-tripping unparser
12
- # - XML namespace support
13
- # - Dedicated class for escaped string. This ease sanitization.
14
- # - XHTML/XML generator
15
- # - template engine: link:files/htree/template_rb.html
16
- # - recursive template expansion
17
- # - REXML tree generator: link:files/htree/rexml_rb.html
18
- #
19
- # == Example
20
- #
21
- # The following one-liner prints parsed tree object.
22
- #
23
- # % ruby -rhtree -e 'pp HTree(ARGF)' html-file
24
- #
25
- # The following two-line script convert HTML to XHTML.
26
- #
27
- # require 'htree'
28
- # HTree(STDIN).display_xml
29
- #
30
- # The conversion method to REXML is provided as to_rexml.
31
- #
32
- # HTree(...).to_rexml
33
- #
34
- # == Module/Class Hierarchy
35
- #
36
- # * HTree
37
- # * HTree::Name
38
- # * HTree::Context
39
- # * HTree::Location
40
- # * HTree::Node
41
- # * HTree::Doc
42
- # * HTree::Elem
43
- # * HTree::Text
44
- # * HTree::XMLDecl
45
- # * HTree::DocType
46
- # * HTree::ProcIns
47
- # * HTree::Comment
48
- # * HTree::BogusETag
49
- # * HTree::Error
50
- #
51
- # == Method Summary
52
- #
53
- # HTree provides following methods.
54
- #
55
- # - Parsing Methods
56
- # - HTree(<i>html_string</i>) -> HTree::Doc
57
- # - HTree.parse(<i>input</i>) -> HTree::Doc
58
- #
59
- # - Generation Methods
60
- # - HTree::Node#display_xml -> STDOUT
61
- # - HTree::Node#display_xml(<i>out</i>) -> <i>out</i>
62
- # - HTree::Node#display_xml(<i>out</i>, <i>encoding</i>) -> <i>out</i>
63
- # - HTree::Text#to_s -> String
64
- #
65
- # - Template Methods
66
- # - HTree.expand_template{<i>template_string</i>} -> STDOUT
67
- # - HTree.expand_template(<i>out</i>){<i>template_string</i>} -> <i>out</i>
68
- # - HTree.expand_template(<i>out</i>, <i>encoding</i>){<i>template_string</i>} -> <i>out</i>
69
- # - HTree.compile_template(<i>template_string</i>) -> Module
70
- # - HTree{<i>template_string</i>} -> HTree::Doc
71
- #
72
- # - Traverse Methods
73
- # - HTree::Elem#attributes -> Hash[HTree::Name -> HTree::Text]
74
- # - HTree::Elem::Location#attributes -> Hash[HTree::Name -> HTree::Location]
75
- #
76
- # - Predicate Methods
77
- # - HTree::Traverse#doc? -> true or false
78
- # - HTree::Traverse#elem? -> true or false
79
- # - HTree::Traverse#text? -> true or false
80
- # - HTree::Traverse#xmldecl? -> true or false
81
- # - HTree::Traverse#doctype? -> true or false
82
- # - HTree::Traverse#procins? -> true or false
83
- # - HTree::Traverse#comment? -> true or false
84
- # - HTree::Traverse#bogusetag? -> true or false
85
- #
86
- # - REXML Tree Generator
87
- # - HTree::Node#to_rexml -> REXML::Child
88
-
89
- require 'htree/parse'
90
- require 'htree/extract_text'
91
- require 'htree/equality'
92
- require 'htree/inspect'
93
- require 'htree/display'
94
- require 'htree/loc'
95
- require 'htree/traverse'
96
- require 'htree/template'
97
- require 'htree/rexml'
@@ -1,10 +0,0 @@
1
- # :stopdoc:
2
- require 'htree/modules'
3
-
4
- module HTree::Container # :nodoc:
5
- # +children+ returns children nodes as an array.
6
- def children
7
- @children.dup
8
- end
9
- end
10
- # :startdoc:
@@ -1,67 +0,0 @@
1
- # :stopdoc:
2
- module HTree
3
- class Context
4
- DefaultNamespaces = {'xml'=>'http://www.w3.org/XML/1998/namespace'}
5
- DefaultNamespaces.default = ""
6
- DefaultNamespaces.freeze
7
-
8
- # The optional argument `namespaces' should be a hash or nil.
9
- # HTree::DefaultNamespaces is used if nil is specified.
10
- #
11
- # If it is a hash, its key should be nil or a string.
12
- # nil means default namespace.
13
- # The string means some prefix which must not be empty.
14
- #
15
- # The hash value should be a string.
16
- # The empty string "" means unbound namespace.
17
- def initialize(namespaces=nil)
18
- namespaces ||= DefaultNamespaces
19
- namespaces.each_pair {|k, v|
20
- check_namespace_prefix(k)
21
- check_namespace_uri(v)
22
- }
23
- namespaces = namespaces.dup.freeze unless namespaces.frozen?
24
- @namespaces = namespaces
25
- end
26
- attr_reader :namespaces
27
-
28
- # return a namespace URI corresponding to _prefix_.
29
- # It returns nil if _prefix_ is not defined.
30
- def namespace_uri(prefix)
31
- @namespaces[prefix]
32
- end
33
-
34
- # generate a new Context object which namespaces are substituted by
35
- # a hash _declared_namespaces_.
36
- def subst_namespaces(declared_namespaces)
37
- namespaces = @namespaces.dup
38
- declared_namespaces.each {|k, v|
39
- check_namespace_prefix(k)
40
- check_namespace_uri(v)
41
- namespaces[k] = v
42
- }
43
- if namespaces == @namespaces
44
- self
45
- else
46
- Context.new(namespaces)
47
- end
48
- end
49
-
50
- private
51
- def check_namespace_prefix(k)
52
- unless (String === k && !k.empty?) || k == nil
53
- raise ArgumentError, "invalid namespace prefix: #{k.inspect}"
54
- end
55
- end
56
-
57
- def check_namespace_uri(v)
58
- unless String === v
59
- raise ArgumentError, "invalid namespace URI: #{v.inspect}"
60
- end
61
- end
62
- end
63
-
64
- DefaultContext = Context.new
65
- HTMLContext = DefaultContext.subst_namespaces(nil=>"http://www.w3.org/1999/xhtml")
66
- end
67
- # :startdoc:
@@ -1,27 +0,0 @@
1
- # :stopdoc:
2
- require 'htree/output'
3
-
4
- module HTree
5
- module Node
6
- # HTree::Node#display_xml prints the node as XML.
7
- #
8
- # The first optional argument, <i>out</i>,
9
- # specifies output target.
10
- # It should respond to <tt><<</tt>.
11
- # If it is not specified, $stdout is used.
12
- #
13
- # The second optional argument, <i>encoding</i>,
14
- # specifies output MIME charset (character encoding).
15
- # If it is not specified, HTree::Encoder.internal_charset is used.
16
- #
17
- # HTree::Node#display_xml returns <i>out</i>.
18
- def display_xml(out=$stdout, encoding=HTree::Encoder.internal_charset)
19
- encoder = HTree::Encoder.new(encoding)
20
- self.output(encoder, HTree::DefaultContext)
21
- # don't call finish_with_xmldecl because self already has a xml decl.
22
- out << encoder.finish
23
- out
24
- end
25
- end
26
- end
27
- # :startdoc:
@@ -1,149 +0,0 @@
1
- # :stopdoc:
2
- require 'htree/modules'
3
- require 'htree/container'
4
-
5
- module HTree
6
- class Doc
7
- class << self
8
- alias new! new
9
- end
10
-
11
- # The arguments should be a sequence of follows.
12
- # [String object] specified string is converted to HTree::Text.
13
- # [HTree::Node object] used as a child.
14
- # [HTree::Doc object]
15
- # used as children.
16
- # It is expanded except HTree::XMLDecl and HTree::DocType objects.
17
- # [Array of String, HTree::Node and HTree::Doc] used as children.
18
- #
19
- def Doc.new(*args)
20
- children = []
21
- args.each {|arg|
22
- arg = arg.to_node if HTree::Location === arg
23
- case arg
24
- when Array
25
- arg.each {|a|
26
- a = a.to_node if HTree::Location === a
27
- case a
28
- when HTree::Doc
29
- children.concat(a.children.reject {|c|
30
- HTree::XMLDecl === c || HTree::DocType === c
31
- })
32
- when HTree::Node
33
- children << a
34
- when String
35
- children << Text.new(a)
36
- else
37
- raise TypeError, "unexpected argument: #{arg.inspect}"
38
- end
39
- }
40
- when HTree::Doc
41
- children.concat(arg.children.reject {|c|
42
- HTree::XMLDecl === c || HTree::DocType === c
43
- })
44
- when HTree::Node
45
- children << arg
46
- when String
47
- children << Text.new(arg)
48
- else
49
- raise TypeError, "unexpected argument: #{arg.inspect}"
50
- end
51
- }
52
- new!(children)
53
- end
54
-
55
- def initialize(children=[]) # :notnew:
56
- @children = children.dup.freeze
57
- unless @children.all? {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) }
58
- unacceptable = @children.reject {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) }
59
- unacceptable = unacceptable.map {|uc| uc.inspect }.join(', ')
60
- raise TypeError, "Unacceptable document child: #{unacceptable}"
61
- end
62
- end
63
-
64
- def get_subnode_internal(index) # :nodoc:
65
- unless Integer === index
66
- raise TypeError, "invalid index: #{index.inspect}"
67
- end
68
- if index < 0 || @children.length <= index
69
- nil
70
- else
71
- @children[index]
72
- end
73
- end
74
-
75
- # doc.subst_subnode(pairs) -> doc
76
- #
77
- # The argument _pairs_ should be a hash or an assocs.
78
- # Its key should be an integer which means an index for children.
79
- #
80
- # Its value should be one of follows.
81
- # [HTree::Node object] specified object is used as is.
82
- # [String object] specified string is converted to HTree::Text
83
- # [Array of above] specified HTree::Node and String is used in that order.
84
- # [nil] delete corresponding node.
85
- #
86
- # d = HTree('<a/><b/><c/>')
87
- # p d.subst_subnode({0=>HTree('<x/>'), 2=>HTree('<z/>')})
88
- # p d.subst_subnode([[0,HTree('<x/>')], [2,HTree('<z/>')]])
89
- # # =>
90
- # #<HTree::Doc {emptyelem <x>} {emptyelem <b>} {emptyelem <z>}>
91
- # #<HTree::Doc {emptyelem <x>} {emptyelem <b>} {emptyelem <z>}>
92
- #
93
- def subst_subnode(pairs)
94
- hash = {}
95
- pairs.each {|index, value|
96
- unless Integer === index
97
- raise TypeError, "invalid index: #{index.inspect}"
98
- end
99
- value = value.to_node if HTree::Location === value
100
- case value
101
- when Node
102
- value = [value]
103
- when String
104
- value = [value]
105
- when Array
106
- value = value.dup
107
- when nil
108
- value = []
109
- else
110
- raise TypeError, "invalid value: #{value.inspect}"
111
- end
112
- value.map! {|v|
113
- v = v.to_node if HTree::Location === v
114
- case v
115
- when Node
116
- v
117
- when String
118
- Text.new(v)
119
- else
120
- raise TypeError, "invalid value: #{v.inspect}"
121
- end
122
- }
123
- if !hash.include?(index)
124
- hash[index] = []
125
- end
126
- hash[index].concat value
127
- }
128
-
129
- children_left = []
130
- children = @children.dup
131
- children_right = []
132
-
133
- hash.keys.sort.each {|index|
134
- value = hash[index]
135
- if index < 0
136
- children_left << value
137
- elsif children.length <= index
138
- children_right << value
139
- else
140
- children[index] = value
141
- end
142
- }
143
-
144
- children = [children_left, children, children_right].flatten.compact
145
- Doc.new(children)
146
- end
147
- end
148
- end
149
- # :startdoc:
@@ -1,262 +0,0 @@
1
- # :stopdoc:
2
- require 'htree/modules'
3
- require 'htree/tag'
4
- require 'htree/context'
5
- require 'htree/container'
6
-
7
- module HTree
8
- class Elem
9
- class << self
10
- alias new! new
11
- end
12
-
13
- # The first argument _name_ should be an instance of String or HTree::Name.
14
- #
15
- # The rest of arguments should be a sequence of follows.
16
- # [Hash object] used as attributes.
17
- # [String object] specified string is converted to HTree::Text.
18
- # [HTree::Node object] used as a child.
19
- # [HTree::Doc object]
20
- # used as children.
21
- # It is expanded except HTree::XMLDecl and HTree::DocType objects.
22
- # [Array of String, HTree::Node, HTree::Doc] used as children.
23
- # [HTree::Context object]
24
- # used as as context which represents XML namespaces.
25
- # This should apper once at most.
26
- #
27
- # HTree::Location object is accepted just as HTree::Node.
28
- #
29
- # If the rest arguments consists only
30
- # Hash and HTree::Context, empty element is created.
31
- #
32
- # p HTree::Elem.new("e").empty_element? # => true
33
- # p HTree::Elem.new("e", []).empty_element? # => false
34
- def Elem.new(name, *args)
35
- attrs = []
36
- children = []
37
- context = nil
38
- args.each {|arg|
39
- arg = arg.to_node if HTree::Location === arg
40
- case arg
41
- when Context
42
- raise ArgumentError, "multiple context" if context
43
- context = arg
44
- when Hash
45
- arg.each {|k, v| attrs << [k, v] }
46
- when Array
47
- arg.each {|a|
48
- a = a.to_node if HTree::Location === a
49
- case a
50
- when HTree::Doc
51
- children.concat(a.children.reject {|c|
52
- HTree::XMLDecl === c || HTree::DocType === c
53
- })
54
- when HTree::Node
55
- children << a
56
- when String
57
- children << Text.new(a)
58
- else
59
- raise TypeError, "unexpected argument: #{arg.inspect}"
60
- end
61
- }
62
- when HTree::Doc
63
- children.concat(arg.children.reject {|c|
64
- HTree::XMLDecl === c || HTree::DocType === c
65
- })
66
- when HTree::Node
67
- children << arg
68
- when String
69
- children << Text.new(arg)
70
-
71
- else
72
- raise TypeError, "unexpected argument: #{arg.inspect}"
73
- end
74
- }
75
- context ||= DefaultContext
76
- if children.empty? && args.all? {|arg| Hash === arg || Context === arg }
77
- children = nil
78
- end
79
- new!(STag.new(name, attrs, context), children)
80
- end
81
-
82
- def initialize(stag, children=nil, etag=nil) # :notnew:
83
- unless stag.class == STag
84
- raise TypeError, "HTree::STag expected: #{stag.inspect}"
85
- end
86
- unless !children || children.all? {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) }
87
- unacceptable = children.reject {|c| c.kind_of?(HTree::Node) and !c.kind_of?(HTree::Doc) }
88
- unacceptable = unacceptable.map {|uc| uc.inspect }.join(', ')
89
- raise TypeError, "Unacceptable element child: #{unacceptable}"
90
- end
91
- unless !etag || etag.class == ETag
92
- raise TypeError, "HTree::ETag expected: #{etag.inspect}"
93
- end
94
- @stag = stag
95
- @children = (children ? children.dup : []).freeze
96
- @empty = children == nil && etag == nil
97
- @etag = etag
98
- end
99
-
100
- def context; @stag.context end
101
-
102
- # +element_name+ returns the name of the element name as a Name object.
103
- def element_name() @stag.element_name end
104
-
105
- def empty_element?
106
- @empty
107
- end
108
-
109
- def each_attribute(&block) # :yields: attr_name, attr_text
110
- @stag.each_attribute(&block)
111
- end
112
-
113
- def get_subnode_internal(index) # :nodoc:
114
- case index
115
- when String
116
- name = Name.parse_attribute_name(index, DefaultContext)
117
- update_attribute_hash[name.universal_name]
118
- when Name
119
- update_attribute_hash[index.universal_name]
120
- when Integer
121
- if index < 0 || @children.length <= index
122
- nil
123
- else
124
- @children[index]
125
- end
126
- else
127
- raise TypeError, "invalid index: #{index.inspect}"
128
- end
129
- end
130
-
131
- # call-seq:
132
- # elem.subst_subnode(pairs) -> elem
133
- #
134
- # The argument _pairs_ should be a hash or an assocs.
135
- #
136
- # The key of pairs should be one of following.
137
- # [HTree::Name or String object] attribute name.
138
- # [Integer object] child index.
139
- #
140
- # The value of pairs should be one of follows.
141
- # [HTree::Node object] specified object is used as is.
142
- # [String object] specified string is converted to HTree::Text
143
- # [Array of above] specified HTree::Node and String is used in that order.
144
- # [nil] delete corresponding node.
145
- #
146
- # e = HTree('<r><a/><b/><c/></r>').root
147
- # p e.subst_subnode({0=>HTree('<x/>'), 2=>HTree('<z/>')})
148
- # p e.subst_subnode([[0, HTree('<x/>')], [2,HTree('<z/>')]])
149
- # # =>
150
- # {elem <r> {emptyelem <x>} {emptyelem <b>} {emptyelem <z>}}
151
- # {elem <r> {emptyelem <x>} {emptyelem <b>} {emptyelem <z>}}
152
- #
153
- def subst_subnode(pairs)
154
- hash = {}
155
- pairs.each {|index, value|
156
- case index
157
- when Name, Integer
158
- when String
159
- index = Name.parse_attribute_name(index, DefaultContext)
160
- else
161
- raise TypeError, "invalid index: #{index.inspect}"
162
- end
163
- value = value.to_node if HTree::Location === value
164
- case value
165
- when Node
166
- value = [value]
167
- when String
168
- value = [value]
169
- when Array
170
- value = value.dup
171
- when nil
172
- value = []
173
- else
174
- raise TypeError, "invalid value: #{value.inspect}"
175
- end
176
- value.map! {|v|
177
- v = v.to_node if HTree::Location === v
178
- case v
179
- when Node
180
- v
181
- when String
182
- Text.new(v)
183
- else
184
- raise TypeError, "invalid value: #{v.inspect}"
185
- end
186
- }
187
- if !hash.include?(index)
188
- hash[index] = []
189
- end
190
- hash[index].concat value
191
- }
192
-
193
- attrs = []
194
- @stag.attributes.each {|k, v|
195
- if hash.include? k
196
- v = hash[k]
197
- if !v.empty?
198
- attrs << {k=>Text.concat(*v)}
199
- end
200
- hash.delete k
201
- else
202
- attrs << {k=>v}
203
- end
204
- }
205
- hash.keys.each {|k|
206
- if Name === k
207
- v = hash[k]
208
- if !v.empty?
209
- attrs << {k=>Text.concat(*v)}
210
- end
211
- hash.delete k
212
- end
213
- }
214
-
215
- children_left = []
216
- children = @children.dup
217
- children_right = []
218
-
219
- hash.keys.sort.each {|index|
220
- value = hash[index]
221
- if index < 0
222
- children_left << value
223
- elsif children.length <= index
224
- children_right << value
225
- else
226
- children[index] = value
227
- end
228
- }
229
-
230
- children = [children_left, children, children_right].flatten
231
-
232
- if children.empty? && @empty
233
- Elem.new(
234
- @stag.element_name,
235
- @stag.context,
236
- *attrs)
237
- else
238
- Elem.new(
239
- @stag.element_name,
240
- @stag.context,
241
- children,
242
- *attrs)
243
- end
244
- end
245
- end
246
-
247
- module Elem::Trav
248
- private
249
- def update_attribute_hash
250
- if defined?(@attribute_hash)
251
- @attribute_hash
252
- else
253
- h = {}
254
- each_attribute {|name, text|
255
- h[name.universal_name] = text
256
- }
257
- @attribute_hash = h
258
- end
259
- end
260
- end
261
- end
262
- # :startdoc: