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.
- 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
|