fast_haml 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.gitmodules +3 -0
  4. data/.rspec +2 -0
  5. data/.travis.yml +25 -0
  6. data/Appraisals +26 -0
  7. data/CHANGELOG.md +2 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +96 -0
  11. data/Rakefile +11 -0
  12. data/benchmark/rendering.rb +29 -0
  13. data/bin/fast_haml +4 -0
  14. data/ext/attribute_builder/attribute_builder.c +259 -0
  15. data/ext/attribute_builder/extconf.rb +3 -0
  16. data/fast_haml.gemspec +35 -0
  17. data/gemfiles/rails_4.0.gemfile +9 -0
  18. data/gemfiles/rails_4.1.gemfile +9 -0
  19. data/gemfiles/rails_4.2.gemfile +9 -0
  20. data/gemfiles/rails_edge.gemfile +10 -0
  21. data/haml_spec_test.rb +22 -0
  22. data/lib/fast_haml/ast.rb +112 -0
  23. data/lib/fast_haml/cli.rb +38 -0
  24. data/lib/fast_haml/compiler.rb +325 -0
  25. data/lib/fast_haml/element_parser.rb +288 -0
  26. data/lib/fast_haml/engine.rb +32 -0
  27. data/lib/fast_haml/filter_compilers/base.rb +29 -0
  28. data/lib/fast_haml/filter_compilers/cdata.rb +15 -0
  29. data/lib/fast_haml/filter_compilers/css.rb +15 -0
  30. data/lib/fast_haml/filter_compilers/escaped.rb +22 -0
  31. data/lib/fast_haml/filter_compilers/javascript.rb +15 -0
  32. data/lib/fast_haml/filter_compilers/plain.rb +17 -0
  33. data/lib/fast_haml/filter_compilers/preserve.rb +30 -0
  34. data/lib/fast_haml/filter_compilers/ruby.rb +13 -0
  35. data/lib/fast_haml/filter_compilers.rb +37 -0
  36. data/lib/fast_haml/filter_parser.rb +54 -0
  37. data/lib/fast_haml/html.rb +44 -0
  38. data/lib/fast_haml/indent_tracker.rb +84 -0
  39. data/lib/fast_haml/line_parser.rb +66 -0
  40. data/lib/fast_haml/parser.rb +251 -0
  41. data/lib/fast_haml/parser_utils.rb +17 -0
  42. data/lib/fast_haml/rails_handler.rb +10 -0
  43. data/lib/fast_haml/railtie.rb +8 -0
  44. data/lib/fast_haml/ruby_multiline.rb +23 -0
  45. data/lib/fast_haml/static_hash_parser.rb +113 -0
  46. data/lib/fast_haml/syntax_error.rb +10 -0
  47. data/lib/fast_haml/text_compiler.rb +69 -0
  48. data/lib/fast_haml/tilt.rb +16 -0
  49. data/lib/fast_haml/version.rb +3 -0
  50. data/lib/fast_haml.rb +10 -0
  51. data/spec/rails/Rakefile +6 -0
  52. data/spec/rails/app/assets/images/.keep +0 -0
  53. data/spec/rails/app/assets/javascripts/application.js +13 -0
  54. data/spec/rails/app/assets/stylesheets/application.css +15 -0
  55. data/spec/rails/app/controllers/application_controller.rb +5 -0
  56. data/spec/rails/app/controllers/books_controller.rb +8 -0
  57. data/spec/rails/app/controllers/concerns/.keep +0 -0
  58. data/spec/rails/app/helpers/application_helper.rb +2 -0
  59. data/spec/rails/app/mailers/.keep +0 -0
  60. data/spec/rails/app/models/.keep +0 -0
  61. data/spec/rails/app/models/book.rb +9 -0
  62. data/spec/rails/app/models/concerns/.keep +0 -0
  63. data/spec/rails/app/views/books/hello.html.haml +2 -0
  64. data/spec/rails/app/views/books/with_capture.html.haml +4 -0
  65. data/spec/rails/app/views/books/with_variables.html.haml +4 -0
  66. data/spec/rails/app/views/layouts/application.html.haml +9 -0
  67. data/spec/rails/bin/bundle +3 -0
  68. data/spec/rails/bin/rails +4 -0
  69. data/spec/rails/bin/rake +4 -0
  70. data/spec/rails/bin/setup +29 -0
  71. data/spec/rails/config/application.rb +12 -0
  72. data/spec/rails/config/boot.rb +3 -0
  73. data/spec/rails/config/database.yml +25 -0
  74. data/spec/rails/config/environment.rb +5 -0
  75. data/spec/rails/config/environments/development.rb +41 -0
  76. data/spec/rails/config/environments/production.rb +79 -0
  77. data/spec/rails/config/environments/test.rb +42 -0
  78. data/spec/rails/config/initializers/assets.rb +11 -0
  79. data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
  80. data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
  81. data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
  82. data/spec/rails/config/initializers/inflections.rb +16 -0
  83. data/spec/rails/config/initializers/mime_types.rb +4 -0
  84. data/spec/rails/config/initializers/secret_key_base.rb +6 -0
  85. data/spec/rails/config/initializers/session_store.rb +3 -0
  86. data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
  87. data/spec/rails/config/locales/en.yml +23 -0
  88. data/spec/rails/config/routes.rb +7 -0
  89. data/spec/rails/config/secrets.yml +22 -0
  90. data/spec/rails/config.ru +4 -0
  91. data/spec/rails/db/seeds.rb +7 -0
  92. data/spec/rails/lib/assets/.keep +0 -0
  93. data/spec/rails/lib/tasks/.keep +0 -0
  94. data/spec/rails/log/.keep +0 -0
  95. data/spec/rails/public/404.html +67 -0
  96. data/spec/rails/public/422.html +67 -0
  97. data/spec/rails/public/500.html +66 -0
  98. data/spec/rails/public/favicon.ico +0 -0
  99. data/spec/rails/public/robots.txt +5 -0
  100. data/spec/rails/spec/requests/fast_haml_spec.rb +41 -0
  101. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  102. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  103. data/spec/rails_helper.rb +4 -0
  104. data/spec/render/attribute_spec.rb +209 -0
  105. data/spec/render/comment_spec.rb +61 -0
  106. data/spec/render/doctype_spec.rb +62 -0
  107. data/spec/render/element_spec.rb +165 -0
  108. data/spec/render/filters/cdata_spec.rb +12 -0
  109. data/spec/render/filters/css_spec.rb +45 -0
  110. data/spec/render/filters/escaped_spec.rb +14 -0
  111. data/spec/render/filters/javascript_spec.rb +44 -0
  112. data/spec/render/filters/plain_spec.rb +24 -0
  113. data/spec/render/filters/preserve_spec.rb +25 -0
  114. data/spec/render/filters/ruby_spec.rb +13 -0
  115. data/spec/render/filters_spec.rb +11 -0
  116. data/spec/render/haml_comment_spec.rb +24 -0
  117. data/spec/render/multiline_spec.rb +39 -0
  118. data/spec/render/plain_spec.rb +20 -0
  119. data/spec/render/preserve_spec.rb +8 -0
  120. data/spec/render/sanitize_spec.rb +36 -0
  121. data/spec/render/script_spec.rb +74 -0
  122. data/spec/render/silent_script_spec.rb +97 -0
  123. data/spec/render/unescape_spec.rb +40 -0
  124. data/spec/spec_helper.rb +49 -0
  125. data/spec/tilt_spec.rb +33 -0
  126. metadata +427 -0
@@ -0,0 +1,41 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'FastHaml with Rails', type: :request do
4
+ it 'renders views' do
5
+ get '/books/hello'
6
+ expect(response).to be_ok
7
+ expect(response).to render_template('books/hello')
8
+ expect(response).to render_template('layouts/application')
9
+ expect(response.body).to include('<span>Hello, World</span>')
10
+ end
11
+
12
+ it 'renders views with variables' do
13
+ get '/books/with_variables?title=nanika'
14
+ expect(response).to be_ok
15
+ expect(response).to render_template('books/with_variables')
16
+ expect(response).to render_template('layouts/application')
17
+ expect(response.body).to include('<p>nanika</p>')
18
+ end
19
+
20
+ it 'escapes non-html_safe string' do
21
+ uri = URI.parse('/books/with_variables')
22
+ uri.query = URI.encode_www_form(title: '<script>alert(1)</script>')
23
+ get uri.to_s
24
+ expect(response).to be_ok
25
+ expect(response).to render_template('books/with_variables')
26
+ expect(response).to render_template('layouts/application')
27
+ expect(response.body).to include('<a href="/books/hello">hello</a>')
28
+ expect(response.body).to include('<p>&lt;script&gt;alert(1)&lt;/script&gt;</p>')
29
+ end
30
+
31
+ it 'does not escape object which returns html_safe string by to_s' do
32
+ get '/books/with_variables?title=nanika'
33
+ expect(response.body).to include('<span>nanika</span>')
34
+ end
35
+
36
+ it 'works with capture method' do
37
+ get '/books/with_capture'
38
+ expect(response).to be_ok
39
+ expect(response.body).to include("<div><div>\n<p>Hello</p>\n</div>\n</div>\n")
40
+ end
41
+ end
File without changes
File without changes
@@ -0,0 +1,4 @@
1
+ ENV["RAILS_ENV"] ||= 'test'
2
+ require 'spec_helper'
3
+ require File.expand_path("../rails/config/environment", __FILE__)
4
+ require 'rspec/rails'
@@ -0,0 +1,209 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Attributes rendering', type: :render do
4
+ it 'parses attributes' do
5
+ expect(render_string('%span{class: "x"} hello')).to eq(%Q{<span class='x'>hello</span>\n})
6
+ end
7
+
8
+ it 'parses attributes' do
9
+ expect(render_string('%span{class: "x", "old" => 2} hello')).to eq(%Q{<span class='x' old='2'>hello</span>\n})
10
+ end
11
+
12
+ it 'is not element with id attribute' do
13
+ expect(render_string('#{1 + 2}')).to eq("3\n")
14
+ end
15
+
16
+ it 'renders dynamic attributes' do
17
+ expect(render_string(%q|%span#main{class: "na#{'ni'}ka"} hello|)).to eq(%Q{<span class='nanika' id='main'>hello</span>\n})
18
+ end
19
+
20
+ it 'renders array class' do
21
+ expect(render_string('%span.c2{class: "c1"}')).to eq("<span class='c1 c2'></span>\n")
22
+ expect(render_string('%span.c2{class: ["c1", "c3"]}')).to eq("<span class='c1 c2 c3'></span>\n")
23
+ end
24
+
25
+ it 'merges classes' do
26
+ expect(render_string(<<HAML)).to eq("<span class='c1 c2 content {}' id='main_id1_id3_id2'>hello</span>\n")
27
+ - h1 = {class: 'c1', id: ['id1', 'id3']}
28
+ - h2 = {class: [{}, 'c2'], id: 'id2'}
29
+ %span#main.content{h1, h2} hello
30
+ HAML
31
+ end
32
+
33
+ it 'escapes' do
34
+ expect(render_string(%q|%span{class: "x\"y'z"} hello|)).to eq(%Q{<span class='x&quot;y&#39;z'>hello</span>\n})
35
+ end
36
+
37
+ it "doesn't parse extra brace" do
38
+ expect(render_string('%span{foo: 1}{bar: 2}')).to eq("<span foo='1'>{bar: 2}</span>\n")
39
+ end
40
+
41
+ it 'renders only name if value is true' do
42
+ expect(render_string(%q|%span{foo: true, bar: 1} hello|)).to eq(%Q{<span bar='1' foo>hello</span>\n})
43
+ end
44
+
45
+ context 'with xhtml format' do
46
+ it 'renders name="name" if value is true' do
47
+ expect(render_string(%q|%span{foo: true, bar: 1} hello|, format: :xhtml)).to eq(%Q{<span bar='1' foo='foo'>hello</span>\n})
48
+ end
49
+ end
50
+
51
+ it 'renders nested attributes' do
52
+ expect(render_string(%q|%span{foo: {bar: 1+2}} hello|)).to eq(%Q|<span foo='{:bar=&gt;3}'>hello</span>\n|)
53
+ end
54
+
55
+ it 'renders code attributes' do
56
+ expect(render_string(<<HAML)).to eq(%Q|<span bar='{:hoge=&gt;:fuga}' baz foo='1'>hello</span>\n|)
57
+ - attrs = { foo: 1, bar: { hoge: :fuga }, baz: true }
58
+ %span{attrs} hello
59
+ HAML
60
+ end
61
+
62
+ it 'renders dstr attributes' do
63
+ expect(render_string(<<HAML)).to eq(%Q|<span data='x{:foo=&gt;1}y'>hello</span>\n|)
64
+ - data = { foo: 1 }
65
+ %span{data: "x\#{data}y"} hello
66
+ HAML
67
+ end
68
+
69
+ it 'renders nested dstr attributes' do
70
+ expect(render_string(<<'HAML')).to eq(%Q|<span foo='{:bar=&gt;&quot;x1y&quot;}'>hello</span>\n|)
71
+ - data = { foo: 1 }
72
+ %span{foo: {bar: "x#{1}y"}} hello
73
+ HAML
74
+ end
75
+
76
+ it 'optimize send case' do
77
+ expect(render_string('%span{foo: {bar: 1+2}} hello')).to eq("<span foo='{:bar=&gt;3}'>hello</span>\n")
78
+ end
79
+
80
+ it 'merges static id' do
81
+ expect(render_string('#foo{id: "bar"} baz')).to eq("<div id='foo_bar'>baz</div>\n")
82
+ end
83
+
84
+ it 'merges static class' do
85
+ expect(render_string('.foo{class: "bar"} baz')).to eq("<div class='bar foo'>baz</div>\n")
86
+ expect(render_string(<<'HAML')).to eq("<div class='bar foo'>baz</div>\n")
87
+ - bar = 'bar'
88
+ .foo{class: "#{bar}"} baz
89
+ HAML
90
+ end
91
+
92
+ it 'converts underscore to hyphen in data attributes' do
93
+ expect(render_string("%span{data: {foo_bar: 'baz'}}")).to eq("<span data-foo-bar='baz'></span>\n")
94
+ expect(render_string("- h = {foo_bar: 'baz'}\n%span{data: h}")).to eq("<span data-foo-bar='baz'></span>\n")
95
+ end
96
+
97
+ context 'with unmatched brace' do
98
+ it 'raises error' do
99
+ expect { render_string('%span{foo hello') }.to raise_error(FastHaml::SyntaxError)
100
+ end
101
+
102
+ it 'tries to parse next lines' do
103
+ expect(render_string(<<HAML)).to eq("<span bar='2' foo='1'>hello</span>\n")
104
+ %span{foo: 1,
105
+ bar: 2} hello
106
+ HAML
107
+ end
108
+
109
+ it "doesn't try to parse next lines without trailing comma" do
110
+ expect { render_string(<<HAML) }.to raise_error(FastHaml::SyntaxError)
111
+ %span{foo: 1
112
+ , bar: 2} hello
113
+ HAML
114
+ end
115
+ end
116
+
117
+ context 'with data attributes' do
118
+ it 'renders nested attributes' do
119
+ expect(render_string(%q|%span{data: {foo: 1, bar: 'baz', :hoge => :fuga, k1: { k2: 'v3' }}} hello|)).to eq(%Q{<span data-bar='baz' data-foo='1' data-hoge='fuga' data-k1-k2='v3'>hello</span>\n})
120
+ end
121
+
122
+ it 'renders nested dynamic attributes' do
123
+ expect(render_string(%q|%span{data: {foo: "b#{'a'}r"}} hello|)).to eq(%Q{<span data-foo='bar'>hello</span>\n})
124
+ end
125
+
126
+ it 'renders nested attributes' do
127
+ expect(render_string(%q|%span{data: {foo: 1, bar: 2+3}} hello|)).to eq(%Q{<span data-bar='5' data-foo='1'>hello</span>\n})
128
+ end
129
+
130
+ it 'renders nested code attributes' do
131
+ expect(render_string(<<HAML)).to eq(%Q{<span data-bar='2' data-foo='1'>hello</span>\n})
132
+ - data = { foo: 1, bar: 2 }
133
+ %span{data: data} hello
134
+ HAML
135
+ end
136
+ end
137
+
138
+ describe 'with HTML-style attributes' do
139
+ it 'parses simple values' do
140
+ expect(render_string('%span(foo=1 bar=3) hello')).to eq("<span bar='3' foo='1'>hello</span>\n")
141
+ end
142
+
143
+ it 'parses variables' do
144
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='xxx'>hello</span>\n")
145
+ - foo = 'xxx'
146
+ %span(foo=foo bar=3) hello
147
+ HAML
148
+ end
149
+
150
+ it 'parses attributes with old syntax' do
151
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='foo'>hello</span>\n")
152
+ - foo = 'foo'
153
+ %span(foo=foo){bar: 3} hello
154
+ HAML
155
+ end
156
+
157
+ it 'parses multiline attribute list' do
158
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='1'>hello</span>\n")
159
+ %span(foo=1
160
+
161
+ bar=3) hello
162
+ HAML
163
+ end
164
+
165
+ it "doesn't parse extra parens" do
166
+ expect(render_string('%span(foo=1)(bar=3) hello')).to eq("<span foo='1'>(bar=3) hello</span>\n")
167
+ end
168
+
169
+ it 'parses quoted value' do
170
+ expect(render_string('%span(foo=1 bar="baz") hello')).to eq("<span bar='baz' foo='1'>hello</span>\n")
171
+ expect(render_string("%span(foo=1 bar='baz') hello")).to eq("<span bar='baz' foo='1'>hello</span>\n")
172
+ end
173
+
174
+ it 'parses key-only attribute' do
175
+ expect(render_string('%span(foo bar=1) hello')).to eq("<span bar='1' foo>hello</span>\n")
176
+ end
177
+
178
+ it 'renders string interpolation' do
179
+ expect(render_string(%q|%span(foo=1 bar="baz#{1 + 2}") hello|)).to eq("<span bar='baz3' foo='1'>hello</span>\n")
180
+ expect(render_string(%q|%span(foo=1 bar='baz#{1 + 2}') hello|)).to eq("<span bar='baz3' foo='1'>hello</span>\n")
181
+ end
182
+
183
+
184
+ it 'parses escapes' do
185
+ expect(render_string(%q|%span(foo=1 bar="ba\"z") hello|)).to eq("<span bar='ba&quot;z' foo='1'>hello</span>\n")
186
+ expect(render_string(%q|%span(foo=1 bar='ba\'z') hello|)).to eq("<span bar='ba&#39;z' foo='1'>hello</span>\n")
187
+ end
188
+
189
+ it 'raises error when attributes list is unterminated' do
190
+ expect { render_string('%span(foo=1 bar=2') }.to raise_error(FastHaml::SyntaxError)
191
+ end
192
+
193
+ it 'raises error when key is not alnum' do
194
+ expect { render_string('%span(foo=1 3.14=3) hello') }.to raise_error(FastHaml::SyntaxError)
195
+ end
196
+
197
+ it 'raises error when value is missing' do
198
+ expect { render_string('%span(foo=1 bar=) hello') }.to raise_error(FastHaml::SyntaxError)
199
+ end
200
+
201
+ it 'raises error when quote is unterminated' do
202
+ expect { render_string('%span(foo=1 bar="baz) hello') }.to raise_error(FastHaml::SyntaxError)
203
+ end
204
+
205
+ it 'raises error when string interpolation is unterminated' do
206
+ expect { render_string('%span(foo=1 bar="ba#{1") hello') }.to raise_error(FastHaml::SyntaxError)
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Comment rendering', type: :render do
4
+ it 'renders html comment' do
5
+ expect(render_string('/ comments')).to eq("<!-- comments -->\n")
6
+ end
7
+
8
+ it 'strips spaces' do
9
+ expect(render_string('/ comments ')).to eq("<!-- comments -->\n")
10
+ end
11
+
12
+ it 'renders structured comment' do
13
+ expect(render_string(<<HAML)).to eq("<span>hello</span>\n<!--\ngreat\n-->\n<span>world</span>\n")
14
+ %span hello
15
+ /
16
+ great
17
+ %span world
18
+ HAML
19
+ end
20
+
21
+ it 'renders comment with interpolation' do
22
+ expect(render_string(<<'HAML')).to eq("<span>hello</span>\n<!--\ngreat\n-->\n<span>world</span>\n")
23
+ - comment = 'great'
24
+ %span hello
25
+ /
26
+ #{comment}
27
+ %span world
28
+ HAML
29
+ end
30
+
31
+ it 'renders conditional comment' do
32
+ expect(render_string('/ [if IE] hello')).to eq("<!--[if IE]> hello <![endif]-->\n")
33
+ end
34
+
35
+ it 'renders conditional comment with children' do
36
+ expect(render_string(<<HAML)).to eq("<!--[if IE]>\n<span>hello</span>\nworld\n<![endif]-->\n")
37
+ /[if IE]
38
+ %span hello
39
+ world
40
+ HAML
41
+ end
42
+
43
+ it 'parses nested conditional comment' do
44
+ expect(render_string(<<HAML)).to eq("<!--[[if IE]]>\n<span>hello</span>\nworld\n<![endif]-->\n")
45
+ /[[if IE]]
46
+ %span hello
47
+ world
48
+ HAML
49
+ end
50
+
51
+ it 'raises error if conditional comment bracket is unbalanced' do
52
+ expect { render_string('/[[if IE]') }.to raise_error(FastHaml::SyntaxError)
53
+ end
54
+
55
+ it 'raises error if both comment text and children are given' do
56
+ expect { render_string(<<HAML) }.to raise_error(FastHaml::SyntaxError)
57
+ / hehehe
58
+ %span hello
59
+ HAML
60
+ end
61
+ end
@@ -0,0 +1,62 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Doctype rendering', type: :render do
4
+ it 'ignores 1 or 2 exclamation marks' do
5
+ expect(render_string('!')).to eq("!\n")
6
+ expect(render_string('!!')).to eq("!!\n")
7
+ end
8
+
9
+ context 'with html format' do
10
+ it 'renders html5 doctype by default' do
11
+ expect(render_string('!!!')).to eq("<!DOCTYPE html>\n")
12
+ end
13
+
14
+ it 'renders xml doctype (silent)' do
15
+ expect(render_string('!!! xml')).to eq("\n")
16
+ end
17
+ end
18
+
19
+ context 'with html4 format' do
20
+ it 'renders transitional doctype by default' do
21
+ expect(render_string('!!!', format: :html4)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n|)
22
+ end
23
+
24
+ it 'renders frameset doctype' do
25
+ expect(render_string('!!! frameset', format: :html4)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">\n|)
26
+ end
27
+
28
+ it 'renders strict doctype' do
29
+ expect(render_string('!!! strict', format: :html4)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">\n|)
30
+ end
31
+ end
32
+
33
+ context 'with xhtml format' do
34
+ it 'renders transitional doctype by default' do
35
+ expect(render_string('!!!', format: :xhtml)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n|)
36
+ end
37
+
38
+ it 'renders xml doctype' do
39
+ expect(render_string('!!! xml', format: :xhtml)).to eq("<?xml version='1.0' encoding='utf-8' ?>\n")
40
+ end
41
+
42
+ it 'renders xhtml 1.1 doctype' do
43
+ expect(render_string('!!! 1.1', format: :xhtml)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n|)
44
+ end
45
+
46
+ it 'renders xhtml mobile doctype' do
47
+ expect(render_string('!!! mobile', format: :xhtml)).to eq(%Q|<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">\n|)
48
+ end
49
+
50
+ it 'renders xhtml basic doctype' do
51
+ expect(render_string('!!! basic', format: :xhtml)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">\n|)
52
+ end
53
+
54
+ it 'renders xhtml frameset doctype' do
55
+ expect(render_string('!!! frameset', format: :xhtml)).to eq(%Q|<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">\n|)
56
+ end
57
+
58
+ it 'renders html 5 doctype with xhtml syntax' do
59
+ expect(render_string('!!! 5', format: :xhtml)).to eq(%Q|<!DOCTYPE html>\n|)
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,165 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Element rendering', type: :render do
4
+ it 'parses one-line element' do
5
+ expect(render_string('%span hello')).to eq("<span>hello</span>\n")
6
+ end
7
+
8
+ it 'parses multi-line element' do
9
+ expect(render_string(<<HAML)).to eq("<span>\nhello\n</span>\n")
10
+ %span
11
+ hello
12
+ HAML
13
+ end
14
+
15
+ it 'parses nested elements' do
16
+ expect(render_string(<<HAML)).to eq("<span>\n<b>\nhello\n</b>\n<i>\n<small>world</small>\n</i>\n</span>\n")
17
+ %span
18
+ %b
19
+ hello
20
+ %i
21
+ %small world
22
+ HAML
23
+ end
24
+
25
+ it 'parses multi-line texts' do
26
+ expect(render_string(<<HAML)).to eq("<span>\n<b>\nhello\nworld\n</b>\n</span>\n")
27
+ %span
28
+ %b
29
+ hello
30
+ world
31
+ HAML
32
+ end
33
+
34
+ it 'skips empty lines' do
35
+ expect(render_string(<<HAML)).to eq("<span>\n<b>\nhello\n</b>\n</span>\n")
36
+ %span
37
+
38
+ %b
39
+
40
+ hello
41
+
42
+ HAML
43
+ end
44
+
45
+ it 'raises error if indent is wrong' do
46
+ expect { render_string(<<HAML) }.to raise_error(FastHaml::IndentTracker::IndentMismatch)
47
+ %div
48
+ %div
49
+ %div
50
+ %div
51
+ HAML
52
+ end
53
+
54
+ it 'parses classes' do
55
+ expect(render_string('%span.foo.bar hello')).to eq(%Q{<span class='foo bar'>hello</span>\n})
56
+ end
57
+
58
+ it 'parses id' do
59
+ expect(render_string('%span#foo-bar hello')).to eq(%Q{<span id='foo-bar'>hello</span>\n})
60
+ end
61
+
62
+ it 'parses classes and id' do
63
+ expect(render_string('%span.foo#foo-bar.bar hello')).to eq(%Q{<span class='foo bar' id='foo-bar'>hello</span>\n})
64
+ end
65
+
66
+ context 'with invalid tag name' do
67
+ it 'raises error' do
68
+ expect { render_string('%.foo') }.to raise_error(FastHaml::SyntaxError)
69
+ end
70
+ end
71
+
72
+ it 'parses #' do
73
+ expect(render_string('#main')).to eq(%Q{<div id='main'></div>\n})
74
+ end
75
+
76
+ it 'parses .' do
77
+ expect(render_string('.wrapper.main')).to eq(%Q{<div class='wrapper main'></div>\n})
78
+ end
79
+
80
+ it 'parses Ruby multiline' do
81
+ expect(render_string(<<HAML)).to eq("<div>\n<span>2+3i</span>\n</div>\n")
82
+ %div
83
+ %span= Complex(2,
84
+ 3)
85
+ HAML
86
+ end
87
+
88
+ it 'parses string interpolation' do
89
+ expect(render_string(%q|%span hello <span> #{'</span>'} </span>|)).to eq("<span>hello <span> &lt;/span&gt; </span></span>\n")
90
+ expect(render_string(<<'HAML')).to eq("<span>\nhello <span> &lt;/span&gt; </span>\n</span>\n")
91
+ %span
92
+ hello <span> #{{text: '</span>'}[:text]} </span>
93
+ HAML
94
+ expect(render_string(<<'HAML')).to eq("<span>\nhello <span> &lt;/span&gt; </span>\n</span>\n")
95
+ - @var = '</span>'
96
+ %span
97
+ hello <span> #@var </span>
98
+ HAML
99
+ end
100
+
101
+ it 'parses string interpolation with multibyte characters' do
102
+ expect(render_string(%q|#{'日本語'} にほんご|)).to eq("日本語 にほんご\n")
103
+ end
104
+
105
+ it 'recognized escaped string interpolation' do
106
+ expect(render_string(%q|%p hello \#{1 + 2}|)).to eq("<p>hello \#{1 + 2}</p>\n")
107
+ end
108
+
109
+ it 'parses self-closing tag' do
110
+ expect(render_string('%p/')).to eq("<p>\n")
111
+ end
112
+
113
+ it 'renders some attributes as self-closing by default' do
114
+ expect(render_string('%meta{"http-equiv" => "Content-Type", :content => "text/html"}')).to eq("<meta content='text/html' http-equiv='Content-Type'>\n")
115
+ end
116
+
117
+ it 'parses nuke-inner-whitespace (<)' do
118
+ expect(render_string(<<HAML)).to eq("<blockquote><div>\nFoo!\n</div></blockquote>\n")
119
+ %blockquote<
120
+ %div
121
+ Foo!
122
+ HAML
123
+ end
124
+
125
+ it 'renders pre tag as nuke-inner-whitespace by default' do
126
+ expect(render_string(<<HAML)).to eq("<pre>hello\nworld</pre>\n")
127
+ %pre
128
+ hello
129
+ world
130
+ HAML
131
+ end
132
+
133
+ it 'parses nuke-outer-whitespace (>)' do
134
+ expect(render_string(<<HAML)).to eq("<img><span>hello</span><img>\n")
135
+ %img
136
+ %span> hello
137
+ %img
138
+ HAML
139
+ end
140
+
141
+ it 'parses nuke-whitespaces' do
142
+ expect(render_string(<<HAML)).to eq("<img><pre>foo\nbar</pre><img>\n")
143
+ %img
144
+ %pre><
145
+ foo
146
+ bar
147
+ %img
148
+ HAML
149
+ end
150
+
151
+ it 'parses == syntax' do
152
+ expect(render_string('%p== =#{1+2}hello')).to eq("<p>=3hello</p>\n")
153
+ end
154
+
155
+ it 'raises error if self-closing tag have text' do
156
+ expect { render_string('%p/ hello') }.to raise_error(FastHaml::SyntaxError)
157
+ end
158
+
159
+ it 'raises error if self-closing tag have children' do
160
+ expect { render_string(<<HAML) }.to raise_error(FastHaml::SyntaxError)
161
+ %p/
162
+ hello
163
+ HAML
164
+ end
165
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'CDATA filter rendering', type: :render do
4
+ it 'renders CDATA filter' do
5
+ expect(render_string(<<'HAML')).to eq("<![CDATA[\n hello\n world\n <span>hello</span>\n]]>\n")
6
+ :cdata
7
+ hello
8
+ #{'world'}
9
+ <span>hello</span>
10
+ HAML
11
+ end
12
+ end
@@ -0,0 +1,45 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'CSS filter rendering', type: :render do
4
+ it 'renders css filter' do
5
+ expect(render_string(<<HAML)).to eq("<div>\n<style>\n html { font-size: 12px; }\n</style>\n<span>hello</span>\n</div>\n")
6
+ %div
7
+ :css
8
+ html { font-size: 12px; }
9
+ %span hello
10
+ HAML
11
+ end
12
+
13
+ it 'keeps indent' do
14
+ expect(render_string(<<HAML)).to eq("<div>\n<style>\n html {\n font-size: 12px;\n }\n</style>\n<span>hello</span>\n</div>\n")
15
+ %div
16
+ :css
17
+ html {
18
+ font-size: 12px;
19
+ }
20
+ %span hello
21
+ HAML
22
+ end
23
+
24
+ it 'ignores empty filter' do
25
+ expect(render_string(<<HAML)).to eq("<div>\n<span>hello</span>\n</div>\n")
26
+ %div
27
+ :css
28
+ %span hello
29
+ HAML
30
+ end
31
+
32
+ it 'parses string interpolation' do
33
+ expect(render_string(<<'HAML')).to eq("<style>\n html { font-size: 12px; }\n</style>\n")
34
+ :css
35
+ html { font-size: #{10 + 2}px; }
36
+ HAML
37
+ end
38
+
39
+ it "doesn't escape in string interpolation" do
40
+ expect(render_string(<<'HAML')).to eq("<style>\n <span/>\n</style>\n")
41
+ :css
42
+ #{'<span/>'}
43
+ HAML
44
+ end
45
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Escaped filter rendering', type: :render do
4
+ it' renders escaped filter' do
5
+ expect(render_string(<<'HAML')).to eq("<span>start</span>\nhello\n &lt;p&gt;world&lt;/p&gt;\n&lt;span&gt;hello&lt;/span&gt;\n\n<span>end</span>\n")
6
+ %span start
7
+ :escaped
8
+ hello
9
+ #{'<p>world</p>'}
10
+ <span>hello</span>
11
+ %span end
12
+ HAML
13
+ end
14
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'JavaScript filter renderiong', type: :render do
4
+ it 'renders javascript filter' do
5
+ expect(render_string(<<HAML)).to eq("<div>\n<script>\n alert('hello');\n</script>\n<span>world</span>\n</div>\n")
6
+ %div
7
+ :javascript
8
+ alert('hello');
9
+ %span world
10
+ HAML
11
+ end
12
+
13
+ it 'keeps indent' do
14
+ expect(render_string(<<HAML)).to eq("<div>\n<script>\n alert('hello');\n \n alert('world');\n</script>\n</div>\n")
15
+ %div
16
+ :javascript
17
+ alert('hello');
18
+
19
+ alert('world');
20
+ HAML
21
+ end
22
+
23
+ it 'ignores empty filter' do
24
+ expect(render_string(<<HAML)).to eq("<div>\n<span>world</span>\n</div>\n")
25
+ %div
26
+ :javascript
27
+ %span world
28
+ HAML
29
+ end
30
+
31
+ it 'parses string interpolation' do
32
+ expect(render_string(<<'HAML')).to eq("<script>\n var x = 3;\n</script>\n")
33
+ :javascript
34
+ var x = #{1 + 2};
35
+ HAML
36
+ end
37
+
38
+ it "doesn't escape in string interpolation" do
39
+ expect(render_string(<<'HAML')).to eq("<script>\n <span/>\n</script>\n")
40
+ :javascript
41
+ #{'<span/>'}
42
+ HAML
43
+ end
44
+ end