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
@@ -3,21 +3,26 @@ require File.dirname(__FILE__) + '/../test_helper'
3
3
  require 'sass/engine'
4
4
  require 'stringio'
5
5
 
6
+ module Sass::Script::Functions::UserFunctions
7
+ def option(name)
8
+ Sass::Script::String.new(@options[name.value.to_sym].to_s)
9
+ end
10
+ end
11
+
6
12
  class SassEngineTest < Test::Unit::TestCase
7
13
  # A map of erroneous Sass documents to the error messages they should produce.
8
14
  # The error messages may be arrays;
9
15
  # if so, the second element should be the line number that should be reported for the error.
10
16
  # If this isn't provided, the tests will assume the line number should be the last line of the document.
11
17
  EXCEPTION_MAP = {
12
- "!a = 1 + " => 'Expected expression, was end of text.',
13
- "!a = 1 + 2 +" => 'Expected expression, was end of text.',
14
- "!a = 1 + 2 + %" => 'Expected expression, was mod token.',
15
- "!a = foo(\"bar\"" => 'Expected rparen token, was end of text.',
16
- "!a = 1 }" => 'Unexpected end_interpolation token.',
17
- "!a = 1 }foo\"" => 'Unexpected end_interpolation token.',
18
+ "$a: 1 + " => 'Invalid CSS after "1 +": expected expression (e.g. 1px, bold), was ""',
19
+ "$a: 1 + 2 +" => 'Invalid CSS after "1 + 2 +": expected expression (e.g. 1px, bold), was ""',
20
+ "$a: 1 + 2 + %" => 'Invalid CSS after "1 + 2 + ": expected expression (e.g. 1px, bold), was "%"',
21
+ "$a: foo(\"bar\"" => 'Invalid CSS after "foo("bar"": expected ")", was ""',
22
+ "$a: 1 }" => 'Invalid CSS after "1 ": expected expression (e.g. 1px, bold), was "}"',
23
+ "$a: 1 }foo\"" => 'Invalid CSS after "1 ": expected expression (e.g. 1px, bold), was "}foo""',
18
24
  ":" => 'Invalid property: ":".',
19
25
  ": a" => 'Invalid property: ": a".',
20
- ":= a" => 'Invalid property: ":= a".',
21
26
  "a\n :b" => <<MSG,
22
27
  Invalid property: ":b" (no value).
23
28
  If ":b" should be a selector, use "\\:b" instead.
@@ -25,36 +30,32 @@ MSG
25
30
  "a\n b:" => 'Invalid property: "b:" (no value).',
26
31
  "a\n :b: c" => 'Invalid property: ":b: c".',
27
32
  "a\n :b:c d" => 'Invalid property: ":b:c d".',
28
- "a\n :b=c d" => 'Invalid property: ":b=c d".',
29
- "a\n :b c;" => 'Invalid property: ":b c;" (no ";" required at end-of-line).',
30
- "a\n b: c;" => 'Invalid property: "b: c;" (no ";" required at end-of-line).',
31
- "a\n b : c" => 'Invalid property: "b : c".',
32
- "a\n b=c: d" => 'Invalid property: "b=c: d".',
33
+ "a\n :b c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
34
+ "a\n b: c;" => 'Invalid CSS after "c": expected expression (e.g. 1px, bold), was ";"',
35
+ "a: b" => 'Properties aren\'t allowed at the root of a document.',
33
36
  ":a b" => 'Properties aren\'t allowed at the root of a document.',
34
- "a:" => 'Properties aren\'t allowed at the root of a document.',
35
- ":a" => <<MSG,
36
- Properties aren't allowed at the root of a document.
37
- If ":a" should be a selector, use "\\:a" instead.
38
- MSG
39
37
  "!" => 'Invalid variable: "!".',
40
- "!a" => 'Invalid variable: "!a".',
38
+ "$a" => 'Invalid variable: "$a".',
41
39
  "! a" => 'Invalid variable: "! a".',
42
- "!a b" => 'Invalid variable: "!a b".',
43
- "!a = 1b + 2c" => "Incompatible units: 'c' and 'b'.",
44
- "!a = 1b < 2c" => "Incompatible units: 'c' and 'b'.",
45
- "!a = 1b > 2c" => "Incompatible units: 'c' and 'b'.",
46
- "!a = 1b <= 2c" => "Incompatible units: 'c' and 'b'.",
47
- "!a = 1b >= 2c" => "Incompatible units: 'c' and 'b'.",
48
- "a\n :b= 1b * 2c" => "2b*c isn't a valid CSS value.",
49
- "a\n :b= 1b % 2c" => "Cannot modulo by a number with units: 2c.",
50
- "!a = 2px + #ccc" => "Cannot add a number with units (2px) to a color (#cccccc).",
51
- "!a = #ccc + 2px" => "Cannot add a number with units (2px) to a color (#cccccc).",
40
+ "$a b" => 'Invalid variable: "$a b".',
41
+ "$a: 1b + 2c" => "Incompatible units: 'c' and 'b'.",
42
+ "$a: 1b < 2c" => "Incompatible units: 'c' and 'b'.",
43
+ "$a: 1b > 2c" => "Incompatible units: 'c' and 'b'.",
44
+ "$a: 1b <= 2c" => "Incompatible units: 'c' and 'b'.",
45
+ "$a: 1b >= 2c" => "Incompatible units: 'c' and 'b'.",
46
+ "a\n b: 1b * 2c" => "2b*c isn't a valid CSS value.",
47
+ "a\n b: 1b % 2c" => "Cannot modulo by a number with units: 2c.",
48
+ "$a: 2px + #ccc" => "Cannot add a number with units (2px) to a color (#cccccc).",
49
+ "$a: #ccc + 2px" => "Cannot add a number with units (2px) to a color (#cccccc).",
52
50
  "& a\n :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
53
51
  "a\n :b\n c" => "Illegal nesting: Only properties may be nested beneath properties.",
54
52
  "a,\n :b c" => ["Rules can\'t end in commas.", 1],
55
53
  "a," => "Rules can\'t end in commas.",
56
- "a,\n!b = 1" => ["Rules can\'t end in commas.", 1],
57
- "!a = b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
54
+ "a,\n$b: 1" => ["Rules can\'t end in commas.", 1],
55
+ "$a: b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
56
+ "@import foo.sass" => "File to import not found or unreadable: foo.sass.",
57
+ "a,\n$b: 1" => ["Rules can\'t end in commas.", 1],
58
+ "$a: b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
58
59
  "@import foo.sass" => <<MSG,
59
60
  File to import not found or unreadable: foo.sass.
60
61
  Load paths:
@@ -64,8 +65,10 @@ MSG
64
65
  "@import templates/basic\n foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
65
66
  "foo\n @import templates/basic" => "Import directives may only be used at the root of a document.",
66
67
  "foo\n @import #{File.dirname(__FILE__)}/templates/basic" => "Import directives may only be used at the root of a document.",
67
- %Q{!foo = "bar" "baz" !} => %Q{Syntax error in '"bar" "baz" !' at character 20.},
68
+ '$foo: "bar" "baz" !' => %Q{Invalid CSS after ""bar" "baz" ": expected expression (e.g. 1px, bold), was "!"},
68
69
  "=foo\n :color red\n.bar\n +bang" => "Undefined mixin 'bang'.",
70
+ "=foo\n :color red\n.bar\n +bang_bop" => "Undefined mixin 'bang_bop'.",
71
+ "=foo\n :color red\n.bar\n +bang-bop" => "Undefined mixin 'bang-bop'.",
69
72
  ".bar\n =foo\n :color red\n" => ["Mixins may only be defined at the root of a document.", 2],
70
73
  "=foo\n :color red\n.bar\n +foo\n :color red" => "Illegal nesting: Nothing may be nested beneath mixin directives.",
71
74
  " a\n b: c" => ["Indenting at the beginning of the document is illegal.", 1],
@@ -78,26 +81,29 @@ MSG
78
81
  "a\n b: c\na\n d: e" => ["The line was indented 2 levels deeper than the previous line.", 4],
79
82
  "a\n b: c\n a\n d: e" => ["The line was indented 3 levels deeper than the previous line.", 4],
80
83
  "a\n \tb: c" => ["Indentation can't use both tabs and spaces.", 2],
81
- "=a(" => 'Expected rparen token, was end of text.',
82
- "=a(b)" => 'Expected rparen token, was ident token.',
83
- "=a(,)" => "Expected rparen token, was comma token.",
84
- "=a(!)" => "Syntax error in '(!)' at character 4.",
85
- "=a(!foo bar)" => "Expected rparen token, was ident token.",
84
+ "=a(" => 'Invalid CSS after "(": expected ")", was ""',
85
+ "=a(b)" => 'Invalid CSS after "(": expected ")", was "b)"',
86
+ "=a(,)" => 'Invalid CSS after "(": expected ")", was ",)"',
87
+ "=a(!)" => 'Invalid CSS after "(": expected ")", was "!)"',
88
+ "=a($foo bar)" => 'Invalid CSS after "($foo ": expected ")", was "bar)"',
86
89
  "=foo\n bar: baz\n+foo" => ["Properties aren't allowed at the root of a document.", 2],
87
- "a-\#{!b\n c: d" => ["Expected end_interpolation token, was end of text.", 1],
88
- "=a(!b = 1, !c)" => "Required argument !c must come before any optional arguments.",
89
- "=a(!b = 1)\n :a= !b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
90
- "=a(!b)\n :a= !b\ndiv\n +a" => "Mixin a is missing parameter !b.",
90
+ "a-\#{$b\n c: d" => ['Invalid CSS after "a-#{$b": expected "}", was ""', 1],
91
+ "=a($b = 1, $c)" => "Required argument $c must come before any optional arguments.",
92
+ "=a($b = 1)\n a: $b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
93
+ "=a($b)\n a: $b\ndiv\n +a" => "Mixin a is missing parameter $b.",
91
94
  "@else\n a\n b: c" => ["@else must come after @if.", 1],
92
95
  "@if false\n@else foo" => "Invalid else directive '@else foo': expected 'if <expr>'.",
93
96
  "@if false\n@else if " => "Invalid else directive '@else if': expected 'if <expr>'.",
94
- "a\n !b = 12\nc\n d = !b" => 'Undefined variable: "!b".',
95
- "=foo\n !b = 12\nc\n +foo\n d = !b" => 'Undefined variable: "!b".',
96
- '@for !a from "foo" to 1' => '"foo" is not an integer.',
97
- '@for !a from 1 to "2"' => '"2" is not an integer.',
98
- '@for !a from 1 to "foo"' => '"foo" is not an integer.',
99
- '@for !a from 1 to 1.232323' => '1.232 is not an integer.',
100
- '@for !a from 1px to 3em' => "Incompatible units: 'em' and 'px'.",
97
+ "a\n !b: 12\nc\n d: !b" => 'Undefined variable: "$b".',
98
+ "a\n $b: 12\nc\n d: $b" => 'Undefined variable: "$b".',
99
+ "=foo\n $b: 12\nc\n +foo\n d: $b" => 'Undefined variable: "$b".',
100
+ "c\n d: $b-foo" => 'Undefined variable: "$b-foo".',
101
+ "c\n d: $b_foo" => 'Undefined variable: "$b_foo".',
102
+ '@for $a from "foo" to 1' => '"foo" is not an integer.',
103
+ '@for $a from 1 to "2"' => '"2" is not an integer.',
104
+ '@for $a from 1 to "foo"' => '"foo" is not an integer.',
105
+ '@for $a from 1 to 1.232323' => '1.232 is not an integer.',
106
+ '@for $a from 1px to 3em' => "Incompatible units: 'em' and 'px'.",
101
107
  '@if' => "Invalid if directive '@if': expected expression.",
102
108
  '@while' => "Invalid while directive '@while': expected expression.",
103
109
  '@debug' => "Invalid debug directive '@debug': expected expression.",
@@ -194,18 +200,229 @@ SASS
194
200
  end
195
201
 
196
202
  def test_imported_exception
197
- [nil, 2].each do |i|
203
+ [1, 2, 3, 4].each do |i|
198
204
  begin
199
205
  Sass::Engine.new("@import bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
200
206
  rescue Sass::SyntaxError => err
201
207
  assert_equal(2, err.sass_line)
202
- assert_match(/bork#{i}\.sass$/, err.sass_filename)
208
+ assert_match(/(\/|^)bork#{i}\.sass$/, err.sass_filename)
209
+
210
+ assert_hash_has(err.sass_backtrace.first,
211
+ :filename => err.sass_filename, :line => err.sass_line)
212
+
213
+ assert_nil(err.sass_backtrace[1][:filename])
214
+ assert_equal(1, err.sass_backtrace[1][:line])
215
+
216
+ assert_match(/(\/|^)bork#{i}\.sass:2$/, err.backtrace.first)
217
+ assert_equal("(sass):1", err.backtrace[1])
203
218
  else
204
219
  assert(false, "Exception not raised for imported template: bork#{i}")
205
220
  end
206
221
  end
207
222
  end
208
223
 
224
+ def test_double_imported_exception
225
+ [1, 2, 3, 4].each do |i|
226
+ begin
227
+ Sass::Engine.new("@import nested_bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
228
+ rescue Sass::SyntaxError => err
229
+ assert_equal(2, err.sass_line)
230
+ assert_match(/(\/|^)bork#{i}\.sass$/, err.sass_filename)
231
+
232
+ assert_hash_has(err.sass_backtrace.first,
233
+ :filename => err.sass_filename, :line => err.sass_line)
234
+
235
+ assert_match(/(\/|^)nested_bork#{i}\.sass$/, err.sass_backtrace[1][:filename])
236
+ assert_equal(2, err.sass_backtrace[1][:line])
237
+
238
+ assert_nil(err.sass_backtrace[2][:filename])
239
+ assert_equal(1, err.sass_backtrace[2][:line])
240
+
241
+ assert_match(/(\/|^)bork#{i}\.sass:2$/, err.backtrace.first)
242
+ assert_match(/(\/|^)nested_bork#{i}\.sass:2$/, err.backtrace[1])
243
+ assert_equal("(sass):1", err.backtrace[2])
244
+ else
245
+ assert(false, "Exception not raised for imported template: bork#{i}")
246
+ end
247
+ end
248
+ end
249
+
250
+ def test_mixin_exception
251
+ render(<<SASS)
252
+ =error-mixin($a)
253
+ color: $a * 1em * 1px
254
+
255
+ =outer-mixin($a)
256
+ +error-mixin($a)
257
+
258
+ .error
259
+ +outer-mixin(12)
260
+ SASS
261
+ assert(false, "Exception not raised")
262
+ rescue Sass::SyntaxError => err
263
+ assert_equal(2, err.sass_line)
264
+ assert_equal(filename_for_test, err.sass_filename)
265
+ assert_equal("error-mixin", err.sass_mixin)
266
+
267
+ assert_hash_has(err.sass_backtrace.first, :line => err.sass_line,
268
+ :filename => err.sass_filename, :mixin => err.sass_mixin)
269
+ assert_hash_has(err.sass_backtrace[1], :line => 5,
270
+ :filename => filename_for_test, :mixin => "outer-mixin")
271
+ assert_hash_has(err.sass_backtrace[2], :line => 8,
272
+ :filename => filename_for_test, :mixin => nil)
273
+
274
+ assert_equal("#{filename_for_test}:2:in `error-mixin'", err.backtrace.first)
275
+ assert_equal("#{filename_for_test}:5:in `outer-mixin'", err.backtrace[1])
276
+ assert_equal("#{filename_for_test}:8", err.backtrace[2])
277
+ end
278
+
279
+ def test_mixin_callsite_exception
280
+ render(<<SASS)
281
+ =one-arg-mixin($a)
282
+ color: $a
283
+
284
+ =outer-mixin($a)
285
+ +one-arg-mixin($a, 12)
286
+
287
+ .error
288
+ +outer-mixin(12)
289
+ SASS
290
+ assert(false, "Exception not raised")
291
+ rescue Sass::SyntaxError => err
292
+ assert_hash_has(err.sass_backtrace.first, :line => 5,
293
+ :filename => filename_for_test, :mixin => "one-arg-mixin")
294
+ assert_hash_has(err.sass_backtrace[1], :line => 5,
295
+ :filename => filename_for_test, :mixin => "outer-mixin")
296
+ assert_hash_has(err.sass_backtrace[2], :line => 8,
297
+ :filename => filename_for_test, :mixin => nil)
298
+ end
299
+
300
+ def test_mixin_exception_cssize
301
+ render(<<SASS)
302
+ =parent-ref-mixin
303
+ & foo
304
+ a: b
305
+
306
+ =outer-mixin
307
+ +parent-ref-mixin
308
+
309
+ +outer-mixin
310
+ SASS
311
+ assert(false, "Exception not raised")
312
+ rescue Sass::SyntaxError => err
313
+ assert_hash_has(err.sass_backtrace.first, :line => 2,
314
+ :filename => filename_for_test, :mixin => "parent-ref-mixin")
315
+ assert_hash_has(err.sass_backtrace[1], :line => 6,
316
+ :filename => filename_for_test, :mixin => "outer-mixin")
317
+ assert_hash_has(err.sass_backtrace[2], :line => 8,
318
+ :filename => filename_for_test, :mixin => nil)
319
+ end
320
+
321
+ def test_mixin_and_import_exception
322
+ Sass::Engine.new("@import nested_mixin_bork", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
323
+ assert(false, "Exception not raised")
324
+ rescue Sass::SyntaxError => err
325
+ assert_match(/(\/|^)nested_mixin_bork\.sass$/, err.sass_backtrace.first[:filename])
326
+ assert_hash_has(err.sass_backtrace.first, :mixin => "error-mixin", :line => 4)
327
+
328
+ assert_match(/(\/|^)mixin_bork\.sass$/, err.sass_backtrace[1][:filename])
329
+ assert_hash_has(err.sass_backtrace[1], :mixin => "outer-mixin", :line => 2)
330
+
331
+ assert_match(/(\/|^)mixin_bork\.sass$/, err.sass_backtrace[2][:filename])
332
+ assert_hash_has(err.sass_backtrace[2], :mixin => nil, :line => 5)
333
+
334
+ assert_match(/(\/|^)nested_mixin_bork\.sass$/, err.sass_backtrace[3][:filename])
335
+ assert_hash_has(err.sass_backtrace[3], :mixin => nil, :line => 6)
336
+
337
+ assert_hash_has(err.sass_backtrace[4], :filename => nil, :mixin => nil, :line => 1)
338
+ end
339
+
340
+ def test_exception_css_with_offset
341
+ opts = {:full_exception => true, :line => 362}
342
+ render(("a\n b: c\n" * 10) + "d\n e:\n" + ("f\n g: h\n" * 10), opts)
343
+ rescue Sass::SyntaxError => e
344
+ assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e, opts).split("\n")[0..15].join("\n"))
345
+ /*
346
+ Syntax error: Invalid property: "e:" (no value).
347
+ on line 383 of test_exception_css_with_offset_inline.sass
348
+
349
+ 378: a
350
+ 379: b: c
351
+ 380: a
352
+ 381: b: c
353
+ 382: d
354
+ 383: e:
355
+ 384: f
356
+ 385: g: h
357
+ 386: f
358
+ 387: g: h
359
+ 388: f
360
+ CSS
361
+ else
362
+ assert(false, "Exception not raised for test_exception_css_with_offset")
363
+ end
364
+
365
+ def test_exception_css_with_mixins
366
+ opts = {:full_exception => true}
367
+ render(<<SASS, opts)
368
+ =error-mixin($a)
369
+ color: $a * 1em * 1px
370
+
371
+ =outer-mixin($a)
372
+ +error-mixin($a)
373
+
374
+ .error
375
+ +outer-mixin(12)
376
+ SASS
377
+ rescue Sass::SyntaxError => e
378
+ assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e, opts).split("\n")[0..13].join("\n"))
379
+ /*
380
+ Syntax error: 12em*px isn't a valid CSS value.
381
+ on line 2 of test_exception_css_with_mixins_inline.sass, in `error-mixin'
382
+ from line 5 of test_exception_css_with_mixins_inline.sass, in `outer-mixin'
383
+ from line 8 of test_exception_css_with_mixins_inline.sass
384
+
385
+ 1: =error-mixin($a)
386
+ 2: color: $a * 1em * 1px
387
+ 3:
388
+ 4: =outer-mixin($a)
389
+ 5: +error-mixin($a)
390
+ 6:
391
+ 7: .error
392
+ CSS
393
+ else
394
+ assert(false, "Exception not raised")
395
+ end
396
+
397
+ def test_cssize_exception_css
398
+ opts = {:full_exception => true}
399
+ render(<<SASS, opts)
400
+ .filler
401
+ stuff: "stuff!"
402
+
403
+ a: b
404
+
405
+ .more.filler
406
+ a: b
407
+ SASS
408
+ rescue Sass::SyntaxError => e
409
+ assert_equal(<<CSS, Sass::SyntaxError.exception_to_css(e, opts).split("\n")[0..11].join("\n"))
410
+ /*
411
+ Syntax error: Properties aren't allowed at the root of a document.
412
+ on line 4 of test_cssize_exception_css_inline.sass
413
+
414
+ 1: .filler
415
+ 2: stuff: "stuff!"
416
+ 3:
417
+ 4: a: b
418
+ 5:
419
+ 6: .more.filler
420
+ 7: a: b
421
+ CSS
422
+ else
423
+ assert(false, "Exception not raised")
424
+ end
425
+
209
426
  def test_css_import
210
427
  assert_equal("@import url(./fonts.css) screen;\n", render("@import url(./fonts.css) screen"))
211
428
  assert_equal("@import \"./fonts.css\" screen;\n", render("@import \"./fonts.css\" screen"))
@@ -219,7 +436,7 @@ SASS
219
436
 
220
437
  def test_nonexistent_extensionless_import
221
438
  assert_warning(<<WARN) do
222
- WARNING: nonexistent.sass not found. Using nonexistent.css instead.
439
+ WARNING: Neither nonexistent.sass nor .scss found. Using nonexistent.css instead.
223
440
  This behavior is deprecated and will be removed in a future version.
224
441
  If you really need nonexistent.css, import it explicitly.
225
442
  WARN
@@ -241,18 +458,24 @@ WARN
241
458
  end
242
459
 
243
460
  def test_default_function
244
- assert_equal("foo {\n bar: url(foo.png); }\n", render(%Q{foo\n bar = url("foo.png")\n}));
245
- assert_equal("foo {\n bar: url(); }\n", render("foo\n bar = url()\n"));
461
+ assert_equal(<<CSS, render(<<SASS))
462
+ foo {
463
+ bar: url("foo.png"); }
464
+ CSS
465
+ foo
466
+ bar: url("foo.png")
467
+ SASS
468
+ assert_equal("foo {\n bar: url(); }\n", render("foo\n bar: url()\n"));
246
469
  end
247
470
 
248
471
  def test_string_minus
249
- assert_equal("foo {\n bar: baz-boom-bat; }\n", render(%Q{foo\n bar = "baz"-"boom"-"bat"}))
250
- assert_equal("foo {\n bar: -baz-boom; }\n", render(%Q{foo\n bar = -"baz"-"boom"}))
472
+ assert_equal("foo {\n bar: baz-boom-bat; }\n", render(%Q{foo\n bar: baz-boom-bat}))
473
+ assert_equal("foo {\n bar: -baz-boom; }\n", render(%Q{foo\n bar: -baz-boom}))
251
474
  end
252
475
 
253
476
  def test_string_div
254
- assert_equal("foo {\n bar: baz/boom/bat; }\n", render(%Q{foo\n bar = "baz"/"boom"/"bat"}))
255
- assert_equal("foo {\n bar: /baz/boom; }\n", render(%Q{foo\n bar = /"baz"/"boom"}))
477
+ assert_equal("foo {\n bar: baz/boom/bat; }\n", render(%Q{foo\n bar: baz/boom/bat}))
478
+ assert_equal("foo {\n bar: /baz/boom; }\n", render(%Q{foo\n bar: /baz/boom}))
256
479
  end
257
480
 
258
481
  def test_basic_multiline_selector
@@ -414,6 +637,85 @@ SASS
414
637
  renders_correctly "line_numbers", :line_comments => true, :load_paths => [File.dirname(__FILE__) + "/templates"]
415
638
  end
416
639
 
640
+ def test_debug_info
641
+ esc_file_name = Sass::SCSS::RX.escape_ident(Haml::Util.scope("test_debug_info_inline.sass"))
642
+
643
+ assert_equal(<<CSS, render(<<SASS, :debug_info => true, :style => :compact))
644
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000032}}
645
+ foo bar { foo: bar; }
646
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000035}}
647
+ foo baz { blip: blop; }
648
+
649
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000039}}
650
+ floodle { flop: blop; }
651
+
652
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000318}}
653
+ bup { mix: on; }
654
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000315}}
655
+ bup mixin { moop: mup; }
656
+
657
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\0000322}}
658
+ bip hop, skip hop { a: b; }
659
+ CSS
660
+ foo
661
+ bar
662
+ foo: bar
663
+
664
+ baz
665
+ blip: blop
666
+
667
+
668
+ floodle
669
+
670
+ flop: blop
671
+
672
+ =mxn
673
+ mix: on
674
+ mixin
675
+ moop: mup
676
+
677
+ bup
678
+ +mxn
679
+
680
+ bip, skip
681
+ hop
682
+ a: b
683
+ SASS
684
+ end
685
+
686
+ def test_debug_info_without_filename
687
+ assert_equal(<<CSS, Sass::Engine.new(<<SASS, :debug_info => true).render)
688
+ @media -sass-debug-info{filename{font-family:}line{font-family:\\000031}}
689
+ foo {
690
+ a: b; }
691
+ CSS
692
+ foo
693
+ a: b
694
+ SASS
695
+ end
696
+
697
+ def test_debug_info_with_compressed
698
+ assert_equal(<<CSS, render(<<SASS, :debug_info => true, :style => :compressed))
699
+ foo{a:b}
700
+ CSS
701
+ foo
702
+ a: b
703
+ SASS
704
+ end
705
+
706
+ def test_debug_info_with_line_annotations
707
+ esc_file_name = Sass::SCSS::RX.escape_ident(Haml::Util.scope("test_debug_info_with_line_annotations_inline.sass"))
708
+
709
+ assert_equal(<<CSS, render(<<SASS, :debug_info => true, :line_comments => true))
710
+ @media -sass-debug-info{filename{font-family:file\\:\\/\\/#{esc_file_name}}line{font-family:\\000031}}
711
+ foo {
712
+ a: b; }
713
+ CSS
714
+ foo
715
+ a: b
716
+ SASS
717
+ end
718
+
417
719
  def test_empty_first_line
418
720
  assert_equal("#a {\n b: c; }\n", render("#a\n\n b: c"))
419
721
  end
@@ -427,15 +729,124 @@ SASS
427
729
  assert_equal("foo {\n a: b;\n c: d;\n e: f; }\n", render("foo\r a: b\r\n c: d\n\r e: f"))
428
730
  end
429
731
 
430
- def test_or_eq
431
- assert_equal("foo {\n a: b; }\n", render(%Q{!foo = "b"\n!foo ||= "c"\nfoo\n a = !foo}))
432
- assert_equal("foo {\n a: b; }\n", render(%Q{!foo ||= "b"\nfoo\n a = !foo}))
732
+ def test_property_with_content_and_nested_props
733
+ assert_equal(<<CSS, render(<<SASS))
734
+ foo {
735
+ a: b;
736
+ a-c: d;
737
+ a-c-e: f; }
738
+ CSS
739
+ foo
740
+ a: b
741
+ c: d
742
+ e: f
743
+ SASS
744
+
745
+ assert_equal(<<CSS, render(<<SASS))
746
+ foo {
747
+ a: b;
748
+ a-c-e: f; }
749
+ CSS
750
+ foo
751
+ a: b
752
+ c:
753
+ e: f
754
+ SASS
755
+ end
756
+
757
+ def test_equals_warning_for_properties
758
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
759
+ DEPRECATION WARNING:
760
+ On line 3, character 3 of 'test_equals_warning_for_properties_inline.sass'
761
+ Setting properties with = has been deprecated and will be removed in version 3.2.
762
+ Use "a: $var" instead.
763
+
764
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
765
+ WARN
766
+ foo {
767
+ a: 2px 3px; }
768
+ CSS
769
+ $var: 2px 3px
770
+ foo
771
+ a = $var
772
+ SASS
773
+ end
774
+
775
+ def test_equals_warning_for_dynamic_properties
776
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
777
+ DEPRECATION WARNING:
778
+ On line 4, character 3 of 'test_equals_warning_for_dynamic_properties_inline.sass'
779
+ Setting properties with = has been deprecated and will be removed in version 3.2.
780
+ Use "a-\#{$i}: $var" instead.
781
+
782
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
783
+ WARN
784
+ foo {
785
+ a-12: 2px 3px; }
786
+ CSS
787
+ $var: 2px 3px
788
+ $i: 12
789
+ foo
790
+ a-\#{$i} = $var
791
+ SASS
792
+ end
793
+
794
+ def test_equals_warning_for_property_with_string
795
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
796
+ DEPRECATION WARNING:
797
+ On line 2, character 3 of 'test_equals_warning_for_property_with_string_inline.sass'
798
+ Setting properties with = has been deprecated and will be removed in version 3.2.
799
+ Use "a: foo" instead.
800
+
801
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
802
+ WARN
803
+ foo {
804
+ a: foo; }
805
+ CSS
806
+ foo
807
+ a = "foo"
808
+ SASS
809
+ end
810
+
811
+ def test_equals_warning_for_property_with_division
812
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
813
+ DEPRECATION WARNING:
814
+ On line 2, character 3 of 'test_equals_warning_for_property_with_division_inline.sass'
815
+ Setting properties with = has been deprecated and will be removed in version 3.2.
816
+ Use "a: (1px / 2px)" instead.
817
+
818
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
819
+ WARN
820
+ foo {
821
+ a: 0.5; }
822
+ CSS
823
+ foo
824
+ a = 1px/2px
825
+ SASS
826
+ end
827
+
828
+ def test_guarded_assign
829
+ assert_equal("foo {\n a: b; }\n", render(%Q{$foo: b\n$foo: c !default\nfoo\n a: $foo}))
830
+ assert_equal("foo {\n a: b; }\n", render(%Q{$foo: b !default\nfoo\n a: $foo}))
433
831
  end
434
832
 
435
833
  def test_mixins
436
834
  renders_correctly "mixins", { :style => :expanded }
437
835
  end
438
836
 
837
+ def test_directive_style_mixins
838
+ assert_equal <<CSS, render(<<SASS)
839
+ bar {
840
+ prop: baz; }
841
+ CSS
842
+ @mixin foo($arg)
843
+ prop: $arg
844
+
845
+ bar
846
+ @include foo(baz)
847
+ SASS
848
+ end
849
+
439
850
  def test_mixins_dont_interfere_with_sibling_combinator
440
851
  assert_equal("foo + bar {\n a: b; }\nfoo + baz {\n c: d; }\n",
441
852
  render("foo\n +\n bar\n a: b\n baz\n c: d"))
@@ -443,33 +854,33 @@ SASS
443
854
 
444
855
  def test_mixin_args
445
856
  assert_equal("blat {\n baz: hi; }\n", render(<<SASS))
446
- =foo(!bar)
447
- baz = !bar
857
+ =foo($bar)
858
+ baz: $bar
448
859
  blat
449
- +foo(\"hi\")
860
+ +foo(hi)
450
861
  SASS
451
862
  assert_equal("blat {\n baz: 3; }\n", render(<<SASS))
452
- =foo(!a, !b)
453
- baz = !a + !b
863
+ =foo($a, $b)
864
+ baz: $a + $b
454
865
  blat
455
866
  +foo(1, 2)
456
867
  SASS
457
868
  assert_equal("blat {\n baz: 4;\n baz: 3;\n baz: 5;\n bang: 3; }\n", render(<<SASS))
458
- =foo(!c = (6 + 4) / 2)
459
- baz = !c
460
- !c = 3
869
+ =foo($c: (6 + 4) / 2)
870
+ baz: $c
871
+ $c: 3
461
872
  blat
462
- +foo(!c + 1)
463
- +foo((!c + 3)/2)
873
+ +foo($c + 1)
874
+ +foo(($c + 3)/2)
464
875
  +foo
465
- bang = !c
876
+ bang: $c
466
877
  SASS
467
878
  end
468
879
 
469
880
  def test_default_values_for_mixin_arguments
470
881
  assert_equal("white {\n color: white; }\n\nblack {\n color: black; }\n", render(<<SASS))
471
- =foo(!a = #FFF)
472
- :color= !a
882
+ =foo($a: #FFF)
883
+ :color $a
473
884
  white
474
885
  +foo
475
886
  black
@@ -491,11 +902,11 @@ three {
491
902
  padding: 2px;
492
903
  margin: 3px; }
493
904
  CSS
494
- !a = 5px
495
- =foo(!a, !b = 1px, !c = 3px + !b)
496
- :color= !a
497
- :padding= !b
498
- :margin= !c
905
+ $a: 5px
906
+ =foo($a, $b: 1px, $c: 3px + $b)
907
+ :color $a
908
+ :padding $b
909
+ :margin $c
499
910
  one
500
911
  +foo(#fff)
501
912
  two
@@ -505,23 +916,74 @@ three
505
916
  SASS
506
917
  end
507
918
 
919
+ def test_hyphen_underscore_insensitive_mixins
920
+ assert_equal(<<CSS, render(<<SASS))
921
+ a {
922
+ b: 12;
923
+ c: foo; }
924
+ CSS
925
+ =mixin-hyphen
926
+ b: 12
927
+
928
+ =mixin_under
929
+ c: foo
930
+
931
+ a
932
+ +mixin_hyphen
933
+ +mixin-under
934
+ SASS
935
+ end
936
+
937
+ def test_equals_warning_for_mixin_args
938
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
939
+ DEPRECATION WARNING:
940
+ On line 1, character 6 of 'test_equals_warning_for_mixin_args_inline.sass'
941
+ Setting mixin argument defaults with = has been deprecated and will be removed in version 3.2.
942
+ Use "$arg: 1px" instead.
943
+
944
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
945
+ WARN
946
+ bar {
947
+ a: 1px; }
948
+ CSS
949
+ =foo($arg = 1px)
950
+ a: $arg
951
+
952
+ bar
953
+ +foo
954
+ SASS
955
+ end
956
+
957
+ def test_css_identifier_mixin
958
+ assert_equal(<<CSS, render(<<SASS))
959
+ a {
960
+ foo: 12; }
961
+ CSS
962
+ =\\{foo\\(12\\)($a)
963
+ foo: $a
964
+
965
+ a
966
+ +\\{foo\\(12\\)(12)
967
+ SASS
968
+ end
969
+
508
970
  def test_interpolation
509
971
  assert_equal("a-1 {\n b-2-3: c-3; }\n", render(<<SASS))
510
- !a = 1
511
- !b = 2
512
- !c = 3
513
- a-\#{!a}
514
- b-\#{!b}-\#{!c}: c-\#{!a + !b}
972
+ $a: 1
973
+ $b: 2
974
+ $c: 3
975
+ a-\#{$a}
976
+ b-\#{$b}-\#{$c}: c-\#{$a + $b}
515
977
  SASS
516
978
  end
517
979
 
518
980
  def test_if_directive
519
981
  assert_equal("a {\n b: 1; }\n", render(<<SASS))
520
- !var = true
982
+ $var: true
521
983
  a
522
- @if !var
984
+ @if $var
523
985
  b: 1
524
- @if not !var
986
+ @if not $var
525
987
  b: 2
526
988
  SASS
527
989
  end
@@ -552,14 +1014,38 @@ b-3 {
552
1014
  b-4 {
553
1015
  j-1: 3; }
554
1016
  CSS
555
- !a = 3
556
- @for !i from 0 to !a + 1
557
- a-\#{!i}
558
- 2i = 2 * !i
1017
+ $a: 3
1018
+ @for $i from 0 to $a + 1
1019
+ a-\#{$i}
1020
+ 2i: 2 * $i
1021
+
1022
+ @for $j from 1 through 4
1023
+ b-\#{$j}
1024
+ j-1: $j - 1
1025
+ SASS
1026
+ end
1027
+
1028
+ def test_for_with_bang_var
1029
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
1030
+ DEPRECATION WARNING:
1031
+ On line 1, character 6 of 'test_for_with_bang_var_inline.sass'
1032
+ Variables with ! have been deprecated and will be removed in version 3.2.
1033
+ Use "$bar" instead.
1034
+
1035
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
1036
+ WARN
1037
+ a-0 {
1038
+ b: c; }
1039
+
1040
+ a-1 {
1041
+ b: c; }
559
1042
 
560
- @for !j from 1 through 4
561
- b-\#{!j}
562
- j-1 = !j - 1
1043
+ a-2 {
1044
+ b: c; }
1045
+ CSS
1046
+ @for !bar from 0 to 3
1047
+ a-\#{$bar}
1048
+ b: c
563
1049
  SASS
564
1050
  end
565
1051
 
@@ -580,11 +1066,11 @@ a-2 {
580
1066
  a-1 {
581
1067
  blooble: gloop; }
582
1068
  CSS
583
- !a = 5
584
- @while !a != 0
585
- a-\#{!a}
1069
+ $a: 5
1070
+ @while $a != 0
1071
+ a-\#{$a}
586
1072
  blooble: gloop
587
- !a = !a - 1
1073
+ $a: $a - 1
588
1074
  SASS
589
1075
  end
590
1076
 
@@ -634,11 +1120,83 @@ a {
634
1120
  b: 1;
635
1121
  c: 2; }
636
1122
  CSS
637
- !a = 1
1123
+ $a: 1
638
1124
  a
639
- b = !a
640
- !a = 2
641
- c = !a
1125
+ b: $a
1126
+ $a: 2
1127
+ c: $a
1128
+ SASS
1129
+ end
1130
+
1131
+ def test_bang_variables
1132
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
1133
+ DEPRECATION WARNING:
1134
+ On line 1, character 1 of 'test_bang_variables_inline.sass'
1135
+ Variables with ! have been deprecated and will be removed in version 3.2.
1136
+ Use "$bang-var" instead.
1137
+
1138
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
1139
+ WARN
1140
+ foo {
1141
+ a: 1px; }
1142
+ CSS
1143
+ !bang-var: 1px
1144
+ foo
1145
+ a: $bang-var
1146
+ SASS
1147
+
1148
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
1149
+ DEPRECATION WARNING:
1150
+ On line 3, character 6 of 'test_bang_variables_inline.sass'
1151
+ Variables with ! have been deprecated and will be removed in version 3.2.
1152
+ Use "$dollar-var" instead.
1153
+
1154
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
1155
+ WARN
1156
+ foo {
1157
+ a: 1px; }
1158
+ CSS
1159
+ $dollar-var: 1px
1160
+ foo
1161
+ a: !dollar-var
1162
+ SASS
1163
+ end
1164
+
1165
+ def test_equals_warning_for_variables
1166
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
1167
+ DEPRECATION WARNING:
1168
+ On line 2, character 1 of 'test_equals_warning_for_variables_inline.sass'
1169
+ Setting variables with = has been deprecated and will be removed in version 3.2.
1170
+ Use "$equals-var: 2px 3px" instead.
1171
+
1172
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
1173
+ WARN
1174
+ foo {
1175
+ a: 2px 3px; }
1176
+ CSS
1177
+
1178
+ $equals-var = 2px 3px
1179
+ foo
1180
+ a: $equals-var
1181
+ SASS
1182
+ end
1183
+
1184
+ def test_equals_warning_for_guarded_variables
1185
+ assert_warning(<<WARN) {assert_equal(<<CSS, render(<<SASS))}
1186
+ DEPRECATION WARNING:
1187
+ On line 2, character 1 of 'test_equals_warning_for_guarded_variables_inline.sass'
1188
+ Setting variable defaults with ||= has been deprecated and will be removed in version 3.2.
1189
+ Use "$equals-var: 2px 3px !default" instead.
1190
+
1191
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
1192
+ WARN
1193
+ foo {
1194
+ a: 2px 3px; }
1195
+ CSS
1196
+
1197
+ $equals-var ||= 2px 3px
1198
+ foo
1199
+ a: $equals-var
642
1200
  SASS
643
1201
  end
644
1202
 
@@ -652,23 +1210,69 @@ a {
652
1210
  b {
653
1211
  d: 17; }
654
1212
  CSS
655
- !i = 12
1213
+ $i: 12
656
1214
  a
657
- @for !i from 1 through 2
658
- b-\#{!i}: c
659
- d = !i
1215
+ @for $i from 1 through 2
1216
+ b-\#{$i}: c
1217
+ d: $i
660
1218
 
661
1219
  =foo
662
- !i = 17
1220
+ $i: 17
663
1221
 
664
1222
  b
665
1223
  +foo
666
- d = !i
1224
+ d: $i
1225
+ SASS
1226
+ end
1227
+
1228
+ def test_hyphen_underscore_insensitive_variables
1229
+ assert_equal(<<CSS, render(<<SASS))
1230
+ a {
1231
+ b: c; }
1232
+
1233
+ d {
1234
+ e: 13;
1235
+ f: foobar; }
1236
+ CSS
1237
+ $var-hyphen: 12
1238
+ $var_under: foo
1239
+
1240
+ a
1241
+ $var_hyphen: 1 + $var_hyphen
1242
+ $var-under: $var-under + bar
1243
+ b: c
1244
+
1245
+ d
1246
+ e: $var-hyphen
1247
+ f: $var_under
1248
+ SASS
1249
+ end
1250
+
1251
+ def test_css_identifier_variable
1252
+ assert_equal(<<CSS, render(<<SASS))
1253
+ a {
1254
+ b: 12; }
1255
+ CSS
1256
+ $\\{foo\\(12\\): 12
1257
+
1258
+ a
1259
+ b: $\\{foo\\(12\\)
1260
+ SASS
1261
+ end
1262
+
1263
+ def test_important
1264
+ assert_equal(<<CSS, render(<<SASS))
1265
+ a {
1266
+ b: 12px !important; }
1267
+ CSS
1268
+ $foo: 12px
1269
+ a
1270
+ b: $foo !important
667
1271
  SASS
668
1272
  end
669
1273
 
670
1274
  def test_argument_error
671
- assert_raise(Sass::SyntaxError) { render("a\n b = hsl(1)") }
1275
+ assert_raise(Sass::SyntaxError) { render("a\n b: hsl(1)") }
672
1276
  end
673
1277
 
674
1278
  def test_comments_at_the_top_of_a_document
@@ -774,25 +1378,7 @@ SASS
774
1378
  def test_empty_selector_warning
775
1379
  assert_warning(<<END) {render("foo bar")}
776
1380
  WARNING on line 1 of test_empty_selector_warning_inline.sass:
777
- Selector "foo bar" doesn't have any properties and will not be rendered.
778
- END
779
-
780
- assert_warning(<<END) {render(<<SASS)}
781
- WARNING on line 3 of test_empty_selector_warning_inline.sass:
782
- Selector
783
- foo, bar, baz,
784
- bang, bip, bop
785
- doesn't have any properties and will not be rendered.
786
- END
787
-
788
-
789
- foo, bar, baz,
790
- bang, bip, bop
791
- SASS
792
-
793
- assert_warning(<<END) {render("foo bar", :filename => nil)}
794
- WARNING on line 1:
795
- Selector "foo bar" doesn't have any properties and will not be rendered.
1381
+ This selector doesn't have any properties and will not be rendered.
796
1382
  END
797
1383
  end
798
1384
 
@@ -827,6 +1413,302 @@ foo
827
1413
  SASS
828
1414
  end
829
1415
 
1416
+ def test_interpolation_in_raw_functions
1417
+ assert_equal(<<CSS, render(<<SASS))
1418
+ foo {
1419
+ filter: progid:Microsoft.foo.bar.Baz(flip=foobar, bang=#00ff00cc); }
1420
+ CSS
1421
+ foo
1422
+ filter: progid:Microsoft.foo.bar.Baz(flip=\#{foo + bar}, bang=#00ff00cc)
1423
+ SASS
1424
+ end
1425
+
1426
+ # SassScript string behavior
1427
+
1428
+ def test_plus_preserves_quotedness
1429
+ assert_equal(<<CSS, render(<<SASS))
1430
+ foo {
1431
+ a: "foo1";
1432
+ b: "1foo";
1433
+ c: foo1;
1434
+ d: 1foo;
1435
+ e: "foobar";
1436
+ f: foobar; }
1437
+ CSS
1438
+ foo
1439
+ a: "foo" + 1
1440
+ b: 1 + "foo"
1441
+ c: foo + 1
1442
+ d: 1 + foo
1443
+ e: "foo" + bar
1444
+ f: foo + "bar"
1445
+ SASS
1446
+ end
1447
+
1448
+ def test_colon_properties_preserve_quotedness
1449
+ assert_equal(<<CSS, render(<<SASS))
1450
+ foo {
1451
+ a: "foo";
1452
+ b: bar;
1453
+ c: "foo" bar;
1454
+ d: foo, "bar"; }
1455
+ CSS
1456
+ foo
1457
+ a: "foo"
1458
+ b: bar
1459
+ c: "foo" bar
1460
+ d: foo, "bar"
1461
+ SASS
1462
+ end
1463
+
1464
+ def test_colon_variables_preserve_quotedness
1465
+ assert_equal(<<CSS, render(<<SASS))
1466
+ foo {
1467
+ a: "foo";
1468
+ b: bar; }
1469
+ CSS
1470
+ $a: "foo"
1471
+ $b: bar
1472
+
1473
+ foo
1474
+ a: $a
1475
+ b: $b
1476
+ SASS
1477
+ end
1478
+
1479
+ def test_colon_args_preserve_quotedness
1480
+ assert_equal(<<CSS, render(<<SASS))
1481
+ foo {
1482
+ a: "foo";
1483
+ b: bar;
1484
+ c: "foo" bar;
1485
+ d: foo, "bar"; }
1486
+ CSS
1487
+ =foo($a: "foo", $b: bar, $c: "foo" bar, $d: (foo, "bar"))
1488
+ foo
1489
+ a: $a
1490
+ b: $b
1491
+ c: $c
1492
+ d: $d
1493
+
1494
+ +foo
1495
+ SASS
1496
+ end
1497
+
1498
+ def test_interpolation_unquotes_strings
1499
+ assert_equal(<<CSS, render(<<SASS))
1500
+ .foo-bar {
1501
+ a: b; }
1502
+ CSS
1503
+ .foo-\#{"bar"}
1504
+ a: b
1505
+ SASS
1506
+
1507
+ assert_equal(<<CSS, render(<<SASS))
1508
+ .foo {
1509
+ a: b c; }
1510
+ CSS
1511
+ .foo
1512
+ a: b \#{"c"}
1513
+ SASS
1514
+ end
1515
+
1516
+ def test_interpolation_unquotes_strings_in_vars
1517
+ assert_equal(<<CSS, render(<<SASS))
1518
+ .foo-bar {
1519
+ a: b; }
1520
+ CSS
1521
+ $var: "bar"
1522
+
1523
+ .foo-\#{$var}
1524
+ a: b
1525
+ SASS
1526
+ end
1527
+
1528
+ def test_interpolation_doesnt_deep_unquote_strings
1529
+ assert_equal(<<CSS, render(<<SASS))
1530
+ .foo-"bar" "baz" {
1531
+ a: b; }
1532
+ CSS
1533
+ .foo-\#{"bar" "baz"}
1534
+ a: b
1535
+ SASS
1536
+ end
1537
+
1538
+ # Deprecated equals behavior
1539
+
1540
+ def test_equals_properties_unquote_strings
1541
+ silence_warnings do
1542
+ assert_equal(<<CSS, render(<<SASS))
1543
+ foo {
1544
+ a: foo;
1545
+ b: bar;
1546
+ c: foo bar;
1547
+ d: foo, bar; }
1548
+ CSS
1549
+ foo
1550
+ a= "foo"
1551
+ b= bar
1552
+ c= "foo" bar
1553
+ d= foo, "bar"
1554
+ SASS
1555
+ end
1556
+ end
1557
+
1558
+ def test_equals_properties_unquote_value
1559
+ silence_warnings do
1560
+ assert_equal(<<CSS, render(<<SASS))
1561
+ foo {
1562
+ a: foo; }
1563
+ CSS
1564
+ $var: "foo"
1565
+
1566
+ foo
1567
+ a= $var
1568
+ SASS
1569
+ end
1570
+ end
1571
+
1572
+ def test_equals_properties_deep_unquote_vars
1573
+ silence_warnings do
1574
+ assert_equal(<<CSS, render(<<SASS))
1575
+ foo {
1576
+ a: foo bar;
1577
+ b: bar foo; }
1578
+ CSS
1579
+ $var: "foo"
1580
+
1581
+ foo
1582
+ a= $var "bar"
1583
+ b= "bar" $var
1584
+ SASS
1585
+ end
1586
+ end
1587
+
1588
+ def test_equals_vars_unquote_strings
1589
+ silence_warnings do
1590
+ assert_equal(<<CSS, render(<<SASS))
1591
+ foo {
1592
+ a: foo;
1593
+ b: bar;
1594
+ c: foo bar;
1595
+ d: foo, bar; }
1596
+ CSS
1597
+ $a = "foo"
1598
+ $b = bar
1599
+ $c = "foo" bar
1600
+ $d = foo, "bar"
1601
+
1602
+ foo
1603
+ a: $a
1604
+ b: $b
1605
+ c: $c
1606
+ d: $d
1607
+ SASS
1608
+ end
1609
+ end
1610
+
1611
+ def test_equals_vars_unquote_value
1612
+ silence_warnings do
1613
+ assert_equal(<<CSS, render(<<SASS))
1614
+ foo {
1615
+ a: foo; }
1616
+ CSS
1617
+ $var1: "foo"
1618
+ $var2 = $var1
1619
+
1620
+ foo
1621
+ a: $var2
1622
+ SASS
1623
+ end
1624
+ end
1625
+
1626
+ def test_equals_vars_deep_unquote_vars
1627
+ silence_warnings do
1628
+ assert_equal(<<CSS, render(<<SASS))
1629
+ foo {
1630
+ a: foo bar;
1631
+ b: bar foo; }
1632
+ CSS
1633
+ $var: "foo"
1634
+ $a = $var "bar"
1635
+ $b = "bar" $var
1636
+
1637
+ foo
1638
+ a: $a
1639
+ b: $b
1640
+ SASS
1641
+ end
1642
+ end
1643
+
1644
+ def test_equals_args_unquote_strings
1645
+ silence_warnings do
1646
+ assert_equal(<<CSS, render(<<SASS))
1647
+ foo {
1648
+ a: foo;
1649
+ b: bar;
1650
+ c: foo bar;
1651
+ d: foo, bar; }
1652
+ CSS
1653
+ =foo($a = "foo", $b = bar, $c = "foo" bar, $d = (foo, "bar"))
1654
+ foo
1655
+ a: $a
1656
+ b: $b
1657
+ c: $c
1658
+ d: $d
1659
+
1660
+ +foo
1661
+ SASS
1662
+ end
1663
+ end
1664
+
1665
+ def test_equals_args_unquote_value
1666
+ silence_warnings do
1667
+ assert_equal(<<CSS, render(<<SASS))
1668
+ foo {
1669
+ a: foo; }
1670
+ CSS
1671
+ $var1: "foo"
1672
+
1673
+ =foo($var2 = $var1)
1674
+ foo
1675
+ a: $var2
1676
+
1677
+ +foo
1678
+ SASS
1679
+ end
1680
+ end
1681
+
1682
+ def test_equals_args_deep_unquote_vars
1683
+ silence_warnings do
1684
+ assert_equal(<<CSS, render(<<SASS))
1685
+ foo {
1686
+ a: foo bar;
1687
+ b: bar foo; }
1688
+ CSS
1689
+ $var: "foo"
1690
+ =foo($a = $var "bar", $b = "bar" $var)
1691
+ foo
1692
+ a: $a
1693
+ b: $b
1694
+
1695
+ +foo
1696
+ SASS
1697
+ end
1698
+ end
1699
+
1700
+ def test_equals_properties_force_division
1701
+ silence_warnings do
1702
+ assert_equal(<<CSS, render(<<SASS))
1703
+ foo {
1704
+ a: 0.5; }
1705
+ CSS
1706
+ foo
1707
+ a = 1px/2px
1708
+ SASS
1709
+ end
1710
+ end
1711
+
830
1712
  # Regression tests
831
1713
 
832
1714
  def test_parens_in_mixins
@@ -835,9 +1717,9 @@ SASS
835
1717
  color: #01ff7f;
836
1718
  background-color: #000102; }
837
1719
  CSS
838
- =foo(!c1, !c2 = rgb(0, 1, 2))
839
- color = !c1
840
- background-color = !c2
1720
+ =foo($c1, $c2: rgb(0, 1, 2))
1721
+ color: $c1
1722
+ background-color: $c2
841
1723
 
842
1724
  .foo
843
1725
  +foo(rgb(1,255,127))
@@ -862,7 +1744,7 @@ SOURCE
862
1744
  RESULT
863
1745
  .box
864
1746
  :border
865
- /*:color black
1747
+ /* :color black
866
1748
  :style solid
867
1749
  SOURCE
868
1750
 
@@ -942,8 +1824,44 @@ a
942
1824
  SASS
943
1825
  end
944
1826
 
1827
+ def test_options_available_in_environment
1828
+ assert_equal(<<CSS, render(<<SASS))
1829
+ a {
1830
+ b: nested; }
1831
+ CSS
1832
+ a
1833
+ b: option("style")
1834
+ SASS
1835
+ end
1836
+
1837
+ # Encodings
1838
+
1839
+ unless Haml::Util.ruby1_8?
1840
+ def test_encoding_error
1841
+ render("foo\nbar\nb\xFEaz".force_encoding("utf-8"))
1842
+ assert(false, "Expected exception")
1843
+ rescue Sass::SyntaxError => e
1844
+ assert_equal(3, e.sass_line)
1845
+ assert_equal('Invalid UTF-8 character "\xFE"', e.message)
1846
+ end
1847
+
1848
+ def test_ascii_incompatible_encoding_error
1849
+ template = "foo\nbar\nb_z".encode("utf-16le")
1850
+ template[9] = "\xFE".force_encoding("utf-16le")
1851
+ render(template)
1852
+ assert(false, "Expected exception")
1853
+ rescue Sass::SyntaxError => e
1854
+ assert_equal(3, e.sass_line)
1855
+ assert_equal('Invalid UTF-16LE character "\xFE"', e.message)
1856
+ end
1857
+ end
1858
+
945
1859
  private
946
-
1860
+
1861
+ def assert_hash_has(hash, expected)
1862
+ expected.each {|k, v| assert_equal(v, hash[k])}
1863
+ end
1864
+
947
1865
  def render(sass, options = {})
948
1866
  munge_filename options
949
1867
  Sass::Engine.new(sass, options).render