faml 0.2.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 (140) 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 +27 -0
  6. data/Appraisals +26 -0
  7. data/CHANGELOG.md +47 -0
  8. data/Gemfile +8 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +115 -0
  11. data/Rakefile +28 -0
  12. data/benchmark/attribute_builder.haml +5 -0
  13. data/benchmark/rendering.rb +35 -0
  14. data/bin/faml +4 -0
  15. data/ext/attribute_builder/attribute_builder.c +261 -0
  16. data/ext/attribute_builder/extconf.rb +3 -0
  17. data/faml.gemspec +38 -0
  18. data/gemfiles/rails_4.0.gemfile +9 -0
  19. data/gemfiles/rails_4.1.gemfile +9 -0
  20. data/gemfiles/rails_4.2.gemfile +9 -0
  21. data/gemfiles/rails_edge.gemfile +10 -0
  22. data/haml_spec_test.rb +22 -0
  23. data/lib/faml.rb +10 -0
  24. data/lib/faml/ast.rb +112 -0
  25. data/lib/faml/cli.rb +38 -0
  26. data/lib/faml/compiler.rb +374 -0
  27. data/lib/faml/element_parser.rb +235 -0
  28. data/lib/faml/engine.rb +34 -0
  29. data/lib/faml/filter_compilers.rb +41 -0
  30. data/lib/faml/filter_compilers/base.rb +43 -0
  31. data/lib/faml/filter_compilers/cdata.rb +15 -0
  32. data/lib/faml/filter_compilers/coffee.rb +16 -0
  33. data/lib/faml/filter_compilers/css.rb +16 -0
  34. data/lib/faml/filter_compilers/escaped.rb +23 -0
  35. data/lib/faml/filter_compilers/javascript.rb +16 -0
  36. data/lib/faml/filter_compilers/markdown.rb +18 -0
  37. data/lib/faml/filter_compilers/plain.rb +15 -0
  38. data/lib/faml/filter_compilers/preserve.rb +26 -0
  39. data/lib/faml/filter_compilers/ruby.rb +17 -0
  40. data/lib/faml/filter_compilers/sass.rb +15 -0
  41. data/lib/faml/filter_compilers/scss.rb +16 -0
  42. data/lib/faml/filter_compilers/tilt_base.rb +34 -0
  43. data/lib/faml/filter_parser.rb +54 -0
  44. data/lib/faml/html.rb +58 -0
  45. data/lib/faml/indent_tracker.rb +84 -0
  46. data/lib/faml/line_parser.rb +66 -0
  47. data/lib/faml/newline.rb +30 -0
  48. data/lib/faml/parser.rb +211 -0
  49. data/lib/faml/parser_utils.rb +17 -0
  50. data/lib/faml/rails_handler.rb +10 -0
  51. data/lib/faml/railtie.rb +9 -0
  52. data/lib/faml/ruby_multiline.rb +23 -0
  53. data/lib/faml/script_parser.rb +84 -0
  54. data/lib/faml/static_hash_parser.rb +113 -0
  55. data/lib/faml/syntax_error.rb +10 -0
  56. data/lib/faml/text_compiler.rb +69 -0
  57. data/lib/faml/tilt.rb +17 -0
  58. data/lib/faml/version.rb +3 -0
  59. data/spec/compiler_newline_spec.rb +162 -0
  60. data/spec/rails/Rakefile +6 -0
  61. data/spec/rails/app/assets/images/.keep +0 -0
  62. data/spec/rails/app/assets/javascripts/application.js +13 -0
  63. data/spec/rails/app/assets/stylesheets/application.css +15 -0
  64. data/spec/rails/app/controllers/application_controller.rb +5 -0
  65. data/spec/rails/app/controllers/books_controller.rb +8 -0
  66. data/spec/rails/app/controllers/concerns/.keep +0 -0
  67. data/spec/rails/app/helpers/application_helper.rb +2 -0
  68. data/spec/rails/app/mailers/.keep +0 -0
  69. data/spec/rails/app/models/.keep +0 -0
  70. data/spec/rails/app/models/book.rb +9 -0
  71. data/spec/rails/app/models/concerns/.keep +0 -0
  72. data/spec/rails/app/views/books/hello.html.haml +2 -0
  73. data/spec/rails/app/views/books/with_capture.html.haml +4 -0
  74. data/spec/rails/app/views/books/with_variables.html.haml +4 -0
  75. data/spec/rails/app/views/layouts/application.html.haml +9 -0
  76. data/spec/rails/bin/bundle +3 -0
  77. data/spec/rails/bin/rails +4 -0
  78. data/spec/rails/bin/rake +4 -0
  79. data/spec/rails/bin/setup +29 -0
  80. data/spec/rails/config.ru +4 -0
  81. data/spec/rails/config/application.rb +12 -0
  82. data/spec/rails/config/boot.rb +3 -0
  83. data/spec/rails/config/database.yml +25 -0
  84. data/spec/rails/config/environment.rb +5 -0
  85. data/spec/rails/config/environments/development.rb +41 -0
  86. data/spec/rails/config/environments/production.rb +79 -0
  87. data/spec/rails/config/environments/test.rb +42 -0
  88. data/spec/rails/config/initializers/assets.rb +11 -0
  89. data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
  90. data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
  91. data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
  92. data/spec/rails/config/initializers/inflections.rb +16 -0
  93. data/spec/rails/config/initializers/mime_types.rb +4 -0
  94. data/spec/rails/config/initializers/secret_key_base.rb +6 -0
  95. data/spec/rails/config/initializers/session_store.rb +3 -0
  96. data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
  97. data/spec/rails/config/locales/en.yml +23 -0
  98. data/spec/rails/config/routes.rb +7 -0
  99. data/spec/rails/config/secrets.yml +22 -0
  100. data/spec/rails/db/seeds.rb +7 -0
  101. data/spec/rails/lib/assets/.keep +0 -0
  102. data/spec/rails/lib/tasks/.keep +0 -0
  103. data/spec/rails/log/.keep +0 -0
  104. data/spec/rails/public/404.html +67 -0
  105. data/spec/rails/public/422.html +67 -0
  106. data/spec/rails/public/500.html +66 -0
  107. data/spec/rails/public/favicon.ico +0 -0
  108. data/spec/rails/public/robots.txt +5 -0
  109. data/spec/rails/spec/requests/faml_spec.rb +41 -0
  110. data/spec/rails/vendor/assets/javascripts/.keep +0 -0
  111. data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
  112. data/spec/rails_helper.rb +4 -0
  113. data/spec/render/attribute_spec.rb +241 -0
  114. data/spec/render/comment_spec.rb +61 -0
  115. data/spec/render/doctype_spec.rb +57 -0
  116. data/spec/render/element_spec.rb +136 -0
  117. data/spec/render/filters/cdata_spec.rb +12 -0
  118. data/spec/render/filters/coffee_spec.rb +25 -0
  119. data/spec/render/filters/css_spec.rb +45 -0
  120. data/spec/render/filters/escaped_spec.rb +14 -0
  121. data/spec/render/filters/javascript_spec.rb +44 -0
  122. data/spec/render/filters/markdown_spec.rb +19 -0
  123. data/spec/render/filters/plain_spec.rb +24 -0
  124. data/spec/render/filters/preserve_spec.rb +24 -0
  125. data/spec/render/filters/ruby_spec.rb +13 -0
  126. data/spec/render/filters/sass_spec.rb +28 -0
  127. data/spec/render/filters/scss_spec.rb +32 -0
  128. data/spec/render/filters_spec.rb +11 -0
  129. data/spec/render/haml_comment_spec.rb +24 -0
  130. data/spec/render/multiline_spec.rb +39 -0
  131. data/spec/render/newline_spec.rb +83 -0
  132. data/spec/render/plain_spec.rb +20 -0
  133. data/spec/render/preserve_spec.rb +8 -0
  134. data/spec/render/sanitize_spec.rb +36 -0
  135. data/spec/render/script_spec.rb +81 -0
  136. data/spec/render/silent_script_spec.rb +97 -0
  137. data/spec/render/unescape_spec.rb +45 -0
  138. data/spec/spec_helper.rb +47 -0
  139. data/spec/tilt_spec.rb +33 -0
  140. metadata +489 -0
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ body {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body>
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
@@ -0,0 +1,5 @@
1
+ # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file
2
+ #
3
+ # To ban all spiders from the entire site uncomment the next two lines:
4
+ # User-agent: *
5
+ # Disallow: /
@@ -0,0 +1,41 @@
1
+ require 'rails_helper'
2
+
3
+ RSpec.describe 'Faml 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
@@ -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,241 @@
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 "renders boolean attributes" do
26
+ expect(render_string('%input{checked: true}')).to eq("<input checked>\n")
27
+ expect(render_string('%input{checked: false}')).to eq("<input>\n")
28
+ expect(render_string('%input{checked: nil}')).to eq("<input>\n")
29
+ expect(render_string('%input{checked: "a" == "a"}')).to eq("<input checked>\n")
30
+ expect(render_string('%input{checked: "a" != "a"}')).to eq("<input>\n")
31
+ expect(render_string("- x = nil\n%input{checked: x}")).to eq("<input>\n")
32
+ expect(render_string("- h = {checked: true}\n%input{h}")).to eq("<input checked>\n")
33
+ expect(render_string("- h = {checked: false}\n%input{h}")).to eq("<input>\n")
34
+ expect(render_string("- h = {checked: nil}\n%input{h}")).to eq("<input>\n")
35
+ end
36
+
37
+ it 'merges classes' do
38
+ expect(render_string(<<HAML)).to eq("<span class='c1 c2 content {}' id='main_id1_id3_id2'>hello</span>\n")
39
+ - h1 = {class: 'c1', id: ['id1', 'id3']}
40
+ - h2 = {class: [{}, 'c2'], id: 'id2'}
41
+ %span#main.content{h1, h2} hello
42
+ HAML
43
+ end
44
+
45
+ it 'strigify non-string classes' do
46
+ expect(render_string('%span.foo{class: :bar} hello')).to eq("<span class='bar foo'>hello</span>\n")
47
+ expect(render_string('%span.foo{class: 1} hello')).to eq("<span class='1 foo'>hello</span>\n")
48
+ end
49
+
50
+ it 'strigify non-string ids' do
51
+ expect(render_string('%span.#foo{id: :bar} hello')).to eq("<span id='foo_bar'>hello</span>\n")
52
+ end
53
+
54
+ it 'escapes' do
55
+ expect(render_string(%q|%span{class: "x\"y'z"} hello|)).to eq(%Q{<span class='x&quot;y&#39;z'>hello</span>\n})
56
+ end
57
+
58
+ it "doesn't parse extra brace" do
59
+ expect(render_string('%span{foo: 1}{bar: 2}')).to eq("<span foo='1'>{bar: 2}</span>\n")
60
+ end
61
+
62
+ it 'renders only name if value is true' do
63
+ expect(render_string(%q|%span{foo: true, bar: 1} hello|)).to eq(%Q{<span bar='1' foo>hello</span>\n})
64
+ end
65
+
66
+ it 'raises error when unparsable Ruby code is given' do
67
+ expect { render_string('%span{x ==== 2}') }.to raise_error(Faml::Compiler::UnparsableRubyCode)
68
+ end
69
+
70
+ context 'with xhtml format' do
71
+ it 'renders name="name" if value is true' do
72
+ expect(render_string(%q|%span{foo: true, bar: 1} hello|, format: :xhtml)).to eq(%Q{<span bar='1' foo='foo'>hello</span>\n})
73
+ end
74
+ end
75
+
76
+ it 'renders nested attributes' do
77
+ expect(render_string(%q|%span{foo: {bar: 1+2}} hello|)).to eq(%Q|<span foo='{:bar=&gt;3}'>hello</span>\n|)
78
+ end
79
+
80
+ it 'renders code attributes' do
81
+ expect(render_string(<<HAML)).to eq(%Q|<span bar='{:hoge=&gt;:fuga}' baz foo='1'>hello</span>\n|)
82
+ - attrs = { foo: 1, bar: { hoge: :fuga }, baz: true }
83
+ %span{attrs} hello
84
+ HAML
85
+ end
86
+
87
+ it 'renders dstr attributes' do
88
+ expect(render_string(<<HAML)).to eq(%Q|<span data='x{:foo=&gt;1}y'>hello</span>\n|)
89
+ - data = { foo: 1 }
90
+ %span{data: "x\#{data}y"} hello
91
+ HAML
92
+ end
93
+
94
+ it 'renders nested dstr attributes' do
95
+ expect(render_string(<<'HAML')).to eq(%Q|<span foo='{:bar=&gt;&quot;x1y&quot;}'>hello</span>\n|)
96
+ - data = { foo: 1 }
97
+ %span{foo: {bar: "x#{1}y"}} hello
98
+ HAML
99
+ end
100
+
101
+ it 'optimize send case' do
102
+ expect(render_string('%span{foo: {bar: 1+2}} hello')).to eq("<span foo='{:bar=&gt;3}'>hello</span>\n")
103
+ end
104
+
105
+ it 'merges static id' do
106
+ expect(render_string('#foo{id: "bar"} baz')).to eq("<div id='foo_bar'>baz</div>\n")
107
+ end
108
+
109
+ it 'merges static class' do
110
+ expect(render_string('.foo{class: "bar"} baz')).to eq("<div class='bar foo'>baz</div>\n")
111
+ expect(render_string(<<'HAML')).to eq("<div class='bar foo'>baz</div>\n")
112
+ - bar = 'bar'
113
+ .foo{class: "#{bar}"} baz
114
+ HAML
115
+ end
116
+
117
+ it 'converts underscore to hyphen in data attributes' do
118
+ expect(render_string("%span{data: {foo_bar: 'baz'}}")).to eq("<span data-foo-bar='baz'></span>\n")
119
+ expect(render_string("- h = {foo_bar: 'baz'}\n%span{data: h}")).to eq("<span data-foo-bar='baz'></span>\n")
120
+ end
121
+
122
+ context 'with unmatched brace' do
123
+ it 'raises error' do
124
+ expect { render_string('%span{foo hello') }.to raise_error(Faml::SyntaxError)
125
+ end
126
+
127
+ it 'tries to parse next lines' do
128
+ expect(render_string(<<HAML)).to eq("<span bar='2' foo='1'>hello</span>\n")
129
+ %span{foo: 1,
130
+ bar: 2} hello
131
+ HAML
132
+ end
133
+
134
+ it "doesn't try to parse next lines without trailing comma" do
135
+ expect { render_string(<<HAML) }.to raise_error(Faml::SyntaxError)
136
+ %span{foo: 1
137
+ , bar: 2} hello
138
+ HAML
139
+ end
140
+ end
141
+
142
+ context 'with data attributes' do
143
+ it 'renders nested attributes' do
144
+ 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})
145
+ end
146
+
147
+ it 'renders nested dynamic attributes' do
148
+ expect(render_string(%q|%span{data: {foo: "b#{'a'}r"}} hello|)).to eq(%Q{<span data-foo='bar'>hello</span>\n})
149
+ end
150
+
151
+ it 'renders nested attributes' do
152
+ 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})
153
+ end
154
+
155
+ it 'renders nested code attributes' do
156
+ expect(render_string(<<HAML)).to eq(%Q{<span data-bar='2' data-foo='1'>hello</span>\n})
157
+ - data = { foo: 1, bar: 2 }
158
+ %span{data: data} hello
159
+ HAML
160
+ end
161
+ end
162
+
163
+ describe 'with HTML-style attributes' do
164
+ it 'parses simple values' do
165
+ expect(render_string('%span(foo=1 bar=3) hello')).to eq("<span bar='3' foo='1'>hello</span>\n")
166
+ end
167
+
168
+ it 'parses variables' do
169
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='xxx'>hello</span>\n")
170
+ - foo = 'xxx'
171
+ %span(foo=foo bar=3) hello
172
+ HAML
173
+ end
174
+
175
+ it 'parses attributes with old syntax' do
176
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='foo'>hello</span>\n")
177
+ - foo = 'foo'
178
+ %span(foo=foo){bar: 3} hello
179
+ HAML
180
+ end
181
+
182
+ it 'parses multiline attribute list' do
183
+ expect(render_string(<<HAML)).to eq("<span data-bar='2' data-foo='1'>\n<span>hello</span>\n</span>\n")
184
+ %span{data: {foo: 1,
185
+ bar: 2}}
186
+ %span hello
187
+ HAML
188
+ end
189
+
190
+ it 'parses HTML-style multiline attribute list' do
191
+ expect(render_string(<<HAML)).to eq("<span bar='3' foo='1'>hello</span>\n")
192
+ %span(foo=1
193
+
194
+ bar=3) hello
195
+ HAML
196
+ end
197
+
198
+ it "doesn't parse extra parens" do
199
+ expect(render_string('%span(foo=1)(bar=3) hello')).to eq("<span foo='1'>(bar=3) hello</span>\n")
200
+ end
201
+
202
+ it 'parses quoted value' do
203
+ expect(render_string('%span(foo=1 bar="baz") hello')).to eq("<span bar='baz' foo='1'>hello</span>\n")
204
+ expect(render_string("%span(foo=1 bar='baz') hello")).to eq("<span bar='baz' foo='1'>hello</span>\n")
205
+ end
206
+
207
+ it 'parses key-only attribute' do
208
+ expect(render_string('%span(foo bar=1) hello')).to eq("<span bar='1' foo>hello</span>\n")
209
+ end
210
+
211
+ it 'renders string interpolation' do
212
+ expect(render_string(%q|%span(foo=1 bar="baz#{1 + 2}") hello|)).to eq("<span bar='baz3' foo='1'>hello</span>\n")
213
+ expect(render_string(%q|%span(foo=1 bar='baz#{1 + 2}') hello|)).to eq("<span bar='baz3' foo='1'>hello</span>\n")
214
+ end
215
+
216
+ it 'parses escapes' do
217
+ expect(render_string(%q|%span(foo=1 bar="ba\"z") hello|)).to eq("<span bar='ba&quot;z' foo='1'>hello</span>\n")
218
+ expect(render_string(%q|%span(foo=1 bar='ba\'z') hello|)).to eq("<span bar='ba&#39;z' foo='1'>hello</span>\n")
219
+ end
220
+
221
+ it 'raises error when attributes list is unterminated' do
222
+ expect { render_string('%span(foo=1 bar=2') }.to raise_error(Faml::SyntaxError)
223
+ end
224
+
225
+ it 'raises error when key is not alnum' do
226
+ expect { render_string('%span(foo=1 3.14=3) hello') }.to raise_error(Faml::SyntaxError)
227
+ end
228
+
229
+ it 'raises error when value is missing' do
230
+ expect { render_string('%span(foo=1 bar=) hello') }.to raise_error(Faml::SyntaxError)
231
+ end
232
+
233
+ it 'raises error when quote is unterminated' do
234
+ expect { render_string('%span(foo=1 bar="baz) hello') }.to raise_error(Faml::SyntaxError)
235
+ end
236
+
237
+ it 'raises error when string interpolation is unterminated' do
238
+ expect { render_string('%span(foo=1 bar="ba#{1") hello') }.to raise_error(Faml::SyntaxError)
239
+ end
240
+ end
241
+ 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(Faml::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(Faml::SyntaxError)
57
+ / hehehe
58
+ %span hello
59
+ HAML
60
+ end
61
+ end
@@ -0,0 +1,57 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Doctype rendering', type: :render do
4
+ context 'with html format' do
5
+ it 'renders html5 doctype by default' do
6
+ expect(render_string('!!!')).to eq("<!DOCTYPE html>\n")
7
+ end
8
+
9
+ it 'renders xml doctype (silent)' do
10
+ expect(render_string('!!! xml')).to eq("\n")
11
+ end
12
+ end
13
+
14
+ context 'with html4 format' do
15
+ it 'renders transitional doctype by default' do
16
+ 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|)
17
+ end
18
+
19
+ it 'renders frameset doctype' do
20
+ 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|)
21
+ end
22
+
23
+ it 'renders strict doctype' do
24
+ 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|)
25
+ end
26
+ end
27
+
28
+ context 'with xhtml format' do
29
+ it 'renders transitional doctype by default' do
30
+ 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|)
31
+ end
32
+
33
+ it 'renders xml doctype' do
34
+ expect(render_string('!!! xml', format: :xhtml)).to eq("<?xml version='1.0' encoding='utf-8' ?>\n")
35
+ end
36
+
37
+ it 'renders xhtml 1.1 doctype' do
38
+ 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|)
39
+ end
40
+
41
+ it 'renders xhtml mobile doctype' do
42
+ 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|)
43
+ end
44
+
45
+ it 'renders xhtml basic doctype' do
46
+ 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|)
47
+ end
48
+
49
+ it 'renders xhtml frameset doctype' do
50
+ 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|)
51
+ end
52
+
53
+ it 'renders html 5 doctype with xhtml syntax' do
54
+ expect(render_string('!!! 5', format: :xhtml)).to eq(%Q|<!DOCTYPE html>\n|)
55
+ end
56
+ end
57
+ end