better_html 0.0.12 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/lib/better_html.rb +0 -2
  3. data/lib/better_html/ast/iterator.rb +32 -0
  4. data/lib/better_html/ast/node.rb +14 -0
  5. data/lib/better_html/better_erb/runtime_checks.rb +3 -3
  6. data/lib/better_html/config.rb +12 -0
  7. data/lib/better_html/parser.rb +286 -0
  8. data/lib/better_html/test_helper/ruby_expr.rb +8 -5
  9. data/lib/better_html/test_helper/safe_erb_tester.rb +121 -108
  10. data/lib/better_html/test_helper/safe_lodash_tester.rb +44 -42
  11. data/lib/better_html/tokenizer/base_erb.rb +79 -0
  12. data/lib/better_html/tokenizer/html_erb.rb +31 -0
  13. data/lib/better_html/{node_iterator → tokenizer}/html_lodash.rb +30 -34
  14. data/lib/better_html/tokenizer/javascript_erb.rb +15 -0
  15. data/lib/better_html/{node_iterator → tokenizer}/location.rb +9 -3
  16. data/lib/better_html/tokenizer/token.rb +16 -0
  17. data/lib/better_html/tokenizer/token_array.rb +54 -0
  18. data/lib/better_html/tree/attribute.rb +31 -0
  19. data/lib/better_html/tree/attributes_list.rb +25 -0
  20. data/lib/better_html/tree/tag.rb +39 -0
  21. data/lib/better_html/version.rb +1 -1
  22. data/test/better_html/parser_test.rb +279 -0
  23. data/test/better_html/test_helper/safe_erb_tester_test.rb +11 -0
  24. data/test/better_html/test_helper/safe_lodash_tester_test.rb +11 -1
  25. data/test/better_html/tokenizer/html_erb_test.rb +158 -0
  26. data/test/better_html/tokenizer/html_lodash_test.rb +98 -0
  27. data/test/better_html/tokenizer/location_test.rb +57 -0
  28. data/test/better_html/tokenizer/token_array_test.rb +144 -0
  29. data/test/better_html/tokenizer/token_test.rb +15 -0
  30. metadata +45 -30
  31. data/lib/better_html/node_iterator.rb +0 -144
  32. data/lib/better_html/node_iterator/attribute.rb +0 -34
  33. data/lib/better_html/node_iterator/base.rb +0 -27
  34. data/lib/better_html/node_iterator/cdata.rb +0 -8
  35. data/lib/better_html/node_iterator/comment.rb +0 -8
  36. data/lib/better_html/node_iterator/content_node.rb +0 -13
  37. data/lib/better_html/node_iterator/element.rb +0 -26
  38. data/lib/better_html/node_iterator/html_erb.rb +0 -70
  39. data/lib/better_html/node_iterator/javascript_erb.rb +0 -55
  40. data/lib/better_html/node_iterator/text.rb +0 -8
  41. data/lib/better_html/node_iterator/token.rb +0 -8
  42. data/lib/better_html/tree.rb +0 -113
  43. data/test/better_html/node_iterator/html_erb_test.rb +0 -116
  44. data/test/better_html/node_iterator/html_lodash_test.rb +0 -132
  45. data/test/better_html/node_iterator/location_test.rb +0 -36
  46. data/test/better_html/node_iterator_test.rb +0 -221
  47. data/test/better_html/tree_test.rb +0 -110
@@ -0,0 +1,98 @@
1
+ require 'test_helper'
2
+ require 'better_html/tokenizer/html_lodash'
3
+
4
+ module BetterHtml
5
+ module Tokenizer
6
+ class HtmlLodashTest < ActiveSupport::TestCase
7
+ test "matches text" do
8
+ scanner = HtmlLodash.new("just some text")
9
+ assert_equal 1, scanner.tokens.size
10
+
11
+ assert_attributes ({ type: :text, loc: { start: 0, stop: 13, source: "just some text" } }), scanner.tokens[0]
12
+ end
13
+
14
+ test "matches strings to be escaped" do
15
+ scanner = HtmlLodash.new("[%= foo %]")
16
+ assert_equal 4, scanner.tokens.size
17
+
18
+ assert_attributes ({ type: :lodash_begin, loc: { start: 0, stop: 1, source: "[%" } }), scanner.tokens[0]
19
+ assert_attributes ({ type: :indicator, loc: { start: 2, stop: 2, source: "=" } }), scanner.tokens[1]
20
+ assert_attributes ({ type: :code, loc: { start: 3, stop: 7, source: " foo " } }), scanner.tokens[2]
21
+ assert_attributes ({ type: :lodash_end, loc: { start: 8, stop: 9, source: "%]" } }), scanner.tokens[3]
22
+ end
23
+
24
+ test "matches interpolate" do
25
+ scanner = HtmlLodash.new("[%! foo %]")
26
+ assert_equal 4, scanner.tokens.size
27
+
28
+ assert_attributes ({ type: :lodash_begin, loc: { start: 0, stop: 1, source: "[%" } }), scanner.tokens[0]
29
+ assert_attributes ({ type: :indicator, loc: { start: 2, stop: 2, source: "!" } }), scanner.tokens[1]
30
+ assert_attributes ({ type: :code, loc: { start: 3, stop: 7, source: " foo " } }), scanner.tokens[2]
31
+ assert_attributes ({ type: :lodash_end, loc: { start: 8, stop: 9, source: "%]" } }), scanner.tokens[3]
32
+ end
33
+
34
+ test "matches statement" do
35
+ scanner = HtmlLodash.new("[% foo %]")
36
+ assert_equal 3, scanner.tokens.size
37
+
38
+ assert_attributes ({ type: :lodash_begin, loc: { start: 0, stop: 1, source: "[%" } }), scanner.tokens[0]
39
+ assert_attributes ({ type: :code, loc: { start: 2, stop: 6, source: " foo " } }), scanner.tokens[1]
40
+ assert_attributes ({ type: :lodash_end, loc: { start: 7, stop: 8, source: "%]" } }), scanner.tokens[2]
41
+ end
42
+
43
+ test "matches text before and after" do
44
+ scanner = HtmlLodash.new("before\n[%= foo %]\nafter")
45
+ assert_equal 6, scanner.tokens.size
46
+
47
+ assert_attributes ({ type: :text, loc: { start: 0, stop: 6, source: "before\n" } }), scanner.tokens[0]
48
+ assert_attributes ({ type: :lodash_begin, loc: { start: 7, stop: 8, source: "[%" } }), scanner.tokens[1]
49
+ assert_attributes ({ type: :indicator, loc: { start: 9, stop: 9, source: "=" } }), scanner.tokens[2]
50
+ assert_attributes ({ type: :code, loc: { start: 10, stop: 14, source: " foo " } }), scanner.tokens[3]
51
+ assert_attributes ({ type: :lodash_end, loc: { start: 15, stop: 16, source: "%]" } }), scanner.tokens[4]
52
+ assert_attributes ({ type: :text, loc: { start: 17, stop: 22, source: "\nafter" } }), scanner.tokens[5]
53
+ end
54
+
55
+ test "matches multiple" do
56
+ scanner = HtmlLodash.new("[% if() { %][%= foo %][% } %]")
57
+ assert_equal 10, scanner.tokens.size
58
+
59
+ assert_attributes ({ type: :lodash_begin, loc: { source: "[%" } }), scanner.tokens[0]
60
+ assert_attributes ({ type: :code, loc: { source: " if() { " } }), scanner.tokens[1]
61
+ assert_attributes ({ type: :lodash_end, loc: { source: "%]" } }), scanner.tokens[2]
62
+
63
+ assert_attributes ({ type: :lodash_begin, loc: { source: "[%" } }), scanner.tokens[3]
64
+ assert_attributes ({ type: :indicator, loc: { source: "=" } }), scanner.tokens[4]
65
+ assert_attributes ({ type: :code, loc: { source: " foo " } }), scanner.tokens[5]
66
+ assert_attributes ({ type: :lodash_end, loc: { source: "%]" } }), scanner.tokens[6]
67
+
68
+ assert_attributes ({ type: :lodash_begin, loc: { source: "[%" } }), scanner.tokens[7]
69
+ assert_attributes ({ type: :code, loc: { source: " } " } }), scanner.tokens[8]
70
+ assert_attributes ({ type: :lodash_end, loc: { source: "%]" } }), scanner.tokens[9]
71
+ end
72
+
73
+ test "parses out html correctly" do
74
+ scanner = HtmlLodash.new('<div class="[%= foo %]">')
75
+ assert_equal 12, scanner.tokens.size
76
+ assert_equal [:tag_start, :tag_name, :whitespace, :attribute_name,
77
+ :equal, :attribute_quoted_value_start,
78
+ :lodash_begin, :indicator, :code, :lodash_end,
79
+ :attribute_quoted_value_end, :tag_end], scanner.tokens.map(&:type)
80
+ assert_equal ["<", "div", " ", "class", "=", "\"", "[%", "=", " foo ", "%]", "\"", ">"], scanner.tokens.map(&:loc).map(&:source)
81
+ end
82
+
83
+ private
84
+
85
+ def assert_attributes(attributes, token)
86
+ attributes.each do |key, value|
87
+ if value.nil?
88
+ assert_nil token.send(key)
89
+ elsif value.is_a?(Hash)
90
+ assert_attributes(value, token.send(key))
91
+ else
92
+ assert_equal value, token.send(key)
93
+ end
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,57 @@
1
+ require 'test_helper'
2
+ require 'better_html/tokenizer/location'
3
+
4
+ module BetterHtml
5
+ module Tokenizer
6
+ class LocationTest < ActiveSupport::TestCase
7
+ test "location start out of bounds" do
8
+ e = assert_raises(ArgumentError) do
9
+ Location.new("foo", 5, 6)
10
+ end
11
+ assert_equal "start location 5 is out of range for document of size 3", e.message
12
+ end
13
+
14
+ test "location stop out of bounds" do
15
+ e = assert_raises(ArgumentError) do
16
+ Location.new("foo", 2, 6)
17
+ end
18
+ assert_equal "stop location 6 is out of range for document of size 3", e.message
19
+ end
20
+
21
+ test "location stop < start" do
22
+ e = assert_raises(ArgumentError) do
23
+ Location.new("aaaaaa", 5, 2)
24
+ end
25
+ assert_equal "end of range must be greater than start of range (2 < 5)", e.message
26
+ end
27
+
28
+ test "location without line and column" do
29
+ loc = Location.new("foo\nbar\nbaz", 9, 9)
30
+
31
+ assert_equal "a", loc.source
32
+ assert_equal 3, loc.line
33
+ assert_equal 1, loc.column
34
+ end
35
+
36
+ test "line_source_with_underline" do
37
+ loc = Location.new("ui_helper(foo)", 10, 12)
38
+
39
+ assert_equal "foo", loc.source
40
+ assert_equal <<~EOL.strip, loc.line_source_with_underline
41
+ ui_helper(foo)
42
+ ^^^
43
+ EOL
44
+ end
45
+
46
+ test "line_source_with_underline removes empty spaces" do
47
+ loc = Location.new(" \t ui_helper(foo)", 17, 19)
48
+
49
+ assert_equal "foo", loc.source
50
+ assert_equal <<~EOL.strip, loc.line_source_with_underline
51
+ ui_helper(foo)
52
+ ^^^
53
+ EOL
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+ require 'better_html/tokenizer/token'
3
+ require 'better_html/tokenizer/location'
4
+ require 'better_html/tokenizer/token_array'
5
+
6
+ module BetterHtml
7
+ module Tokenizer
8
+ class TokenArrayTest < ActiveSupport::TestCase
9
+ setup do
10
+ @document = "<x>"
11
+ @tokens = [
12
+ Token.new(type: :lquote, loc: Location.new(@document, 0, 0)),
13
+ Token.new(type: :name, loc: Location.new(@document, 1, 1)),
14
+ Token.new(type: :rquote, loc: Location.new(@document, 2, 2)),
15
+ ]
16
+ @array = TokenArray.new(@tokens)
17
+ end
18
+
19
+ test "size" do
20
+ assert_equal 3, @array.size
21
+ end
22
+
23
+ test "size for empty array" do
24
+ @array = TokenArray.new([])
25
+ assert_equal 0, @array.size
26
+ end
27
+
28
+ test "shift returns element from beginning of array" do
29
+ assert_equal @tokens.first, @array.shift
30
+ end
31
+
32
+ test "shift decreases the size by 1" do
33
+ assert_difference(-> { @array.size }, -1) do
34
+ @array.shift
35
+ end
36
+ end
37
+
38
+ test "after shift, current element is changed" do
39
+ assert_equal @tokens.first, @array.current
40
+ assert_equal @tokens.first, @array.shift
41
+ assert_equal @tokens.second, @array.current
42
+ end
43
+
44
+ test "pop returns element from the end of array" do
45
+ assert_equal @tokens.last, @array.pop
46
+ end
47
+
48
+ test "pop decreases the size by 1" do
49
+ assert_difference(-> { @array.size }, -1) do
50
+ @array.pop
51
+ end
52
+ end
53
+
54
+ test "after pop, last element is changed" do
55
+ assert_equal @tokens.last, @array.last
56
+ assert_equal @tokens.last, @array.pop
57
+ assert_equal @tokens.second, @array.last
58
+ end
59
+
60
+ test "current returns element from beginning of array" do
61
+ assert_equal @tokens.first, @array.current
62
+ end
63
+
64
+ test "current does not change size" do
65
+ assert_no_difference(-> { @array.size }) do
66
+ @array.current
67
+ end
68
+ end
69
+
70
+ test "last returns element from the end of array" do
71
+ assert_equal @tokens.last, @array.last
72
+ end
73
+
74
+ test "last does not change size" do
75
+ assert_no_difference(-> { @array.size }) do
76
+ @array.last
77
+ end
78
+ end
79
+
80
+ test "empty?" do
81
+ refute_predicate @array, :empty?
82
+ 3.times { @array.shift }
83
+ assert_predicate @array, :empty?
84
+ end
85
+
86
+ test "any?" do
87
+ assert_predicate @array, :any?
88
+ 3.times { @array.shift }
89
+ refute_predicate @array, :any?
90
+ end
91
+
92
+ test "current is nil when array is empty" do
93
+ @array = TokenArray.new([])
94
+ assert_nil @array.current
95
+ end
96
+
97
+ test "last is nil when array is empty" do
98
+ @array = TokenArray.new([])
99
+ assert_nil @array.last
100
+ end
101
+
102
+ test "shift raises for empty array" do
103
+ @array = TokenArray.new([])
104
+ e = assert_raises(RuntimeError) do
105
+ @array.shift
106
+ end
107
+ assert_equal 'no tokens left to shift', e.message
108
+ end
109
+
110
+ test "pop raises for empty array" do
111
+ @array = TokenArray.new([])
112
+ e = assert_raises(RuntimeError) do
113
+ @array.pop
114
+ end
115
+ assert_equal 'no tokens left to pop', e.message
116
+ end
117
+
118
+ test "trim takes elements from the beginning of array" do
119
+ assert_difference(-> { @array.size }, -1) do
120
+ @array.trim(:lquote)
121
+ end
122
+
123
+ assert_equal @tokens.second, @array.current
124
+ end
125
+
126
+ test "trim takes elements from the end of array" do
127
+ assert_difference(-> { @array.size }, -1) do
128
+ @array.trim(:rquote)
129
+ end
130
+
131
+ assert_equal @tokens.second, @array.last
132
+ end
133
+
134
+ test "trim does not change array when element types are not at front nor back of array" do
135
+ assert_no_difference(-> { @array.size }) do
136
+ @array.trim(:name)
137
+ end
138
+
139
+ assert_equal @tokens.first, @array.current
140
+ assert_equal @tokens.last, @array.last
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,15 @@
1
+ require 'test_helper'
2
+ require 'better_html/tokenizer/location'
3
+ require 'better_html/tokenizer/token'
4
+
5
+ module BetterHtml
6
+ module Tokenizer
7
+ class TokenTest < ActiveSupport::TestCase
8
+ test "token inspect" do
9
+ loc = Location.new("foo", 0, 2)
10
+ token = Token.new(type: :foo, loc: loc)
11
+ assert_equal "t(:foo, \"foo\")", token.inspect
12
+ end
13
+ end
14
+ end
15
+ end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_html
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.12
4
+ version: 1.0.0
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-15 00:00:00.000000000 Z
11
+ date: 2017-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ast
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: erubi
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -84,16 +98,16 @@ dependencies:
84
98
  name: html_tokenizer
85
99
  requirement: !ruby/object:Gem::Requirement
86
100
  requirements:
87
- - - ">="
101
+ - - "~>"
88
102
  - !ruby/object:Gem::Version
89
- version: '0'
103
+ version: 0.0.5
90
104
  type: :runtime
91
105
  prerelease: false
92
106
  version_requirements: !ruby/object:Gem::Requirement
93
107
  requirements:
94
- - - ">="
108
+ - - "~>"
95
109
  - !ruby/object:Gem::Version
96
- version: '0'
110
+ version: 0.0.5
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: rake
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -119,6 +133,8 @@ files:
119
133
  - MIT-LICENSE
120
134
  - Rakefile
121
135
  - lib/better_html.rb
136
+ - lib/better_html/ast/iterator.rb
137
+ - lib/better_html/ast/node.rb
122
138
  - lib/better_html/better_erb.rb
123
139
  - lib/better_html/better_erb/erubi_implementation.rb
124
140
  - lib/better_html/better_erb/erubis_implementation.rb
@@ -128,37 +144,35 @@ files:
128
144
  - lib/better_html/errors.rb
129
145
  - lib/better_html/helpers.rb
130
146
  - lib/better_html/html_attributes.rb
131
- - lib/better_html/node_iterator.rb
132
- - lib/better_html/node_iterator/attribute.rb
133
- - lib/better_html/node_iterator/base.rb
134
- - lib/better_html/node_iterator/cdata.rb
135
- - lib/better_html/node_iterator/comment.rb
136
- - lib/better_html/node_iterator/content_node.rb
137
- - lib/better_html/node_iterator/element.rb
138
- - lib/better_html/node_iterator/html_erb.rb
139
- - lib/better_html/node_iterator/html_lodash.rb
140
- - lib/better_html/node_iterator/javascript_erb.rb
141
- - lib/better_html/node_iterator/location.rb
142
- - lib/better_html/node_iterator/text.rb
143
- - lib/better_html/node_iterator/token.rb
147
+ - lib/better_html/parser.rb
144
148
  - lib/better_html/railtie.rb
145
149
  - lib/better_html/test_helper/ruby_expr.rb
146
150
  - lib/better_html/test_helper/safe_erb_tester.rb
147
151
  - lib/better_html/test_helper/safe_lodash_tester.rb
148
152
  - lib/better_html/test_helper/safety_error.rb
149
- - lib/better_html/tree.rb
153
+ - lib/better_html/tokenizer/base_erb.rb
154
+ - lib/better_html/tokenizer/html_erb.rb
155
+ - lib/better_html/tokenizer/html_lodash.rb
156
+ - lib/better_html/tokenizer/javascript_erb.rb
157
+ - lib/better_html/tokenizer/location.rb
158
+ - lib/better_html/tokenizer/token.rb
159
+ - lib/better_html/tokenizer/token_array.rb
160
+ - lib/better_html/tree/attribute.rb
161
+ - lib/better_html/tree/attributes_list.rb
162
+ - lib/better_html/tree/tag.rb
150
163
  - lib/better_html/version.rb
151
164
  - lib/tasks/better_html_tasks.rake
152
165
  - test/better_html/better_erb/implementation_test.rb
153
166
  - test/better_html/helpers_test.rb
154
- - test/better_html/node_iterator/html_erb_test.rb
155
- - test/better_html/node_iterator/html_lodash_test.rb
156
- - test/better_html/node_iterator/location_test.rb
157
- - test/better_html/node_iterator_test.rb
167
+ - test/better_html/parser_test.rb
158
168
  - test/better_html/test_helper/ruby_expr_test.rb
159
169
  - test/better_html/test_helper/safe_erb_tester_test.rb
160
170
  - test/better_html/test_helper/safe_lodash_tester_test.rb
161
- - test/better_html/tree_test.rb
171
+ - test/better_html/tokenizer/html_erb_test.rb
172
+ - test/better_html/tokenizer/html_lodash_test.rb
173
+ - test/better_html/tokenizer/location_test.rb
174
+ - test/better_html/tokenizer/token_array_test.rb
175
+ - test/better_html/tokenizer/token_test.rb
162
176
  - test/dummy/README.rdoc
163
177
  - test/dummy/Rakefile
164
178
  - test/dummy/app/assets/javascripts/application.js
@@ -255,12 +269,13 @@ test_files:
255
269
  - test/dummy/Rakefile
256
270
  - test/test_helper.rb
257
271
  - test/better_html/helpers_test.rb
258
- - test/better_html/node_iterator_test.rb
259
- - test/better_html/node_iterator/location_test.rb
260
- - test/better_html/node_iterator/html_lodash_test.rb
261
- - test/better_html/node_iterator/html_erb_test.rb
272
+ - test/better_html/parser_test.rb
262
273
  - test/better_html/better_erb/implementation_test.rb
263
274
  - test/better_html/test_helper/safe_erb_tester_test.rb
264
275
  - test/better_html/test_helper/safe_lodash_tester_test.rb
265
276
  - test/better_html/test_helper/ruby_expr_test.rb
266
- - test/better_html/tree_test.rb
277
+ - test/better_html/tokenizer/location_test.rb
278
+ - test/better_html/tokenizer/html_lodash_test.rb
279
+ - test/better_html/tokenizer/html_erb_test.rb
280
+ - test/better_html/tokenizer/token_array_test.rb
281
+ - test/better_html/tokenizer/token_test.rb