feedtools 0.2.26 → 0.2.27
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +232 -216
- data/db/migration.rb +2 -0
- data/db/schema.mysql.sql +2 -0
- data/db/schema.postgresql.sql +3 -1
- data/db/schema.sqlite.sql +3 -1
- data/lib/feed_tools.rb +37 -14
- data/lib/feed_tools/database_feed_cache.rb +13 -2
- data/lib/feed_tools/feed.rb +430 -104
- data/lib/feed_tools/feed_item.rb +533 -268
- data/lib/feed_tools/helpers/generic_helper.rb +1 -1
- data/lib/feed_tools/helpers/html_helper.rb +78 -116
- data/lib/feed_tools/helpers/retrieval_helper.rb +33 -3
- data/lib/feed_tools/helpers/uri_helper.rb +46 -54
- data/lib/feed_tools/monkey_patch.rb +27 -1
- data/lib/feed_tools/vendor/html5/History.txt +10 -0
- data/lib/feed_tools/vendor/html5/Manifest.txt +117 -0
- data/lib/feed_tools/vendor/html5/README +45 -0
- data/lib/feed_tools/vendor/html5/Rakefile.rb +33 -0
- data/lib/feed_tools/vendor/html5/bin/html5 +217 -0
- data/lib/feed_tools/vendor/html5/lib/core_ext/string.rb +17 -0
- data/lib/feed_tools/vendor/html5/lib/html5.rb +13 -0
- data/lib/feed_tools/vendor/html5/lib/html5/constants.rb +1046 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/base.rb +10 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/inject_meta_charset.rb +82 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/iso639codes.rb +752 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/optionaltags.rb +198 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/rfc2046.rb +30 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/rfc3987.rb +89 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/sanitizer.rb +15 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/validator.rb +830 -0
- data/lib/feed_tools/vendor/html5/lib/html5/filters/whitespace.rb +36 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser.rb +248 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_body_phase.rb +46 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_frameset_phase.rb +33 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/after_head_phase.rb +50 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/before_head_phase.rb +41 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_body_phase.rb +613 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_caption_phase.rb +69 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_cell_phase.rb +78 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_column_group_phase.rb +55 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_frameset_phase.rb +57 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_head_phase.rb +138 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_row_phase.rb +89 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_select_phase.rb +85 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_table_body_phase.rb +86 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/in_table_phase.rb +115 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/initial_phase.rb +133 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/phase.rb +154 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/root_element_phase.rb +41 -0
- data/lib/feed_tools/vendor/html5/lib/html5/html5parser/trailing_end_phase.rb +35 -0
- data/lib/feed_tools/vendor/html5/lib/html5/inputstream.rb +648 -0
- data/lib/feed_tools/vendor/html5/lib/html5/liberalxmlparser.rb +158 -0
- data/lib/feed_tools/vendor/html5/lib/html5/sanitizer.rb +188 -0
- data/lib/feed_tools/vendor/html5/lib/html5/serializer.rb +2 -0
- data/lib/feed_tools/vendor/html5/lib/html5/serializer/htmlserializer.rb +179 -0
- data/lib/feed_tools/vendor/html5/lib/html5/serializer/xhtmlserializer.rb +20 -0
- data/lib/feed_tools/vendor/html5/lib/html5/sniffer.rb +45 -0
- data/lib/feed_tools/vendor/html5/lib/html5/tokenizer.rb +966 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treebuilders.rb +24 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/base.rb +334 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/hpricot.rb +231 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/rexml.rb +209 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treebuilders/simpletree.rb +185 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treewalkers.rb +26 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/base.rb +162 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/hpricot.rb +48 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/rexml.rb +48 -0
- data/lib/feed_tools/vendor/html5/lib/html5/treewalkers/simpletree.rb +48 -0
- data/lib/feed_tools/vendor/html5/lib/html5/version.rb +3 -0
- data/lib/feed_tools/vendor/html5/testdata/encoding/chardet/test_big5.txt +51 -0
- data/lib/feed_tools/vendor/html5/testdata/encoding/test-yahoo-jp.dat +10 -0
- data/lib/feed_tools/vendor/html5/testdata/encoding/tests1.dat +394 -0
- data/lib/feed_tools/vendor/html5/testdata/encoding/tests2.dat +81 -0
- data/lib/feed_tools/vendor/html5/testdata/sanitizer/tests1.dat +416 -0
- data/lib/feed_tools/vendor/html5/testdata/serializer/core.test +104 -0
- data/lib/feed_tools/vendor/html5/testdata/serializer/injectmeta.test +65 -0
- data/lib/feed_tools/vendor/html5/testdata/serializer/optionaltags.test +900 -0
- data/lib/feed_tools/vendor/html5/testdata/serializer/options.test +60 -0
- data/lib/feed_tools/vendor/html5/testdata/serializer/whitespace.test +51 -0
- data/lib/feed_tools/vendor/html5/testdata/sites/google-results.htm +1 -0
- data/lib/feed_tools/vendor/html5/testdata/sites/python-ref-import.htm +1 -0
- data/lib/feed_tools/vendor/html5/testdata/sites/web-apps-old.htm +1 -0
- data/lib/feed_tools/vendor/html5/testdata/sites/web-apps.htm +34275 -0
- data/lib/feed_tools/vendor/html5/testdata/sniffer/htmlOrFeed.json +43 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/contentModelFlags.test +48 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/entities.test +2339 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/escapeFlag.test +21 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/test1.test +172 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/test2.test +129 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/test3.test +367 -0
- data/lib/feed_tools/vendor/html5/testdata/tokenizer/test4.test +198 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests1.dat +1950 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests2.dat +773 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests3.dat +270 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests4.dat +60 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests5.dat +175 -0
- data/lib/feed_tools/vendor/html5/testdata/tree-construction/tests6.dat +196 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/attributes.test +1035 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/base-href-attribute.test +787 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/base-target-attribute.test +35 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/blockquote-cite-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/classattribute.test +152 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/contenteditableattribute.test +59 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/contextmenuattribute.test +115 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/dirattribute.test +59 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/draggableattribute.test +63 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/html-xmlns-attribute.test +23 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/idattribute.test +115 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/inputattributes.test +2795 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/irrelevantattribute.test +63 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/langattribute.test +5579 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/li-value-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/link-href-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/link-hreflang-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/link-rel-attribute.test +271 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/ol-start-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/starttags.test +375 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/style-scoped-attribute.test +7 -0
- data/lib/feed_tools/vendor/html5/testdata/validator/tabindexattribute.test +79 -0
- data/lib/feed_tools/vendor/html5/tests/preamble.rb +72 -0
- data/lib/feed_tools/vendor/html5/tests/test_encoding.rb +35 -0
- data/lib/feed_tools/vendor/html5/tests/test_lxp.rb +279 -0
- data/lib/feed_tools/vendor/html5/tests/test_parser.rb +68 -0
- data/lib/feed_tools/vendor/html5/tests/test_sanitizer.rb +142 -0
- data/lib/feed_tools/vendor/html5/tests/test_serializer.rb +68 -0
- data/lib/feed_tools/vendor/html5/tests/test_sniffer.rb +27 -0
- data/lib/feed_tools/vendor/html5/tests/test_stream.rb +62 -0
- data/lib/feed_tools/vendor/html5/tests/test_tokenizer.rb +94 -0
- data/lib/feed_tools/vendor/html5/tests/test_treewalkers.rb +135 -0
- data/lib/feed_tools/vendor/html5/tests/test_validator.rb +31 -0
- data/lib/feed_tools/vendor/html5/tests/tokenizer_test_parser.rb +63 -0
- data/lib/feed_tools/vendor/uri.rb +781 -0
- data/lib/feed_tools/version.rb +1 -1
- data/rakefile +27 -6
- data/test/unit/atom_test.rb +298 -210
- data/test/unit/helper_test.rb +7 -12
- data/test/unit/rdf_test.rb +51 -1
- data/test/unit/rss_test.rb +13 -3
- metadata +239 -116
- data/lib/feed_tools/vendor/htree.rb +0 -97
- data/lib/feed_tools/vendor/htree/container.rb +0 -10
- data/lib/feed_tools/vendor/htree/context.rb +0 -67
- data/lib/feed_tools/vendor/htree/display.rb +0 -27
- data/lib/feed_tools/vendor/htree/doc.rb +0 -149
- data/lib/feed_tools/vendor/htree/elem.rb +0 -262
- data/lib/feed_tools/vendor/htree/encoder.rb +0 -163
- data/lib/feed_tools/vendor/htree/equality.rb +0 -218
- data/lib/feed_tools/vendor/htree/extract_text.rb +0 -37
- data/lib/feed_tools/vendor/htree/fstr.rb +0 -33
- data/lib/feed_tools/vendor/htree/gencode.rb +0 -97
- data/lib/feed_tools/vendor/htree/htmlinfo.rb +0 -672
- data/lib/feed_tools/vendor/htree/inspect.rb +0 -108
- data/lib/feed_tools/vendor/htree/leaf.rb +0 -94
- data/lib/feed_tools/vendor/htree/loc.rb +0 -367
- data/lib/feed_tools/vendor/htree/modules.rb +0 -48
- data/lib/feed_tools/vendor/htree/name.rb +0 -124
- data/lib/feed_tools/vendor/htree/output.rb +0 -207
- data/lib/feed_tools/vendor/htree/parse.rb +0 -409
- data/lib/feed_tools/vendor/htree/raw_string.rb +0 -124
- data/lib/feed_tools/vendor/htree/regexp-util.rb +0 -15
- data/lib/feed_tools/vendor/htree/rexml.rb +0 -130
- data/lib/feed_tools/vendor/htree/scan.rb +0 -166
- data/lib/feed_tools/vendor/htree/tag.rb +0 -111
- data/lib/feed_tools/vendor/htree/template.rb +0 -909
- data/lib/feed_tools/vendor/htree/text.rb +0 -115
- 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,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:
|