htree 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. data.tar.gz.sig +4 -0
  2. data/Makefile +20 -0
  3. data/Manifest +58 -0
  4. data/README +61 -0
  5. data/Rakefile +37 -0
  6. data/htree.gemspec +32 -0
  7. data/init.rb +1 -0
  8. data/install.rb +112 -0
  9. data/lib/htree.rb +97 -0
  10. data/lib/htree/container.rb +8 -0
  11. data/lib/htree/context.rb +69 -0
  12. data/lib/htree/display.rb +46 -0
  13. data/lib/htree/doc.rb +149 -0
  14. data/lib/htree/elem.rb +262 -0
  15. data/lib/htree/encoder.rb +217 -0
  16. data/lib/htree/equality.rb +219 -0
  17. data/lib/htree/extract_text.rb +37 -0
  18. data/lib/htree/fstr.rb +32 -0
  19. data/lib/htree/gencode.rb +193 -0
  20. data/lib/htree/htmlinfo.rb +672 -0
  21. data/lib/htree/inspect.rb +108 -0
  22. data/lib/htree/leaf.rb +92 -0
  23. data/lib/htree/loc.rb +369 -0
  24. data/lib/htree/modules.rb +49 -0
  25. data/lib/htree/name.rb +122 -0
  26. data/lib/htree/output.rb +212 -0
  27. data/lib/htree/parse.rb +410 -0
  28. data/lib/htree/raw_string.rb +127 -0
  29. data/lib/htree/regexp-util.rb +19 -0
  30. data/lib/htree/rexml.rb +131 -0
  31. data/lib/htree/scan.rb +176 -0
  32. data/lib/htree/tag.rb +113 -0
  33. data/lib/htree/template.rb +961 -0
  34. data/lib/htree/text.rb +115 -0
  35. data/lib/htree/traverse.rb +497 -0
  36. data/test-all.rb +5 -0
  37. data/test/assign.html +1 -0
  38. data/test/template.html +4 -0
  39. data/test/test-attr.rb +67 -0
  40. data/test/test-charset.rb +79 -0
  41. data/test/test-context.rb +29 -0
  42. data/test/test-display_xml.rb +45 -0
  43. data/test/test-elem-new.rb +101 -0
  44. data/test/test-encoder.rb +53 -0
  45. data/test/test-equality.rb +55 -0
  46. data/test/test-extract_text.rb +18 -0
  47. data/test/test-gencode.rb +27 -0
  48. data/test/test-leaf.rb +25 -0
  49. data/test/test-loc.rb +60 -0
  50. data/test/test-namespace.rb +147 -0
  51. data/test/test-output.rb +133 -0
  52. data/test/test-parse.rb +115 -0
  53. data/test/test-raw_string.rb +17 -0
  54. data/test/test-rexml.rb +70 -0
  55. data/test/test-scan.rb +153 -0
  56. data/test/test-security.rb +37 -0
  57. data/test/test-subnode.rb +142 -0
  58. data/test/test-template.rb +313 -0
  59. data/test/test-text.rb +43 -0
  60. data/test/test-traverse.rb +69 -0
  61. metadata +166 -0
  62. metadata.gz.sig +1 -0
@@ -0,0 +1,17 @@
1
+ require 'test/unit'
2
+ require 'htree'
3
+
4
+ class TestRawString < Test::Unit::TestCase
5
+ def test_elem
6
+ t = HTree.parse("<a>x</a>")
7
+ assert_equal("<a>x</a>", t.root.raw_string)
8
+ assert_equal("<a>x</a>", t.root.raw_string) # raw_string shouldn't have side effect.
9
+ end
10
+
11
+ def test_no_raw_string
12
+ t = HTree::Elem.new('a')
13
+ assert_equal(nil, t.raw_string)
14
+ t = HTree::Elem.new('a', HTree.parse("<a>x</a>").root)
15
+ assert_equal(nil, t.raw_string)
16
+ end
17
+ end
@@ -0,0 +1,70 @@
1
+ require 'test/unit'
2
+ require 'htree/parse'
3
+ require 'htree/rexml'
4
+ begin
5
+ require 'rexml/document'
6
+ rescue LoadError
7
+ end
8
+
9
+ class TestREXML < Test::Unit::TestCase
10
+ def test_doc
11
+ r = HTree.parse('<root/>').to_rexml
12
+ assert_instance_of(REXML::Document, r)
13
+ end
14
+
15
+ def test_elem
16
+ r = HTree.parse('<root a="b"/>').to_rexml
17
+ assert_instance_of(REXML::Element, e = r.root)
18
+ assert_equal('root', e.name)
19
+ assert_equal('b', e.attribute('a').to_s)
20
+ end
21
+
22
+ def test_text
23
+ r = HTree.parse('<root>aaa</root>').to_rexml
24
+ assert_instance_of(REXML::Text, t = r.root.children[0])
25
+ assert_equal('aaa', t.to_s)
26
+ end
27
+
28
+ def test_xmldecl
29
+ s = '<?xml version="1.0"?>'
30
+ r = HTree.parse(s + '<root>aaa</root>').to_rexml
31
+ assert_instance_of(REXML::XMLDecl, x = r.children[0])
32
+ assert_equal('1.0', x.version)
33
+ assert_equal(nil, x.standalone)
34
+
35
+ assert_instance_of(REXML::XMLDecl, HTree.parse(s).children[0].to_rexml)
36
+ end
37
+
38
+ def test_doctype
39
+ s = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
40
+ r = HTree.parse(s + '<html><title>xxx</title></html>').to_rexml
41
+ assert_instance_of(REXML::DocType, d = r.children[0])
42
+ assert_equal('html', d.name)
43
+ assert_equal('PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"', d.external_id)
44
+
45
+ assert_instance_of(REXML::DocType, HTree.parse(s).children[0].to_rexml)
46
+ end
47
+
48
+ def test_procins
49
+ r = HTree.parse('<root><?xxx yyy?></root>').to_rexml
50
+ assert_instance_of(REXML::Instruction, i = r.root.children[0])
51
+ assert_equal('xxx', i.target)
52
+ assert_equal('yyy', i.content)
53
+
54
+ assert_instance_of(REXML::Instruction, HTree.parse('<?xxx yyy?>').children[0].to_rexml)
55
+ end
56
+
57
+ def test_comment
58
+ r = HTree.parse('<root><!-- zzz --></root>').to_rexml
59
+ assert_instance_of(REXML::Comment, c = r.root.children[0])
60
+ assert_equal(' zzz ', c.to_s)
61
+ end
62
+
63
+ def test_bogusetag
64
+ assert_equal(nil, HTree.parse('</e>').children[0].to_rexml)
65
+ end
66
+
67
+ def test_style
68
+ assert_equal('<style>a&lt;b</style>', HTree.parse('<html><style>a<b</style></html>').to_rexml.to_s[/<style.*style>/])
69
+ end
70
+ end if defined? REXML
@@ -0,0 +1,153 @@
1
+ require 'test/unit'
2
+ require 'htree/scan'
3
+
4
+ class TestScan < Test::Unit::TestCase
5
+ def scan(str)
6
+ result = []
7
+ HTree.scan(str) {|e| result << e }
8
+ result
9
+ end
10
+
11
+ def test_empty
12
+ assert_equal([], scan(''))
13
+ end
14
+
15
+ def t_single(s)
16
+ n = yield
17
+ assert_equal([n], scan(s))
18
+ end
19
+
20
+ def test_single
21
+ s = '<?xml version="1.0"?>'
22
+ assert_equal([[:xmldecl, s]], scan(s))
23
+
24
+ s = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">'
25
+ assert_equal([[:doctype, s]], scan(s))
26
+
27
+ s = '<?xxx yyy?>'
28
+ assert_equal([[:procins, s]], scan(s))
29
+
30
+ s = '<a>'
31
+ assert_equal([[:stag, s]], scan(s))
32
+ s = '</a>'
33
+ assert_equal([[:etag, s]], scan(s))
34
+ s = '<a/>'
35
+ assert_equal([[:emptytag, s]], scan(s))
36
+ s = '<!-- abc -->'
37
+ assert_equal([[:comment, s]], scan(s))
38
+ s = '<![CDATA[abc]]>'
39
+ assert_equal([[:text_cdata_section, s]], scan(s))
40
+ s = 'abc'
41
+ assert_equal([[:text_pcdata, s]], scan(s))
42
+ end
43
+
44
+ def test_xmldecl_seen
45
+ s0 = '<?xml version="1.0"?>'
46
+ s1 = '<A>'
47
+ assert_equal([[:stag, s1]], scan(s1))
48
+ assert_equal([[:xmldecl, s0], [:stag, s1]], scan(s0 + s1))
49
+ end
50
+
51
+ def test_cdata_content
52
+ s = '<html><script><a></script><a>'
53
+ assert_equal([
54
+ [:stag, '<html>'],
55
+ [:stag, '<script>'],
56
+ [:text_cdata_content, '<a>'],
57
+ [:etag, '</script>'],
58
+ [:stag, '<a>'],
59
+ ], scan(s))
60
+
61
+ s = '<html><script><a>'
62
+ assert_equal([
63
+ [:stag, '<html>'],
64
+ [:stag, '<script>'],
65
+ [:text_cdata_content, '<a>'],
66
+ ], scan(s))
67
+ end
68
+
69
+ def test_text
70
+ s = 'a<e>b<e>c<e>d'
71
+ assert_equal([
72
+ [:text_pcdata, 'a'],
73
+ [:stag, '<e>'],
74
+ [:text_pcdata, 'b'],
75
+ [:stag, '<e>'],
76
+ [:text_pcdata, 'c'],
77
+ [:stag, '<e>'],
78
+ [:text_pcdata, 'd'],
79
+ ], scan(s))
80
+ end
81
+
82
+ def test_eol_html
83
+ # In SGML, a line break just after start tag and
84
+ # a line break just before end tag is ignored.
85
+ # http://www.w3.org/TR/REC-html40/appendix/notes.html#notes-line-breaks
86
+ #
87
+ # But usual browser including mozilla doesn't.
88
+ # So HTree doesn't ignore them and treat as usual text.
89
+ s = "<html>a\n<e>\nb\n<f>\nc\n</f>\nd\n</e>\ne"
90
+ assert_equal([
91
+ [:stag, "<html>"],
92
+ [:text_pcdata, "a\n"],
93
+ [:stag, "<e>"],
94
+ [:text_pcdata, "\nb\n"],
95
+ [:stag, "<f>"],
96
+ [:text_pcdata, "\nc\n"],
97
+ [:etag, "</f>"],
98
+ [:text_pcdata, "\nd\n"],
99
+ [:etag, "</e>"],
100
+ [:text_pcdata, "\ne"],
101
+ ], scan(s))
102
+
103
+ s = "<html>a\n<e>\nb\n<script>\nc\n</script>\nd\n</e>\ne"
104
+ assert_equal([
105
+ [:stag, "<html>"],
106
+ [:text_pcdata, "a\n"],
107
+ [:stag, "<e>"],
108
+ [:text_pcdata, "\nb\n"],
109
+ [:stag, "<script>"],
110
+ [:text_cdata_content, "\nc\n"],
111
+ [:etag, "</script>"],
112
+ [:text_pcdata, "\nd\n"],
113
+ [:etag, "</e>"],
114
+ [:text_pcdata, "\ne"],
115
+ ], scan(s))
116
+
117
+ end
118
+
119
+ def test_eol_xml
120
+ # In XML, line breaks are treated as part of content.
121
+ # It's because KEEPRSRE is yes in XML.
122
+ # http://www.satoshii.org/markup/websgml/valid-xml#keeprsre
123
+ s = "<?xml version='1.0'?>a\n<e>\nb\n<f>\nc\n</f>\nd\n</e>\ne"
124
+ assert_equal([
125
+ [:xmldecl, "<?xml version='1.0'?>"],
126
+ [:text_pcdata, "a\n"],
127
+ [:stag, "<e>"],
128
+ [:text_pcdata, "\nb\n"],
129
+ [:stag, "<f>"],
130
+ [:text_pcdata, "\nc\n"],
131
+ [:etag, "</f>"],
132
+ [:text_pcdata, "\nd\n"],
133
+ [:etag, "</e>"],
134
+ [:text_pcdata, "\ne"],
135
+ ], scan(s))
136
+ end
137
+
138
+ def test_xml_html_detection
139
+ assert_equal([false, true], HTree.scan("<html></html>") {})
140
+ assert_equal([true, false], HTree.scan("<rss></rss>") {})
141
+ assert_equal([true, true], HTree.scan('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">') {})
142
+ end
143
+
144
+ def test_quoted_attr
145
+ assert_equal([[:emptytag, '<e a=">"/>']], scan('<e a=">"/>'))
146
+ end
147
+
148
+ def test_bare_slash
149
+ assert_equal([[:stag, '<n dir=/foo/bar/>']], scan('<n dir=/foo/bar/>'))
150
+ assert_equal([[:stag, '<n a=v/>']], scan('<n a=v/>'))
151
+ end
152
+
153
+ end
@@ -0,0 +1,37 @@
1
+ require 'test/unit'
2
+ require 'htree/parse'
3
+ require 'htree/template'
4
+ require 'pathname'
5
+
6
+ class TestSecurity < Test::Unit::TestCase
7
+ def safe(n)
8
+ assert_equal(0, $SAFE)
9
+ Thread.new {
10
+ $SAFE = n
11
+ assert_equal(n, $SAFE)
12
+ yield
13
+ }.join
14
+ assert_equal(0, $SAFE)
15
+ end
16
+
17
+ def test_parse
18
+ safe(1) {
19
+ assert_equal(1, $SAFE)
20
+ assert_nothing_raised { HTree.parse("") }
21
+ assert_raise(SecurityError) { HTree.parse("".taint) }
22
+ }
23
+ assert_nothing_raised { HTree.parse("") }
24
+ assert_nothing_raised { HTree.parse("".taint) }
25
+ end
26
+
27
+ def test_template
28
+ safe(1) {
29
+ assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') }
30
+ assert_raise(SecurityError) { HTree.expand_template("/dev/null".taint, nil, '') }
31
+ }
32
+ assert_nothing_raised { HTree.expand_template("/dev/null", nil, '') }
33
+ assert_nothing_raised { HTree.expand_template("/dev/null".taint, nil, '') }
34
+ end
35
+
36
+ end
37
+
@@ -0,0 +1,142 @@
1
+ require 'test/unit'
2
+ require 'htree'
3
+
4
+ class TestSubnode < Test::Unit::TestCase
5
+ def test_elem_get
6
+ e1 = HTree.parse("<a href=x>abc</a>").root
7
+ assert_equal(HTree::Text.new("x"), e1.get_subnode("href"))
8
+ assert_equal(HTree::Text.new("abc"), e1.get_subnode(0))
9
+ end
10
+
11
+ def test_elem_subst
12
+ e1 = HTree.parse_xml("<a href=x>abc</a>").root
13
+ e2 = e1.subst_subnode("href"=>"xxx", 0=>"def")
14
+ assert_equal("a", e2.name)
15
+ assert_equal("xxx", e2.fetch_attr("href"))
16
+ assert_equal([HTree::Text.new("def")], e2.children)
17
+ assert_equal([], e1.subst_subnode(0=>nil).children)
18
+ end
19
+
20
+ def test_elem_subst_empty
21
+ e1 = HTree.parse("<img />").root
22
+ assert_equal(true, e1.empty_element?)
23
+ assert_equal(true, e1.subst_subnode("src"=>"xxx").empty_element?)
24
+ assert_equal(false, e1.subst_subnode(0=>"xxx").empty_element?)
25
+ end
26
+
27
+ def test_elem_multiple_attr_value
28
+ h = {"b"=>"c", HTree::Name.new(nil, "", "b")=>"d"}
29
+ assert_match(/\A(cd|dc)\z/,
30
+ HTree::Elem.new("a").subst_subnode(h).get_subnode('b').to_s)
31
+
32
+ a = [["b","c"], [HTree::Name.new(nil, "", "b"),"d"]]
33
+ assert_equal('cd',
34
+ HTree::Elem.new("a").subst_subnode(a).get_subnode('b').to_s)
35
+ assert_equal('dc',
36
+ HTree::Elem.new("a").subst_subnode(a.reverse).get_subnode('b').to_s)
37
+ end
38
+
39
+ def test_elem_subst_outrange
40
+ e1 = HTree("<r>abc</r>").root
41
+ e2 = e1.subst_subnode(-1=>HTree('<x/>'), 1=>HTree('<y/>'))
42
+ assert_equal(HTree('<r><x/>abc<y/></r>').root, e2)
43
+ end
44
+
45
+ def test_doc_subst_outrange
46
+ d1 = HTree("<r>abc</r>")
47
+ d2 = d1.subst_subnode(-1=>HTree('<x/>'), 1=>HTree('<y/>'))
48
+ assert_equal(HTree('<x/><r>abc</r><y/>'), d2)
49
+ end
50
+
51
+ def test_doc_get
52
+ doc = HTree.parse("<?xml?><a href=x>abc</a> ")
53
+ assert_equal(doc.root, doc.get_subnode(1))
54
+ end
55
+
56
+ def test_doc_subst
57
+ doc1 = HTree.parse("<?xml?><a href=x>abc</a> ")
58
+ doc2 = doc1.subst_subnode(1=>"yy")
59
+ assert_equal(HTree::Text.new("yy"), doc2.children[1])
60
+ assert_equal([], doc1.subst_subnode(0=>nil, 1=>nil, 2=>nil).children)
61
+ end
62
+
63
+ def test_doc_loc
64
+ d1 = HTree.parse("<r>a</r>")
65
+ d2 = HTree.parse("<q/>")
66
+ assert_equal(d2, d1.subst_subnode(0=>d2.make_loc))
67
+ end
68
+
69
+ def test_doc
70
+ e = HTree.parse("<r>a</r>").root
71
+ d = HTree.parse("<?xml version='1.0'?><!DOCTYPE q><q/>")
72
+ r = HTree('<r><q/></r>').root
73
+ assert_equal(r, e.subst_subnode(0=>d))
74
+ assert_equal(r, e.subst_subnode(0=>d.make_loc))
75
+ assert_equal(r, e.subst_subnode(0=>[d]))
76
+ assert_equal(r, e.subst_subnode(0=>[d.make_loc]))
77
+ end
78
+
79
+ def test_doc2
80
+ e = HTree.parse("<r>a</r>")
81
+ d = HTree.parse("<?xml version='1.0'?><!DOCTYPE q><q/>")
82
+ r = HTree('<q/>')
83
+ assert_equal(r, e.subst_subnode(0=>d))
84
+ assert_equal(r, e.subst_subnode(0=>d.make_loc))
85
+ assert_equal(r, e.subst_subnode(0=>[d]))
86
+ assert_equal(r, e.subst_subnode(0=>[d.make_loc]))
87
+ end
88
+
89
+ def test_change_by_subst_itself
90
+ l = HTree("<r>a</r>").make_loc
91
+ l2 = l.get_subnode(0, 0).subst_itself('x')
92
+ assert_equal(HTree::Text.new('x'), l2.to_node)
93
+ assert_equal(HTree('<r>x</r>'), l2.top.to_node)
94
+ l2 = l.get_subnode(0).subst_itself('xxx')
95
+ assert_equal(HTree::Text.new('xxx'), l2.to_node)
96
+ assert_equal(HTree('xxx'), l2.top.to_node)
97
+ end
98
+
99
+ def test_add_by_subst_itself
100
+ l = HTree("<r>a</r>").make_loc
101
+ l2 = l.get_subnode(0, 'x').subst_itself('y')
102
+ assert_equal(HTree::Text.new('y'), l2.to_node)
103
+ assert_equal(HTree('<r x="y">a</r>'), l2.top.to_node)
104
+ l2 = l.get_subnode(0, 0).subst_itself('b')
105
+ assert_equal(HTree::Text.new('b'), l2.to_node)
106
+ assert_equal(HTree('<r>b</r>'), l2.top.to_node)
107
+ xmldecl = HTree('<?xml version="1.0"?>').get_subnode(0)
108
+ l2 = l.get_subnode(-1).subst_itself(xmldecl)
109
+ assert_equal(0, l2.index)
110
+ assert_equal(xmldecl, l2.to_node)
111
+ assert_equal(HTree('<?xml version="1.0"?><r>a</r>'), l2.top.to_node)
112
+ procins = HTree('<?xxx yyy?>').get_subnode(0)
113
+ l2 = l.get_subnode(10).subst_itself(procins)
114
+ assert_equal(1, l2.index)
115
+ assert_equal(procins, l2.to_node)
116
+ assert_equal(HTree('<r>a</r><?xxx yyy?>'), l2.top.to_node)
117
+ end
118
+
119
+ def test_del_by_subst_itself
120
+ l = HTree("<r x='y'><x/>y<z/></r>").make_loc
121
+ l2 = l.get_subnode(0, 'x').subst_itself(nil)
122
+ assert_equal(nil, l2.to_node)
123
+ assert_equal(HTree('<r><x/>y<z/></r>'), l2.top.to_node)
124
+ l2 = l.get_subnode(0, 1).subst_itself(nil)
125
+ assert_equal(HTree('<r x="y"><x/><z/></r>'), l2.top.to_node)
126
+ l = HTree('<?xml version="1.0"?><r/>').make_loc
127
+ l2 = l.get_subnode(0).subst_itself(nil)
128
+ assert_equal(HTree('<r/>'), l2.top.to_node)
129
+ end
130
+
131
+ def test_subst
132
+ l = HTree('<?xml version="1.0"?><r><x/><y/><z/></r>').make_loc
133
+ assert_equal(HTree("<r>x<y>a</y><z k=v /></r>"),
134
+ l.to_node.subst({
135
+ l.get_subnode(0) => nil,
136
+ l.get_subnode(1, 0) => 'x',
137
+ l.get_subnode(1, 1, 0) => 'a',
138
+ l.get_subnode(1, 2, 'k') => 'v'
139
+ }))
140
+ end
141
+
142
+ end
@@ -0,0 +1,313 @@
1
+ require 'test/unit'
2
+ require 'htree/template'
3
+ require 'stringio'
4
+
5
+ class TestTemplate < Test::Unit::TestCase
6
+ Decl = '<?xml version="1.0" encoding="US-ASCII"?>'
7
+
8
+ def assert_xhtml(expected, template, message=nil)
9
+ prefix = '<?xml version="1.0" encoding="US-ASCII"?>' +
10
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\"\n>"
11
+ suffix = "</html\n>"
12
+ result = HTree.expand_template(''){"<?xml version=\"1.0\"?><html>#{template}</html>"}
13
+ assert_match(/\A#{Regexp.quote prefix}/, result)
14
+ assert_match(/#{Regexp.quote suffix}\z/, result)
15
+ result = result[prefix.length..(-suffix.length-1)]
16
+ assert_equal(expected, result, message)
17
+ end
18
+
19
+ def test_text
20
+ assert_xhtml("<e\n>1</e\n>", '<e _text=1>d</e>')
21
+ assert_xhtml('1', '<span _text=1>d</span>')
22
+ assert_xhtml("<span x=\"2\"\n>1</span\n>", '<span x=2 _text=1>d</span>')
23
+ assert_xhtml("abc", %q{a<span _text="'b'"/>c})
24
+ end
25
+
26
+ def test_tree
27
+ assert_xhtml("<e\n><z\n>x</z\n></e\n>", '<e _tree="HTree(&quot;<z>x</z>&quot;)">d</e>')
28
+ assert_xhtml("<n:e xmlns:n=\"a\"\n><n:z\n>x</n:z\n></n:e\n>", '<n:e xmlns:n=a _tree="HTree(&quot;<n:z xmlns:n=a>x</n:z>&quot;)">d</n:e>')
29
+ end
30
+
31
+ def test_attr
32
+ assert_xhtml("<e x=\"1\"\n>d</e\n>", '<e _attr_x=1>d</e>')
33
+ assert_xhtml("<span x=\"1\"\n>d</span\n>", '<span _attr_x=1>d</span>')
34
+ assert_xhtml("<span x=\"&quot;\"\n>d</span\n>", '<span _attr_x=\'"\x22"\'>d</span>')
35
+ end
36
+
37
+ def test_if
38
+ assert_xhtml("<e\n>d</e\n>", '<e _if=true>d</e>')
39
+ assert_xhtml('', '<e _if=false>d</e>')
40
+ assert_xhtml("<f\n>dd</f\n>", '<e _if=false _else=m>d</e><f _template=m>dd</f>')
41
+
42
+ assert_xhtml('d', '<span _if=true>d</span>')
43
+ end
44
+
45
+ def test_iter
46
+ assert_xhtml("<o\n><i\n>1</i\n></o\n><o\n><i\n>2</i\n></o\n><o\n><i\n>3</i\n></o\n>",
47
+ '<o _iter=[1,2,3].each//v><i _text=v /></o>')
48
+ assert_xhtml("<i\n>1</i\n><i\n>2</i\n><i\n>3</i\n>",
49
+ '<span _iter=[1,2,3].each//v><i _text=v /></span>')
50
+ end
51
+
52
+ def test_iter_content
53
+ assert_xhtml("<o\n><i\n>1</i\n><i\n>2</i\n><i\n>3</i\n></o\n>",
54
+ '<o _iter_content=[1,2,3].each//v><i _text=v /></o>')
55
+ assert_xhtml("<i\n>1</i\n><i\n>2</i\n><i\n>3</i\n>",
56
+ '<span _iter_content=[1,2,3].each//v><i _text=v /></span>')
57
+ end
58
+
59
+ def test_iter_local_template
60
+ assert_xhtml("<o\n><i\n>1</i\n></o\n><o\n><i\n>2</i\n></o\n><o\n><i\n>3</i\n></o\n>",
61
+ '<o _iter=[1,2,3].each//v><i _call=m /><i _template=m _text=v></i></o>')
62
+ end
63
+
64
+ def test_call
65
+ assert_xhtml("<f\n>1</f\n>",
66
+ '<e _call=m(1) /><f _template=m(v) _text=v></f>')
67
+ end
68
+
69
+ def test_template
70
+ assert_xhtml('d',
71
+ '<span _template="span()">d</span><e _call="span()"></e>')
72
+ end
73
+
74
+ def test_file
75
+ assert_equal(<<'End'.chop,
76
+ <?xml version="1.0" encoding="US-ASCII"?><html xmlns="http://www.w3.org/1999/xhtml"
77
+ ><title
78
+ >aaa</title
79
+ ></html
80
+ >
81
+ End
82
+ HTree.expand_template("#{File.dirname __FILE__}/template.html", "aaa", ''))
83
+ end
84
+
85
+ def test_whitespace
86
+ assert_xhtml("<x\n></x\n>", '<x> </x>')
87
+ assert_xhtml("<x\n>&#32;</x\n>", '<x>&#32;</x>')
88
+ assert_xhtml("<pre\n> </pre\n>", '<pre> </pre>')
89
+ assert_xhtml(" ", %q{<span _text="' '"> </span>})
90
+ assert_xhtml(" ", %q{<span _text="' '"/>})
91
+ end
92
+
93
+ def test_ignorable
94
+ assert_xhtml("<div\n>a</div\n>", '<div>a</div>')
95
+ assert_xhtml("<span\n>a</span\n>", '<span>a</span>')
96
+ assert_xhtml("1", '<span _text="1">a</span>')
97
+ end
98
+
99
+ def test_not_ignorable
100
+ assert_xhtml("<p\n>1</p\n>", '<p _text="\'1\'">a</p>')
101
+ end
102
+
103
+ def test_template_in_attr
104
+ assert_xhtml("<a x=\"1\"\n></a\n>", '<a _attr_x=1><b _template=m></b></a>')
105
+ end
106
+
107
+ def test_empty_block_argument
108
+ assert_xhtml("vv", '<span _iter="2.times//">v</span>')
109
+ end
110
+
111
+ def test_empty_element
112
+ assert_xhtml("<elem\n/>", '<elem />') # 2004-06-10: reported by Takuo KITAME
113
+ assert_xhtml("<elem x=\"1\"\n/>", '<elem _attr_x=1 />')
114
+ assert_xhtml("<elem\n></elem\n>", '<elem _text=\'""\' />')
115
+ assert_xhtml("<elem\n/>", '<elem _if="true" />')
116
+ assert_xhtml("", '<elem _if="false" />')
117
+ assert_xhtml("<foo\n/>", '<elem _if="false" _else="foo"/><foo _template="foo"/>')
118
+ assert_xhtml("<elem\n/><elem\n/>", '<elem _iter="2.times//" />')
119
+ assert_xhtml("<elem\n></elem\n>", '<elem _iter_content="2.times//" />')
120
+ end
121
+
122
+ def test_empty_element_start_end_tag
123
+ assert_xhtml("<elem\n></elem\n>", '<elem></elem>')
124
+ assert_xhtml("<elem x=\"1\"\n></elem\n>", '<elem _attr_x=1 ></elem>')
125
+ assert_xhtml("<elem\n></elem\n>", '<elem _text=\'""\' ></elem>')
126
+ assert_xhtml("<elem\n></elem\n>", '<elem _if="true" ></elem>')
127
+ assert_xhtml("", '<elem _if="false" ></elem>')
128
+ assert_xhtml("<foo\n></foo\n>", '<elem _if="false" _else="foo"></elem><foo _template="foo"></foo>')
129
+ assert_xhtml("<elem\n></elem\n><elem\n></elem\n>", '<elem _iter="2.times//" ></elem>')
130
+ assert_xhtml("<elem\n></elem\n>", '<elem _iter_content="2.times//" ></elem>')
131
+ end
132
+
133
+ def test_toplevel_local_variable
134
+ eval("htree_test_toplevel_local_variable = :non_modified_value", TOPLEVEL_BINDING)
135
+ HTree.expand_template("#{File.dirname __FILE__}/assign.html", "aaa", '')
136
+ assert_equal(:non_modified_value, eval("htree_test_toplevel_local_variable", TOPLEVEL_BINDING))
137
+ eval("htree_test_toplevel_local_variable = 1", TOPLEVEL_BINDING)
138
+ end
139
+
140
+ def test_extend_compiled_template
141
+ m = HTree.compile_template('<div _template="m">self is <span _text="inspect"></span></div>')
142
+ o = "zzz"
143
+ o.extend m
144
+ assert_equal('<?xml version="1.0" encoding="US-ASCII"?>self is "zzz"',
145
+ HTree.expand_template(''){'<div _call="o.m"></div>'})
146
+ end
147
+
148
+ def test_attr_nbsp
149
+ @t = HTree::Text.parse_pcdata('&nbsp;')
150
+ assert_xhtml("<span x=\"&nbsp;\"\n>d</span\n>", '<span _attr_x="@t">d</span>')
151
+ end
152
+
153
+ def test_text_nbsp
154
+ @t = HTree::Text.parse_pcdata('&nbsp;')
155
+ assert_xhtml("&nbsp;", '<span _text="@t">d</span>')
156
+ end
157
+
158
+ def test_content_text
159
+ assert_xhtml("<e\n>ab</e\n>", '<e _text>"a"+"b"</e>')
160
+ assert_xhtml("<e\n>2</e\n>", '<e _text>1+1</e>')
161
+ end
162
+
163
+ end
164
+
165
+ class MemFile
166
+ def initialize(str)
167
+ @str = str
168
+ end
169
+
170
+ def read
171
+ @str
172
+ end
173
+ end
174
+
175
+ class TestTemplateScopeObj
176
+ Const = 'good_const'
177
+ @@cvar = 'good_cvar'
178
+ def initialize
179
+ @ivar = 'good_ivar'
180
+ end
181
+ end
182
+
183
+ class TestTemplateScope < Test::Unit::TestCase
184
+ Const = 'bad_const'
185
+ @@cvar = 'bad_cvar'
186
+ def setup
187
+ @ivar = 'bad_ivar'
188
+ eval("test_local_variable = 'bad_lvar'", TOPLEVEL_BINDING)
189
+ end
190
+
191
+ XMLDeclStr = '<?xml version="1.0" encoding="US-ASCII"?>'
192
+
193
+ def test_expand_template
194
+ obj = TestTemplateScopeObj.new
195
+ assert_equal("#{XMLDeclStr}[TestTemplateScopeObj]",
196
+ HTree.expand_template(MemFile.new('<span _text="Module.nesting.inspect"/>'), obj, ''))
197
+ assert_equal("#{XMLDeclStr}good_ivar",
198
+ HTree.expand_template(MemFile.new('<span _text="@ivar"/>'), obj, ''))
199
+ assert_equal("#{XMLDeclStr}good_cvar",
200
+ HTree.expand_template(MemFile.new('<span _text="@@cvar"/>'), obj, ''))
201
+ assert_equal("#{XMLDeclStr}good_const",
202
+ HTree.expand_template(MemFile.new('<span _text="Const"/>'), obj, ''))
203
+ test_local_variable = 'bad_lvar'
204
+ assert_equal("#{XMLDeclStr}good_lvar",
205
+ HTree.expand_template(MemFile.new('<span _text="begin test_local_variable rescue NameError; \'good_lvar\' end"/>'), obj, ''))
206
+ end
207
+
208
+ def test_compile_template
209
+ obj = TestTemplateScopeObj.new
210
+ mod = HTree.compile_template(MemFile.new(<<-'End'))
211
+ <span _template=test_nesting _text="Module.nesting.inspect"/>
212
+ <span _template=test_const _text="Const"/>
213
+ <span _template=test_cvar _text="@@cvar"/>
214
+ <span _template=test_ivar _text="@ivar"/>
215
+ End
216
+ mod.module_eval <<-'End'
217
+ Const = 'mod_const'
218
+ @@cvar = 'mod_cvar'
219
+ @ivar = 'mod_ivar'
220
+ End
221
+ assert_equal("[#{mod.inspect}]", mod.test_nesting.extract_text.to_s)
222
+ assert_equal("mod_const", mod.test_const.extract_text.to_s)
223
+ assert_equal("mod_cvar", mod.test_cvar.extract_text.to_s)
224
+ assert_equal("mod_ivar", mod.test_ivar.extract_text.to_s)
225
+ obj = Object.new
226
+ obj.instance_variable_set :@ivar, 'obj_ivar'
227
+ obj.extend mod
228
+ assert_equal("[#{mod.inspect}]", obj.__send__(:test_nesting).extract_text.to_s)
229
+ assert_equal("mod_const", obj.__send__(:test_const).extract_text.to_s)
230
+ assert_equal("mod_cvar", obj.__send__(:test_cvar).extract_text.to_s)
231
+ assert_equal("obj_ivar", obj.__send__(:test_ivar).extract_text.to_s)
232
+ end
233
+ end
234
+
235
+ class TestCDATA < Test::Unit::TestCase
236
+ def test_html_script
237
+ v = "x<y"
238
+ assert_equal("<html><script>x<y</script></html>",
239
+ HTree.expand_template('') {"<html><script _text=\"v\">ab</script>"}.gsub(/\n/, ''))
240
+ end
241
+
242
+ def test_xml_script
243
+ v = "x<y"
244
+ assert_equal("<?xml version=\"1.0\" encoding=\"US-ASCII\"?><html xmlns=\"http://www.w3.org/1999/xhtml\"><script>x&lt;y</script></html>",
245
+ HTree.expand_template('') {"<?xml version=\"1.0\"?><html><script _text=\"v\">ab</script>"}.gsub(/\n/, ''))
246
+ end
247
+
248
+ def test_html_script_invalid_content
249
+ v = "x</y"
250
+ assert_raise(ArgumentError) {
251
+ HTree.expand_template('') {"<html><script _text=\"v\">ab</script>"}
252
+ }
253
+ end
254
+
255
+ def test_stylexxx
256
+ v = "x<y"
257
+ assert_equal("<html><stylexxx>x&lt;y</stylexxx></html>",
258
+ HTree.expand_template('') {"<html><stylexxx _text=\"v\">ab</stylexxx>"}.gsub(/\n/, ''))
259
+ end
260
+
261
+ end
262
+
263
+ class TestCharset2 < Test::Unit::TestCase
264
+ class CharsetString < String
265
+ attr_accessor :charset
266
+ end
267
+
268
+ def with_kcode(kcode)
269
+ if "".respond_to? :force_encoding
270
+ if HTree::Encoder.internal_charset.start_with?(kcode.upcase)
271
+ yield
272
+ end
273
+ else
274
+ old = $KCODE
275
+ begin
276
+ $KCODE = kcode
277
+ yield
278
+ ensure
279
+ $KCODE = old
280
+ end
281
+ end
282
+ end
283
+
284
+ def test_us_ascii
285
+ with_kcode('E') {
286
+ out = HTree.expand_template(CharsetString.new) { "<html>abc" }
287
+ assert_equal(out.charset, 'US-ASCII')
288
+ }
289
+ end
290
+
291
+ def test_euc_jp
292
+ with_kcode('E') {
293
+ out = HTree.expand_template(CharsetString.new) { "<html>\xa1\xa1" }
294
+ assert_equal(out.charset, 'EUC-JP')
295
+ }
296
+ end
297
+
298
+ def test_utf_8
299
+ with_kcode('U') {
300
+ out = HTree.expand_template(CharsetString.new) { "<html>\xc2\xa1" }
301
+ assert_equal(out.charset, 'UTF-8')
302
+ }
303
+ end
304
+
305
+ end
306
+
307
+ class TestTemplateDOCTYPE < Test::Unit::TestCase
308
+ def test_html
309
+ assert_equal(
310
+ '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html></html>',
311
+ HTree.expand_template('') {'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"><html>'}.gsub(/\n/, ''))
312
+ end
313
+ end