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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/lib/better_html.rb +53 -0
  5. data/lib/better_html/better_erb.rb +68 -0
  6. data/lib/better_html/better_erb/erubi_implementation.rb +50 -0
  7. data/lib/better_html/better_erb/erubis_implementation.rb +44 -0
  8. data/lib/better_html/better_erb/runtime_checks.rb +161 -0
  9. data/lib/better_html/better_erb/validated_output_buffer.rb +166 -0
  10. data/lib/better_html/errors.rb +22 -0
  11. data/lib/better_html/helpers.rb +5 -0
  12. data/lib/better_html/html_attributes.rb +26 -0
  13. data/lib/better_html/node_iterator.rb +144 -0
  14. data/lib/better_html/node_iterator/attribute.rb +34 -0
  15. data/lib/better_html/node_iterator/base.rb +27 -0
  16. data/lib/better_html/node_iterator/cdata.rb +8 -0
  17. data/lib/better_html/node_iterator/comment.rb +8 -0
  18. data/lib/better_html/node_iterator/content_node.rb +13 -0
  19. data/lib/better_html/node_iterator/element.rb +26 -0
  20. data/lib/better_html/node_iterator/html_erb.rb +78 -0
  21. data/lib/better_html/node_iterator/html_lodash.rb +101 -0
  22. data/lib/better_html/node_iterator/javascript_erb.rb +60 -0
  23. data/lib/better_html/node_iterator/location.rb +14 -0
  24. data/lib/better_html/node_iterator/text.rb +8 -0
  25. data/lib/better_html/node_iterator/token.rb +8 -0
  26. data/lib/better_html/railtie.rb +7 -0
  27. data/lib/better_html/test_helper/ruby_expr.rb +89 -0
  28. data/lib/better_html/test_helper/safe_erb_tester.rb +202 -0
  29. data/lib/better_html/test_helper/safe_lodash_tester.rb +121 -0
  30. data/lib/better_html/test_helper/safety_tester_base.rb +34 -0
  31. data/lib/better_html/tree.rb +113 -0
  32. data/lib/better_html/version.rb +3 -0
  33. data/lib/tasks/better_html_tasks.rake +4 -0
  34. data/test/better_html/better_erb/implementation_test.rb +402 -0
  35. data/test/better_html/helpers_test.rb +49 -0
  36. data/test/better_html/node_iterator/html_lodash_test.rb +132 -0
  37. data/test/better_html/node_iterator_test.rb +221 -0
  38. data/test/better_html/test_helper/ruby_expr_test.rb +206 -0
  39. data/test/better_html/test_helper/safe_erb_tester_test.rb +358 -0
  40. data/test/better_html/test_helper/safe_lodash_tester_test.rb +80 -0
  41. data/test/better_html/tree_test.rb +110 -0
  42. data/test/dummy/README.rdoc +28 -0
  43. data/test/dummy/Rakefile +6 -0
  44. data/test/dummy/app/assets/javascripts/application.js +13 -0
  45. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  46. data/test/dummy/app/controllers/application_controller.rb +5 -0
  47. data/test/dummy/app/helpers/application_helper.rb +2 -0
  48. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  49. data/test/dummy/bin/bundle +3 -0
  50. data/test/dummy/bin/rails +4 -0
  51. data/test/dummy/bin/rake +4 -0
  52. data/test/dummy/bin/setup +29 -0
  53. data/test/dummy/config.ru +4 -0
  54. data/test/dummy/config/application.rb +26 -0
  55. data/test/dummy/config/boot.rb +5 -0
  56. data/test/dummy/config/database.yml +25 -0
  57. data/test/dummy/config/environment.rb +5 -0
  58. data/test/dummy/config/environments/development.rb +41 -0
  59. data/test/dummy/config/environments/production.rb +79 -0
  60. data/test/dummy/config/environments/test.rb +42 -0
  61. data/test/dummy/config/initializers/assets.rb +11 -0
  62. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  63. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  64. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  65. data/test/dummy/config/initializers/inflections.rb +16 -0
  66. data/test/dummy/config/initializers/mime_types.rb +4 -0
  67. data/test/dummy/config/initializers/session_store.rb +3 -0
  68. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  69. data/test/dummy/config/locales/en.yml +23 -0
  70. data/test/dummy/config/routes.rb +56 -0
  71. data/test/dummy/config/secrets.yml +22 -0
  72. data/test/dummy/public/404.html +67 -0
  73. data/test/dummy/public/422.html +67 -0
  74. data/test/dummy/public/500.html +66 -0
  75. data/test/dummy/public/favicon.ico +0 -0
  76. data/test/test_helper.rb +19 -0
  77. 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 &quot;&gt; 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 &quot;&gt; 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=\"&lt;&quot;&gt;\">")
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=\"&lt;<%= &gt; %>&gt;\">")
175
+
176
+ element = tree.nodes.first
177
+ assert_equal 1, element.attributes.size
178
+ attribute = element['foo']
179
+ assert_equal '<<%= &gt; %>>', 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