better_html 0.0.3
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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +30 -0
- data/lib/better_html.rb +53 -0
- data/lib/better_html/better_erb.rb +68 -0
- data/lib/better_html/better_erb/erubi_implementation.rb +50 -0
- data/lib/better_html/better_erb/erubis_implementation.rb +44 -0
- data/lib/better_html/better_erb/runtime_checks.rb +161 -0
- data/lib/better_html/better_erb/validated_output_buffer.rb +166 -0
- data/lib/better_html/errors.rb +22 -0
- data/lib/better_html/helpers.rb +5 -0
- data/lib/better_html/html_attributes.rb +26 -0
- data/lib/better_html/node_iterator.rb +144 -0
- data/lib/better_html/node_iterator/attribute.rb +34 -0
- data/lib/better_html/node_iterator/base.rb +27 -0
- data/lib/better_html/node_iterator/cdata.rb +8 -0
- data/lib/better_html/node_iterator/comment.rb +8 -0
- data/lib/better_html/node_iterator/content_node.rb +13 -0
- data/lib/better_html/node_iterator/element.rb +26 -0
- data/lib/better_html/node_iterator/html_erb.rb +78 -0
- data/lib/better_html/node_iterator/html_lodash.rb +101 -0
- data/lib/better_html/node_iterator/javascript_erb.rb +60 -0
- data/lib/better_html/node_iterator/location.rb +14 -0
- data/lib/better_html/node_iterator/text.rb +8 -0
- data/lib/better_html/node_iterator/token.rb +8 -0
- data/lib/better_html/railtie.rb +7 -0
- data/lib/better_html/test_helper/ruby_expr.rb +89 -0
- data/lib/better_html/test_helper/safe_erb_tester.rb +202 -0
- data/lib/better_html/test_helper/safe_lodash_tester.rb +121 -0
- data/lib/better_html/test_helper/safety_tester_base.rb +34 -0
- data/lib/better_html/tree.rb +113 -0
- data/lib/better_html/version.rb +3 -0
- data/lib/tasks/better_html_tasks.rake +4 -0
- data/test/better_html/better_erb/implementation_test.rb +402 -0
- data/test/better_html/helpers_test.rb +49 -0
- data/test/better_html/node_iterator/html_lodash_test.rb +132 -0
- data/test/better_html/node_iterator_test.rb +221 -0
- data/test/better_html/test_helper/ruby_expr_test.rb +206 -0
- data/test/better_html/test_helper/safe_erb_tester_test.rb +358 -0
- data/test/better_html/test_helper/safe_lodash_tester_test.rb +80 -0
- data/test/better_html/tree_test.rb +110 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +56 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/test_helper.rb +19 -0
- metadata +205 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class BetterHtml::HelpersTest < ActiveSupport::TestCase
|
4
|
+
include BetterHtml::Helpers
|
5
|
+
|
6
|
+
test "html_attributes return a HtmlAttributes object" do
|
7
|
+
assert_equal BetterHtml::HtmlAttributes, html_attributes(foo: "bar").class
|
8
|
+
end
|
9
|
+
|
10
|
+
test "html_attributes are formatted as string" do
|
11
|
+
assert_equal 'foo="bar" baz="qux"',
|
12
|
+
html_attributes(foo: "bar", baz: "qux").to_s
|
13
|
+
end
|
14
|
+
|
15
|
+
test "html_attributes keys cannot contain invalid characters" do
|
16
|
+
e = assert_raises(ArgumentError) do
|
17
|
+
html_attributes("invalid key": "bar", baz: "qux").to_s
|
18
|
+
end
|
19
|
+
assert_equal "Attribute names must match the pattern /\\A[a-zA-Z0-9\\-\\:]+\\z/", e.message
|
20
|
+
end
|
21
|
+
|
22
|
+
test "#html_attributes does not accept incorrectly escaped html_safe values" do
|
23
|
+
e = assert_raises(ArgumentError) do
|
24
|
+
html_attributes('something': 'with "> double quote'.html_safe).to_s
|
25
|
+
end
|
26
|
+
assert_equal "The value provided for attribute 'something' contains a `\"` character which is not allowed. "\
|
27
|
+
"Did you call .html_safe without properly escaping this data?", e.message
|
28
|
+
end
|
29
|
+
|
30
|
+
test "#html_attributes accepts correctly escaped html_safe values" do
|
31
|
+
assert_equal 'something="with "> double quote"',
|
32
|
+
html_attributes('something': CGI.escapeHTML('with "> double quote').html_safe).to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
test "#html_attributes escapes non-html_safe values" do
|
36
|
+
assert_equal 'something="with "> double quote"',
|
37
|
+
html_attributes('something': 'with "> double quote').to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
test "#html_attributes accepts nil values as value-less attributes" do
|
41
|
+
assert_equal 'data-thing data-other-thing',
|
42
|
+
html_attributes('data-thing': nil, 'data-other-thing': nil).to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
test "#html_attributes empty string value is output" do
|
46
|
+
assert_equal 'data-thing="" data-other-thing=""',
|
47
|
+
html_attributes('data-thing': "", 'data-other-thing': "").to_s
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module BetterHtml
|
4
|
+
class NodeIterator
|
5
|
+
class HtmlLodashTest < ActiveSupport::TestCase
|
6
|
+
test "matches text" do
|
7
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("just some text")
|
8
|
+
assert_equal 1, scanner.tokens.size
|
9
|
+
token = scanner.tokens[0]
|
10
|
+
assert_equal :text, token.type
|
11
|
+
assert_equal "just some text", token.text
|
12
|
+
assert_nil token.code
|
13
|
+
assert_equal 0, token.location.start
|
14
|
+
assert_equal 14, token.location.stop
|
15
|
+
assert_equal 1, token.location.line
|
16
|
+
assert_equal 0, token.location.column
|
17
|
+
end
|
18
|
+
|
19
|
+
test "matches strings to be escaped" do
|
20
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("[%= foo %]")
|
21
|
+
assert_equal 1, scanner.tokens.size
|
22
|
+
token = scanner.tokens[0]
|
23
|
+
assert_equal :expr_literal, token.type
|
24
|
+
assert_equal "[%= foo %]", token.text
|
25
|
+
assert_equal " foo ", token.code
|
26
|
+
assert_equal 0, token.location.start
|
27
|
+
assert_equal 10, token.location.stop
|
28
|
+
assert_equal 1, token.location.line
|
29
|
+
assert_equal 0, token.location.column
|
30
|
+
end
|
31
|
+
|
32
|
+
test "matches interpolate" do
|
33
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("[%! foo %]")
|
34
|
+
assert_equal 1, scanner.tokens.size
|
35
|
+
token = scanner.tokens[0]
|
36
|
+
assert_equal :expr_escaped, token.type
|
37
|
+
assert_equal "[%! foo %]", token.text
|
38
|
+
assert_equal " foo ", token.code
|
39
|
+
assert_equal 0, token.location.start
|
40
|
+
assert_equal 10, token.location.stop
|
41
|
+
assert_equal 1, token.location.line
|
42
|
+
assert_equal 0, token.location.column
|
43
|
+
end
|
44
|
+
|
45
|
+
test "matches statement" do
|
46
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("[% foo %]")
|
47
|
+
assert_equal 1, scanner.tokens.size
|
48
|
+
token = scanner.tokens[0]
|
49
|
+
assert_equal :stmt, token.type
|
50
|
+
assert_equal "[% foo %]", token.text
|
51
|
+
assert_equal " foo ", token.code
|
52
|
+
assert_equal 0, token.location.start
|
53
|
+
assert_equal 9, token.location.stop
|
54
|
+
assert_equal 1, token.location.line
|
55
|
+
assert_equal 0, token.location.column
|
56
|
+
end
|
57
|
+
|
58
|
+
test "matches text before and after" do
|
59
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("before\n[%= foo %]\nafter")
|
60
|
+
assert_equal 3, scanner.tokens.size
|
61
|
+
|
62
|
+
token = scanner.tokens[0]
|
63
|
+
assert_equal :text, token.type
|
64
|
+
assert_equal "before\n", token.text
|
65
|
+
assert_nil token.code
|
66
|
+
assert_equal 0, token.location.start
|
67
|
+
assert_equal 7, token.location.stop
|
68
|
+
assert_equal 1, token.location.line
|
69
|
+
assert_equal 0, token.location.column
|
70
|
+
|
71
|
+
token = scanner.tokens[1]
|
72
|
+
assert_equal :expr_literal, token.type
|
73
|
+
assert_equal "[%= foo %]", token.text
|
74
|
+
assert_equal " foo ", token.code
|
75
|
+
assert_equal 7, token.location.start
|
76
|
+
assert_equal 17, token.location.stop
|
77
|
+
assert_equal 2, token.location.line
|
78
|
+
assert_equal 0, token.location.column
|
79
|
+
|
80
|
+
token = scanner.tokens[2]
|
81
|
+
assert_equal :text, token.type
|
82
|
+
assert_equal "\nafter", token.text
|
83
|
+
assert_nil token.code
|
84
|
+
assert_equal 17, token.location.start
|
85
|
+
assert_equal 23, token.location.stop
|
86
|
+
assert_equal 2, token.location.line
|
87
|
+
assert_equal 10, token.location.column
|
88
|
+
end
|
89
|
+
|
90
|
+
test "matches multiple" do
|
91
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new("[% if() { %][%= foo %][% } %]")
|
92
|
+
assert_equal 3, scanner.tokens.size
|
93
|
+
|
94
|
+
token = scanner.tokens[0]
|
95
|
+
assert_equal :stmt, token.type
|
96
|
+
assert_equal "[% if() { %]", token.text
|
97
|
+
assert_equal " if() { ", token.code
|
98
|
+
assert_equal 0, token.location.start
|
99
|
+
assert_equal 12, token.location.stop
|
100
|
+
assert_equal 1, token.location.line
|
101
|
+
assert_equal 0, token.location.column
|
102
|
+
|
103
|
+
token = scanner.tokens[1]
|
104
|
+
assert_equal :expr_literal, token.type
|
105
|
+
assert_equal "[%= foo %]", token.text
|
106
|
+
assert_equal " foo ", token.code
|
107
|
+
assert_equal 12, token.location.start
|
108
|
+
assert_equal 22, token.location.stop
|
109
|
+
assert_equal 1, token.location.line
|
110
|
+
assert_equal 12, token.location.column
|
111
|
+
|
112
|
+
token = scanner.tokens[2]
|
113
|
+
assert_equal :stmt, token.type
|
114
|
+
assert_equal "[% } %]", token.text
|
115
|
+
assert_equal " } ", token.code
|
116
|
+
assert_equal 22, token.location.start
|
117
|
+
assert_equal 29, token.location.stop
|
118
|
+
assert_equal 1, token.location.line
|
119
|
+
assert_equal 22, token.location.column
|
120
|
+
end
|
121
|
+
|
122
|
+
test "parses out html correctly" do
|
123
|
+
scanner = BetterHtml::NodeIterator::HtmlLodash.new('<div class="[%= foo %]">')
|
124
|
+
assert_equal 9, scanner.tokens.size
|
125
|
+
assert_equal [:tag_start, :tag_name, :whitespace, :attribute_name,
|
126
|
+
:equal, :attribute_quoted_value_start, :expr_literal,
|
127
|
+
:attribute_quoted_value_end, :tag_end], scanner.tokens.map(&:type)
|
128
|
+
assert_equal ["<", "div", " ", "class", "=", "\"", "[%= foo %]", "\"", ">"], scanner.tokens.map(&:text)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module BetterHtml
|
4
|
+
class NodeIteratorTest < ActiveSupport::TestCase
|
5
|
+
test "consume cdata nodes" do
|
6
|
+
tree = BetterHtml::NodeIterator.new("<![CDATA[ foo ]]>")
|
7
|
+
|
8
|
+
assert_equal 1, tree.nodes.size
|
9
|
+
assert_equal BetterHtml::NodeIterator::CData, tree.nodes.first.class
|
10
|
+
assert_equal [" foo "], tree.nodes.first.content_parts.map(&:text)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "unterminated cdata nodes are consumed until end" do
|
14
|
+
tree = BetterHtml::NodeIterator.new("<![CDATA[ foo")
|
15
|
+
|
16
|
+
assert_equal 1, tree.nodes.size
|
17
|
+
assert_equal BetterHtml::NodeIterator::CData, tree.nodes.first.class
|
18
|
+
assert_equal [" foo"], tree.nodes.first.content_parts.map(&:text)
|
19
|
+
end
|
20
|
+
|
21
|
+
test "consume cdata with interpolation" do
|
22
|
+
tree = BetterHtml::NodeIterator.new("<![CDATA[ foo <%= bar %> baz ]]>")
|
23
|
+
|
24
|
+
assert_equal 1, tree.nodes.size
|
25
|
+
assert_equal BetterHtml::NodeIterator::CData, tree.nodes.first.class
|
26
|
+
assert_equal [" foo ", "<%= bar %>", " baz "], tree.nodes.first.content_parts.map(&:text)
|
27
|
+
end
|
28
|
+
|
29
|
+
test "consume comment nodes" do
|
30
|
+
tree = BetterHtml::NodeIterator.new("<!-- foo -->")
|
31
|
+
|
32
|
+
assert_equal 1, tree.nodes.size
|
33
|
+
assert_equal BetterHtml::NodeIterator::Comment, tree.nodes.first.class
|
34
|
+
assert_equal [" foo "], tree.nodes.first.content_parts.map(&:text)
|
35
|
+
end
|
36
|
+
|
37
|
+
test "unterminated comment nodes are consumed until end" do
|
38
|
+
tree = BetterHtml::NodeIterator.new("<!-- foo")
|
39
|
+
|
40
|
+
assert_equal 1, tree.nodes.size
|
41
|
+
assert_equal BetterHtml::NodeIterator::Comment, tree.nodes.first.class
|
42
|
+
assert_equal [" foo"], tree.nodes.first.content_parts.map(&:text)
|
43
|
+
end
|
44
|
+
|
45
|
+
test "consume comment with interpolation" do
|
46
|
+
tree = BetterHtml::NodeIterator.new("<!-- foo <%= bar %> baz -->")
|
47
|
+
|
48
|
+
assert_equal 1, tree.nodes.size
|
49
|
+
assert_equal BetterHtml::NodeIterator::Comment, tree.nodes.first.class
|
50
|
+
assert_equal [" foo ", "<%= bar %>", " baz "], tree.nodes.first.content_parts.map(&:text)
|
51
|
+
end
|
52
|
+
|
53
|
+
test "consume tag nodes" do
|
54
|
+
tree = BetterHtml::NodeIterator.new("<div>")
|
55
|
+
|
56
|
+
assert_equal 1, tree.nodes.size
|
57
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
58
|
+
assert_equal ["div"], tree.nodes.first.name_parts.map(&:text)
|
59
|
+
assert_equal false, tree.nodes.first.self_closing?
|
60
|
+
end
|
61
|
+
|
62
|
+
test "consume tag nodes with solidus" do
|
63
|
+
tree = BetterHtml::NodeIterator.new("</div>")
|
64
|
+
|
65
|
+
assert_equal 1, tree.nodes.size
|
66
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
67
|
+
assert_equal ["div"], tree.nodes.first.name_parts.map(&:text)
|
68
|
+
assert_equal true, tree.nodes.first.closing?
|
69
|
+
end
|
70
|
+
|
71
|
+
test "sets self_closing when appropriate" do
|
72
|
+
tree = BetterHtml::NodeIterator.new("<div/>")
|
73
|
+
|
74
|
+
assert_equal 1, tree.nodes.size
|
75
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
76
|
+
assert_equal ["div"], tree.nodes.first.name_parts.map(&:text)
|
77
|
+
assert_equal true, tree.nodes.first.self_closing?
|
78
|
+
end
|
79
|
+
|
80
|
+
test "consume tag nodes until name ends" do
|
81
|
+
tree = BetterHtml::NodeIterator.new("<div/>")
|
82
|
+
assert_equal 1, tree.nodes.size
|
83
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
84
|
+
assert_equal ["div"], tree.nodes.first.name_parts.map(&:text)
|
85
|
+
|
86
|
+
tree = BetterHtml::NodeIterator.new("<div ")
|
87
|
+
assert_equal 1, tree.nodes.size
|
88
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
89
|
+
assert_equal ["div"], tree.nodes.first.name_parts.map(&:text)
|
90
|
+
end
|
91
|
+
|
92
|
+
test "consume tag nodes with interpolation" do
|
93
|
+
tree = BetterHtml::NodeIterator.new("<ns:<%= name %>-thing>")
|
94
|
+
|
95
|
+
assert_equal 1, tree.nodes.size
|
96
|
+
assert_equal BetterHtml::NodeIterator::Element, tree.nodes.first.class
|
97
|
+
assert_equal ["ns:", "<%= name %>", "-thing"], tree.nodes.first.name_parts.map(&:text)
|
98
|
+
end
|
99
|
+
|
100
|
+
test "consume tag attributes nodes unquoted value" do
|
101
|
+
tree = BetterHtml::NodeIterator.new("<div foo=bar>")
|
102
|
+
|
103
|
+
assert_equal 1, tree.nodes.size
|
104
|
+
tag = tree.nodes.first
|
105
|
+
assert_equal BetterHtml::NodeIterator::Element, tag.class
|
106
|
+
assert_equal 1, tag.attributes.size
|
107
|
+
attribute = tag.attributes.first
|
108
|
+
assert_equal BetterHtml::NodeIterator::Attribute, attribute.class
|
109
|
+
assert_equal ["foo"], attribute.name_parts.map(&:text)
|
110
|
+
assert_equal ["bar"], attribute.value_parts.map(&:text)
|
111
|
+
end
|
112
|
+
|
113
|
+
test "consume attributes without name" do
|
114
|
+
tree = BetterHtml::NodeIterator.new("<div 'thing'>")
|
115
|
+
|
116
|
+
assert_equal 1, tree.nodes.size
|
117
|
+
tag = tree.nodes.first
|
118
|
+
assert_equal BetterHtml::NodeIterator::Element, tag.class
|
119
|
+
assert_equal 1, tag.attributes.size
|
120
|
+
attribute = tag.attributes.first
|
121
|
+
assert_equal BetterHtml::NodeIterator::Attribute, attribute.class
|
122
|
+
assert_predicate attribute.name, :empty?
|
123
|
+
assert_equal ["'", "thing", "'"], attribute.value_parts.map(&:text)
|
124
|
+
end
|
125
|
+
|
126
|
+
test "consume tag attributes nodes quoted value" do
|
127
|
+
tree = BetterHtml::NodeIterator.new("<div foo=\"bar\">")
|
128
|
+
|
129
|
+
assert_equal 1, tree.nodes.size
|
130
|
+
tag = tree.nodes.first
|
131
|
+
assert_equal BetterHtml::NodeIterator::Element, tag.class
|
132
|
+
assert_equal 1, tag.attributes.size
|
133
|
+
attribute = tag.attributes.first
|
134
|
+
assert_equal BetterHtml::NodeIterator::Attribute, attribute.class
|
135
|
+
assert_equal ["foo"], attribute.name_parts.map(&:text)
|
136
|
+
assert_equal ['"', "bar", '"'], attribute.value_parts.map(&:text)
|
137
|
+
end
|
138
|
+
|
139
|
+
test "consume tag attributes nodes interpolation in name and value" do
|
140
|
+
tree = BetterHtml::NodeIterator.new("<div data-<%= foo %>=\"some <%= value %> foo\">")
|
141
|
+
|
142
|
+
assert_equal 1, tree.nodes.size
|
143
|
+
tag = tree.nodes.first
|
144
|
+
assert_equal BetterHtml::NodeIterator::Element, tag.class
|
145
|
+
assert_equal 1, tag.attributes.size
|
146
|
+
attribute = tag.attributes.first
|
147
|
+
assert_equal BetterHtml::NodeIterator::Attribute, attribute.class
|
148
|
+
assert_equal ["data-", "<%= foo %>"], attribute.name_parts.map(&:text)
|
149
|
+
assert_equal ['"', "some ", "<%= value %>", " foo", '"'], attribute.value_parts.map(&:text)
|
150
|
+
end
|
151
|
+
|
152
|
+
test "attributes can be accessed through [] on Element object" do
|
153
|
+
tree = BetterHtml::NodeIterator.new("<div foo=\"bar\">")
|
154
|
+
|
155
|
+
assert_equal 1, tree.nodes.size
|
156
|
+
element = tree.nodes.first
|
157
|
+
assert_equal BetterHtml::NodeIterator::Element, element.class
|
158
|
+
assert_equal 1, element.attributes.size
|
159
|
+
assert_nil element['nonexistent']
|
160
|
+
refute_nil attribute = element['foo']
|
161
|
+
assert_equal BetterHtml::NodeIterator::Attribute, attribute.class
|
162
|
+
end
|
163
|
+
|
164
|
+
test "attribute values can be read unescaped" do
|
165
|
+
tree = BetterHtml::NodeIterator.new("<div foo=\"<">\">")
|
166
|
+
|
167
|
+
element = tree.nodes.first
|
168
|
+
assert_equal 1, element.attributes.size
|
169
|
+
attribute = element['foo']
|
170
|
+
assert_equal '<">', attribute.unescaped_value
|
171
|
+
end
|
172
|
+
|
173
|
+
test "attribute values does not unescape stuff inside erb" do
|
174
|
+
tree = BetterHtml::NodeIterator.new("<div foo=\"<<%= > %>>\">")
|
175
|
+
|
176
|
+
element = tree.nodes.first
|
177
|
+
assert_equal 1, element.attributes.size
|
178
|
+
attribute = element['foo']
|
179
|
+
assert_equal '<<%= > %>>', attribute.unescaped_value
|
180
|
+
end
|
181
|
+
|
182
|
+
test "consume text nodes" do
|
183
|
+
tree = BetterHtml::NodeIterator.new("here is <%= some %> text")
|
184
|
+
|
185
|
+
assert_equal 1, tree.nodes.size
|
186
|
+
assert_equal BetterHtml::NodeIterator::Text, tree.nodes.first.class
|
187
|
+
assert_equal ["here is ", "<%= some %>", " text"], tree.nodes.first.content_parts.map(&:text)
|
188
|
+
end
|
189
|
+
|
190
|
+
test "javascript template parsing works" do
|
191
|
+
tree = BetterHtml::NodeIterator.new("here is <%= some %> text", template_language: :javascript)
|
192
|
+
|
193
|
+
assert_equal 1, tree.nodes.size
|
194
|
+
assert_equal BetterHtml::NodeIterator::Text, tree.nodes.first.class
|
195
|
+
assert_equal ["here is ", "<%= some %>", " text"], tree.nodes.first.content_parts.map(&:text)
|
196
|
+
end
|
197
|
+
|
198
|
+
test "javascript template does not consume html tags" do
|
199
|
+
tree = BetterHtml::NodeIterator.new("<div <%= some %> />", template_language: :javascript)
|
200
|
+
|
201
|
+
assert_equal 1, tree.nodes.size
|
202
|
+
assert_equal BetterHtml::NodeIterator::Text, tree.nodes.first.class
|
203
|
+
assert_equal ["<div ", "<%= some %>", " />"], tree.nodes.first.content_parts.map(&:text)
|
204
|
+
end
|
205
|
+
|
206
|
+
test "lodash template parsing works" do
|
207
|
+
tree = BetterHtml::NodeIterator.new('<div class="[%= foo %]">', template_language: :lodash)
|
208
|
+
|
209
|
+
assert_equal 1, tree.nodes.size
|
210
|
+
node = tree.nodes.first
|
211
|
+
assert_equal BetterHtml::NodeIterator::Element, node.class
|
212
|
+
assert_equal "div", node.name
|
213
|
+
assert_equal 1, node.attributes.size
|
214
|
+
attribute = node.attributes.first
|
215
|
+
assert_equal "class", attribute.name
|
216
|
+
assert_equal [:attribute_quoted_value_start, :expr_literal,
|
217
|
+
:attribute_quoted_value_end], attribute.value_parts.map(&:type)
|
218
|
+
assert_equal ["\"", "[%= foo %]", "\""], attribute.value_parts.map(&:text)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'better_html/test_helper/ruby_expr'
|
3
|
+
|
4
|
+
module BetterHtml
|
5
|
+
module TestHelper
|
6
|
+
class RubyExprTest < ActiveSupport::TestCase
|
7
|
+
test "simple call" do
|
8
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo")
|
9
|
+
assert_equal 1, expr.calls.size
|
10
|
+
assert_nil expr.calls.first.instance
|
11
|
+
assert_equal "foo", expr.calls.first.method
|
12
|
+
assert_nil expr.calls.first.arguments
|
13
|
+
end
|
14
|
+
|
15
|
+
test "instance call" do
|
16
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo.bar")
|
17
|
+
assert_equal 1, expr.calls.size
|
18
|
+
assert_equal [:vcall, [:@ident, "foo", [1, 0]]], expr.calls.first.instance
|
19
|
+
assert_equal "bar", expr.calls.first.method
|
20
|
+
assert_nil expr.calls.first.arguments
|
21
|
+
end
|
22
|
+
|
23
|
+
test "instance call with arguments" do
|
24
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo(x).bar")
|
25
|
+
assert_equal 1, expr.calls.size
|
26
|
+
assert_equal [:method_add_arg, [:fcall, [:@ident, "foo", [1, 0]]], [:arg_paren, [:args_add_block, [[:vcall, [:@ident, "x", [1, 4]]]], false]]], expr.calls.first.instance
|
27
|
+
assert_equal "bar", expr.calls.first.method
|
28
|
+
assert_nil expr.calls.first.arguments
|
29
|
+
end
|
30
|
+
|
31
|
+
test "instance call with parenthesis" do
|
32
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "(foo).bar")
|
33
|
+
assert_equal 1, expr.calls.size
|
34
|
+
assert_equal [:paren, [[:vcall, [:@ident, "foo", [1, 1]]]]], expr.calls.first.instance
|
35
|
+
assert_equal "bar", expr.calls.first.method
|
36
|
+
assert_nil expr.calls.first.arguments
|
37
|
+
end
|
38
|
+
|
39
|
+
test "instance call with parenthesis 2" do
|
40
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "(foo)")
|
41
|
+
assert_equal 1, expr.calls.size
|
42
|
+
assert_nil expr.calls.first.instance
|
43
|
+
assert_equal "foo", expr.calls.first.method
|
44
|
+
assert_nil expr.calls.first.arguments
|
45
|
+
end
|
46
|
+
|
47
|
+
test "command call" do
|
48
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo bar")
|
49
|
+
assert_equal 1, expr.calls.size
|
50
|
+
assert_nil expr.calls.first.instance
|
51
|
+
assert_equal "foo", expr.calls.first.method
|
52
|
+
assert_equal [[:vcall, [:@ident, "bar", [1, 4]]]], expr.calls.first.arguments
|
53
|
+
end
|
54
|
+
|
55
|
+
test "command call with block" do
|
56
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo bar do")
|
57
|
+
assert_equal 1, expr.calls.size
|
58
|
+
assert_nil expr.calls.first.instance
|
59
|
+
assert_equal "foo", expr.calls.first.method
|
60
|
+
assert_equal [[:vcall, [:@ident, "bar", [1, 4]]]], expr.calls.first.arguments
|
61
|
+
end
|
62
|
+
|
63
|
+
test "call with parameters" do
|
64
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo(bar)")
|
65
|
+
assert_equal 1, expr.calls.size
|
66
|
+
assert_nil expr.calls.first.instance
|
67
|
+
assert_equal "foo", expr.calls.first.method
|
68
|
+
assert_equal [[:vcall, [:@ident, "bar", [1, 4]]]], expr.calls.first.arguments
|
69
|
+
end
|
70
|
+
|
71
|
+
test "instance call with parameters" do
|
72
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo.bar(baz, x)")
|
73
|
+
assert_equal 1, expr.calls.size
|
74
|
+
assert_equal [:vcall, [:@ident, "foo", [1, 0]]], expr.calls.first.instance
|
75
|
+
assert_equal "bar", expr.calls.first.method
|
76
|
+
assert_equal [[:vcall, [:@ident, "baz", [1, 8]]], [:vcall, [:@ident, "x", [1, 13]]]], expr.calls.first.arguments
|
77
|
+
end
|
78
|
+
|
79
|
+
test "call with parameters with if conditional modifier" do
|
80
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo(bar) if something?")
|
81
|
+
assert_equal 1, expr.calls.size
|
82
|
+
assert_nil expr.calls.first.instance
|
83
|
+
assert_equal "foo", expr.calls.first.method
|
84
|
+
assert_equal [[:vcall, [:@ident, "bar", [1, 4]]]], expr.calls.first.arguments
|
85
|
+
end
|
86
|
+
|
87
|
+
test "call with parameters with unless conditional modifier" do
|
88
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "foo(bar) unless something?")
|
89
|
+
assert_equal 1, expr.calls.size
|
90
|
+
assert_nil expr.calls.first.instance
|
91
|
+
assert_equal "foo", expr.calls.first.method
|
92
|
+
assert_equal [[:vcall, [:@ident, "bar", [1, 4]]]], expr.calls.first.arguments
|
93
|
+
end
|
94
|
+
|
95
|
+
test "expression call in ternary" do
|
96
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "something? ? foo : bar")
|
97
|
+
assert_equal 2, expr.calls.size
|
98
|
+
|
99
|
+
assert_nil expr.calls.first.instance
|
100
|
+
assert_equal "foo", expr.calls.first.method
|
101
|
+
assert_nil expr.calls.first.arguments
|
102
|
+
|
103
|
+
assert_nil expr.calls.last.instance
|
104
|
+
assert_equal "bar", expr.calls.last.method
|
105
|
+
assert_nil expr.calls.last.arguments
|
106
|
+
end
|
107
|
+
|
108
|
+
test "expression call with args in ternary" do
|
109
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: "something? ? foo(x) : bar(x)")
|
110
|
+
assert_equal 2, expr.calls.size
|
111
|
+
|
112
|
+
assert_nil expr.calls.first.instance
|
113
|
+
assert_equal "foo", expr.calls.first.method
|
114
|
+
assert_equal [[:vcall, [:@ident, "x", [1, 17]]]], expr.calls.first.arguments
|
115
|
+
|
116
|
+
assert_nil expr.calls.last.instance
|
117
|
+
assert_equal "bar", expr.calls.last.method
|
118
|
+
assert_equal [[:vcall, [:@ident, "x", [1, 26]]]], expr.calls.last.arguments
|
119
|
+
end
|
120
|
+
|
121
|
+
test "string without interpolation" do
|
122
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '"foo"')
|
123
|
+
assert_equal 0, expr.calls.size
|
124
|
+
end
|
125
|
+
|
126
|
+
test "string with interpolation" do
|
127
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '"foo #{bar}"')
|
128
|
+
assert_equal 1, expr.calls.size
|
129
|
+
assert_nil expr.calls.first.instance
|
130
|
+
assert_equal "bar", expr.calls.first.method
|
131
|
+
assert_nil expr.calls.first.arguments
|
132
|
+
end
|
133
|
+
|
134
|
+
test "ternary in string with interpolation" do
|
135
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '"foo #{foo? ? bar : baz}"')
|
136
|
+
assert_equal 2, expr.calls.size
|
137
|
+
|
138
|
+
assert_nil expr.calls.first.instance
|
139
|
+
assert_equal "bar", expr.calls.first.method
|
140
|
+
assert_nil expr.calls.first.arguments
|
141
|
+
|
142
|
+
assert_nil expr.calls.last.instance
|
143
|
+
assert_equal "baz", expr.calls.last.method
|
144
|
+
assert_nil expr.calls.last.arguments
|
145
|
+
end
|
146
|
+
|
147
|
+
test "assignment to variable" do
|
148
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: 'x = foo.bar')
|
149
|
+
assert_equal 1, expr.calls.size
|
150
|
+
assert_equal [:vcall, [:@ident, "foo", [1, 4]]], expr.calls.first.instance
|
151
|
+
assert_equal "bar", expr.calls.first.method
|
152
|
+
assert_nil expr.calls.first.arguments
|
153
|
+
end
|
154
|
+
|
155
|
+
test "assignment to variable with command call" do
|
156
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: 'raw x = foo.bar')
|
157
|
+
assert_equal 1, expr.calls.size
|
158
|
+
assert_nil expr.calls.first.instance
|
159
|
+
assert_equal "raw", expr.calls.first.method
|
160
|
+
assert_equal [[:assign, [:var_field, [:@ident, "x", [1, 4]]], [:call, [:vcall, [:@ident, "foo", [1, 8]]], :".", [:@ident, "bar", [1, 12]]]]], expr.calls.first.arguments
|
161
|
+
end
|
162
|
+
|
163
|
+
test "assignment with instance call" do
|
164
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '(x = foo).bar')
|
165
|
+
assert_equal 1, expr.calls.size
|
166
|
+
assert_equal [:paren, [[:assign, [:var_field, [:@ident, "x", [1, 1]]], [:vcall, [:@ident, "foo", [1, 5]]]]]], expr.calls.first.instance
|
167
|
+
assert_equal "bar", expr.calls.first.method
|
168
|
+
assert_nil expr.calls.first.arguments
|
169
|
+
end
|
170
|
+
|
171
|
+
test "assignment to multiple variables" do
|
172
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: 'x, y = foo.bar')
|
173
|
+
assert_equal 1, expr.calls.size
|
174
|
+
assert_equal [:vcall, [:@ident, "foo", [1, 7]]], expr.calls.first.instance
|
175
|
+
assert_equal "bar", expr.calls.first.method
|
176
|
+
assert_nil expr.calls.first.arguments
|
177
|
+
end
|
178
|
+
|
179
|
+
test "safe navigation operator" do
|
180
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: 'foo&.bar')
|
181
|
+
assert_equal 1, expr.calls.size
|
182
|
+
assert_equal [:vcall, [:@ident, "foo", [1, 0]]], expr.calls.first.instance
|
183
|
+
assert_equal "bar", expr.calls.first.method
|
184
|
+
assert_nil expr.calls.first.arguments
|
185
|
+
end
|
186
|
+
|
187
|
+
test "instance variable" do
|
188
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '@foo')
|
189
|
+
assert_equal 0, expr.calls.size
|
190
|
+
end
|
191
|
+
|
192
|
+
test "instance method on variable" do
|
193
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: '@foo.bar')
|
194
|
+
assert_equal 1, expr.calls.size
|
195
|
+
assert_equal [:var_ref, [:@ivar, "@foo", [1, 0]]], expr.calls.first.instance
|
196
|
+
assert_equal "bar", expr.calls.first.method
|
197
|
+
assert_nil expr.calls.first.arguments
|
198
|
+
end
|
199
|
+
|
200
|
+
test "index into array" do
|
201
|
+
expr = BetterHtml::TestHelper::RubyExpr.new(code: 'local_assigns[:text_class] if local_assigns[:text_class]')
|
202
|
+
assert_equal 0, expr.calls.size
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|