better_html 0.0.9 → 0.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17ea4709e995bab97c314fd892b1926582788ab4
4
- data.tar.gz: 497c12a9e1e060b4564d2310695fe06d54e3af86
3
+ metadata.gz: b6246bfb4cf4ae99f87a12370d99b362b9b2737b
4
+ data.tar.gz: 67a8747a32552d237bacafe3cc782dc7b1815ffc
5
5
  SHA512:
6
- metadata.gz: 6cb55f55293eb9875635480ada4148fd3afb4a148284e24998c5cfa0a0648598f5659a8dccc41ea2329aa630f194fa8fe7d7f08bebea732310e8aebc7f80f5ff
7
- data.tar.gz: 8786bbc8fe5a6df5da740715413f6ef05e9b05302f4b9cf1fe5672f4eb98ef931519155e3f219b6b3dc53c5fd1142d626e7b8c5c6f008ca655f7e9eab8daba2c
6
+ metadata.gz: 07c548e1027d5f582ee796df6b536bd6f895edcd42c3c2898d0eb1da61c9adffaff6683bf83cbfee3e59d0f2acb2ed70c3371606cb772b39b3a8c4df30a75d8a
7
+ data.tar.gz: d5168282725b6e5ba210eae30eefcfa88b8270063422f0127be7f53cc888dfa1470c9a82db09971d2b9ec540024a28f57337cf9d4e092afb5aa86c092f9aef0a
data/lib/better_html.rb CHANGED
@@ -3,49 +3,21 @@ require 'active_support/core_ext/module/delegation'
3
3
  require 'active_support/core_ext/class/attribute_accessors'
4
4
 
5
5
  module BetterHtml
6
- class Config
7
- # regex to validate "foo" in "<foo>"
8
- cattr_accessor :partial_tag_name_pattern
9
- self.partial_tag_name_pattern = /\A[a-z0-9\-\:]+\z/
10
-
11
- # regex to validate "bar" in "<foo bar=1>"
12
- cattr_accessor :partial_attribute_name_pattern
13
- self.partial_attribute_name_pattern = /\A[a-zA-Z0-9\-\:]+\z/
14
-
15
- # true if "<foo bar='1'>" is valid syntax
16
- cattr_accessor :allow_single_quoted_attributes
17
- self.allow_single_quoted_attributes = false
18
-
19
- # true if "<foo bar=1>" is valid syntax
20
- cattr_accessor :allow_unquoted_attributes
21
- self.allow_unquoted_attributes = false
22
-
23
- # all methods that return "javascript-safe" strings
24
- cattr_accessor :javascript_safe_methods
25
- self.javascript_safe_methods = ['to_json']
26
-
27
- # name of all html attributes that may contain javascript
28
- cattr_accessor :javascript_attribute_names
29
- self.javascript_attribute_names = [/\Aon/i]
30
-
31
- cattr_accessor :template_exclusion_filter_block
32
-
33
- def self.template_exclusion_filter(&block)
34
- self.template_exclusion_filter_block = block
35
- end
36
-
37
- cattr_accessor :lodash_safe_javascript_expression
38
- self.lodash_safe_javascript_expression = [/\AJSON\.stringify\(/]
6
+ def self.configure
7
+ yield config if block_given?
39
8
  end
40
9
 
41
10
  def self.config
42
11
  @config ||= Config.new
43
- yield @config if block_given?
44
- @config
12
+ end
13
+
14
+ def self.config=(new_config)
15
+ @config = new_config
45
16
  end
46
17
  end
47
18
 
48
19
  require 'better_html/version'
20
+ require 'better_html/config'
49
21
  require 'better_html/helpers'
50
22
  require 'better_html/errors'
51
23
  require 'better_html/html_attributes'
@@ -52,7 +52,7 @@ class BetterHtml::BetterErb
52
52
  # Always make sure we return a String in the default_internal
53
53
  erb.encode!
54
54
 
55
- excluded_template = !!BetterHtml::Config.template_exclusion_filter_block&.call(template.identifier)
55
+ excluded_template = !!BetterHtml.config.template_exclusion_filter_block&.call(template.identifier)
56
56
  klass = BetterHtml::BetterErb.content_types[exts] unless excluded_template
57
57
  klass ||= self.class.erb_implementation
58
58
 
@@ -3,9 +3,10 @@ require 'action_view'
3
3
 
4
4
  class BetterHtml::BetterErb
5
5
  module RuntimeChecks
6
- def initialize(*)
6
+ def initialize(erb, config: BetterHtml.config, **options)
7
7
  @parser = HtmlTokenizer::Parser.new
8
- super
8
+ @config = config
9
+ super(erb, **options)
9
10
  end
10
11
 
11
12
  def validate!
@@ -112,26 +113,26 @@ class BetterHtml::BetterErb
112
113
  def check_tag_name(type, start, stop, line, column)
113
114
  text = @parser.extract(start, stop)
114
115
  return if text.upcase == "!DOCTYPE"
115
- return if BetterHtml.config.partial_tag_name_pattern === text
116
+ return if @config.partial_tag_name_pattern === text
116
117
 
117
118
  s = "Invalid tag name #{text.inspect} does not match "\
118
- "regular expression #{BetterHtml.config.partial_tag_name_pattern.inspect}\n"
119
+ "regular expression #{@config.partial_tag_name_pattern.inspect}\n"
119
120
  s << build_location(line, column, text.size)
120
121
  raise BetterHtml::HtmlError, s
121
122
  end
122
123
 
123
124
  def check_attribute_name(type, start, stop, line, column)
124
125
  text = @parser.extract(start, stop)
125
- return if BetterHtml.config.partial_attribute_name_pattern === text
126
+ return if @config.partial_attribute_name_pattern === text
126
127
 
127
128
  s = "Invalid attribute name #{text.inspect} does not match "\
128
- "regular expression #{BetterHtml.config.partial_attribute_name_pattern.inspect}\n"
129
+ "regular expression #{@config.partial_attribute_name_pattern.inspect}\n"
129
130
  s << build_location(line, column, text.size)
130
131
  raise BetterHtml::HtmlError, s
131
132
  end
132
133
 
133
134
  def check_quoted_value(type, start, stop, line, column)
134
- return if BetterHtml.config.allow_single_quoted_attributes
135
+ return if @config.allow_single_quoted_attributes
135
136
  text = @parser.extract(start, stop)
136
137
  return if text == '"'
137
138
 
@@ -141,7 +142,7 @@ class BetterHtml::BetterErb
141
142
  end
142
143
 
143
144
  def check_unquoted_value(type, start, stop, line, column)
144
- return if BetterHtml.config.allow_unquoted_attributes
145
+ return if @config.allow_unquoted_attributes
145
146
  s = "Unquoted attribute values are not allowed\n"
146
147
  s << build_location(line, column, stop-start)
147
148
  raise BetterHtml::HtmlError, s
@@ -0,0 +1,16 @@
1
+ require 'smart_properties'
2
+
3
+ module BetterHtml
4
+ class Config
5
+ include SmartProperties
6
+
7
+ property :partial_tag_name_pattern, default: /\A[a-z0-9\-\:]+\z/
8
+ property :partial_attribute_name_pattern, default: /\A[a-zA-Z0-9\-\:]+\z/
9
+ property :allow_single_quoted_attributes, default: true
10
+ property :allow_unquoted_attributes, default: false
11
+ property :javascript_safe_methods, default: ['to_json']
12
+ property :javascript_attribute_names, default: [/\Aon/i]
13
+ property :template_exclusion_filter
14
+ property :lodash_safe_javascript_expression, default: [/\AJSON\.stringify\(/]
15
+ end
16
+ end
@@ -28,10 +28,9 @@ module BetterHtml
28
28
  end
29
29
 
30
30
  def line_source_with_underline
31
- line_content = @document.lines[line-1]
32
- line_content = line_content.nil? ? "" : line_content.gsub(/\n$/, '')
31
+ line_content = extract_line(line: line)
33
32
  spaces = line_content.scan(/\A\s*/).first
34
- column_without_spaces = column - spaces.length
33
+ column_without_spaces = [column - spaces.length, 0].max
35
34
  underscore_length = [[stop - start, line_content.length - column_without_spaces].min, 1].max
36
35
  "#{line_content.gsub(/\A\s*/, '')}\n#{' ' * column_without_spaces}#{'^' * underscore_length}"
37
36
  end
@@ -45,6 +44,10 @@ module BetterHtml
45
44
  def calculate_column
46
45
  @document[0..start-1]&.split("\n", -1)&.last&.length || 0
47
46
  end
47
+
48
+ def extract_line(line:)
49
+ @document.split("\n", -1)[line - 1]&.gsub(/\n$/, '') || ""
50
+ end
48
51
  end
49
52
  end
50
53
  end
@@ -52,8 +52,9 @@ EOF
52
52
 
53
53
  VALID_JAVASCRIPT_TAG_TYPES = ['text/javascript', 'text/template', 'text/html']
54
54
 
55
- def initialize(data, **options)
55
+ def initialize(data, config: BetterHtml.config, **options)
56
56
  @data = data
57
+ @config = config
57
58
  @errors = Errors.new
58
59
  @options = options.present? ? options.dup : {}
59
60
  @options[:template_language] ||= :html
@@ -228,11 +229,11 @@ EOF
228
229
  end
229
230
 
230
231
  def javascript_attribute_name?(name)
231
- BetterHtml.config.javascript_attribute_names.any?{ |other| other === name.to_s }
232
+ @config.javascript_attribute_names.any?{ |other| other === name.to_s }
232
233
  end
233
234
 
234
235
  def javascript_safe_method?(name)
235
- BetterHtml.config.javascript_safe_methods.include?(name.to_s)
236
+ @config.javascript_safe_methods.include?(name.to_s)
236
237
  end
237
238
 
238
239
  def validate_script_tag_content(node)
@@ -240,19 +241,20 @@ EOF
240
241
  case token.type
241
242
  when :expr_literal, :expr_escaped
242
243
  expr = RubyExpr.parse(token.code)
243
- if expr.calls.empty?
244
- add_error(
245
- "erb interpolation in javascript tag must call '(...).to_json'",
246
- location: token.location,
247
- )
248
- else
249
- validate_script_expression(node, token, expr)
250
- end
244
+ validate_script_expression(node, token, expr)
251
245
  end
252
246
  end
253
247
  end
254
248
 
255
249
  def validate_script_expression(node, token, expr)
250
+ if expr.calls.empty?
251
+ add_error(
252
+ "erb interpolation in javascript tag must call '(...).to_json'",
253
+ location: token.location,
254
+ )
255
+ return
256
+ end
257
+
256
258
  expr.calls.each do |call|
257
259
  if call.method == :raw
258
260
  call.arguments.each do |argument_node|
@@ -25,8 +25,8 @@ Never use <script> tags inside lodash template.
25
25
  -----------
26
26
  EOF
27
27
 
28
- def assert_lodash_safety(data)
29
- tester = Tester.new(data)
28
+ def assert_lodash_safety(data, **options)
29
+ tester = Tester.new(data, **options)
30
30
 
31
31
  message = ""
32
32
  tester.errors.each do |error|
@@ -47,8 +47,9 @@ EOF
47
47
  class Tester
48
48
  attr_reader :errors
49
49
 
50
- def initialize(data)
50
+ def initialize(data, config: BetterHtml.config)
51
51
  @data = data
52
+ @config = config
52
53
  @errors = Errors.new
53
54
  @nodes = BetterHtml::NodeIterator.new(data, template_language: :lodash)
54
55
  validate!
@@ -109,11 +110,11 @@ EOF
109
110
  end
110
111
 
111
112
  def javascript_attribute_name?(name)
112
- BetterHtml.config.javascript_attribute_names.any?{ |other| other === name }
113
+ @config.javascript_attribute_names.any?{ |other| other === name }
113
114
  end
114
115
 
115
116
  def lodash_safe_javascript_expression?(code)
116
- BetterHtml.config.lodash_safe_javascript_expression.any?{ |other| other === code }
117
+ @config.lodash_safe_javascript_expression.any?{ |other| other === code }
117
118
  end
118
119
 
119
120
  def validate_no_statements(node)
@@ -1,3 +1,3 @@
1
1
  module BetterHtml
2
- VERSION = "0.0.9"
2
+ VERSION = "0.0.10"
3
3
  end
@@ -6,36 +6,36 @@ require 'json'
6
6
  class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
7
7
  test "simple template rendering" do
8
8
  assert_equal "<foo>some value<foo>",
9
- render("<foo><%= bar %><foo>", { bar: 'some value' })
9
+ render("<foo><%= bar %><foo>", locals: { bar: 'some value' })
10
10
  end
11
11
 
12
12
  test "html_safe interpolation" do
13
13
  assert_equal "<foo><bar /><foo>",
14
- render("<foo><%= bar %><foo>", { bar: '<bar />'.html_safe })
14
+ render("<foo><%= bar %><foo>", locals: { bar: '<bar />'.html_safe })
15
15
  end
16
16
 
17
17
  test "non html_safe interpolation" do
18
18
  assert_equal "<foo>&lt;bar /&gt;<foo>",
19
- render("<foo><%= bar %><foo>", { bar: '<bar />' })
19
+ render("<foo><%= bar %><foo>", locals: { bar: '<bar />' })
20
20
  end
21
21
 
22
22
  test "interpolate non-html_safe inside attribute is escaped" do
23
23
  assert_equal "<a href=\" &#39;&quot;&gt;x \">",
24
- render("<a href=\"<%= value %>\">", { value: ' \'">x ' })
24
+ render("<a href=\"<%= value %>\">", locals: { value: ' \'">x ' })
25
25
  end
26
26
 
27
27
  test "interpolate html_safe inside attribute is magically force-escaped" do
28
28
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
29
- render("<a href=\"<%= value %>\">", { value: ' \'">x '.html_safe })
29
+ render("<a href=\"<%= value %>\">", locals: { value: ' \'">x '.html_safe })
30
30
  end
31
31
  assert_equal "Detected invalid characters as part of the interpolation "\
32
32
  "into a quoted attribute value. The value cannot contain the character \".", e.message
33
33
  end
34
34
 
35
35
  test "interpolate html_safe inside single quoted attribute" do
36
- BetterHtml.config.stubs(:allow_single_quoted_attributes).returns(true)
36
+ config = build_config(allow_single_quoted_attributes: true)
37
37
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
38
- render("<a href=\'<%= value %>\'>", { value: ' \'">x '.html_safe })
38
+ render("<a href=\'<%= value %>\'>", config: config, locals: { value: ' \'">x '.html_safe })
39
39
  end
40
40
  assert_equal "Detected invalid characters as part of the interpolation "\
41
41
  "into a quoted attribute value. The value cannot contain the character '.", e.message
@@ -43,12 +43,12 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
43
43
 
44
44
  test "interpolate in attribute name" do
45
45
  assert_equal "<a data-safe-foo>",
46
- render("<a data-<%= value %>-foo>", { value: "safe" })
46
+ render("<a data-<%= value %>-foo>", locals: { value: "safe" })
47
47
  end
48
48
 
49
49
  test "interpolate in attribute name with unsafe value with spaces" do
50
50
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
51
- render("<a data-<%= value %>-foo>", { value: "un safe" })
51
+ render("<a data-<%= value %>-foo>", locals: { value: "un safe" })
52
52
  end
53
53
  assert_equal "Detected invalid characters as part of the interpolation "\
54
54
  "into a attribute name around 'data-<%= value %>'.", e.message
@@ -56,7 +56,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
56
56
 
57
57
  test "interpolate in attribute name with unsafe value with equal sign" do
58
58
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
59
- render("<a data-<%= value %>-foo>", { value: "un=safe" })
59
+ render("<a data-<%= value %>-foo>", locals: { value: "un=safe" })
60
60
  end
61
61
  assert_equal "Detected invalid characters as part of the "\
62
62
  "interpolation into a attribute name around 'data-<%= value %>'.", e.message
@@ -64,7 +64,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
64
64
 
65
65
  test "interpolate in attribute name with unsafe value with quote" do
66
66
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
67
- render("<a data-<%= value %>-foo>", { value: "un\"safe" })
67
+ render("<a data-<%= value %>-foo>", locals: { value: "un\"safe" })
68
68
  end
69
69
  assert_equal "Detected invalid characters as part of the "\
70
70
  "interpolation into a attribute name around 'data-<%= value %>'.", e.message
@@ -76,9 +76,9 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
76
76
  end
77
77
 
78
78
  test "interpolate after an attribute name with equal sign" do
79
- BetterHtml.config.stubs(:allow_unquoted_attributes).returns(true)
79
+ config = build_config(allow_unquoted_attributes: true)
80
80
  e = assert_raises(BetterHtml::DontInterpolateHere) do
81
- render("<a data-foo= <%= html_attributes(foo: 'bar') %>>")
81
+ render("<a data-foo= <%= html_attributes(foo: 'bar') %>>", config: config)
82
82
  end
83
83
  assert_equal "Do not interpolate without quotes after "\
84
84
  "attribute around 'data-foo=<%= html_attributes(foo: 'bar') %>'.", e.message
@@ -94,18 +94,18 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
94
94
  end
95
95
 
96
96
  test "interpolate in attribute without quotes" do
97
- BetterHtml.config.stubs(:allow_unquoted_attributes).returns(true)
97
+ config = build_config(allow_unquoted_attributes: true)
98
98
  e = assert_raises(BetterHtml::DontInterpolateHere) do
99
- render("<a href=<%= value %>>", { value: "un safe" })
99
+ render("<a href=<%= value %>>", config: config, locals: { value: "un safe" })
100
100
  end
101
101
  assert_equal "Do not interpolate without quotes after "\
102
102
  "attribute around 'href=<%= value %>'.", e.message
103
103
  end
104
104
 
105
105
  test "interpolate in attribute after value" do
106
- BetterHtml.config.stubs(:allow_unquoted_attributes).returns(true)
106
+ config = build_config(allow_unquoted_attributes: true)
107
107
  e = assert_raises(BetterHtml::DontInterpolateHere) do
108
- render("<a href=something<%= value %>>", { value: "" })
108
+ render("<a href=something<%= value %>>", config: config, locals: { value: "" })
109
109
  end
110
110
  assert_equal "Do not interpolate without quotes around this "\
111
111
  "attribute value. Instead of <a href=something<%= value %>> "\
@@ -114,12 +114,12 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
114
114
 
115
115
  test "interpolate in tag name" do
116
116
  assert_equal "<tag-safe-foo>",
117
- render("<tag-<%= value %>-foo>", { value: "safe" })
117
+ render("<tag-<%= value %>-foo>", locals: { value: "safe" })
118
118
  end
119
119
 
120
120
  test "interpolate in tag name with space" do
121
121
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
122
- render("<tag-<%= value %>-foo>", { value: "un safe" })
122
+ render("<tag-<%= value %>-foo>", locals: { value: "un safe" })
123
123
  end
124
124
  assert_equal "Detected invalid characters as part of the interpolation "\
125
125
  "into a tag name around: <tag-<%= value %>>.", e.message
@@ -127,7 +127,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
127
127
 
128
128
  test "interpolate in tag name with slash" do
129
129
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
130
- render("<tag-<%= value %>-foo>", { value: "un/safe" })
130
+ render("<tag-<%= value %>-foo>", locals: { value: "un/safe" })
131
131
  end
132
132
  assert_equal "Detected invalid characters as part of the interpolation "\
133
133
  "into a tag name around: <tag-<%= value %>>.", e.message
@@ -135,7 +135,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
135
135
 
136
136
  test "interpolate in tag name with end of tag" do
137
137
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
138
- render("<tag-<%= value %>-foo>", { value: "><script>" })
138
+ render("<tag-<%= value %>-foo>", locals: { value: "><script>" })
139
139
  end
140
140
  assert_equal "Detected invalid characters as part of the interpolation "\
141
141
  "into a tag name around: <tag-<%= value %>>.", e.message
@@ -143,12 +143,12 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
143
143
 
144
144
  test "interpolate in comment" do
145
145
  assert_equal "<!-- safe -->",
146
- render("<!-- <%= value %> -->", { value: "safe" })
146
+ render("<!-- <%= value %> -->", locals: { value: "safe" })
147
147
  end
148
148
 
149
149
  test "interpolate in comment with end-of-comment" do
150
150
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
151
- render("<!-- <%= value %> -->", { value: "-->".html_safe })
151
+ render("<!-- <%= value %> -->", locals: { value: "-->".html_safe })
152
152
  end
153
153
  assert_equal "Detected invalid characters as part of the interpolation "\
154
154
  "into a html comment around: <!-- <%= value %>.", e.message
@@ -156,18 +156,18 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
156
156
 
157
157
  test "non html_safe interpolation into comment tag" do
158
158
  assert_equal "<!-- --&gt; -->",
159
- render("<!-- <%= value %> -->", value: '-->')
159
+ render("<!-- <%= value %> -->", locals: { value: '-->' })
160
160
  end
161
161
 
162
162
  test "interpolate in script tag" do
163
163
  assert_equal "<script> foo safe bar<script>",
164
- render("<script> foo <%= value %> bar<script>", { value: "safe" })
164
+ render("<script> foo <%= value %> bar<script>", locals: { value: "safe" })
165
165
  end
166
166
 
167
167
  test "interpolate in script tag with start of comment" do
168
168
  skip "skip for now; causing problems"
169
169
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
170
- render("<script> foo <%= value %> bar<script>", { value: "<!--".html_safe })
170
+ render("<script> foo <%= value %> bar<script>", locals: { value: "<!--".html_safe })
171
171
  end
172
172
  assert_equal "Detected invalid characters as part of the interpolation "\
173
173
  "into a script tag around: <script> foo <%= value %>. "\
@@ -176,7 +176,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
176
176
 
177
177
  test "interpolate in script tag with start of script" do
178
178
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
179
- render("<script> foo <%= value %> bar<script>", { value: "<script".html_safe })
179
+ render("<script> foo <%= value %> bar<script>", locals: { value: "<script".html_safe })
180
180
  end
181
181
  assert_equal "Detected invalid characters as part of the interpolation "\
182
182
  "into a script tag around: <script> foo <%= value %>. "\
@@ -185,12 +185,12 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
185
185
 
186
186
  test "interpolate in script tag with raw interpolation" do
187
187
  assert_equal "<script> x = \"foo\" </script>",
188
- render("<script> x = <%== value %> </script>", { value: JSON.dump("foo") })
188
+ render("<script> x = <%== value %> </script>", locals: { value: JSON.dump("foo") })
189
189
  end
190
190
 
191
191
  test "interpolate in script tag with start of script case insensitive" do
192
192
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
193
- render("<script> foo <%= value %> bar<script>", { value: "<ScRIpT".html_safe })
193
+ render("<script> foo <%= value %> bar<script>", locals: { value: "<ScRIpT".html_safe })
194
194
  end
195
195
  assert_equal "Detected invalid characters as part of the interpolation "\
196
196
  "into a script tag around: <script> foo <%= value %>. "\
@@ -199,7 +199,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
199
199
 
200
200
  test "interpolate in script tag with end of script" do
201
201
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
202
- render("<script> foo <%= value %> bar<script>", { value: "</script".html_safe })
202
+ render("<script> foo <%= value %> bar<script>", locals: { value: "</script".html_safe })
203
203
  end
204
204
  assert_equal "Detected invalid characters as part of the interpolation "\
205
205
  "into a script tag around: <script> foo <%= value %>. "\
@@ -221,17 +221,17 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
221
221
 
222
222
  test "non html_safe interpolation into rawtext tag" do
223
223
  assert_equal "<title>&lt;/title&gt;</title>",
224
- render("<title><%= value %></title>", value: '</title>')
224
+ render("<title><%= value %></title>", locals: { value: '</title>' })
225
225
  end
226
226
 
227
227
  test "html_safe interpolation into rawtext tag" do
228
228
  assert_equal "<title><safe></title>",
229
- render("<title><%= value %></title>", value: '<safe>'.html_safe)
229
+ render("<title><%= value %></title>", locals: { value: '<safe>'.html_safe })
230
230
  end
231
231
 
232
232
  test "html_safe interpolation terminating the current tag" do
233
233
  e = assert_raises(BetterHtml::UnsafeHtmlError) do
234
- render("<title><%= value %></title>", value: '</title>'.html_safe)
234
+ render("<title><%= value %></title>", locals: { value: '</title>'.html_safe })
235
235
  end
236
236
  assert_equal "Detected invalid characters as part of the interpolation "\
237
237
  "into a title tag around: <title><%= value %>.", e.message
@@ -273,7 +273,7 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
273
273
 
274
274
  test "can interpolate method calls without parenthesis" do
275
275
  assert_equal "<div>foo</div>",
276
- render("<div><%= send 'value' %></div>", value: 'foo')
276
+ render("<div><%= send 'value' %></div>", locals: { value: 'foo' })
277
277
  end
278
278
 
279
279
  test "tag names are validated against tag_name_pattern regexp" do
@@ -290,16 +290,16 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
290
290
  e = assert_raises(BetterHtml::HtmlError) do
291
291
  render("<foo bar_baz=\"1\">")
292
292
  end
293
- assert_equal "Invalid attribute name \"bar_baz\" does not match regular expression #{BetterHtml.config.partial_attribute_name_pattern.inspect}\n"\
293
+ assert_equal "Invalid attribute name \"bar_baz\" does not match regular expression #{build_config.partial_attribute_name_pattern.inspect}\n"\
294
294
  "On line 1 column 5:\n"\
295
295
  "<foo bar_baz=\"1\">\n"\
296
296
  " ^^^^^^^", e.message
297
297
  end
298
298
 
299
299
  test "single quotes are disallowed when allow_single_quoted_attributes=false" do
300
- BetterHtml.config.stubs(:allow_single_quoted_attributes).returns(false)
300
+ config = build_config(allow_single_quoted_attributes: false)
301
301
  e = assert_raises(BetterHtml::HtmlError) do
302
- render("<foo bar='1'>")
302
+ render("<foo bar='1'>", config: config)
303
303
  end
304
304
  assert_equal "Single-quoted attributes are not allowed\n"\
305
305
  "On line 1 column 9:\n"\
@@ -308,16 +308,16 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
308
308
  end
309
309
 
310
310
  test "single quotes are allowed when allow_single_quoted_attributes=true" do
311
- BetterHtml.config.stubs(:allow_single_quoted_attributes).returns(true)
311
+ config = build_config(allow_single_quoted_attributes: true)
312
312
  assert_nothing_raised do
313
- render("<foo bar='1'>")
313
+ render("<foo bar='1'>", config: config)
314
314
  end
315
315
  end
316
316
 
317
317
  test "unquoted values are disallowed when allow_unquoted_attributes=false" do
318
- BetterHtml.config.stubs(:allow_unquoted_attributes).returns(false)
318
+ config = build_config(allow_unquoted_attributes: false)
319
319
  e = assert_raises(BetterHtml::HtmlError) do
320
- render("<foo bar=1>")
320
+ render("<foo bar=1>", config: config)
321
321
  end
322
322
  assert_equal "Unquoted attribute values are not allowed\n"\
323
323
  "On line 1 column 9:\n"\
@@ -326,9 +326,9 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
326
326
  end
327
327
 
328
328
  test "unquoted values are allowed when allow_unquoted_attributes=true" do
329
- BetterHtml.config.stubs(:allow_unquoted_attributes).returns(true)
329
+ config = build_config(allow_unquoted_attributes: true)
330
330
  assert_nothing_raised do
331
- render("<foo bar=1>")
331
+ render("<foo bar=1>", config: config)
332
332
  end
333
333
  end
334
334
 
@@ -382,9 +382,13 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
382
382
  end
383
383
  end
384
384
 
385
- def render(source, locals={})
385
+ def build_config(**options)
386
+ BetterHtml::Config.new(**options)
387
+ end
388
+
389
+ def render(source, config: build_config, locals: {})
386
390
  context = ViewContext.new(locals)
387
- impl = compile(source)
391
+ impl = compile(source, config: config)
388
392
  if ActionView.version < Gem::Version.new("5.1")
389
393
  impl.result(context.get_binding)
390
394
  else
@@ -392,11 +396,11 @@ class BetterHtml::BetterErb::ImplementationTest < ActiveSupport::TestCase
392
396
  end
393
397
  end
394
398
 
395
- def compile(source)
399
+ def compile(source, config: build_config)
396
400
  if ActionView.version < Gem::Version.new("5.1")
397
- BetterHtml::BetterErb::ErubisImplementation.new(source)
401
+ BetterHtml::BetterErb::ErubisImplementation.new(source, config: config)
398
402
  else
399
- BetterHtml::BetterErb::ErubiImplementation.new(source)
403
+ BetterHtml::BetterErb::ErubiImplementation.new(source, config: config)
400
404
  end
401
405
  end
402
406
  end
@@ -5,12 +5,10 @@ module BetterHtml
5
5
  module TestHelper
6
6
  class SafeErbTesterTest < ActiveSupport::TestCase
7
7
  setup do
8
- BetterHtml.config
9
- .stubs(:javascript_safe_methods)
10
- .returns(['j', 'escape_javascript', 'to_json'])
11
- BetterHtml.config
12
- .stubs(:javascript_attribute_names)
13
- .returns([/\Aon/i, 'data-eval'])
8
+ @config = BetterHtml::Config.new(
9
+ javascript_safe_methods: ['j', 'escape_javascript', 'to_json'],
10
+ javascript_attribute_names: [/\Aon/i, 'data-eval'],
11
+ )
14
12
  end
15
13
 
16
14
  test "string without interpolation is safe" do
@@ -390,9 +388,17 @@ module BetterHtml
390
388
  assert_equal "erb interpolation in javascript attribute must call '(...).to_json'", errors.first.message
391
389
  end
392
390
 
391
+ test "ivar missing .to_json is unsafe" do
392
+ errors = parse('<script><%= @feature.html_safe %></script>').errors
393
+
394
+ assert_equal 1, errors.size
395
+ assert_equal "<%= @feature.html_safe %>", errors.first.location.source
396
+ assert_equal "erb interpolation in javascript tag must call '(...).to_json'", errors.first.message
397
+ end
398
+
393
399
  private
394
400
  def parse(data, template_language: :html)
395
- SafeErbTester::Tester.new(data, template_language: template_language)
401
+ SafeErbTester::Tester.new(data, config: @config, template_language: template_language)
396
402
  end
397
403
  end
398
404
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Francois Chagnon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-11-06 00:00:00.000000000 Z
11
+ date: 2017-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: erubi
@@ -66,6 +66,34 @@ dependencies:
66
66
  - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: smart_properties
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: html_tokenizer
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
69
97
  - !ruby/object:Gem::Dependency
70
98
  name: rake
71
99
  requirement: !ruby/object:Gem::Requirement
@@ -96,6 +124,7 @@ files:
96
124
  - lib/better_html/better_erb/erubis_implementation.rb
97
125
  - lib/better_html/better_erb/runtime_checks.rb
98
126
  - lib/better_html/better_erb/validated_output_buffer.rb
127
+ - lib/better_html/config.rb
99
128
  - lib/better_html/errors.rb
100
129
  - lib/better_html/helpers.rb
101
130
  - lib/better_html/html_attributes.rb