haml-edge 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. data/EDGE_GEM_VERSION +1 -0
  2. data/FAQ +138 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +332 -0
  5. data/REVISION +1 -0
  6. data/Rakefile +226 -0
  7. data/VERSION +1 -0
  8. data/bin/css2sass +7 -0
  9. data/bin/haml +9 -0
  10. data/bin/html2haml +7 -0
  11. data/bin/sass +8 -0
  12. data/extra/edge_gem_watch.rb +13 -0
  13. data/extra/haml-mode.el +596 -0
  14. data/extra/sass-mode.el +200 -0
  15. data/init.rb +8 -0
  16. data/lib/haml/buffer.rb +255 -0
  17. data/lib/haml/engine.rb +268 -0
  18. data/lib/haml/error.rb +22 -0
  19. data/lib/haml/exec.rb +395 -0
  20. data/lib/haml/filters.rb +275 -0
  21. data/lib/haml/helpers/action_view_extensions.rb +45 -0
  22. data/lib/haml/helpers/action_view_mods.rb +181 -0
  23. data/lib/haml/helpers.rb +488 -0
  24. data/lib/haml/html.rb +222 -0
  25. data/lib/haml/precompiler.rb +904 -0
  26. data/lib/haml/shared.rb +45 -0
  27. data/lib/haml/template/patch.rb +58 -0
  28. data/lib/haml/template/plugin.rb +72 -0
  29. data/lib/haml/template.rb +42 -0
  30. data/lib/haml/util.rb +88 -0
  31. data/lib/haml/version.rb +47 -0
  32. data/lib/haml.rb +1044 -0
  33. data/lib/sass/css.rb +388 -0
  34. data/lib/sass/engine.rb +495 -0
  35. data/lib/sass/environment.rb +46 -0
  36. data/lib/sass/error.rb +35 -0
  37. data/lib/sass/plugin/merb.rb +56 -0
  38. data/lib/sass/plugin/rails.rb +24 -0
  39. data/lib/sass/plugin.rb +204 -0
  40. data/lib/sass/repl.rb +51 -0
  41. data/lib/sass/script/bool.rb +13 -0
  42. data/lib/sass/script/color.rb +97 -0
  43. data/lib/sass/script/funcall.rb +29 -0
  44. data/lib/sass/script/functions.rb +134 -0
  45. data/lib/sass/script/lexer.rb +148 -0
  46. data/lib/sass/script/literal.rb +82 -0
  47. data/lib/sass/script/number.rb +231 -0
  48. data/lib/sass/script/operation.rb +30 -0
  49. data/lib/sass/script/parser.rb +142 -0
  50. data/lib/sass/script/string.rb +9 -0
  51. data/lib/sass/script/unary_operation.rb +21 -0
  52. data/lib/sass/script/variable.rb +20 -0
  53. data/lib/sass/script.rb +38 -0
  54. data/lib/sass/tree/attr_node.rb +64 -0
  55. data/lib/sass/tree/comment_node.rb +30 -0
  56. data/lib/sass/tree/debug_node.rb +22 -0
  57. data/lib/sass/tree/directive_node.rb +50 -0
  58. data/lib/sass/tree/file_node.rb +27 -0
  59. data/lib/sass/tree/for_node.rb +29 -0
  60. data/lib/sass/tree/if_node.rb +27 -0
  61. data/lib/sass/tree/mixin_def_node.rb +18 -0
  62. data/lib/sass/tree/mixin_node.rb +35 -0
  63. data/lib/sass/tree/node.rb +99 -0
  64. data/lib/sass/tree/rule_node.rb +161 -0
  65. data/lib/sass/tree/variable_node.rb +24 -0
  66. data/lib/sass/tree/while_node.rb +21 -0
  67. data/lib/sass.rb +1062 -0
  68. data/rails/init.rb +1 -0
  69. data/test/benchmark.rb +99 -0
  70. data/test/haml/engine_test.rb +795 -0
  71. data/test/haml/helper_test.rb +228 -0
  72. data/test/haml/html2haml_test.rb +108 -0
  73. data/test/haml/markaby/standard.mab +52 -0
  74. data/test/haml/mocks/article.rb +6 -0
  75. data/test/haml/results/content_for_layout.xhtml +15 -0
  76. data/test/haml/results/eval_suppressed.xhtml +9 -0
  77. data/test/haml/results/filters.xhtml +62 -0
  78. data/test/haml/results/helpers.xhtml +93 -0
  79. data/test/haml/results/helpful.xhtml +10 -0
  80. data/test/haml/results/just_stuff.xhtml +68 -0
  81. data/test/haml/results/list.xhtml +12 -0
  82. data/test/haml/results/nuke_inner_whitespace.xhtml +40 -0
  83. data/test/haml/results/nuke_outer_whitespace.xhtml +148 -0
  84. data/test/haml/results/original_engine.xhtml +20 -0
  85. data/test/haml/results/partial_layout.xhtml +5 -0
  86. data/test/haml/results/partials.xhtml +21 -0
  87. data/test/haml/results/render_layout.xhtml +3 -0
  88. data/test/haml/results/silent_script.xhtml +74 -0
  89. data/test/haml/results/standard.xhtml +162 -0
  90. data/test/haml/results/tag_parsing.xhtml +23 -0
  91. data/test/haml/results/very_basic.xhtml +5 -0
  92. data/test/haml/results/whitespace_handling.xhtml +89 -0
  93. data/test/haml/rhtml/_av_partial_1.rhtml +12 -0
  94. data/test/haml/rhtml/_av_partial_2.rhtml +8 -0
  95. data/test/haml/rhtml/action_view.rhtml +62 -0
  96. data/test/haml/rhtml/standard.rhtml +54 -0
  97. data/test/haml/template_test.rb +204 -0
  98. data/test/haml/templates/_av_partial_1.haml +9 -0
  99. data/test/haml/templates/_av_partial_1_ugly.haml +9 -0
  100. data/test/haml/templates/_av_partial_2.haml +5 -0
  101. data/test/haml/templates/_av_partial_2_ugly.haml +5 -0
  102. data/test/haml/templates/_layout.erb +3 -0
  103. data/test/haml/templates/_layout_for_partial.haml +3 -0
  104. data/test/haml/templates/_partial.haml +8 -0
  105. data/test/haml/templates/_text_area.haml +3 -0
  106. data/test/haml/templates/action_view.haml +47 -0
  107. data/test/haml/templates/action_view_ugly.haml +47 -0
  108. data/test/haml/templates/breakage.haml +8 -0
  109. data/test/haml/templates/content_for_layout.haml +10 -0
  110. data/test/haml/templates/eval_suppressed.haml +11 -0
  111. data/test/haml/templates/filters.haml +66 -0
  112. data/test/haml/templates/helpers.haml +95 -0
  113. data/test/haml/templates/helpful.haml +11 -0
  114. data/test/haml/templates/just_stuff.haml +83 -0
  115. data/test/haml/templates/list.haml +12 -0
  116. data/test/haml/templates/nuke_inner_whitespace.haml +32 -0
  117. data/test/haml/templates/nuke_outer_whitespace.haml +144 -0
  118. data/test/haml/templates/original_engine.haml +17 -0
  119. data/test/haml/templates/partial_layout.haml +3 -0
  120. data/test/haml/templates/partialize.haml +1 -0
  121. data/test/haml/templates/partials.haml +12 -0
  122. data/test/haml/templates/render_layout.haml +2 -0
  123. data/test/haml/templates/silent_script.haml +40 -0
  124. data/test/haml/templates/standard.haml +42 -0
  125. data/test/haml/templates/standard_ugly.haml +42 -0
  126. data/test/haml/templates/tag_parsing.haml +21 -0
  127. data/test/haml/templates/very_basic.haml +4 -0
  128. data/test/haml/templates/whitespace_handling.haml +87 -0
  129. data/test/haml/util_test.rb +87 -0
  130. data/test/linked_rails.rb +12 -0
  131. data/test/sass/css2sass_test.rb +193 -0
  132. data/test/sass/engine_test.rb +709 -0
  133. data/test/sass/functions_test.rb +109 -0
  134. data/test/sass/more_results/more1.css +9 -0
  135. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  136. data/test/sass/more_results/more_import.css +29 -0
  137. data/test/sass/more_templates/_more_partial.sass +2 -0
  138. data/test/sass/more_templates/more1.sass +23 -0
  139. data/test/sass/more_templates/more_import.sass +11 -0
  140. data/test/sass/plugin_test.rb +213 -0
  141. data/test/sass/results/alt.css +4 -0
  142. data/test/sass/results/basic.css +9 -0
  143. data/test/sass/results/compact.css +5 -0
  144. data/test/sass/results/complex.css +87 -0
  145. data/test/sass/results/compressed.css +1 -0
  146. data/test/sass/results/expanded.css +19 -0
  147. data/test/sass/results/import.css +29 -0
  148. data/test/sass/results/line_numbers.css +49 -0
  149. data/test/sass/results/mixins.css +95 -0
  150. data/test/sass/results/multiline.css +24 -0
  151. data/test/sass/results/nested.css +22 -0
  152. data/test/sass/results/parent_ref.css +13 -0
  153. data/test/sass/results/script.css +16 -0
  154. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  155. data/test/sass/results/subdir/subdir.css +3 -0
  156. data/test/sass/results/units.css +11 -0
  157. data/test/sass/script_test.rb +250 -0
  158. data/test/sass/templates/_partial.sass +2 -0
  159. data/test/sass/templates/alt.sass +16 -0
  160. data/test/sass/templates/basic.sass +23 -0
  161. data/test/sass/templates/bork.sass +2 -0
  162. data/test/sass/templates/bork2.sass +2 -0
  163. data/test/sass/templates/compact.sass +17 -0
  164. data/test/sass/templates/complex.sass +309 -0
  165. data/test/sass/templates/compressed.sass +15 -0
  166. data/test/sass/templates/expanded.sass +17 -0
  167. data/test/sass/templates/import.sass +11 -0
  168. data/test/sass/templates/importee.sass +19 -0
  169. data/test/sass/templates/line_numbers.sass +13 -0
  170. data/test/sass/templates/mixins.sass +76 -0
  171. data/test/sass/templates/multiline.sass +20 -0
  172. data/test/sass/templates/nested.sass +25 -0
  173. data/test/sass/templates/parent_ref.sass +25 -0
  174. data/test/sass/templates/script.sass +101 -0
  175. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  176. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  177. data/test/sass/templates/subdir/subdir.sass +6 -0
  178. data/test/sass/templates/units.sass +11 -0
  179. data/test/test_helper.rb +21 -0
  180. metadata +278 -0
@@ -0,0 +1,709 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'sass/engine'
4
+ require 'stringio'
5
+
6
+ class SassEngineTest < Test::Unit::TestCase
7
+ # A map of erroneous Sass documents to the error messages they should produce.
8
+ # The error messages may be arrays;
9
+ # if so, the second element should be the line number that should be reported for the error.
10
+ # If this isn't provided, the tests will assume the line number should be the last line of the document.
11
+ 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
+ ":" => 'Invalid attribute: ":".',
19
+ ": a" => 'Invalid attribute: ": a".',
20
+ ":= a" => 'Invalid attribute: ":= a".',
21
+ "a\n :b" => 'Invalid attribute: ":b ".',
22
+ "a\n :b: c" => 'Invalid attribute: ":b: c".',
23
+ "a\n :b:c d" => 'Invalid attribute: ":b:c d".',
24
+ "a\n :b=c d" => 'Invalid attribute: ":b=c d".',
25
+ "a\n :b c;" => 'Invalid attribute: ":b c;" (This isn\'t CSS!).',
26
+ "a\n b : c" => 'Invalid attribute: "b : c".',
27
+ "a\n b=c: d" => 'Invalid attribute: "b=c: d".',
28
+ ":a" => 'Attributes aren\'t allowed at the root of a document.',
29
+ "!" => 'Invalid variable: "!".',
30
+ "!a" => 'Invalid variable: "!a".',
31
+ "! a" => 'Invalid variable: "! a".',
32
+ "!a b" => 'Invalid variable: "!a b".',
33
+ "!a = 1b + 2c" => "Incompatible units: 'c' and 'b'.",
34
+ "a\n :b= 1b * 2c" => "2b*c isn't a valid CSS value.",
35
+ "a\n :b= 1b % 2c" => "Cannot modulo by a number with units: 2c.",
36
+ "!a = 2px + #ccc" => "Cannot add a number with units (2px) to a color (#cccccc).",
37
+ "!a = #ccc + 2px" => "Cannot add a number with units (2px) to a color (#cccccc).",
38
+ "& a\n :b c" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
39
+ "a\n :b\n c" => "Illegal nesting: Only attributes may be nested beneath attributes.",
40
+ "a,\n :b c" => ["Rules can\'t end in commas.", 1],
41
+ "a," => "Rules can\'t end in commas.",
42
+ "a,\n!b = 1" => ["Rules can\'t end in commas.", 1],
43
+ "!a = b\n :c d\n" => "Illegal nesting: Nothing may be nested beneath variable declarations.",
44
+ "@import foo.sass" => "File to import not found or unreadable: foo.sass.",
45
+ "@import templates/basic\n foo" => "Illegal nesting: Nothing may be nested beneath import directives.",
46
+ "foo\n @import templates/basic" => "Import directives may only be used at the root of a document.",
47
+ "foo\n @import #{File.dirname(__FILE__)}/templates/basic" => "Import directives may only be used at the root of a document.",
48
+ %Q{!foo = "bar" "baz" !} => %Q{Syntax error in '"bar" "baz" !' at character 20.},
49
+ "=foo\n :color red\n.bar\n +bang" => "Undefined mixin 'bang'.",
50
+ ".bar\n =foo\n :color red\n" => ["Mixins may only be defined at the root of a document.", 2],
51
+ "=foo\n :color red\n.bar\n +foo\n :color red" => "Illegal nesting: Nothing may be nested beneath mixin directives.",
52
+ " a\n b: c" => ["Indenting at the beginning of the document is illegal.", 1],
53
+ " \n \n\t\n a\n b: c" => ["Indenting at the beginning of the document is illegal.", 4],
54
+ "a\n b: c\n b: c" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 3],
55
+ "a\n b: c\na\n b: c" => ["Inconsistent indentation: 1 space was used for indentation, but the rest of the document was indented using 2 spaces.", 4],
56
+ "a\n\t\tb: c\n\tb: c" => ["Inconsistent indentation: 1 tab was used for indentation, but the rest of the document was indented using 2 tabs.", 3],
57
+ "a\n b: c\n b: c" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 3],
58
+ "a\n b: c\n a\n d: e" => ["Inconsistent indentation: 3 spaces were used for indentation, but the rest of the document was indented using 2 spaces.", 4],
59
+ "a\n b: c\na\n d: e" => ["The line was indented 2 levels deeper than the previous line.", 4],
60
+ "a\n b: c\n a\n d: e" => ["The line was indented 3 levels deeper than the previous line.", 4],
61
+ "a\n \tb: c" => ["Indentation can't use both tabs and spaces.", 2],
62
+ "=a(" => 'Invalid mixin "a(".',
63
+ "=a(b)" => 'Mixin argument "b" must begin with an exclamation point (!).',
64
+ "=a(,)" => "Mixin arguments can't be empty.",
65
+ "=a(!)" => "Mixin arguments can't be empty.",
66
+ "=a(!foo bar)" => "Invalid variable \"!foo bar\".",
67
+ "=foo\n bar: baz\n+foo" => ["Attributes aren't allowed at the root of a document.", 2],
68
+ "a-\#{!b\n c: d" => ["Expected end_interpolation token, was end of text.", 1],
69
+ "=a(!b = 1, !c)" => "Required arguments must not follow optional arguments \"!c\".",
70
+ "=a(!b = 1)\n :a= !b\ndiv\n +a(1,2)" => "Mixin a takes 1 argument but 2 were passed.",
71
+ "=a(!b)\n :a= !b\ndiv\n +a" => "Mixin a is missing parameter !b.",
72
+ "@else\n a\n b: c" => ["@else must come after @if.", 1],
73
+ "@if false\n@else foo" => "Invalid else directive '@else foo': expected 'if <expr>'.",
74
+ "@if false\n@else if " => "Invalid else directive '@else if': expected 'if <expr>'.",
75
+ "a\n !b = 12\nc\n d = !b" => 'Undefined variable: "!b".',
76
+ "=foo\n !b = 12\nc\n +foo\n d = !b" => 'Undefined variable: "!b".',
77
+ '@for !a from 1 to "foo"' => '"foo" is not an integer.',
78
+ '@for !a from 1 to 1.232323' => '1.232 is not an integer.',
79
+ '@if' => "Invalid if directive '@if': expected expression.",
80
+ '@while' => "Invalid while directive '@while': expected expression.",
81
+ '@debug' => "Invalid debug directive '@debug': expected expression.",
82
+
83
+ # Regression tests
84
+ "a\n b:\n c\n d" => ["Illegal nesting: Only attributes may be nested beneath attributes.", 3],
85
+ "& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 1],
86
+ "a\n b: c\n& foo\n bar: baz\n blat: bang" => ["Base-level rules cannot contain the parent-selector-referencing character '&'.", 3],
87
+ }
88
+
89
+ def test_basic_render
90
+ renders_correctly "basic", { :style => :compact }
91
+ end
92
+
93
+ def test_empty_render
94
+ assert_equal "", render("")
95
+ end
96
+
97
+ def test_multiple_calls_to_render
98
+ sass = Sass::Engine.new("a\n b: c")
99
+ assert_equal sass.render, sass.render
100
+ end
101
+
102
+ def test_alternate_styles
103
+ renders_correctly "expanded", { :style => :expanded }
104
+ renders_correctly "compact", { :style => :compact }
105
+ renders_correctly "nested", { :style => :nested }
106
+ renders_correctly "compressed", { :style => :compressed }
107
+ end
108
+
109
+ def test_flexible_tabulation
110
+ assert_equal("p {\n a: b; }\n p q {\n c: d; }\n",
111
+ render("p\n a: b\n q\n c: d\n"))
112
+ assert_equal("p {\n a: b; }\n p q {\n c: d; }\n",
113
+ render("p\n\ta: b\n\tq\n\t\tc: d\n"))
114
+ end
115
+
116
+ def test_exceptions
117
+ EXCEPTION_MAP.each do |key, value|
118
+ line = 10
119
+ begin
120
+ Sass::Engine.new(key, :filename => __FILE__, :line => line).render
121
+ rescue Sass::SyntaxError => err
122
+ value = [value] unless value.is_a?(Array)
123
+
124
+ assert_equal(value.first, err.message, "Line: #{key}")
125
+ assert_equal(__FILE__, err.sass_filename)
126
+ assert_equal((value[1] || key.split("\n").length) + line - 1, err.sass_line, "Line: #{key}")
127
+ assert_match(/#{Regexp.escape(__FILE__)}:[0-9]+/, err.backtrace[0], "Line: #{key}")
128
+ else
129
+ assert(false, "Exception not raised for\n#{key}")
130
+ end
131
+ end
132
+ end
133
+
134
+ def test_exception_line
135
+ to_render = <<SASS
136
+ rule
137
+ :attr val
138
+ // comment!
139
+
140
+ :broken
141
+ SASS
142
+ begin
143
+ Sass::Engine.new(to_render).render
144
+ rescue Sass::SyntaxError => err
145
+ assert_equal(5, err.sass_line)
146
+ else
147
+ assert(false, "Exception not raised for '#{to_render}'!")
148
+ end
149
+ end
150
+
151
+ def test_exception_location
152
+ to_render = <<SASS
153
+ rule
154
+ :attr val
155
+ // comment!
156
+
157
+ :broken
158
+ SASS
159
+ begin
160
+ Sass::Engine.new(to_render, :filename => __FILE__, :line => (__LINE__-7)).render
161
+ rescue Sass::SyntaxError => err
162
+ assert_equal(__FILE__, err.sass_filename)
163
+ assert_equal((__LINE__-6), err.sass_line)
164
+ else
165
+ assert(false, "Exception not raised for '#{to_render}'!")
166
+ end
167
+ end
168
+
169
+ def test_imported_exception
170
+ [nil, 2].each do |i|
171
+ begin
172
+ Sass::Engine.new("@import bork#{i}", :load_paths => [File.dirname(__FILE__) + '/templates/']).render
173
+ rescue Sass::SyntaxError => err
174
+ assert_equal(2, err.sass_line)
175
+ assert_match(/bork#{i}\.sass$/, err.sass_filename)
176
+ else
177
+ assert(false, "Exception not raised for imported template: bork#{i}")
178
+ end
179
+ end
180
+ end
181
+
182
+ def test_css_import
183
+ assert_equal("@import url(./fonts.css) screen;", render("@import url(./fonts.css) screen"))
184
+ assert_equal("@import \"./fonts.css\" screen;", render("@import \"./fonts.css\" screen"))
185
+ end
186
+
187
+ def test_sass_import
188
+ renders_correctly "import", { :style => :compact, :load_paths => [File.dirname(__FILE__) + "/templates"] }
189
+ end
190
+
191
+ def test_units
192
+ renders_correctly "units"
193
+ end
194
+
195
+ def test_default_function
196
+ assert_equal("foo {\n bar: url(foo.png); }\n", render(%Q{foo\n bar = url("foo.png")\n}));
197
+ assert_equal("foo {\n bar: url(); }\n", render("foo\n bar = url()\n"));
198
+ end
199
+
200
+ def test_string_minus
201
+ assert_equal("foo {\n bar: baz-boom-bat; }\n", render(%Q{foo\n bar = "baz"-"boom"-"bat"}))
202
+ assert_equal("foo {\n bar: -baz-boom; }\n", render(%Q{foo\n bar = -"baz"-"boom"}))
203
+ end
204
+
205
+ def test_string_div
206
+ assert_equal("foo {\n bar: baz/boom/bat; }\n", render(%Q{foo\n bar = "baz"/"boom"/"bat"}))
207
+ assert_equal("foo {\n bar: /baz/boom; }\n", render(%Q{foo\n bar = /"baz"/"boom"}))
208
+ end
209
+
210
+ def test_basic_multiline_selector
211
+ assert_equal("#foo #bar,\n#baz #boom {\n foo: bar; }\n",
212
+ render("#foo #bar,\n#baz #boom\n :foo bar"))
213
+ assert_equal("#foo #bar,\n#foo #baz {\n foo: bar; }\n",
214
+ render("#foo\n #bar,\n #baz\n :foo bar"))
215
+ assert_equal("#foo,\n#bar {\n foo: bar; }\n #foo #baz,\n #bar #baz {\n foo: bar; }\n",
216
+ render("#foo,\n#bar\n :foo bar\n #baz\n :foo bar"))
217
+ assert_equal("#foo #bar, #baz #boom { foo: bar; }\n",
218
+ render("#foo #bar,\n#baz #boom\n :foo bar", :style => :compact))
219
+
220
+ assert_equal("#foo #bar,#baz #boom{foo:bar}\n",
221
+ render("#foo #bar,\n#baz #boom\n :foo bar", :style => :compressed))
222
+ end
223
+
224
+ def test_complex_multiline_selector
225
+ renders_correctly "multiline"
226
+ end
227
+
228
+ def test_colon_only
229
+ begin
230
+ render("a\n b: c", :attribute_syntax => :normal)
231
+ rescue Sass::SyntaxError => e
232
+ assert_equal("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.",
233
+ e.message)
234
+ else
235
+ assert(false, "SyntaxError not raised for :attribute_syntax => :normal")
236
+ end
237
+
238
+ begin
239
+ render("a\n :b c", :attribute_syntax => :alternate)
240
+ rescue Sass::SyntaxError => e
241
+ assert_equal("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.",
242
+ e.message)
243
+ else
244
+ assert(false, "SyntaxError not raised for :attribute_syntax => :alternate")
245
+ end
246
+ end
247
+
248
+ def test_pseudo_elements
249
+ assert_equal(<<CSS, render(<<SASS))
250
+ ::first-line {
251
+ size: 10em; }
252
+ CSS
253
+ ::first-line
254
+ size: 10em
255
+ SASS
256
+ end
257
+
258
+ def test_directive
259
+ assert_equal("@a b;", render("@a b"))
260
+
261
+ assert_equal("@a {\n b: c; }\n", render("@a\n :b c"))
262
+ assert_equal("@a { b: c; }\n", render("@a\n :b c", :style => :compact))
263
+ assert_equal("@a {\n b: c;\n}\n", render("@a\n :b c", :style => :expanded))
264
+ assert_equal("@a{b:c}\n", render("@a\n :b c", :style => :compressed))
265
+
266
+ assert_equal("@a {\n b: c;\n d: e; }\n",
267
+ render("@a\n :b c\n :d e"))
268
+ assert_equal("@a { b: c; d: e; }\n",
269
+ render("@a\n :b c\n :d e", :style => :compact))
270
+ assert_equal("@a {\n b: c;\n d: e;\n}\n",
271
+ render("@a\n :b c\n :d e", :style => :expanded))
272
+ assert_equal("@a{b:c;d:e}\n",
273
+ render("@a\n :b c\n :d e", :style => :compressed))
274
+
275
+ assert_equal("@a {\n #b {\n c: d; } }\n",
276
+ render("@a\n #b\n :c d"))
277
+ assert_equal("@a { #b { c: d; } }\n",
278
+ render("@a\n #b\n :c d", :style => :compact))
279
+ assert_equal("@a {\n #b {\n c: d;\n }\n}\n",
280
+ render("@a\n #b\n :c d", :style => :expanded))
281
+ assert_equal("@a{#b{c:d}}\n",
282
+ render("@a\n #b\n :c d", :style => :compressed))
283
+
284
+ assert_equal("@a {\n #b {\n a: b; }\n #b #c {\n d: e; } }\n",
285
+ render("@a\n #b\n :a b\n #c\n :d e"))
286
+ assert_equal("@a { #b { a: b; }\n #b #c { d: e; } }\n",
287
+ render("@a\n #b\n :a b\n #c\n :d e", :style => :compact))
288
+ assert_equal("@a {\n #b {\n a: b;\n }\n #b #c {\n d: e;\n }\n}\n",
289
+ render("@a\n #b\n :a b\n #c\n :d e", :style => :expanded))
290
+ assert_equal("@a{#b{a:b}#b #c{d:e}}\n",
291
+ render("@a\n #b\n :a b\n #c\n :d e", :style => :compressed))
292
+
293
+ assert_equal("@a {\n #foo,\n #bar {\n b: c; } }\n",
294
+ render("@a\n #foo, \n #bar\n :b c"))
295
+ assert_equal("@a { #foo, #bar { b: c; } }\n",
296
+ render("@a\n #foo, \n #bar\n :b c", :style => :compact))
297
+ assert_equal("@a {\n #foo,\n #bar {\n b: c;\n }\n}\n",
298
+ render("@a\n #foo, \n #bar\n :b c", :style => :expanded))
299
+ assert_equal("@a{#foo,#bar{b:c}}\n",
300
+ render("@a\n #foo, \n #bar\n :b c", :style => :compressed))
301
+
302
+ to_render = <<END
303
+ @a
304
+ :b c
305
+ #d
306
+ :e f
307
+ :g h
308
+ END
309
+ rendered = <<END
310
+ @a { b: c;
311
+ #d { e: f; }
312
+ g: h; }
313
+ END
314
+ assert_equal(rendered, render(to_render, :style => :compact))
315
+
316
+ assert_equal("@a{b:c;#d{e:f}g:h}\n", render(to_render, :style => :compressed))
317
+ end
318
+
319
+ def test_line_annotations
320
+ assert_equal(<<CSS, render(<<SASS, :line_comments => true, :style => :compact))
321
+ /* line 2, test_line_annotations_inline.sass */
322
+ foo bar { foo: bar; }
323
+ /* line 5, test_line_annotations_inline.sass */
324
+ foo baz { blip: blop; }
325
+
326
+ /* line 9, test_line_annotations_inline.sass */
327
+ floodle { flop: blop; }
328
+
329
+ /* line 18, test_line_annotations_inline.sass */
330
+ bup { mix: on; }
331
+ /* line 15, test_line_annotations_inline.sass */
332
+ bup mixin { moop: mup; }
333
+
334
+ /* line 22, test_line_annotations_inline.sass */
335
+ bip hop, skip hop { a: b; }
336
+ CSS
337
+ foo
338
+ bar
339
+ foo: bar
340
+
341
+ baz
342
+ blip: blop
343
+
344
+
345
+ floodle
346
+
347
+ flop: blop
348
+
349
+ =mxn
350
+ mix: on
351
+ mixin
352
+ moop: mup
353
+
354
+ bup
355
+ +mxn
356
+
357
+ bip, skip
358
+ hop
359
+ a: b
360
+ SASS
361
+ end
362
+
363
+ def test_line_annotations_with_filename
364
+ renders_correctly "line_numbers", :line_comments => true, :load_paths => [File.dirname(__FILE__) + "/templates"]
365
+ end
366
+
367
+ def test_empty_first_line
368
+ assert_equal("#a {\n b: c; }\n", render("#a\n\n b: c"))
369
+ end
370
+
371
+ def test_escaped_rule
372
+ assert_equal(":focus {\n a: b; }\n", render("\\:focus\n a: b"))
373
+ assert_equal("a {\n b: c; }\n a :focus {\n d: e; }\n", render("\\a\n b: c\n \\:focus\n d: e"))
374
+ end
375
+
376
+ def test_cr_newline
377
+ 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"))
378
+ end
379
+
380
+ def test_or_eq
381
+ assert_equal("foo {\n a: b; }\n", render(%Q{!foo = "b"\n!foo ||= "c"\nfoo\n a = !foo}))
382
+ assert_equal("foo {\n a: b; }\n", render(%Q{!foo ||= "b"\nfoo\n a = !foo}))
383
+ end
384
+
385
+ def test_mixins
386
+ renders_correctly "mixins", { :style => :expanded }
387
+ end
388
+
389
+ def test_mixins_dont_interfere_with_sibling_combinator
390
+ assert_equal("foo + bar {\n a: b; }\nfoo + baz {\n c: d; }\n",
391
+ render("foo\n +\n bar\n a: b\n baz\n c: d"))
392
+ end
393
+
394
+ def test_mixin_args
395
+ assert_equal("blat {\n baz: hi; }\n", render(<<SASS))
396
+ =foo(!bar)
397
+ baz = !bar
398
+ blat
399
+ +foo(\"hi\")
400
+ SASS
401
+ assert_equal("blat {\n baz: 3; }\n", render(<<SASS))
402
+ =foo(!a, !b)
403
+ baz = !a + !b
404
+ blat
405
+ +foo(1, 2)
406
+ SASS
407
+ assert_equal("blat {\n baz: 4;\n baz: 3;\n baz: 5;\n bang: 3; }\n", render(<<SASS))
408
+ =foo(!c = (6 + 4) / 2)
409
+ baz = !c
410
+ !c = 3
411
+ blat
412
+ +foo(!c + 1)
413
+ +foo((!c + 3)/2)
414
+ +foo
415
+ bang = !c
416
+ SASS
417
+ end
418
+
419
+ def test_default_values_for_mixin_arguments
420
+ assert_equal("white {\n color: white; }\n\nblack {\n color: black; }\n", render(<<SASS))
421
+ =foo(!a = #FFF)
422
+ :color= !a
423
+ white
424
+ +foo
425
+ black
426
+ +foo(#000)
427
+ SASS
428
+ assert_equal(<<CSS, render(<<SASS))
429
+ one {
430
+ color: white;
431
+ padding: 1px;
432
+ margin: 4px; }
433
+
434
+ two {
435
+ color: white;
436
+ padding: 2px;
437
+ margin: 5px; }
438
+
439
+ three {
440
+ color: white;
441
+ padding: 2px;
442
+ margin: 3px; }
443
+ CSS
444
+ !a = 5px
445
+ =foo(!a, !b = 1px, !c = 3px + !b)
446
+ :color= !a
447
+ :padding= !b
448
+ :margin= !c
449
+ one
450
+ +foo(#fff)
451
+ two
452
+ +foo(#fff, 2px)
453
+ three
454
+ +foo(#fff, 2px, 3px)
455
+ SASS
456
+ end
457
+
458
+ def test_interpolation
459
+ assert_equal("a-1 {\n b-2-3: c-3; }\n", render(<<SASS))
460
+ !a = 1
461
+ !b = 2
462
+ !c = 3
463
+ a-\#{!a}
464
+ b-\#{!b}-\#{!c}: c-\#{!a + !b}
465
+ SASS
466
+ end
467
+
468
+ def test_if_directive
469
+ assert_equal("a {\n b: 1; }\n", render(<<SASS))
470
+ !var = true
471
+ a
472
+ @if !var
473
+ b: 1
474
+ @if not !var
475
+ b: 2
476
+ SASS
477
+ end
478
+
479
+ def test_for
480
+ assert_equal(<<CSS, render(<<SASS))
481
+ a-0 {
482
+ 2i: 0; }
483
+
484
+ a-1 {
485
+ 2i: 2; }
486
+
487
+ a-2 {
488
+ 2i: 4; }
489
+
490
+ a-3 {
491
+ 2i: 6; }
492
+
493
+ b-1 {
494
+ j-1: 0; }
495
+
496
+ b-2 {
497
+ j-1: 1; }
498
+
499
+ b-3 {
500
+ j-1: 2; }
501
+
502
+ b-4 {
503
+ j-1: 3; }
504
+ CSS
505
+ !a = 3
506
+ @for !i from 0 to !a + 1
507
+ a-\#{!i}
508
+ 2i = 2 * !i
509
+
510
+ @for !j from 1 through 4
511
+ b-\#{!j}
512
+ j-1 = !j - 1
513
+ SASS
514
+ end
515
+
516
+ def test_while
517
+ assert_equal(<<CSS, render(<<SASS))
518
+ a-5 {
519
+ blooble: gloop; }
520
+
521
+ a-4 {
522
+ blooble: gloop; }
523
+
524
+ a-3 {
525
+ blooble: gloop; }
526
+
527
+ a-2 {
528
+ blooble: gloop; }
529
+
530
+ a-1 {
531
+ blooble: gloop; }
532
+ CSS
533
+ !a = 5
534
+ @while !a != 0
535
+ a-\#{!a}
536
+ blooble: gloop
537
+ !a = !a - 1
538
+ SASS
539
+ end
540
+
541
+ def test_else
542
+ assert_equal(<<CSS, render(<<SASS))
543
+ a {
544
+ t1: t;
545
+ t2: t;
546
+ t3: t;
547
+ t4: t; }
548
+ CSS
549
+ a
550
+ @if true
551
+ t1: t
552
+ @else
553
+ f1: f
554
+
555
+ @if false
556
+ f2: f
557
+ @else
558
+ t2: t
559
+
560
+ @if false
561
+ f3: f1
562
+ @else if 1 + 1 == 3
563
+ f3: f2
564
+ @else
565
+ t3: t
566
+
567
+ @if false
568
+ f4: f1
569
+ @else if 1 + 1 == 2
570
+ t4: t
571
+ @else
572
+ f4: f2
573
+
574
+ @if false
575
+ f5: f1
576
+ @else if false
577
+ f5: f2
578
+ SASS
579
+ end
580
+
581
+ def test_variable_reassignment
582
+ assert_equal(<<CSS, render(<<SASS))
583
+ a {
584
+ b: 1;
585
+ c: 2; }
586
+ CSS
587
+ !a = 1
588
+ a
589
+ b = !a
590
+ !a = 2
591
+ c = !a
592
+ SASS
593
+ end
594
+
595
+ def test_variable_scope
596
+ assert_equal(<<CSS, render(<<SASS))
597
+ a {
598
+ b-1: c;
599
+ b-2: c;
600
+ d: 12; }
601
+
602
+ b {
603
+ d: 17; }
604
+ CSS
605
+ !i = 12
606
+ a
607
+ @for !i from 1 through 2
608
+ b-\#{!i}: c
609
+ d = !i
610
+
611
+ =foo
612
+ !i = 17
613
+
614
+ b
615
+ +foo
616
+ d = !i
617
+ SASS
618
+ end
619
+
620
+ def test_argument_error
621
+ assert_raise(Sass::SyntaxError) { render("a\n b = hsl(1)") }
622
+ end
623
+
624
+ def test_comments_at_the_top_of_a_document
625
+ render(<<SASS)
626
+ //
627
+ This is a comment that
628
+ continues to the second line.
629
+ foo
630
+ bar: baz
631
+ SASS
632
+ end
633
+
634
+ def test_loud_comments_containing_a_comment_close
635
+ actual_css = render(<<SASS)
636
+ /*
637
+ This is a comment that
638
+ continues to the second line. */
639
+ foo
640
+ bar: baz
641
+ SASS
642
+ assert_equal(<<CSS, actual_css)
643
+ /*
644
+ * This is a comment that
645
+ * continues to the second line. */
646
+ foo {
647
+ bar: baz; }
648
+ CSS
649
+ end
650
+
651
+ def test_quoted_colon
652
+ assert_equal(<<CSS, render(<<SASS))
653
+ a b[foo="bar: baz"] {
654
+ c: d; }
655
+ CSS
656
+ a
657
+ b[foo="bar: baz"]
658
+ c: d
659
+ SASS
660
+ end
661
+
662
+ def test_quoted_comma
663
+ assert_equal(<<CSS, render(<<SASS))
664
+ a b[foo="bar, baz"] {
665
+ c: d; }
666
+ CSS
667
+ a
668
+ b[foo="bar, baz"]
669
+ c: d
670
+ SASS
671
+ end
672
+
673
+ def test_quoted_ampersand
674
+ assert_equal(<<CSS, render(<<SASS))
675
+ a b[foo="bar & baz"] {
676
+ c: d; }
677
+ CSS
678
+ a
679
+ b[foo="bar & baz"]
680
+ c: d
681
+ SASS
682
+ end
683
+
684
+ private
685
+
686
+ def render(sass, options = {})
687
+ munge_filename options
688
+ Sass::Engine.new(sass, options).render
689
+ end
690
+
691
+ def renders_correctly(name, options={})
692
+ sass_file = load_file(name, "sass")
693
+ css_file = load_file(name, "css")
694
+ options[:filename] ||= filename(name, "sass")
695
+ options[:css_filename] ||= filename(name, "css")
696
+ css_result = Sass::Engine.new(sass_file, options).render
697
+ assert_equal css_file, css_result
698
+ end
699
+
700
+ def load_file(name, type = "sass")
701
+ @result = ''
702
+ File.new(filename(name, type)).each_line { |l| @result += l }
703
+ @result
704
+ end
705
+
706
+ def filename(name, type)
707
+ File.dirname(__FILE__) + "/#{type == 'sass' ? 'templates' : 'results'}/#{name}.#{type}"
708
+ end
709
+ end