haml 2.2.17 → 2.2.18
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of haml might be problematic. Click here for more details.
- data/.yardopts +3 -0
- data/Rakefile +6 -6
- data/VERSION +1 -1
- data/extra/haml-mode.el +99 -13
- data/extra/sass-mode.el +2 -2
- data/lib/haml/engine.rb +1 -1
- data/lib/haml/exec.rb +13 -5
- data/lib/haml/filters.rb +1 -1
- data/lib/haml/helpers.rb +3 -2
- data/lib/haml/helpers/action_view_mods.rb +2 -1
- data/lib/haml/helpers/xss_mods.rb +43 -13
- data/lib/haml/html.rb +8 -0
- data/lib/haml/precompiler.rb +20 -1
- data/lib/haml/template.rb +2 -2
- data/lib/haml/util.rb +27 -0
- data/lib/sass/engine.rb +42 -2
- data/lib/sass/plugin.rb +5 -4
- data/lib/sass/plugin/rails.rb +2 -2
- data/lib/sass/script.rb +3 -0
- data/lib/sass/script/color.rb +4 -2
- data/lib/sass/script/lexer.rb +8 -5
- data/lib/sass/script/number.rb +2 -0
- data/lib/sass/script/parser.rb +1 -1
- data/lib/sass/tree/rule_node.rb +1 -0
- data/test/haml/engine_test.rb +21 -0
- data/test/haml/helper_test.rb +0 -0
- data/test/haml/html2haml_test.rb +0 -0
- data/test/haml/spec/lua_haml_spec.lua +1 -1
- data/test/haml/spec/tests.json +64 -18
- data/test/haml/template_test.rb +17 -3
- data/test/haml/util_test.rb +0 -0
- data/test/sass/css2sass_test.rb +1 -0
- data/test/sass/engine_test.rb +31 -0
- data/test/sass/functions_test.rb +1 -0
- data/test/sass/plugin_test.rb +28 -17
- data/test/sass/script_test.rb +7 -7
- data/test/sass/to_sass_test.rb +549 -0
- metadata +144 -142
data/test/haml/engine_test.rb
CHANGED
@@ -72,6 +72,7 @@ class EngineTest < Test::Unit::TestCase
|
|
72
72
|
"/ foo\n\n bar" => ["Illegal nesting: nesting within a tag that already has content is illegal.", 3],
|
73
73
|
"!!!\n\n bar" => ["Illegal nesting: nesting within a header command is illegal.", 3],
|
74
74
|
"foo\n:ruby\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
|
75
|
+
"foo\n:erb\n 1\n 2\n 3\n- raise 'foo'" => ["foo", 6],
|
75
76
|
"= raise 'foo'\nfoo\nbar\nbaz\nbang" => ["foo", 1],
|
76
77
|
}
|
77
78
|
|
@@ -567,6 +568,17 @@ HTML
|
|
567
568
|
HAML
|
568
569
|
end
|
569
570
|
|
571
|
+
def test_erb_filter_with_multiline_expr
|
572
|
+
assert_equal(<<HTML, render(<<HAML))
|
573
|
+
foobarbaz
|
574
|
+
HTML
|
575
|
+
:erb
|
576
|
+
<%= "foo" +
|
577
|
+
"bar" +
|
578
|
+
"baz" %>
|
579
|
+
HAML
|
580
|
+
end
|
581
|
+
|
570
582
|
def test_silent_script_with_hyphen_case
|
571
583
|
assert_equal("", render("- 'foo-case-bar-case'"))
|
572
584
|
end
|
@@ -595,6 +607,15 @@ HTML
|
|
595
607
|
HAML
|
596
608
|
end
|
597
609
|
|
610
|
+
def test_html_attributes_with_hash
|
611
|
+
assert_equal("<a href='#' rel='top'>Foo</a>\n",
|
612
|
+
render('%a(href="#" rel="top") Foo'))
|
613
|
+
assert_equal("<a href='#'>Foo</a>\n",
|
614
|
+
render('%a(href="#") #{"Foo"}'))
|
615
|
+
|
616
|
+
assert_equal("<a href='#\"'></a>\n", render('%a(href="#\\"")'))
|
617
|
+
end
|
618
|
+
|
598
619
|
# HTML escaping tests
|
599
620
|
|
600
621
|
def test_ampersand_equals_should_escape
|
data/test/haml/helper_test.rb
CHANGED
File without changes
|
data/test/haml/html2haml_test.rb
CHANGED
File without changes
|
data/test/haml/spec/tests.json
CHANGED
@@ -31,6 +31,11 @@
|
|
31
31
|
"html" : "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">"
|
32
32
|
},
|
33
33
|
|
34
|
+
"an HTML 5 doctype with XHTML syntax" : {
|
35
|
+
"haml" : "!!! 5",
|
36
|
+
"html" : "<!DOCTYPE html>"
|
37
|
+
},
|
38
|
+
|
34
39
|
"an HTML 5 XML prolog (silent)" : {
|
35
40
|
"haml" : "!!! XML",
|
36
41
|
"html" : "",
|
@@ -147,8 +152,12 @@
|
|
147
152
|
"an implicit div with a CSS class" : {
|
148
153
|
"haml" : ".class1",
|
149
154
|
"html" : "<div class='class1'></div>"
|
150
|
-
}
|
155
|
+
},
|
151
156
|
|
157
|
+
"multiple simple Haml tags" : {
|
158
|
+
"haml" : "%div\n %div\n %p",
|
159
|
+
"html" : "<div>\n <div>\n <p></p>\n </div>\n</div>"
|
160
|
+
}
|
152
161
|
},
|
153
162
|
|
154
163
|
"tags with unusual HTML characters" : {
|
@@ -208,8 +217,12 @@
|
|
208
217
|
"a tag with CSS" : {
|
209
218
|
"haml" : "%p.class1 hello",
|
210
219
|
"html" : "<p class='class1'>hello</p>"
|
211
|
-
}
|
220
|
+
},
|
212
221
|
|
222
|
+
"multiple simple tags" : {
|
223
|
+
"haml" : "%div\n %div\n %p text",
|
224
|
+
"html" : "<div>\n <div>\n <p>text</p>\n </div>\n</div>"
|
225
|
+
}
|
213
226
|
},
|
214
227
|
|
215
228
|
"tags with nested content" : {
|
@@ -222,6 +235,11 @@
|
|
222
235
|
"a tag with CSS" : {
|
223
236
|
"haml" : "%p.class1\n hello",
|
224
237
|
"html" : "<p class='class1'>\n hello\n</p>"
|
238
|
+
},
|
239
|
+
|
240
|
+
"multiple simple tags" : {
|
241
|
+
"haml" : "%div\n %div\n %p\n text",
|
242
|
+
"html" : "<div>\n <div>\n <p>\n text\n </p>\n </div>\n</div>"
|
225
243
|
}
|
226
244
|
|
227
245
|
},
|
@@ -374,14 +392,6 @@
|
|
374
392
|
"locals" : {
|
375
393
|
"var" : "a"
|
376
394
|
}
|
377
|
-
},
|
378
|
-
|
379
|
-
"an interpolated attribute" : {
|
380
|
-
"haml" : "%p{:a =>\"#{var}\"}",
|
381
|
-
"html" : "<p a='value'></p>",
|
382
|
-
"locals" : {
|
383
|
-
"var" : "value"
|
384
|
-
}
|
385
395
|
}
|
386
396
|
|
387
397
|
},
|
@@ -446,14 +456,6 @@
|
|
446
456
|
|
447
457
|
"interpolation": {
|
448
458
|
|
449
|
-
"interpolation inside code" : {
|
450
|
-
"haml" : "%p= \"#{var}\"",
|
451
|
-
"html" : "<p>value</p>",
|
452
|
-
"locals" : {
|
453
|
-
"var" : "value"
|
454
|
-
}
|
455
|
-
},
|
456
|
-
|
457
459
|
"interpolation inside inline content" : {
|
458
460
|
"haml" : "%p #{var}",
|
459
461
|
"html" : "<p>value</p>",
|
@@ -483,6 +485,50 @@
|
|
483
485
|
}
|
484
486
|
}
|
485
487
|
|
488
|
+
},
|
489
|
+
|
490
|
+
"HTML escaping" : {
|
491
|
+
|
492
|
+
"code following '&='" : {
|
493
|
+
"haml" : "&= '<\"&>'",
|
494
|
+
"html" : "<"&>"
|
495
|
+
},
|
496
|
+
|
497
|
+
"code following '=' when escape_haml is set to true" : {
|
498
|
+
"haml" : "= '<\"&>'",
|
499
|
+
"html" : "<"&>",
|
500
|
+
"config" : {
|
501
|
+
"escape_html" : "true"
|
502
|
+
}
|
503
|
+
},
|
504
|
+
|
505
|
+
"code following '!=' when escape_haml is set to true" : {
|
506
|
+
"haml" : "!= '<\"&>'",
|
507
|
+
"html" : "<\"&>",
|
508
|
+
"config" : {
|
509
|
+
"escape_html" : "true"
|
510
|
+
}
|
511
|
+
}
|
512
|
+
|
513
|
+
},
|
514
|
+
|
515
|
+
"Boolean attributes" : {
|
516
|
+
|
517
|
+
"boolean attribute with XHTML" : {
|
518
|
+
"haml" : "%input(checked=true)",
|
519
|
+
"html" : "<input checked='checked' />",
|
520
|
+
"config" : {
|
521
|
+
"format" : "xhtml"
|
522
|
+
}
|
523
|
+
},
|
524
|
+
|
525
|
+
"boolean attribute with HTML" : {
|
526
|
+
"haml" : "%input(checked=true)",
|
527
|
+
"html" : "<input checked>",
|
528
|
+
"config" : {
|
529
|
+
"format" : "html5"
|
530
|
+
}
|
531
|
+
}
|
486
532
|
}
|
487
533
|
|
488
534
|
}
|
data/test/haml/template_test.rb
CHANGED
@@ -258,7 +258,7 @@ END
|
|
258
258
|
end
|
259
259
|
|
260
260
|
def test_xss_protection_with_safe_strings
|
261
|
-
assert_equal("Foo & Bar\n", render('= "Foo & Bar"
|
261
|
+
assert_equal("Foo & Bar\n", render('= Haml::Util.html_safe("Foo & Bar")', :action_view))
|
262
262
|
end
|
263
263
|
|
264
264
|
def test_xss_protection_with_bang
|
@@ -274,11 +274,11 @@ END
|
|
274
274
|
end
|
275
275
|
|
276
276
|
def test_xss_protection_with_safe_strings_in_interpolation
|
277
|
-
assert_equal("Foo & Bar\n", render('Foo #{"&"
|
277
|
+
assert_equal("Foo & Bar\n", render('Foo #{Haml::Util.html_safe("&")} Bar', :action_view))
|
278
278
|
end
|
279
279
|
|
280
280
|
def test_xss_protection_with_mixed_strings_in_interpolation
|
281
|
-
assert_equal("Foo & Bar & Baz\n", render('Foo #{"&"
|
281
|
+
assert_equal("Foo & Bar & Baz\n", render('Foo #{Haml::Util.html_safe("&")} Bar #{"&"} Baz', :action_view))
|
282
282
|
end
|
283
283
|
|
284
284
|
def test_rendered_string_is_html_safe
|
@@ -292,5 +292,19 @@ END
|
|
292
292
|
def test_xss_html_escaping_with_non_strings
|
293
293
|
assert_equal("4\n", render("= html_escape(4)"))
|
294
294
|
end
|
295
|
+
|
296
|
+
def test_xss_protection_with_concat
|
297
|
+
assert_equal("Foo & Bar", render('- concat "Foo & Bar"', :action_view))
|
298
|
+
end
|
299
|
+
|
300
|
+
def test_xss_protection_with_concat_with_safe_string
|
301
|
+
assert_equal("Foo & Bar", render('- concat(Haml::Util.html_safe("Foo & Bar"))', :action_view))
|
302
|
+
end
|
303
|
+
|
304
|
+
if Haml::Util.has?(:instance_method, ActionView::Helpers::TextHelper, :safe_concat)
|
305
|
+
def test_xss_protection_with_safe_concat
|
306
|
+
assert_equal("Foo & Bar", render('- safe_concat "Foo & Bar"', :action_view))
|
307
|
+
end
|
308
|
+
end
|
295
309
|
end
|
296
310
|
end
|
data/test/haml/util_test.rb
CHANGED
File without changes
|
data/test/sass/css2sass_test.rb
CHANGED
data/test/sass/engine_test.rb
CHANGED
@@ -96,6 +96,7 @@ MSG
|
|
96
96
|
'@if' => "Invalid if directive '@if': expected expression.",
|
97
97
|
'@while' => "Invalid while directive '@while': expected expression.",
|
98
98
|
'@debug' => "Invalid debug directive '@debug': expected expression.",
|
99
|
+
"/* foo\n bar\n baz" => "Inconsistent indentation: previous line was indented by 4 spaces, but this line was indented by 2 spaces.",
|
99
100
|
|
100
101
|
# Regression tests
|
101
102
|
"a\n b:\n c\n d" => ["Illegal nesting: Only properties may be nested beneath properties.", 3],
|
@@ -691,6 +692,36 @@ foo {
|
|
691
692
|
CSS
|
692
693
|
end
|
693
694
|
|
695
|
+
def test_comment_indentation_at_beginning_of_doc
|
696
|
+
assert_equal <<CSS, render(<<SASS)
|
697
|
+
/* foo
|
698
|
+
* bar
|
699
|
+
* baz */
|
700
|
+
foo {
|
701
|
+
a: b; }
|
702
|
+
CSS
|
703
|
+
/* foo
|
704
|
+
bar
|
705
|
+
baz
|
706
|
+
foo
|
707
|
+
a: b
|
708
|
+
SASS
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_unusual_comment_indentation
|
712
|
+
assert_equal <<CSS, render(<<SASS)
|
713
|
+
foo {
|
714
|
+
/* foo
|
715
|
+
* bar
|
716
|
+
* baz */ }
|
717
|
+
CSS
|
718
|
+
foo
|
719
|
+
/* foo
|
720
|
+
bar
|
721
|
+
baz
|
722
|
+
SASS
|
723
|
+
end
|
724
|
+
|
694
725
|
def test_attribute_selector_with_spaces
|
695
726
|
assert_equal(<<CSS, render(<<SASS))
|
696
727
|
a b[foo = bar] {
|
data/test/sass/functions_test.rb
CHANGED
data/test/sass/plugin_test.rb
CHANGED
@@ -14,6 +14,7 @@ class SassPluginTest < Test::Unit::TestCase
|
|
14
14
|
FileUtils.mkdir tempfile_loc(nil,"more_")
|
15
15
|
set_plugin_opts
|
16
16
|
Sass::Plugin.update_stylesheets
|
17
|
+
reset_mtimes
|
17
18
|
end
|
18
19
|
|
19
20
|
def teardown
|
@@ -30,23 +31,21 @@ class SassPluginTest < Test::Unit::TestCase
|
|
30
31
|
|
31
32
|
def test_no_update
|
32
33
|
File.delete(tempfile_loc('basic'))
|
33
|
-
|
34
|
+
assert_needs_update 'basic'
|
34
35
|
Sass::Plugin.update_stylesheets
|
35
36
|
assert_stylesheet_updated 'basic'
|
36
37
|
end
|
37
38
|
|
38
39
|
def test_update_needed_when_modified
|
39
|
-
|
40
|
-
|
41
|
-
assert Sass::Plugin.stylesheet_needs_update?('basic', template_loc, tempfile_loc)
|
40
|
+
touch 'basic'
|
41
|
+
assert_needs_update 'basic'
|
42
42
|
Sass::Plugin.update_stylesheets
|
43
43
|
assert_stylesheet_updated 'basic'
|
44
44
|
end
|
45
45
|
|
46
46
|
def test_update_needed_when_dependency_modified
|
47
|
-
|
48
|
-
|
49
|
-
assert Sass::Plugin.stylesheet_needs_update?('import', template_loc, tempfile_loc)
|
47
|
+
touch 'basic'
|
48
|
+
assert_needs_update 'import'
|
50
49
|
Sass::Plugin.update_stylesheets
|
51
50
|
assert_stylesheet_updated 'basic'
|
52
51
|
end
|
@@ -108,7 +107,7 @@ class SassPluginTest < Test::Unit::TestCase
|
|
108
107
|
set_plugin_opts
|
109
108
|
|
110
109
|
File.delete(tempfile_loc('basic'))
|
111
|
-
|
110
|
+
assert_needs_update 'basic'
|
112
111
|
|
113
112
|
if defined?(MerbHandler)
|
114
113
|
MerbHandler.new('.').process nil, nil
|
@@ -129,9 +128,8 @@ class SassPluginTest < Test::Unit::TestCase
|
|
129
128
|
FileUtils.mv(template_loc("basic"), template_loc("basic", "more_"))
|
130
129
|
set_plugin_opts :load_paths => [result_loc, template_loc(nil, "more_")]
|
131
130
|
|
132
|
-
|
133
|
-
|
134
|
-
assert Sass::Plugin.stylesheet_needs_update?("import", template_loc, tempfile_loc)
|
131
|
+
touch 'basic', 'more_'
|
132
|
+
assert_needs_update "import"
|
135
133
|
Sass::Plugin.update_stylesheets
|
136
134
|
assert_renders_correctly("import")
|
137
135
|
ensure
|
@@ -162,7 +160,7 @@ class SassPluginTest < Test::Unit::TestCase
|
|
162
160
|
end
|
163
161
|
|
164
162
|
def assert_stylesheet_updated(name)
|
165
|
-
|
163
|
+
assert_doesnt_need_update name
|
166
164
|
|
167
165
|
# Make sure it isn't an exception
|
168
166
|
expected_lines = File.read(result_loc(name)).split("\n")
|
@@ -172,6 +170,24 @@ class SassPluginTest < Test::Unit::TestCase
|
|
172
170
|
end
|
173
171
|
end
|
174
172
|
|
173
|
+
def assert_needs_update(name)
|
174
|
+
assert(Sass::Plugin.stylesheet_needs_update?(name, template_loc, tempfile_loc),
|
175
|
+
"Expected #{template_loc(name)} to need an update.")
|
176
|
+
end
|
177
|
+
|
178
|
+
def assert_doesnt_need_update(name)
|
179
|
+
assert(!Sass::Plugin.stylesheet_needs_update?(name, template_loc, tempfile_loc),
|
180
|
+
"Expected #{template_loc(name)} not to need an update.")
|
181
|
+
end
|
182
|
+
|
183
|
+
def touch(*args)
|
184
|
+
FileUtils.touch(template_loc(*args))
|
185
|
+
end
|
186
|
+
|
187
|
+
def reset_mtimes
|
188
|
+
Dir["{#{template_loc},#{tempfile_loc}}/**/*.{css,sass}"].each {|f| File.utime(Time.now, Time.now - 1, f)}
|
189
|
+
end
|
190
|
+
|
175
191
|
def template_loc(name = nil, prefix = nil)
|
176
192
|
if name
|
177
193
|
absolutize "#{prefix}templates/#{name}.sass"
|
@@ -209,11 +225,6 @@ class SassPluginTest < Test::Unit::TestCase
|
|
209
225
|
:always_update => true,
|
210
226
|
}.merge(overrides)
|
211
227
|
end
|
212
|
-
|
213
|
-
def wait_a_tick
|
214
|
-
time = Time.now
|
215
|
-
loop {break if Time.now.sec != time.sec}
|
216
|
-
end
|
217
228
|
end
|
218
229
|
|
219
230
|
module Sass::Plugin
|
data/test/sass/script_test.rb
CHANGED
@@ -65,19 +65,19 @@ SASS
|
|
65
65
|
assert_warning(<<WARN) {eval("foo")}
|
66
66
|
DEPRECATION WARNING:
|
67
67
|
On line 1, character 1 of 'test_implicit_string_warning_inline.sass'
|
68
|
-
Implicit strings have been deprecated and will be removed in version
|
68
|
+
Implicit strings have been deprecated and will be removed in version 3.0.
|
69
69
|
'foo' was not quoted. Please add double quotes (e.g. "foo").
|
70
70
|
WARN
|
71
71
|
assert_warning(<<WARN) {eval("1 + foo")}
|
72
72
|
DEPRECATION WARNING:
|
73
73
|
On line 1, character 5 of 'test_implicit_string_warning_inline.sass'
|
74
|
-
Implicit strings have been deprecated and will be removed in version
|
74
|
+
Implicit strings have been deprecated and will be removed in version 3.0.
|
75
75
|
'foo' was not quoted. Please add double quotes (e.g. "foo").
|
76
76
|
WARN
|
77
77
|
assert_warning(<<WARN) {render("@if 1 + foo")}
|
78
78
|
DEPRECATION WARNING:
|
79
79
|
On line 1, character 9 of 'test_implicit_string_warning_inline.sass'
|
80
|
-
Implicit strings have been deprecated and will be removed in version
|
80
|
+
Implicit strings have been deprecated and will be removed in version 3.0.
|
81
81
|
'foo' was not quoted. Please add double quotes (e.g. "foo").
|
82
82
|
WARN
|
83
83
|
|
@@ -85,7 +85,7 @@ WARN
|
|
85
85
|
assert_warning(<<WARN) {render("@if if")}
|
86
86
|
DEPRECATION WARNING:
|
87
87
|
On line 1, character 5 of 'test_implicit_string_warning_inline.sass'
|
88
|
-
Implicit strings have been deprecated and will be removed in version
|
88
|
+
Implicit strings have been deprecated and will be removed in version 3.0.
|
89
89
|
'if' was not quoted. Please add double quotes (e.g. "if").
|
90
90
|
WARN
|
91
91
|
end
|
@@ -94,7 +94,7 @@ WARN
|
|
94
94
|
assert_warning <<WARN do
|
95
95
|
DEPRECATION WARNING:
|
96
96
|
On line 2, character 6 of 'test_inaccessible_functions_inline.sass'
|
97
|
-
Implicit strings have been deprecated and will be removed in version
|
97
|
+
Implicit strings have been deprecated and will be removed in version 3.0.
|
98
98
|
'to_s' was not quoted. Please add double quotes (e.g. "to_s").
|
99
99
|
WARN
|
100
100
|
assert_equal "send(to_s)", resolve("send(to_s)", :line => 2)
|
@@ -108,14 +108,14 @@ WARN
|
|
108
108
|
assert_warning(<<WARN) {eval("!a-!b", {}, env("a" => a, "b" => b))}
|
109
109
|
DEPRECATION WARNING:
|
110
110
|
On line 1, character 3 of 'test_hyphen_warning_inline.sass'
|
111
|
-
- will be allowed as part of variable names in version
|
111
|
+
- will be allowed as part of variable names in version 3.0.
|
112
112
|
Please add whitespace to separate it from the previous token.
|
113
113
|
WARN
|
114
114
|
|
115
115
|
assert_warning(<<WARN) {eval("true-false")}
|
116
116
|
DEPRECATION WARNING:
|
117
117
|
On line 1, character 5 of 'test_hyphen_warning_inline.sass'
|
118
|
-
- will be allowed as part of variable names in version
|
118
|
+
- will be allowed as part of variable names in version 3.0.
|
119
119
|
Please add whitespace to separate it from the previous token.
|
120
120
|
WARN
|
121
121
|
end
|
@@ -0,0 +1,549 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
3
|
+
|
4
|
+
class ToSassTest < Test::Unit::TestCase
|
5
|
+
def test_basic
|
6
|
+
assert_renders <<SASS, <<SCSS
|
7
|
+
foo bar
|
8
|
+
baz: bang
|
9
|
+
bip: bop
|
10
|
+
SASS
|
11
|
+
foo bar {
|
12
|
+
baz: bang;
|
13
|
+
bip: bop; }
|
14
|
+
SCSS
|
15
|
+
assert_renders <<SASS, <<SCSS, :old => true
|
16
|
+
foo bar
|
17
|
+
:baz bang
|
18
|
+
:bip bop
|
19
|
+
SASS
|
20
|
+
foo bar {
|
21
|
+
baz: bang;
|
22
|
+
bip: bop; }
|
23
|
+
SCSS
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_nesting
|
27
|
+
assert_renders <<SASS, <<SCSS
|
28
|
+
foo bar
|
29
|
+
baz bang
|
30
|
+
baz: bang
|
31
|
+
bip: bop
|
32
|
+
blat: boo
|
33
|
+
SASS
|
34
|
+
foo bar {
|
35
|
+
baz bang {
|
36
|
+
baz: bang;
|
37
|
+
bip: bop; }
|
38
|
+
blat: boo; }
|
39
|
+
SCSS
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_nesting_with_parent_ref
|
43
|
+
assert_renders <<SASS, <<SCSS
|
44
|
+
foo bar
|
45
|
+
&:hover
|
46
|
+
baz: bang
|
47
|
+
SASS
|
48
|
+
foo bar {
|
49
|
+
&:hover {
|
50
|
+
baz: bang; } }
|
51
|
+
SCSS
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_selector_interpolation
|
55
|
+
assert_renders <<SASS, <<SCSS
|
56
|
+
foo \#{!bar + "baz"}.bip
|
57
|
+
baz: bang
|
58
|
+
SASS
|
59
|
+
foo \#{!bar + "baz"}.bip {
|
60
|
+
baz: bang; }
|
61
|
+
SCSS
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_multiline_selector_with_commas
|
65
|
+
assert_renders <<SASS, <<SCSS
|
66
|
+
foo bar,
|
67
|
+
baz bang
|
68
|
+
baz: bang
|
69
|
+
SASS
|
70
|
+
foo bar,
|
71
|
+
baz bang {
|
72
|
+
baz: bang; }
|
73
|
+
SCSS
|
74
|
+
|
75
|
+
assert_renders <<SASS, <<SCSS
|
76
|
+
blat
|
77
|
+
foo bar,
|
78
|
+
baz bang
|
79
|
+
baz: bang
|
80
|
+
SASS
|
81
|
+
blat {
|
82
|
+
foo bar,
|
83
|
+
baz bang {
|
84
|
+
baz: bang; } }
|
85
|
+
SCSS
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_multiline_selector_without_commas
|
89
|
+
assert_renders <<SASS, <<SCSS
|
90
|
+
foo bar baz bang
|
91
|
+
baz: bang
|
92
|
+
SASS
|
93
|
+
foo bar
|
94
|
+
baz bang {
|
95
|
+
baz: bang; }
|
96
|
+
SCSS
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_escaped_selector
|
100
|
+
assert_renders <<SASS, <<SCSS
|
101
|
+
foo bar
|
102
|
+
\\:hover
|
103
|
+
baz: bang
|
104
|
+
SASS
|
105
|
+
foo bar {
|
106
|
+
:hover {
|
107
|
+
baz: bang; } }
|
108
|
+
SCSS
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_property_name_interpolation
|
112
|
+
assert_renders <<SASS, <<SCSS
|
113
|
+
foo bar
|
114
|
+
baz\#{!bang}bip\#{!bop}: 12
|
115
|
+
SASS
|
116
|
+
foo bar {
|
117
|
+
baz\#{!bang}bip\#{!bop}: 12; }
|
118
|
+
SCSS
|
119
|
+
end
|
120
|
+
|
121
|
+
def test_property_name_interpolation
|
122
|
+
assert_renders <<SASS, <<SCSS
|
123
|
+
foo bar
|
124
|
+
baz\#{!bang}bip\#{!bop}: 12
|
125
|
+
SASS
|
126
|
+
foo bar {
|
127
|
+
baz\#{!bang}bip\#{!bop}: 12; }
|
128
|
+
SCSS
|
129
|
+
end
|
130
|
+
|
131
|
+
def test_property_value_interpolation
|
132
|
+
assert_renders <<SASS, <<SCSS
|
133
|
+
foo bar
|
134
|
+
baz: 12 \#{!bang} bip \#{"bop"} blat
|
135
|
+
SASS
|
136
|
+
foo bar {
|
137
|
+
baz: 12 \#{!bang} bip \#{"bop"} blat; }
|
138
|
+
SCSS
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_dynamic_properties
|
142
|
+
assert_renders <<SASS, <<SCSS
|
143
|
+
foo bar
|
144
|
+
baz= 12 !bang "bip"
|
145
|
+
SASS
|
146
|
+
foo bar {
|
147
|
+
baz= 12 !bang "bip"; }
|
148
|
+
SCSS
|
149
|
+
end
|
150
|
+
|
151
|
+
def test_dynamic_properties_with_old
|
152
|
+
assert_renders <<SASS, <<SCSS, :old => true
|
153
|
+
foo bar
|
154
|
+
:baz= 12 !bang "bip"
|
155
|
+
SASS
|
156
|
+
foo bar {
|
157
|
+
baz= 12 !bang "bip"; }
|
158
|
+
SCSS
|
159
|
+
end
|
160
|
+
|
161
|
+
def test_multiline_properties
|
162
|
+
assert_renders <<SASS, <<SCSS
|
163
|
+
foo bar
|
164
|
+
baz: bip bam boon
|
165
|
+
SASS
|
166
|
+
foo bar {
|
167
|
+
baz:
|
168
|
+
bip
|
169
|
+
bam
|
170
|
+
boon; }
|
171
|
+
SCSS
|
172
|
+
end
|
173
|
+
|
174
|
+
def test_multiline_dynamic_properties
|
175
|
+
assert_renders <<SASS, <<SCSS
|
176
|
+
foo bar
|
177
|
+
baz= !bip "bam" 12px
|
178
|
+
SASS
|
179
|
+
foo bar {
|
180
|
+
baz=
|
181
|
+
!bip
|
182
|
+
"bam"
|
183
|
+
12px; }
|
184
|
+
SCSS
|
185
|
+
end
|
186
|
+
|
187
|
+
def test_silent_comments
|
188
|
+
assert_renders <<SASS, <<SCSS
|
189
|
+
// foo
|
190
|
+
|
191
|
+
// bar
|
192
|
+
|
193
|
+
// baz
|
194
|
+
|
195
|
+
foo bar
|
196
|
+
a: b
|
197
|
+
SASS
|
198
|
+
// foo
|
199
|
+
|
200
|
+
// bar
|
201
|
+
|
202
|
+
// baz
|
203
|
+
|
204
|
+
foo bar {
|
205
|
+
a: b; }
|
206
|
+
SCSS
|
207
|
+
|
208
|
+
assert_renders <<SASS, <<SCSS
|
209
|
+
// foo
|
210
|
+
bar
|
211
|
+
baz
|
212
|
+
bang
|
213
|
+
|
214
|
+
foo bar
|
215
|
+
a: b
|
216
|
+
SASS
|
217
|
+
// foo
|
218
|
+
// bar
|
219
|
+
// baz
|
220
|
+
// bang
|
221
|
+
|
222
|
+
foo bar {
|
223
|
+
a: b; }
|
224
|
+
SCSS
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
def test_loud_comments
|
229
|
+
assert_renders <<SASS, <<SCSS
|
230
|
+
/* foo
|
231
|
+
|
232
|
+
/* bar
|
233
|
+
|
234
|
+
/* baz
|
235
|
+
|
236
|
+
foo bar
|
237
|
+
a: b
|
238
|
+
SASS
|
239
|
+
/* foo */
|
240
|
+
|
241
|
+
/* bar */
|
242
|
+
|
243
|
+
/* baz */
|
244
|
+
|
245
|
+
foo bar {
|
246
|
+
a: b; }
|
247
|
+
SCSS
|
248
|
+
|
249
|
+
assert_renders <<SASS, <<SCSS
|
250
|
+
/* foo
|
251
|
+
bar
|
252
|
+
baz
|
253
|
+
bang
|
254
|
+
|
255
|
+
foo bar
|
256
|
+
a: b
|
257
|
+
SASS
|
258
|
+
/* foo
|
259
|
+
bar
|
260
|
+
baz
|
261
|
+
bang */
|
262
|
+
|
263
|
+
foo bar {
|
264
|
+
a: b; }
|
265
|
+
SCSS
|
266
|
+
|
267
|
+
assert_renders <<SASS, <<SCSS
|
268
|
+
/* foo
|
269
|
+
bar
|
270
|
+
baz
|
271
|
+
bang
|
272
|
+
|
273
|
+
foo bar
|
274
|
+
a: b
|
275
|
+
SASS
|
276
|
+
/* foo
|
277
|
+
* bar
|
278
|
+
* baz
|
279
|
+
* bang */
|
280
|
+
|
281
|
+
foo bar {
|
282
|
+
a: b; }
|
283
|
+
SCSS
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_loud_comments_with_weird_indentation
|
287
|
+
assert_renders <<SASS, <<SCSS
|
288
|
+
foo
|
289
|
+
/* foo
|
290
|
+
bar
|
291
|
+
baz
|
292
|
+
a: b
|
293
|
+
SASS
|
294
|
+
foo {
|
295
|
+
/* foo
|
296
|
+
bar
|
297
|
+
baz */
|
298
|
+
a: b; }
|
299
|
+
SCSS
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_debug
|
303
|
+
assert_renders <<SASS, <<SCSS
|
304
|
+
foo
|
305
|
+
@debug 12px
|
306
|
+
bar: baz
|
307
|
+
SASS
|
308
|
+
foo {
|
309
|
+
@debug 12px;
|
310
|
+
bar: baz; }
|
311
|
+
SCSS
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_directive_without_children
|
315
|
+
assert_renders <<SASS, <<SCSS
|
316
|
+
foo
|
317
|
+
@foo #bar "baz"
|
318
|
+
bar: baz
|
319
|
+
SASS
|
320
|
+
foo {
|
321
|
+
@foo #bar "baz";
|
322
|
+
bar: baz; }
|
323
|
+
SCSS
|
324
|
+
end
|
325
|
+
|
326
|
+
def test_directive_with_prop_children
|
327
|
+
assert_renders <<SASS, <<SCSS
|
328
|
+
foo
|
329
|
+
@foo #bar "baz"
|
330
|
+
a: b
|
331
|
+
c: d
|
332
|
+
|
333
|
+
bar: baz
|
334
|
+
SASS
|
335
|
+
foo {
|
336
|
+
@foo #bar "baz" {
|
337
|
+
a: b;
|
338
|
+
c: d; }
|
339
|
+
|
340
|
+
bar: baz; }
|
341
|
+
SCSS
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_directive_with_rule_children
|
345
|
+
assert_renders <<SASS, <<SCSS
|
346
|
+
foo
|
347
|
+
@foo #bar "baz"
|
348
|
+
#blat
|
349
|
+
a: b
|
350
|
+
.bang
|
351
|
+
c: d
|
352
|
+
e: f
|
353
|
+
|
354
|
+
bar: baz
|
355
|
+
SASS
|
356
|
+
foo {
|
357
|
+
@foo #bar "baz" {
|
358
|
+
#blat {
|
359
|
+
a: b; }
|
360
|
+
.bang {
|
361
|
+
c: d;
|
362
|
+
e: f; } }
|
363
|
+
|
364
|
+
bar: baz; }
|
365
|
+
SCSS
|
366
|
+
end
|
367
|
+
|
368
|
+
def test_directive_with_rule_and_prop_children
|
369
|
+
assert_renders <<SASS, <<SCSS
|
370
|
+
foo
|
371
|
+
@foo #bar "baz"
|
372
|
+
g: h
|
373
|
+
#blat
|
374
|
+
a: b
|
375
|
+
.bang
|
376
|
+
c: d
|
377
|
+
e: f
|
378
|
+
i: j
|
379
|
+
|
380
|
+
bar: baz
|
381
|
+
SASS
|
382
|
+
foo {
|
383
|
+
@foo #bar "baz" {
|
384
|
+
g: h;
|
385
|
+
#blat {
|
386
|
+
a: b; }
|
387
|
+
.bang {
|
388
|
+
c: d;
|
389
|
+
e: f; }
|
390
|
+
i: j; }
|
391
|
+
|
392
|
+
bar: baz; }
|
393
|
+
SCSS
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_for
|
397
|
+
assert_renders <<SASS, <<SCSS
|
398
|
+
foo
|
399
|
+
@for !a from !b to !c
|
400
|
+
a: b
|
401
|
+
@for !c from 1 to 16
|
402
|
+
d: e
|
403
|
+
f: g
|
404
|
+
SASS
|
405
|
+
foo {
|
406
|
+
@for !a from !b to !c {
|
407
|
+
a: b; }
|
408
|
+
@for !c from 1 to 16 {
|
409
|
+
d: e;
|
410
|
+
f: g; } }
|
411
|
+
SCSS
|
412
|
+
end
|
413
|
+
|
414
|
+
def test_if
|
415
|
+
assert_renders <<SASS, <<SCSS
|
416
|
+
foo
|
417
|
+
@if !foo or !bar
|
418
|
+
a: b
|
419
|
+
@if !baz
|
420
|
+
d: e
|
421
|
+
@else if !bang
|
422
|
+
f: g
|
423
|
+
@else
|
424
|
+
h: i
|
425
|
+
SASS
|
426
|
+
foo {
|
427
|
+
@if !foo or !bar {
|
428
|
+
a: b; }
|
429
|
+
@if !baz {
|
430
|
+
d: e; }
|
431
|
+
@else if !bang {
|
432
|
+
f: g; }
|
433
|
+
@else {
|
434
|
+
h: i; } }
|
435
|
+
SCSS
|
436
|
+
end
|
437
|
+
|
438
|
+
def test_import
|
439
|
+
assert_renders <<SASS, <<SCSS
|
440
|
+
@import foo
|
441
|
+
|
442
|
+
foo
|
443
|
+
bar: baz
|
444
|
+
SASS
|
445
|
+
@import "foo";
|
446
|
+
|
447
|
+
foo {
|
448
|
+
bar: baz; }
|
449
|
+
SCSS
|
450
|
+
|
451
|
+
assert_renders <<SASS, <<SCSS
|
452
|
+
@import foo.css
|
453
|
+
|
454
|
+
foo
|
455
|
+
bar: baz
|
456
|
+
SASS
|
457
|
+
@import "foo.css";
|
458
|
+
|
459
|
+
foo {
|
460
|
+
bar: baz; }
|
461
|
+
SCSS
|
462
|
+
end
|
463
|
+
|
464
|
+
def test_import_as_directive_in_sass
|
465
|
+
assert_sass_to_sass '@import "foo.css"'
|
466
|
+
assert_sass_to_sass '@import url(foo.css)'
|
467
|
+
end
|
468
|
+
|
469
|
+
def test_import_as_directive_in_scss
|
470
|
+
assert_renders <<SASS, <<SCSS
|
471
|
+
@import "foo.css" print
|
472
|
+
SASS
|
473
|
+
@import "foo.css" print;
|
474
|
+
SCSS
|
475
|
+
|
476
|
+
assert_renders <<SASS, <<SCSS
|
477
|
+
@import url(foo.css) screen, print
|
478
|
+
SASS
|
479
|
+
@import url(foo.css) screen, print;
|
480
|
+
SCSS
|
481
|
+
end
|
482
|
+
|
483
|
+
def test_argless_mixin_definition
|
484
|
+
assert_renders <<SASS, <<SCSS
|
485
|
+
=foo-bar
|
486
|
+
baz
|
487
|
+
a: b
|
488
|
+
SASS
|
489
|
+
@mixin foo-bar {
|
490
|
+
baz {
|
491
|
+
a: b; } }
|
492
|
+
SCSS
|
493
|
+
|
494
|
+
assert_renders <<SASS, render(<<SCSS)
|
495
|
+
=foo-bar
|
496
|
+
baz
|
497
|
+
a: b
|
498
|
+
SASS
|
499
|
+
@mixin foo-bar() {
|
500
|
+
baz {
|
501
|
+
a: b; } }
|
502
|
+
SCSS
|
503
|
+
end
|
504
|
+
|
505
|
+
def test_mixin_definition_without_defaults
|
506
|
+
assert_renders <<SASS, <<SCSS
|
507
|
+
=foo-bar(!baz, !bang)
|
508
|
+
baz
|
509
|
+
a = !baz !bang
|
510
|
+
SASS
|
511
|
+
@mixin foo-bar(!baz, !bang) {
|
512
|
+
baz {
|
513
|
+
a = !baz !bang; } }
|
514
|
+
SCSS
|
515
|
+
end
|
516
|
+
|
517
|
+
def test_mixin_definition_with_defaults
|
518
|
+
assert_renders <<SASS, <<SCSS
|
519
|
+
=foo-bar(!baz, !bang = 12px)
|
520
|
+
baz
|
521
|
+
a = !baz !bang
|
522
|
+
SASS
|
523
|
+
@mixin foo-bar(!baz, !bang = 12px) {
|
524
|
+
baz {
|
525
|
+
a = !baz !bang; } }
|
526
|
+
SCSS
|
527
|
+
end
|
528
|
+
|
529
|
+
private
|
530
|
+
|
531
|
+
def assert_sass_to_sass(sass, options = {})
|
532
|
+
assert_equal(sass.rstrip, render(sass, options).rstrip,
|
533
|
+
"Expected Sass to transform to itself")
|
534
|
+
end
|
535
|
+
|
536
|
+
def assert_scss_to_sass(sass, scss, options = {})
|
537
|
+
assert_equal(sass.rstrip, render(scss, options.merge(:syntax => :scss)).rstrip,
|
538
|
+
"Expected SCSS to transform to Sass")
|
539
|
+
end
|
540
|
+
|
541
|
+
def assert_renders(sass, scss, options = {})
|
542
|
+
assert_sass_to_sass(sass, options)
|
543
|
+
assert_scss_to_sass(sass, scss, options)
|
544
|
+
end
|
545
|
+
|
546
|
+
def render(scss, options = {})
|
547
|
+
Sass::Engine.new(scss, options).to_tree.to_sass(options)
|
548
|
+
end
|
549
|
+
end
|