faml 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.gitmodules +3 -0
- data/.rspec +2 -0
- data/.travis.yml +27 -0
- data/Appraisals +26 -0
- data/CHANGELOG.md +47 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +115 -0
- data/Rakefile +28 -0
- data/benchmark/attribute_builder.haml +5 -0
- data/benchmark/rendering.rb +35 -0
- data/bin/faml +4 -0
- data/ext/attribute_builder/attribute_builder.c +261 -0
- data/ext/attribute_builder/extconf.rb +3 -0
- data/faml.gemspec +38 -0
- data/gemfiles/rails_4.0.gemfile +9 -0
- data/gemfiles/rails_4.1.gemfile +9 -0
- data/gemfiles/rails_4.2.gemfile +9 -0
- data/gemfiles/rails_edge.gemfile +10 -0
- data/haml_spec_test.rb +22 -0
- data/lib/faml.rb +10 -0
- data/lib/faml/ast.rb +112 -0
- data/lib/faml/cli.rb +38 -0
- data/lib/faml/compiler.rb +374 -0
- data/lib/faml/element_parser.rb +235 -0
- data/lib/faml/engine.rb +34 -0
- data/lib/faml/filter_compilers.rb +41 -0
- data/lib/faml/filter_compilers/base.rb +43 -0
- data/lib/faml/filter_compilers/cdata.rb +15 -0
- data/lib/faml/filter_compilers/coffee.rb +16 -0
- data/lib/faml/filter_compilers/css.rb +16 -0
- data/lib/faml/filter_compilers/escaped.rb +23 -0
- data/lib/faml/filter_compilers/javascript.rb +16 -0
- data/lib/faml/filter_compilers/markdown.rb +18 -0
- data/lib/faml/filter_compilers/plain.rb +15 -0
- data/lib/faml/filter_compilers/preserve.rb +26 -0
- data/lib/faml/filter_compilers/ruby.rb +17 -0
- data/lib/faml/filter_compilers/sass.rb +15 -0
- data/lib/faml/filter_compilers/scss.rb +16 -0
- data/lib/faml/filter_compilers/tilt_base.rb +34 -0
- data/lib/faml/filter_parser.rb +54 -0
- data/lib/faml/html.rb +58 -0
- data/lib/faml/indent_tracker.rb +84 -0
- data/lib/faml/line_parser.rb +66 -0
- data/lib/faml/newline.rb +30 -0
- data/lib/faml/parser.rb +211 -0
- data/lib/faml/parser_utils.rb +17 -0
- data/lib/faml/rails_handler.rb +10 -0
- data/lib/faml/railtie.rb +9 -0
- data/lib/faml/ruby_multiline.rb +23 -0
- data/lib/faml/script_parser.rb +84 -0
- data/lib/faml/static_hash_parser.rb +113 -0
- data/lib/faml/syntax_error.rb +10 -0
- data/lib/faml/text_compiler.rb +69 -0
- data/lib/faml/tilt.rb +17 -0
- data/lib/faml/version.rb +3 -0
- data/spec/compiler_newline_spec.rb +162 -0
- data/spec/rails/Rakefile +6 -0
- data/spec/rails/app/assets/images/.keep +0 -0
- data/spec/rails/app/assets/javascripts/application.js +13 -0
- data/spec/rails/app/assets/stylesheets/application.css +15 -0
- data/spec/rails/app/controllers/application_controller.rb +5 -0
- data/spec/rails/app/controllers/books_controller.rb +8 -0
- data/spec/rails/app/controllers/concerns/.keep +0 -0
- data/spec/rails/app/helpers/application_helper.rb +2 -0
- data/spec/rails/app/mailers/.keep +0 -0
- data/spec/rails/app/models/.keep +0 -0
- data/spec/rails/app/models/book.rb +9 -0
- data/spec/rails/app/models/concerns/.keep +0 -0
- data/spec/rails/app/views/books/hello.html.haml +2 -0
- data/spec/rails/app/views/books/with_capture.html.haml +4 -0
- data/spec/rails/app/views/books/with_variables.html.haml +4 -0
- data/spec/rails/app/views/layouts/application.html.haml +9 -0
- data/spec/rails/bin/bundle +3 -0
- data/spec/rails/bin/rails +4 -0
- data/spec/rails/bin/rake +4 -0
- data/spec/rails/bin/setup +29 -0
- data/spec/rails/config.ru +4 -0
- data/spec/rails/config/application.rb +12 -0
- data/spec/rails/config/boot.rb +3 -0
- data/spec/rails/config/database.yml +25 -0
- data/spec/rails/config/environment.rb +5 -0
- data/spec/rails/config/environments/development.rb +41 -0
- data/spec/rails/config/environments/production.rb +79 -0
- data/spec/rails/config/environments/test.rb +42 -0
- data/spec/rails/config/initializers/assets.rb +11 -0
- data/spec/rails/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/rails/config/initializers/cookies_serializer.rb +3 -0
- data/spec/rails/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/rails/config/initializers/inflections.rb +16 -0
- data/spec/rails/config/initializers/mime_types.rb +4 -0
- data/spec/rails/config/initializers/secret_key_base.rb +6 -0
- data/spec/rails/config/initializers/session_store.rb +3 -0
- data/spec/rails/config/initializers/wrap_parameters.rb +14 -0
- data/spec/rails/config/locales/en.yml +23 -0
- data/spec/rails/config/routes.rb +7 -0
- data/spec/rails/config/secrets.yml +22 -0
- data/spec/rails/db/seeds.rb +7 -0
- data/spec/rails/lib/assets/.keep +0 -0
- data/spec/rails/lib/tasks/.keep +0 -0
- data/spec/rails/log/.keep +0 -0
- data/spec/rails/public/404.html +67 -0
- data/spec/rails/public/422.html +67 -0
- data/spec/rails/public/500.html +66 -0
- data/spec/rails/public/favicon.ico +0 -0
- data/spec/rails/public/robots.txt +5 -0
- data/spec/rails/spec/requests/faml_spec.rb +41 -0
- data/spec/rails/vendor/assets/javascripts/.keep +0 -0
- data/spec/rails/vendor/assets/stylesheets/.keep +0 -0
- data/spec/rails_helper.rb +4 -0
- data/spec/render/attribute_spec.rb +241 -0
- data/spec/render/comment_spec.rb +61 -0
- data/spec/render/doctype_spec.rb +57 -0
- data/spec/render/element_spec.rb +136 -0
- data/spec/render/filters/cdata_spec.rb +12 -0
- data/spec/render/filters/coffee_spec.rb +25 -0
- data/spec/render/filters/css_spec.rb +45 -0
- data/spec/render/filters/escaped_spec.rb +14 -0
- data/spec/render/filters/javascript_spec.rb +44 -0
- data/spec/render/filters/markdown_spec.rb +19 -0
- data/spec/render/filters/plain_spec.rb +24 -0
- data/spec/render/filters/preserve_spec.rb +24 -0
- data/spec/render/filters/ruby_spec.rb +13 -0
- data/spec/render/filters/sass_spec.rb +28 -0
- data/spec/render/filters/scss_spec.rb +32 -0
- data/spec/render/filters_spec.rb +11 -0
- data/spec/render/haml_comment_spec.rb +24 -0
- data/spec/render/multiline_spec.rb +39 -0
- data/spec/render/newline_spec.rb +83 -0
- data/spec/render/plain_spec.rb +20 -0
- data/spec/render/preserve_spec.rb +8 -0
- data/spec/render/sanitize_spec.rb +36 -0
- data/spec/render/script_spec.rb +81 -0
- data/spec/render/silent_script_spec.rb +97 -0
- data/spec/render/unescape_spec.rb +45 -0
- data/spec/spec_helper.rb +47 -0
- data/spec/tilt_spec.rb +33 -0
- 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,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><script>alert(1)</script></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,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"y'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=>3}'>hello</span>\n|)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'renders code attributes' do
|
81
|
+
expect(render_string(<<HAML)).to eq(%Q|<span bar='{:hoge=>: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=>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=>"x1y"}'>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=>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"z' foo='1'>hello</span>\n")
|
218
|
+
expect(render_string(%q|%span(foo=1 bar='ba\'z') hello|)).to eq("<span bar='ba'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
|