haml 2.2.24 → 3.0.0.beta.1

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.

Files changed (168) hide show
  1. data/.yardopts +0 -1
  2. data/README.md +91 -151
  3. data/REMEMBER +11 -1
  4. data/Rakefile +73 -55
  5. data/VERSION +1 -1
  6. data/VERSION_NAME +1 -1
  7. data/bin/css2sass +7 -1
  8. data/bin/sass-convert +7 -0
  9. data/extra/haml-mode.el +2 -1
  10. data/lib/haml/buffer.rb +22 -4
  11. data/lib/haml/engine.rb +5 -1
  12. data/lib/haml/exec.rb +231 -46
  13. data/lib/haml/filters.rb +19 -8
  14. data/lib/haml/helpers.rb +47 -20
  15. data/lib/haml/helpers/action_view_extensions.rb +2 -4
  16. data/lib/haml/helpers/action_view_mods.rb +11 -8
  17. data/lib/haml/helpers/xss_mods.rb +13 -2
  18. data/lib/haml/html.rb +179 -48
  19. data/lib/haml/html/erb.rb +141 -0
  20. data/lib/haml/precompiler.rb +40 -15
  21. data/lib/haml/railtie.rb +1 -5
  22. data/lib/haml/root.rb +3 -0
  23. data/lib/haml/template.rb +4 -14
  24. data/lib/haml/util.rb +120 -30
  25. data/lib/haml/version.rb +25 -2
  26. data/lib/sass.rb +5 -1
  27. data/lib/sass/callbacks.rb +50 -0
  28. data/lib/sass/css.rb +40 -191
  29. data/lib/sass/engine.rb +170 -74
  30. data/lib/sass/environment.rb +8 -2
  31. data/lib/sass/error.rb +163 -25
  32. data/lib/sass/files.rb +31 -28
  33. data/lib/sass/plugin.rb +268 -87
  34. data/lib/sass/plugin/rails.rb +9 -4
  35. data/lib/sass/repl.rb +1 -1
  36. data/lib/sass/script.rb +31 -29
  37. data/lib/sass/script/bool.rb +1 -0
  38. data/lib/sass/script/color.rb +290 -23
  39. data/lib/sass/script/css_lexer.rb +22 -0
  40. data/lib/sass/script/css_parser.rb +28 -0
  41. data/lib/sass/script/funcall.rb +22 -3
  42. data/lib/sass/script/functions.rb +523 -33
  43. data/lib/sass/script/interpolation.rb +42 -0
  44. data/lib/sass/script/lexer.rb +169 -52
  45. data/lib/sass/script/literal.rb +58 -9
  46. data/lib/sass/script/node.rb +79 -1
  47. data/lib/sass/script/number.rb +20 -5
  48. data/lib/sass/script/operation.rb +49 -3
  49. data/lib/sass/script/parser.rb +162 -28
  50. data/lib/sass/script/string.rb +50 -2
  51. data/lib/sass/script/unary_operation.rb +25 -2
  52. data/lib/sass/script/variable.rb +21 -4
  53. data/lib/sass/scss.rb +14 -0
  54. data/lib/sass/scss/css_parser.rb +39 -0
  55. data/lib/sass/scss/parser.rb +683 -0
  56. data/lib/sass/scss/rx.rb +112 -0
  57. data/lib/sass/scss/script_lexer.rb +13 -0
  58. data/lib/sass/scss/script_parser.rb +25 -0
  59. data/lib/sass/tree/comment_node.rb +69 -27
  60. data/lib/sass/tree/debug_node.rb +7 -2
  61. data/lib/sass/tree/directive_node.rb +41 -35
  62. data/lib/sass/tree/for_node.rb +6 -0
  63. data/lib/sass/tree/if_node.rb +13 -1
  64. data/lib/sass/tree/import_node.rb +52 -27
  65. data/lib/sass/tree/mixin_def_node.rb +18 -0
  66. data/lib/sass/tree/mixin_node.rb +41 -6
  67. data/lib/sass/tree/node.rb +197 -70
  68. data/lib/sass/tree/prop_node.rb +152 -57
  69. data/lib/sass/tree/root_node.rb +118 -0
  70. data/lib/sass/tree/rule_node.rb +193 -96
  71. data/lib/sass/tree/variable_node.rb +9 -5
  72. data/lib/sass/tree/while_node.rb +4 -0
  73. data/test/benchmark.rb +5 -5
  74. data/test/haml/engine_test.rb +147 -10
  75. data/test/haml/{rhtml/_av_partial_1.rhtml → erb/_av_partial_1.erb} +1 -1
  76. data/test/haml/{rhtml/_av_partial_2.rhtml → erb/_av_partial_2.erb} +1 -1
  77. data/test/haml/{rhtml/action_view.rhtml → erb/action_view.erb} +1 -1
  78. data/test/haml/{rhtml/standard.rhtml → erb/standard.erb} +0 -0
  79. data/test/haml/helper_test.rb +91 -24
  80. data/test/haml/html2haml/erb_tests.rb +410 -0
  81. data/test/haml/html2haml_test.rb +210 -66
  82. data/test/haml/results/filters.xhtml +1 -1
  83. data/test/haml/results/just_stuff.xhtml +2 -0
  84. data/test/haml/spec_test.rb +44 -0
  85. data/test/haml/template_test.rb +22 -2
  86. data/test/haml/templates/helpers.haml +0 -13
  87. data/test/haml/templates/just_stuff.haml +2 -0
  88. data/test/haml/util_test.rb +48 -0
  89. data/test/sass/callbacks_test.rb +61 -0
  90. data/test/sass/conversion_test.rb +884 -0
  91. data/test/sass/css2sass_test.rb +99 -18
  92. data/test/sass/data/hsl-rgb.txt +319 -0
  93. data/test/sass/engine_test.rb +1049 -131
  94. data/test/sass/functions_test.rb +398 -47
  95. data/test/sass/more_results/more_import.css +1 -1
  96. data/test/sass/more_templates/more_import.sass +3 -3
  97. data/test/sass/plugin_test.rb +184 -10
  98. data/test/sass/results/compact.css +1 -1
  99. data/test/sass/results/complex.css +5 -5
  100. data/test/sass/results/compressed.css +1 -1
  101. data/test/sass/results/expanded.css +1 -1
  102. data/test/sass/results/import.css +3 -1
  103. data/test/sass/results/mixins.css +12 -12
  104. data/test/sass/results/nested.css +1 -1
  105. data/test/sass/results/options.css +1 -0
  106. data/test/sass/results/parent_ref.css +4 -4
  107. data/test/sass/results/script.css +3 -3
  108. data/test/sass/results/scss_import.css +15 -0
  109. data/test/sass/results/scss_importee.css +2 -0
  110. data/test/sass/script_conversion_test.rb +153 -0
  111. data/test/sass/script_test.rb +137 -70
  112. data/test/sass/scss/css_test.rb +811 -0
  113. data/test/sass/scss/rx_test.rb +156 -0
  114. data/test/sass/scss/scss_test.rb +871 -0
  115. data/test/sass/scss/test_helper.rb +37 -0
  116. data/test/sass/templates/alt.sass +2 -2
  117. data/test/sass/templates/bork1.sass +2 -0
  118. data/test/sass/templates/bork3.sass +2 -0
  119. data/test/sass/templates/bork4.sass +2 -0
  120. data/test/sass/templates/import.sass +4 -4
  121. data/test/sass/templates/importee.sass +3 -3
  122. data/test/sass/templates/line_numbers.sass +1 -1
  123. data/test/sass/templates/mixin_bork.sass +5 -0
  124. data/test/sass/templates/mixins.sass +2 -2
  125. data/test/sass/templates/nested_bork1.sass +2 -0
  126. data/test/sass/templates/nested_bork2.sass +2 -0
  127. data/test/sass/templates/nested_bork3.sass +2 -0
  128. data/test/sass/templates/nested_bork4.sass +2 -0
  129. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  130. data/test/sass/templates/options.sass +2 -0
  131. data/test/sass/templates/parent_ref.sass +2 -2
  132. data/test/sass/templates/script.sass +69 -69
  133. data/test/sass/templates/scss_import.scss +10 -0
  134. data/test/sass/templates/scss_importee.scss +1 -0
  135. data/test/sass/templates/units.sass +10 -10
  136. data/test/test_helper.rb +20 -8
  137. data/vendor/fssm/LICENSE +20 -0
  138. data/vendor/fssm/README.markdown +55 -0
  139. data/vendor/fssm/Rakefile +59 -0
  140. data/vendor/fssm/VERSION.yml +5 -0
  141. data/vendor/fssm/example.rb +9 -0
  142. data/vendor/fssm/fssm.gemspec +77 -0
  143. data/vendor/fssm/lib/fssm.rb +33 -0
  144. data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  145. data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  146. data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  147. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  148. data/vendor/fssm/lib/fssm/monitor.rb +26 -0
  149. data/vendor/fssm/lib/fssm/path.rb +91 -0
  150. data/vendor/fssm/lib/fssm/pathname.rb +502 -0
  151. data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  152. data/vendor/fssm/lib/fssm/state/file.rb +24 -0
  153. data/vendor/fssm/lib/fssm/support.rb +63 -0
  154. data/vendor/fssm/lib/fssm/tree.rb +176 -0
  155. data/vendor/fssm/profile/prof-cache.rb +40 -0
  156. data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  157. data/vendor/fssm/profile/prof-pathname.rb +68 -0
  158. data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  159. data/vendor/fssm/profile/prof.html +2379 -0
  160. data/vendor/fssm/spec/path_spec.rb +75 -0
  161. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  162. data/vendor/fssm/spec/root/file.css +0 -0
  163. data/vendor/fssm/spec/root/file.rb +0 -0
  164. data/vendor/fssm/spec/root/file.yml +0 -0
  165. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  166. data/vendor/fssm/spec/spec_helper.rb +14 -0
  167. metadata +94 -14
  168. data/test/sass/templates/bork.sass +0 -2
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../../test_helper'
4
+ require 'sass/engine'
5
+
6
+ class ScssRxTest < Test::Unit::TestCase
7
+ include Sass::SCSS::RX
8
+
9
+ def test_identifiers
10
+ assert_match IDENT, "foo"
11
+ assert_match IDENT, "\xC3\xBFoo" # Initial char can be nonascii
12
+ assert_match IDENT, "\\123abcoo" # Initial char can be unicode escape
13
+ assert_match IDENT, "\\f oo" # Unicode escapes can be followed by whitespace
14
+ assert_match IDENT, "\\fa\too"
15
+ assert_match IDENT, "\\ff2\roo"
16
+ assert_match IDENT, "\\f13a\foo"
17
+ assert_match IDENT, "\\f13abcoo"
18
+ assert_match IDENT, "\\ oo" # Initial char can be a plain escape as well
19
+ assert_match IDENT, "\\~oo"
20
+ assert_match IDENT, "\\\\oo"
21
+ assert_match IDENT, "\\{oo"
22
+ assert_match IDENT, "\\\xC3\xBFoo"
23
+ assert_match IDENT, "-foo" # Can put a - before anything
24
+ assert_match IDENT, "-\xC3\xBFoo"
25
+ assert_match IDENT, "-\\f oo"
26
+ assert_match IDENT, "_foo" # Can put a _ before anything
27
+ assert_match IDENT, "_\xC3\xBFoo"
28
+ assert_match IDENT, "_\\f oo"
29
+
30
+ assert_match IDENT, "foo-bar"
31
+ assert_match IDENT, "f012-23"
32
+ assert_match IDENT, "foo_-_bar"
33
+ assert_match IDENT, "f012_23"
34
+
35
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-003.xht
36
+ assert_match IDENT, "c\\lass"
37
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-004.xht
38
+ assert_match IDENT, "c\\00006Cas\\000073"
39
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-001.xht
40
+ assert_match IDENT, "IdE6n-3t0_6"
41
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-006.xht
42
+ assert_match IDENT, "\\6000ident"
43
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-007.xht
44
+ assert_match IDENT, "iden\\6000t\\6000"
45
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/ident-013.xht
46
+ assert_match IDENT, "\\-ident"
47
+ end
48
+
49
+ def test_underscores_in_identifiers
50
+ assert_match IDENT, "foo_bar"
51
+ assert_match IDENT, "_\xC3\xBFfoo"
52
+ end
53
+
54
+ def test_invalid_identifiers
55
+ assert_no_match IDENT, ""
56
+ assert_no_match IDENT, "1foo"
57
+ assert_no_match IDENT, "-1foo"
58
+ assert_no_match IDENT, "--foo"
59
+ assert_no_match IDENT, "_1foo"
60
+ assert_no_match IDENT, "__foo"
61
+ assert_no_match IDENT, "-_foo"
62
+ assert_no_match IDENT, "_-foo"
63
+ assert_no_match IDENT, "foo bar"
64
+ assert_no_match IDENT, "foo~bar"
65
+
66
+ # http://www.w3.org/Style/CSS/Test/CSS2.1/current/xhtml1/escapes-008.xht
67
+ assert_no_match IDENT, "c\\06C ass"
68
+ assert_no_match IDENT, "back\\67\n round"
69
+ end
70
+
71
+ def test_double_quote_strings
72
+ assert_match STRING, '"foo bar"'
73
+ assert_match STRING, '"foo\\\nbar"'
74
+ assert_match STRING, "\"\\\"\""
75
+ assert_match STRING, '"\t !#$%&(-~()*+,-./0123456789~"'
76
+ end
77
+
78
+ def test_single_quote_strings
79
+ assert_match STRING, "'foo bar'"
80
+ assert_match STRING, "'foo\\\nbar'"
81
+ assert_match STRING, "'\\''"
82
+ assert_match STRING, "'\t !#\$%&(-~()*+,-./0123456789~'"
83
+ end
84
+
85
+ def test_invalid_strings
86
+ assert_no_match STRING, "\"foo\nbar\""
87
+ assert_no_match STRING, "\"foo\"bar\""
88
+ assert_no_match STRING, "'foo\nbar'"
89
+ assert_no_match STRING, "'foo'bar'"
90
+ end
91
+
92
+ def test_uri
93
+ assert_match URI, 'url("foo bar)")'
94
+ assert_match URI, "url('foo bar)')"
95
+ assert_match URI, 'url( "foo bar)" )'
96
+ assert_match URI, "url(!#\$%&**+,-./0123456789~)"
97
+ end
98
+
99
+ def test_invalid_uri
100
+ assert_no_match URI, 'url(foo)bar)'
101
+ end
102
+
103
+ def test_unicode_range
104
+ assert_match UNICODERANGE, 'U+00-Ff'
105
+ assert_match UNICODERANGE, 'u+980-9FF'
106
+ assert_match UNICODERANGE, 'U+9aF??'
107
+ assert_match UNICODERANGE, 'U+??'
108
+ end
109
+
110
+ def test_escape_empty_ident
111
+ assert_equal "", Sass::SCSS::RX.escape_ident("")
112
+ end
113
+
114
+ def test_escape_just_prefix_ident
115
+ assert_equal "\\-", Sass::SCSS::RX.escape_ident("-")
116
+ assert_equal "\\_", Sass::SCSS::RX.escape_ident("_")
117
+ end
118
+
119
+ def test_escape_plain_ident
120
+ assert_equal "foo", Sass::SCSS::RX.escape_ident("foo")
121
+ assert_equal "foo-1bar", Sass::SCSS::RX.escape_ident("foo-1bar")
122
+ assert_equal "-foo-bar", Sass::SCSS::RX.escape_ident("-foo-bar")
123
+ assert_equal "f2oo_bar", Sass::SCSS::RX.escape_ident("f2oo_bar")
124
+ assert_equal "_foo_bar", Sass::SCSS::RX.escape_ident("_foo_bar")
125
+ end
126
+
127
+ def test_escape_initial_funky_ident
128
+ assert_equal "\\000035foo", Sass::SCSS::RX.escape_ident("5foo")
129
+ assert_equal "-\\000035foo", Sass::SCSS::RX.escape_ident("-5foo")
130
+ assert_equal "_\\000035foo", Sass::SCSS::RX.escape_ident("_5foo")
131
+
132
+ assert_equal "\\&foo", Sass::SCSS::RX.escape_ident("&foo")
133
+ assert_equal "-\\&foo", Sass::SCSS::RX.escape_ident("-&foo")
134
+
135
+ assert_equal "-\\ foo", Sass::SCSS::RX.escape_ident("- foo")
136
+ end
137
+
138
+ def test_escape_mid_funky_ident
139
+ assert_equal "foo\\&bar", Sass::SCSS::RX.escape_ident("foo&bar")
140
+ assert_equal "foo\\ \\ bar", Sass::SCSS::RX.escape_ident("foo bar")
141
+ assert_equal "foo\\00007fbar", Sass::SCSS::RX.escape_ident("foo\177bar")
142
+ end
143
+
144
+ private
145
+
146
+ def assert_match(rx, str)
147
+ assert_not_nil(match = rx.match(str))
148
+ assert_equal str.size, match[0].size
149
+ end
150
+
151
+ def assert_no_match(rx, str)
152
+ match = rx.match(str)
153
+ assert_not_equal str.size, match && match[0].size
154
+ end
155
+
156
+ end
@@ -0,0 +1,871 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/test_helper'
4
+
5
+ class ScssTest < Test::Unit::TestCase
6
+ include ScssTestHelper
7
+
8
+ ## One-Line Comments
9
+
10
+ def test_one_line_comments
11
+ assert_equal <<CSS, render(<<SCSS)
12
+ .foo {
13
+ baz: bang; }
14
+ CSS
15
+ .foo {// bar: baz;}
16
+ baz: bang; //}
17
+ }
18
+ SCSS
19
+ assert_equal <<CSS, render(<<SCSS)
20
+ .foo bar[val="//"] {
21
+ baz: bang; }
22
+ CSS
23
+ .foo bar[val="//"] {
24
+ baz: bang; //}
25
+ }
26
+ SCSS
27
+ end
28
+
29
+ ## Script
30
+
31
+ def test_variables
32
+ assert_equal <<CSS, render(<<SCSS)
33
+ blat {
34
+ a: foo; }
35
+ CSS
36
+ $var: foo;
37
+
38
+ blat {a: $var}
39
+ SCSS
40
+
41
+ assert_equal <<CSS, render(<<SCSS)
42
+ foo {
43
+ a: 2;
44
+ b: 6; }
45
+ CSS
46
+ foo {
47
+ $var: 2;
48
+ $another-var: 4;
49
+ a: $var;
50
+ b: $var + $another-var;}
51
+ SCSS
52
+ end
53
+
54
+ def test_unicode_variables
55
+ assert_equal <<CSS, render(<<SCSS)
56
+ blat {
57
+ a: foo; }
58
+ CSS
59
+ $vär: foo;
60
+
61
+ blat {a: $vär}
62
+ SCSS
63
+ end
64
+
65
+ def test_guard_assign
66
+ assert_equal <<CSS, render(<<SCSS)
67
+ foo {
68
+ a: 1; }
69
+ CSS
70
+ $var: 1;
71
+ $var: 2 !default;
72
+
73
+ foo {a: $var}
74
+ SCSS
75
+
76
+ assert_equal <<CSS, render(<<SCSS)
77
+ foo {
78
+ a: 2; }
79
+ CSS
80
+ $var: 2 !default;
81
+
82
+ foo {a: $var}
83
+ SCSS
84
+ end
85
+
86
+ def test_sass_script
87
+ assert_equal <<CSS, render(<<SCSS)
88
+ foo {
89
+ a: 3;
90
+ b: foobar;
91
+ c: 12px; }
92
+ CSS
93
+ foo {
94
+ a: 1 + 2;
95
+ b: foo + bar;
96
+ c: floor(12.3px); }
97
+ SCSS
98
+ end
99
+
100
+ def test_debug_directive
101
+ assert_warning "test_debug_directive_inline.scss:2 DEBUG: hello world!" do
102
+ assert_equal <<CSS, render(<<SCSS)
103
+ foo {
104
+ a: b; }
105
+
106
+ bar {
107
+ c: d; }
108
+ CSS
109
+ foo {a: b}
110
+ @debug "hello world!";
111
+ bar {c: d}
112
+ SCSS
113
+ end
114
+ end
115
+
116
+ def test_for_directive
117
+ assert_equal <<CSS, render(<<SCSS)
118
+ .foo {
119
+ a: 1;
120
+ a: 2;
121
+ a: 3;
122
+ a: 4; }
123
+ CSS
124
+ .foo {
125
+ @for $var from 1 to 5 {a: $var;}
126
+ }
127
+ SCSS
128
+
129
+ assert_equal <<CSS, render(<<SCSS)
130
+ .foo {
131
+ a: 1;
132
+ a: 2;
133
+ a: 3;
134
+ a: 4;
135
+ a: 5; }
136
+ CSS
137
+ .foo {
138
+ @for $var from 1 through 5 {a: $var;}
139
+ }
140
+ SCSS
141
+ end
142
+
143
+ def test_if_directive
144
+ assert_equal <<CSS, render(<<SCSS)
145
+ foo {
146
+ a: b; }
147
+ CSS
148
+ @if "foo" == "foo" {foo {a: b}}
149
+ @if "foo" != "foo" {bar {a: b}}
150
+ SCSS
151
+
152
+ assert_equal <<CSS, render(<<SCSS)
153
+ bar {
154
+ a: b; }
155
+ CSS
156
+ @if "foo" != "foo" {foo {a: b}}
157
+ @else if "foo" == "foo" {bar {a: b}}
158
+ @else if true {baz {a: b}}
159
+ SCSS
160
+
161
+ assert_equal <<CSS, render(<<SCSS)
162
+ bar {
163
+ a: b; }
164
+ CSS
165
+ @if "foo" != "foo" {foo {a: b}}
166
+ @else {bar {a: b}}
167
+ SCSS
168
+ end
169
+
170
+ def test_while_directive
171
+ assert_equal <<CSS, render(<<SCSS)
172
+ .foo {
173
+ a: 1;
174
+ a: 2;
175
+ a: 3;
176
+ a: 4; }
177
+ CSS
178
+ $i: 1;
179
+
180
+ .foo {
181
+ @while $i != 5 {
182
+ a: $i;
183
+ $i: $i + 1;
184
+ }
185
+ }
186
+ SCSS
187
+ end
188
+
189
+ def test_css_import_directive
190
+ assert_equal "@import url(foo.css);\n", render('@import "foo.css";')
191
+ assert_equal "@import url(foo.css);\n", render("@import 'foo.css';")
192
+ assert_equal "@import url(foo.css);\n", render('@import url("foo.css");')
193
+ assert_equal "@import url(foo.css);\n", render("@import url('foo.css');")
194
+ assert_equal "@import url(foo.css);\n", render('@import url(foo.css);')
195
+ end
196
+
197
+ def test_block_comment_in_script
198
+ assert_equal <<CSS, render(<<SCSS)
199
+ foo {
200
+ a: 1bar; }
201
+ CSS
202
+ foo {a: 1 + /* flang */ bar}
203
+ SCSS
204
+ end
205
+
206
+ def test_line_comment_in_script
207
+ assert_equal <<CSS, render(<<SCSS)
208
+ foo {
209
+ a: 1blang; }
210
+ CSS
211
+ foo {a: 1 + // flang }
212
+ blang }
213
+ SCSS
214
+ end
215
+
216
+ ## Nested Rules
217
+
218
+ def test_nested_rules
219
+ assert_equal <<CSS, render(<<SCSS)
220
+ foo bar {
221
+ a: b; }
222
+ CSS
223
+ foo {bar {a: b}}
224
+ SCSS
225
+ assert_equal <<CSS, render(<<SCSS)
226
+ foo bar {
227
+ a: b; }
228
+ foo baz {
229
+ b: c; }
230
+ CSS
231
+ foo {
232
+ bar {a: b}
233
+ baz {b: c}}
234
+ SCSS
235
+ assert_equal <<CSS, render(<<SCSS)
236
+ foo bar baz {
237
+ a: b; }
238
+ foo bang bip {
239
+ a: b; }
240
+ CSS
241
+ foo {
242
+ bar {baz {a: b}}
243
+ bang {bip {a: b}}}
244
+ SCSS
245
+ end
246
+
247
+ def test_nested_rules_with_declarations
248
+ assert_equal <<CSS, render(<<SCSS)
249
+ foo {
250
+ a: b; }
251
+ foo bar {
252
+ c: d; }
253
+ CSS
254
+ foo {
255
+ a: b;
256
+ bar {c: d}}
257
+ SCSS
258
+ assert_equal <<CSS, render(<<SCSS)
259
+ foo {
260
+ a: b; }
261
+ foo bar {
262
+ c: d; }
263
+ CSS
264
+ foo {
265
+ bar {c: d}
266
+ a: b}
267
+ SCSS
268
+ assert_equal <<CSS, render(<<SCSS)
269
+ foo {
270
+ ump: nump;
271
+ grump: clump; }
272
+ foo bar {
273
+ blat: bang;
274
+ habit: rabbit; }
275
+ foo bar baz {
276
+ a: b; }
277
+ foo bar bip {
278
+ c: d; }
279
+ foo bibble bap {
280
+ e: f; }
281
+ CSS
282
+ foo {
283
+ ump: nump;
284
+ grump: clump;
285
+ bar {
286
+ blat: bang;
287
+ habit: rabbit;
288
+ baz {a: b}
289
+ bip {c: d}}
290
+ bibble {
291
+ bap {e: f}}}
292
+ SCSS
293
+ end
294
+
295
+ def test_nested_rules_with_fancy_selectors
296
+ assert_equal <<CSS, render(<<SCSS)
297
+ foo .bar {
298
+ a: b; }
299
+ foo :baz {
300
+ c: d; }
301
+ foo bang:bop {
302
+ e: f; }
303
+ CSS
304
+ foo {
305
+ .bar {a: b}
306
+ :baz {c: d}
307
+ bang:bop {e: f}}
308
+ SCSS
309
+ end
310
+
311
+ def test_almost_ambiguous_nested_rules_and_declarations
312
+ assert_equal <<CSS, render(<<SCSS)
313
+ foo {
314
+ bar: baz bang bop biddle woo look at all these elems; }
315
+ foo bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {
316
+ a: b; }
317
+ foo bar:baz bang bop biddle woo look at all these elems {
318
+ a: b; }
319
+ CSS
320
+ foo {
321
+ bar:baz:bang:bop:biddle:woo:look:at:all:these:pseudoclasses {a: b};
322
+ bar:baz bang bop biddle woo look at all these elems {a: b};
323
+ bar:baz bang bop biddle woo look at all these elems; }
324
+ SCSS
325
+ end
326
+
327
+ def test_newlines_in_selectors
328
+ assert_equal <<CSS, render(<<SCSS)
329
+ foo
330
+ bar {
331
+ a: b; }
332
+ CSS
333
+ foo
334
+ bar {a: b}
335
+ SCSS
336
+
337
+ assert_equal <<CSS, render(<<SCSS)
338
+ foo baz,
339
+ foo bang,
340
+ bar baz,
341
+ bar bang {
342
+ a: b; }
343
+ CSS
344
+ foo,
345
+ bar {
346
+ baz,
347
+ bang {a: b}}
348
+ SCSS
349
+
350
+ assert_equal <<CSS, render(<<SCSS)
351
+ foo
352
+ bar baz
353
+ bang {
354
+ a: b; }
355
+ foo
356
+ bar bip bop {
357
+ c: d; }
358
+ CSS
359
+ foo
360
+ bar {
361
+ baz
362
+ bang {a: b}
363
+
364
+ bip bop {c: d}}
365
+ SCSS
366
+
367
+ assert_equal <<CSS, render(<<SCSS)
368
+ foo bang, foo bip
369
+ bop, bar
370
+ baz bang, bar
371
+ baz bip
372
+ bop {
373
+ a: b; }
374
+ CSS
375
+ foo, bar
376
+ baz {
377
+ bang, bip
378
+ bop {a: b}}
379
+ SCSS
380
+ end
381
+
382
+ def test_parent_selectors
383
+ assert_equal <<CSS, render(<<SCSS)
384
+ foo:hover {
385
+ a: b; }
386
+ bar foo.baz {
387
+ c: d; }
388
+ CSS
389
+ foo {
390
+ &:hover {a: b}
391
+ bar &.baz {c: d}}
392
+ SCSS
393
+ end
394
+
395
+ ## Namespace Properties
396
+
397
+ def test_namespace_properties
398
+ assert_equal <<CSS, render(<<SCSS)
399
+ foo {
400
+ bar: baz;
401
+ bang-bip: 1px;
402
+ bang-bop: bar; }
403
+ CSS
404
+ foo {
405
+ bar: baz;
406
+ bang: {
407
+ bip: 1px;
408
+ bop: bar;}}
409
+ SCSS
410
+ end
411
+
412
+ def test_nested_namespace_properties
413
+ assert_equal <<CSS, render(<<SCSS)
414
+ foo {
415
+ bar: baz;
416
+ bang-bip: 1px;
417
+ bang-bop: bar;
418
+ bang-blat-baf: bort; }
419
+ CSS
420
+ foo {
421
+ bar: baz;
422
+ bang: {
423
+ bip: 1px;
424
+ bop: bar;
425
+ blat:{baf:bort}}}
426
+ SCSS
427
+ end
428
+
429
+ def test_namespace_properties_with_value
430
+ assert_equal <<CSS, render(<<SCSS)
431
+ foo {
432
+ bar: baz;
433
+ bar-bip: bop;
434
+ bar-bing: bop; }
435
+ CSS
436
+ foo {
437
+ bar: baz {
438
+ bip: bop;
439
+ bing: bop; }}
440
+ SCSS
441
+ end
442
+
443
+ def test_namespace_properties_with_script_value
444
+ assert_equal <<CSS, render(<<SCSS)
445
+ foo {
446
+ bar: bazbang;
447
+ bar-bip: bop;
448
+ bar-bing: bop; }
449
+ CSS
450
+ foo {
451
+ bar: baz + bang {
452
+ bip: bop;
453
+ bing: bop; }}
454
+ SCSS
455
+ end
456
+
457
+ def test_no_namespace_properties_without_space
458
+ assert_equal <<CSS, render(<<SCSS)
459
+ foo bar:baz {
460
+ bip: bop; }
461
+ CSS
462
+ foo {
463
+ bar:baz {
464
+ bip: bop }}
465
+ SCSS
466
+ end
467
+
468
+ def test_no_namespace_properties_without_space_even_when_its_unambiguous
469
+ render(<<SCSS)
470
+ foo {
471
+ bar:1px {
472
+ bip: bop }}
473
+ SCSS
474
+ assert(false, "Expected syntax error")
475
+ rescue Sass::SyntaxError => e
476
+ assert_equal <<MESSAGE, e.message
477
+ Invalid CSS: a space is required between a property and its definition
478
+ when it has other properties nested beneath it.
479
+ MESSAGE
480
+ assert_equal 2, e.sass_line
481
+ end
482
+
483
+ ## Mixins
484
+
485
+ def test_basic_mixins
486
+ assert_equal <<CSS, render(<<SCSS)
487
+ .foo {
488
+ a: b; }
489
+ CSS
490
+ @mixin foo {
491
+ .foo {a: b}}
492
+
493
+ @include foo;
494
+ SCSS
495
+
496
+ assert_equal <<CSS, render(<<SCSS)
497
+ bar {
498
+ c: d; }
499
+ bar .foo {
500
+ a: b; }
501
+ CSS
502
+ @mixin foo {
503
+ .foo {a: b}}
504
+
505
+ bar {
506
+ @include foo;
507
+ c: d; }
508
+ SCSS
509
+
510
+ assert_equal <<CSS, render(<<SCSS)
511
+ bar {
512
+ a: b;
513
+ c: d; }
514
+ CSS
515
+ @mixin foo {a: b}
516
+
517
+ bar {
518
+ @include foo;
519
+ c: d; }
520
+ SCSS
521
+ end
522
+
523
+ def test_mixins_with_empty_args
524
+ assert_equal <<CSS, render(<<SCSS)
525
+ .foo {
526
+ a: b; }
527
+ CSS
528
+ @mixin foo() {a: b}
529
+
530
+ .foo {@include foo();}
531
+ SCSS
532
+
533
+ assert_equal <<CSS, render(<<SCSS)
534
+ .foo {
535
+ a: b; }
536
+ CSS
537
+ @mixin foo() {a: b}
538
+
539
+ .foo {@include foo;}
540
+ SCSS
541
+
542
+ assert_equal <<CSS, render(<<SCSS)
543
+ .foo {
544
+ a: b; }
545
+ CSS
546
+ @mixin foo {a: b}
547
+
548
+ .foo {@include foo();}
549
+ SCSS
550
+ end
551
+
552
+ def test_mixins_with_args
553
+ assert_equal <<CSS, render(<<SCSS)
554
+ .foo {
555
+ a: bar; }
556
+ CSS
557
+ @mixin foo($a) {a: $a}
558
+
559
+ .foo {@include foo(bar)}
560
+ SCSS
561
+
562
+ assert_equal <<CSS, render(<<SCSS)
563
+ .foo {
564
+ a: bar;
565
+ b: 12px; }
566
+ CSS
567
+ @mixin foo($a, $b) {
568
+ a: $a;
569
+ b: $b; }
570
+
571
+ .foo {@include foo(bar, 12px)}
572
+ SCSS
573
+ end
574
+
575
+ ## Interpolation
576
+
577
+ def test_basic_selector_interpolation
578
+ assert_equal <<CSS, render(<<SCSS)
579
+ foo 3 baz {
580
+ a: b; }
581
+ CSS
582
+ foo \#{1 + 2} baz {a: b}
583
+ SCSS
584
+ assert_equal <<CSS, render(<<SCSS)
585
+ foo.bar baz {
586
+ a: b; }
587
+ CSS
588
+ foo\#{".bar"} baz {a: b}
589
+ SCSS
590
+ assert_equal <<CSS, render(<<SCSS)
591
+ foo.bar baz {
592
+ a: b; }
593
+ CSS
594
+ \#{"foo"}.bar baz {a: b}
595
+ SCSS
596
+ end
597
+
598
+ def test_selector_only_interpolation
599
+ assert_equal <<CSS, render(<<SCSS)
600
+ foo bar {
601
+ a: b; }
602
+ CSS
603
+ \#{"foo" + " bar"} {a: b}
604
+ SCSS
605
+ end
606
+
607
+ def test_selector_interpolation_before_element_name
608
+ assert_equal <<CSS, render(<<SCSS)
609
+ foo barbaz {
610
+ a: b; }
611
+ CSS
612
+ \#{"foo" + " bar"}baz {a: b}
613
+ SCSS
614
+ end
615
+
616
+ def test_selector_interpolation_in_string
617
+ assert_equal <<CSS, render(<<SCSS)
618
+ foo[val="bar foo bar baz"] {
619
+ a: b; }
620
+ CSS
621
+ foo[val="bar \#{"foo" + " bar"} baz"] {a: b}
622
+ SCSS
623
+ end
624
+
625
+ def test_selector_interpolation_in_pseudoclass
626
+ assert_equal <<CSS, render(<<SCSS)
627
+ foo:nth-child(5n) {
628
+ a: b; }
629
+ CSS
630
+ foo:nth-child(\#{5 + "n"}) {a: b}
631
+ SCSS
632
+ end
633
+
634
+ def test_basic_prop_val_interpolation
635
+ assert_equal <<CSS, render(<<SCSS)
636
+ foo {
637
+ bar: foo 3 baz; }
638
+ CSS
639
+ foo {bar: foo \#{1 + 2} baz}
640
+ SCSS
641
+ assert_equal <<CSS, render(<<SCSS)
642
+ foo {
643
+ bar: foo3 baz; }
644
+ CSS
645
+ foo {bar: foo\#{1 + 2} baz}
646
+ SCSS
647
+ assert_equal <<CSS, render(<<SCSS)
648
+ foo {
649
+ bar: foo 3, baz; }
650
+ CSS
651
+ foo {bar: foo \#{1 + 2},baz}
652
+ SCSS
653
+ end
654
+
655
+ def test_prop_val_only_interpolation
656
+ assert_equal <<CSS, render(<<SCSS)
657
+ foo {
658
+ bar: bazbang; }
659
+ CSS
660
+ foo {bar: \#{"baz" + "bang"}}
661
+ SCSS
662
+ end
663
+
664
+ def test_prop_val_interpolation_in_string
665
+ assert_equal <<CSS, render(<<SCSS)
666
+ foo {
667
+ bar: "bizzle bazbang bop"; }
668
+ CSS
669
+ foo {bar: "bizzle \#{"baz" + "bang"} bop"}
670
+ SCSS
671
+ end
672
+
673
+ def test_prop_val_interpolation_in_function
674
+ assert_equal <<CSS, render(<<SCSS)
675
+ foo {
676
+ bar: flabnabbit(1foo); }
677
+ CSS
678
+ foo {bar: flabnabbit(\#{1 + "foo"})}
679
+ SCSS
680
+ end
681
+
682
+ def test_basic_prop_name_interpolation
683
+ assert_equal <<CSS, render(<<SCSS)
684
+ foo {
685
+ barbazbang: blip; }
686
+ CSS
687
+ foo {bar\#{"baz" + "bang"}: blip}
688
+ SCSS
689
+ assert_equal <<CSS, render(<<SCSS)
690
+ foo {
691
+ bar3: blip; }
692
+ CSS
693
+ foo {bar\#{1 + 2}: blip}
694
+ SCSS
695
+ end
696
+
697
+ def test_prop_name_only_interpolation
698
+ assert_equal <<CSS, render(<<SCSS)
699
+ foo {
700
+ bazbang: blip; }
701
+ CSS
702
+ foo {\#{"baz" + "bang"}: blip}
703
+ SCSS
704
+ end
705
+
706
+ ## Errors
707
+
708
+ def test_mixin_defs_only_at_toplevel
709
+ render <<SCSS
710
+ foo {
711
+ @mixin bar {a: b}}
712
+ SCSS
713
+ assert(false, "Expected syntax error")
714
+ rescue Sass::SyntaxError => e
715
+ assert_equal "Mixins may only be defined at the root of a document.", e.message
716
+ assert_equal 2, e.sass_line
717
+ end
718
+
719
+ def test_imports_only_at_toplevel
720
+ render <<SCSS
721
+ foo {
722
+ @import "foo.scss";}
723
+ SCSS
724
+ assert(false, "Expected syntax error")
725
+ rescue Sass::SyntaxError => e
726
+ assert_equal "Import directives may only be used at the root of a document.", e.message
727
+ assert_equal 2, e.sass_line
728
+ end
729
+
730
+ def test_rules_beneath_properties
731
+ render <<SCSS
732
+ foo {
733
+ bar: {
734
+ baz {
735
+ bang: bop }}}
736
+ SCSS
737
+ assert(false, "Expected syntax error")
738
+ rescue Sass::SyntaxError => e
739
+ assert_equal 'Illegal nesting: Only properties may be nested beneath properties.', e.message
740
+ assert_equal 3, e.sass_line
741
+ end
742
+
743
+ def test_uses_property_exception_with_star_hack
744
+ render <<SCSS
745
+ foo {
746
+ *bar:baz [fail]; }
747
+ SCSS
748
+ assert(false, "Expected syntax error")
749
+ rescue Sass::SyntaxError => e
750
+ assert_equal 'Invalid CSS after " *bar:baz ": expected ";", was "[fail]; }"', e.message
751
+ assert_equal 2, e.sass_line
752
+ end
753
+
754
+ def test_uses_property_exception_with_colon_hack
755
+ render <<SCSS
756
+ foo {
757
+ :bar:baz [fail]; }
758
+ SCSS
759
+ assert(false, "Expected syntax error")
760
+ rescue Sass::SyntaxError => e
761
+ assert_equal 'Invalid CSS after " :bar:baz ": expected ";", was "[fail]; }"', e.message
762
+ assert_equal 2, e.sass_line
763
+ end
764
+
765
+ def test_uses_rule_exception_with_dot_hack
766
+ render <<SCSS
767
+ foo {
768
+ .bar:baz <fail>; }
769
+ SCSS
770
+ assert(false, "Expected syntax error")
771
+ rescue Sass::SyntaxError => e
772
+ assert_equal 'Invalid CSS after " .bar:baz ": expected "{", was "<fail>; }"', e.message
773
+ assert_equal 2, e.sass_line
774
+ end
775
+
776
+ def test_uses_property_exception_with_space_after_name
777
+ render <<SCSS
778
+ foo {
779
+ bar: baz [fail]; }
780
+ SCSS
781
+ assert(false, "Expected syntax error")
782
+ rescue Sass::SyntaxError => e
783
+ assert_equal 'Invalid CSS after " bar: baz ": expected ";", was "[fail]; }"', e.message
784
+ assert_equal 2, e.sass_line
785
+ end
786
+
787
+ def test_uses_property_exception_with_non_identifier_after_name
788
+ render <<SCSS
789
+ foo {
790
+ bar:1px [fail]; }
791
+ SCSS
792
+ assert(false, "Expected syntax error")
793
+ rescue Sass::SyntaxError => e
794
+ assert_equal 'Invalid CSS after " bar:1px ": expected ";", was "[fail]; }"', e.message
795
+ assert_equal 2, e.sass_line
796
+ end
797
+
798
+ def test_uses_property_exception_when_followed_by_open_bracket
799
+ render <<SCSS
800
+ foo {
801
+ bar:{baz: .fail} }
802
+ SCSS
803
+ assert(false, "Expected syntax error")
804
+ rescue Sass::SyntaxError => e
805
+ assert_equal 'Invalid CSS after " bar:{baz: ": expected expression (e.g. 1px, bold), was ".fail} }"', e.message
806
+ assert_equal 2, e.sass_line
807
+ end
808
+
809
+ def test_script_error
810
+ render <<SCSS
811
+ foo {
812
+ bar: "baz" * * }
813
+ SCSS
814
+ assert(false, "Expected syntax error")
815
+ rescue Sass::SyntaxError => e
816
+ assert_equal 'Invalid CSS after " bar: "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
817
+ assert_equal 2, e.sass_line
818
+ end
819
+
820
+ def test_multiline_script_syntax_error
821
+ render <<SCSS
822
+ foo {
823
+ bar:
824
+ "baz" * * }
825
+ SCSS
826
+ assert(false, "Expected syntax error")
827
+ rescue Sass::SyntaxError => e
828
+ assert_equal 'Invalid CSS after " "baz" * ": expected expression (e.g. 1px, bold), was "* }"', e.message
829
+ assert_equal 3, e.sass_line
830
+ end
831
+
832
+ def test_multiline_script_runtime_error
833
+ render <<SCSS
834
+ foo {
835
+ bar: "baz" +
836
+ "bar" +
837
+ $bang }
838
+ SCSS
839
+ assert(false, "Expected syntax error")
840
+ rescue Sass::SyntaxError => e
841
+ assert_equal "Undefined variable: \"$bang\".", e.message
842
+ assert_equal 4, e.sass_line
843
+ end
844
+
845
+ def test_post_multiline_script_runtime_error
846
+ render <<SCSS
847
+ foo {
848
+ bar: "baz" +
849
+ "bar" +
850
+ "baz";
851
+ bip: $bop; }
852
+ SCSS
853
+ assert(false, "Expected syntax error")
854
+ rescue Sass::SyntaxError => e
855
+ assert_equal "Undefined variable: \"$bop\".", e.message
856
+ assert_equal 5, e.sass_line
857
+ end
858
+
859
+ def test_multiline_property_runtime_error
860
+ render <<SCSS
861
+ foo {
862
+ bar: baz
863
+ bar
864
+ \#{$bang} }
865
+ SCSS
866
+ assert(false, "Expected syntax error")
867
+ rescue Sass::SyntaxError => e
868
+ assert_equal "Undefined variable: \"$bang\".", e.message
869
+ assert_equal 4, e.sass_line
870
+ end
871
+ end