sass 3.1.0.alpha.2

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 (205) hide show
  1. data/.yardopts +11 -0
  2. data/CONTRIBUTING +3 -0
  3. data/EDGE_GEM_VERSION +1 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.md +201 -0
  6. data/REVISION +1 -0
  7. data/Rakefile +353 -0
  8. data/VERSION +1 -0
  9. data/VERSION_NAME +1 -0
  10. data/bin/css2sass +13 -0
  11. data/bin/sass +8 -0
  12. data/bin/sass-convert +7 -0
  13. data/extra/update_watch.rb +13 -0
  14. data/init.rb +18 -0
  15. data/lib/sass.rb +71 -0
  16. data/lib/sass/cache_store.rb +208 -0
  17. data/lib/sass/callbacks.rb +66 -0
  18. data/lib/sass/css.rb +294 -0
  19. data/lib/sass/engine.rb +792 -0
  20. data/lib/sass/environment.rb +143 -0
  21. data/lib/sass/error.rb +201 -0
  22. data/lib/sass/exec.rb +619 -0
  23. data/lib/sass/importers.rb +22 -0
  24. data/lib/sass/importers/base.rb +138 -0
  25. data/lib/sass/importers/filesystem.rb +121 -0
  26. data/lib/sass/less.rb +363 -0
  27. data/lib/sass/plugin.rb +126 -0
  28. data/lib/sass/plugin/compiler.rb +346 -0
  29. data/lib/sass/plugin/configuration.rb +123 -0
  30. data/lib/sass/plugin/generic.rb +15 -0
  31. data/lib/sass/plugin/merb.rb +48 -0
  32. data/lib/sass/plugin/rack.rb +47 -0
  33. data/lib/sass/plugin/rails.rb +41 -0
  34. data/lib/sass/plugin/staleness_checker.rb +145 -0
  35. data/lib/sass/railtie.rb +8 -0
  36. data/lib/sass/repl.rb +58 -0
  37. data/lib/sass/root.rb +7 -0
  38. data/lib/sass/script.rb +63 -0
  39. data/lib/sass/script/bool.rb +18 -0
  40. data/lib/sass/script/color.rb +490 -0
  41. data/lib/sass/script/css_lexer.rb +29 -0
  42. data/lib/sass/script/css_parser.rb +31 -0
  43. data/lib/sass/script/funcall.rb +78 -0
  44. data/lib/sass/script/functions.rb +852 -0
  45. data/lib/sass/script/interpolation.rb +70 -0
  46. data/lib/sass/script/lexer.rb +337 -0
  47. data/lib/sass/script/literal.rb +236 -0
  48. data/lib/sass/script/node.rb +101 -0
  49. data/lib/sass/script/number.rb +420 -0
  50. data/lib/sass/script/operation.rb +92 -0
  51. data/lib/sass/script/parser.rb +392 -0
  52. data/lib/sass/script/string.rb +67 -0
  53. data/lib/sass/script/string_interpolation.rb +93 -0
  54. data/lib/sass/script/unary_operation.rb +57 -0
  55. data/lib/sass/script/variable.rb +48 -0
  56. data/lib/sass/scss.rb +17 -0
  57. data/lib/sass/scss/css_parser.rb +51 -0
  58. data/lib/sass/scss/parser.rb +838 -0
  59. data/lib/sass/scss/rx.rb +126 -0
  60. data/lib/sass/scss/sass_parser.rb +11 -0
  61. data/lib/sass/scss/script_lexer.rb +15 -0
  62. data/lib/sass/scss/script_parser.rb +25 -0
  63. data/lib/sass/scss/static_parser.rb +40 -0
  64. data/lib/sass/selector.rb +361 -0
  65. data/lib/sass/selector/abstract_sequence.rb +62 -0
  66. data/lib/sass/selector/comma_sequence.rb +82 -0
  67. data/lib/sass/selector/sequence.rb +236 -0
  68. data/lib/sass/selector/simple.rb +113 -0
  69. data/lib/sass/selector/simple_sequence.rb +135 -0
  70. data/lib/sass/shared.rb +78 -0
  71. data/lib/sass/tree/comment_node.rb +128 -0
  72. data/lib/sass/tree/debug_node.rb +36 -0
  73. data/lib/sass/tree/directive_node.rb +75 -0
  74. data/lib/sass/tree/extend_node.rb +65 -0
  75. data/lib/sass/tree/for_node.rb +67 -0
  76. data/lib/sass/tree/if_node.rb +81 -0
  77. data/lib/sass/tree/import_node.rb +124 -0
  78. data/lib/sass/tree/mixin_def_node.rb +60 -0
  79. data/lib/sass/tree/mixin_node.rb +123 -0
  80. data/lib/sass/tree/node.rb +490 -0
  81. data/lib/sass/tree/prop_node.rb +220 -0
  82. data/lib/sass/tree/root_node.rb +125 -0
  83. data/lib/sass/tree/rule_node.rb +273 -0
  84. data/lib/sass/tree/variable_node.rb +39 -0
  85. data/lib/sass/tree/warn_node.rb +42 -0
  86. data/lib/sass/tree/while_node.rb +48 -0
  87. data/lib/sass/util.rb +687 -0
  88. data/lib/sass/util/subset_map.rb +101 -0
  89. data/lib/sass/version.rb +109 -0
  90. data/rails/init.rb +1 -0
  91. data/test/sass/cache_test.rb +74 -0
  92. data/test/sass/callbacks_test.rb +61 -0
  93. data/test/sass/conversion_test.rb +1210 -0
  94. data/test/sass/css2sass_test.rb +364 -0
  95. data/test/sass/data/hsl-rgb.txt +319 -0
  96. data/test/sass/engine_test.rb +2273 -0
  97. data/test/sass/extend_test.rb +1348 -0
  98. data/test/sass/functions_test.rb +565 -0
  99. data/test/sass/importer_test.rb +104 -0
  100. data/test/sass/less_conversion_test.rb +632 -0
  101. data/test/sass/mock_importer.rb +49 -0
  102. data/test/sass/more_results/more1.css +9 -0
  103. data/test/sass/more_results/more1_with_line_comments.css +26 -0
  104. data/test/sass/more_results/more_import.css +29 -0
  105. data/test/sass/more_templates/_more_partial.sass +2 -0
  106. data/test/sass/more_templates/more1.sass +23 -0
  107. data/test/sass/more_templates/more_import.sass +11 -0
  108. data/test/sass/plugin_test.rb +430 -0
  109. data/test/sass/results/alt.css +4 -0
  110. data/test/sass/results/basic.css +9 -0
  111. data/test/sass/results/compact.css +5 -0
  112. data/test/sass/results/complex.css +86 -0
  113. data/test/sass/results/compressed.css +1 -0
  114. data/test/sass/results/expanded.css +19 -0
  115. data/test/sass/results/import.css +31 -0
  116. data/test/sass/results/line_numbers.css +49 -0
  117. data/test/sass/results/mixins.css +95 -0
  118. data/test/sass/results/multiline.css +24 -0
  119. data/test/sass/results/nested.css +22 -0
  120. data/test/sass/results/options.css +1 -0
  121. data/test/sass/results/parent_ref.css +13 -0
  122. data/test/sass/results/script.css +16 -0
  123. data/test/sass/results/scss_import.css +31 -0
  124. data/test/sass/results/scss_importee.css +2 -0
  125. data/test/sass/results/subdir/nested_subdir/nested_subdir.css +1 -0
  126. data/test/sass/results/subdir/subdir.css +3 -0
  127. data/test/sass/results/units.css +11 -0
  128. data/test/sass/results/warn.css +0 -0
  129. data/test/sass/results/warn_imported.css +0 -0
  130. data/test/sass/script_conversion_test.rb +254 -0
  131. data/test/sass/script_test.rb +459 -0
  132. data/test/sass/scss/css_test.rb +897 -0
  133. data/test/sass/scss/rx_test.rb +156 -0
  134. data/test/sass/scss/scss_test.rb +1088 -0
  135. data/test/sass/scss/test_helper.rb +37 -0
  136. data/test/sass/templates/_partial.sass +2 -0
  137. data/test/sass/templates/alt.sass +16 -0
  138. data/test/sass/templates/basic.sass +23 -0
  139. data/test/sass/templates/bork1.sass +2 -0
  140. data/test/sass/templates/bork2.sass +2 -0
  141. data/test/sass/templates/bork3.sass +2 -0
  142. data/test/sass/templates/bork4.sass +2 -0
  143. data/test/sass/templates/compact.sass +17 -0
  144. data/test/sass/templates/complex.sass +305 -0
  145. data/test/sass/templates/compressed.sass +15 -0
  146. data/test/sass/templates/expanded.sass +17 -0
  147. data/test/sass/templates/import.sass +12 -0
  148. data/test/sass/templates/importee.less +2 -0
  149. data/test/sass/templates/importee.sass +19 -0
  150. data/test/sass/templates/line_numbers.sass +13 -0
  151. data/test/sass/templates/mixin_bork.sass +5 -0
  152. data/test/sass/templates/mixins.sass +76 -0
  153. data/test/sass/templates/multiline.sass +20 -0
  154. data/test/sass/templates/nested.sass +25 -0
  155. data/test/sass/templates/nested_bork1.sass +2 -0
  156. data/test/sass/templates/nested_bork2.sass +2 -0
  157. data/test/sass/templates/nested_bork3.sass +2 -0
  158. data/test/sass/templates/nested_bork4.sass +2 -0
  159. data/test/sass/templates/nested_mixin_bork.sass +6 -0
  160. data/test/sass/templates/options.sass +2 -0
  161. data/test/sass/templates/parent_ref.sass +25 -0
  162. data/test/sass/templates/script.sass +101 -0
  163. data/test/sass/templates/scss_import.scss +11 -0
  164. data/test/sass/templates/scss_importee.scss +1 -0
  165. data/test/sass/templates/subdir/nested_subdir/_nested_partial.sass +2 -0
  166. data/test/sass/templates/subdir/nested_subdir/nested_subdir.sass +3 -0
  167. data/test/sass/templates/subdir/subdir.sass +6 -0
  168. data/test/sass/templates/units.sass +11 -0
  169. data/test/sass/templates/warn.sass +3 -0
  170. data/test/sass/templates/warn_imported.sass +4 -0
  171. data/test/sass/test_helper.rb +8 -0
  172. data/test/sass/util/subset_map_test.rb +91 -0
  173. data/test/sass/util_test.rb +275 -0
  174. data/test/test_helper.rb +64 -0
  175. data/vendor/fssm/LICENSE +20 -0
  176. data/vendor/fssm/README.markdown +55 -0
  177. data/vendor/fssm/Rakefile +59 -0
  178. data/vendor/fssm/VERSION.yml +5 -0
  179. data/vendor/fssm/example.rb +9 -0
  180. data/vendor/fssm/fssm.gemspec +77 -0
  181. data/vendor/fssm/lib/fssm.rb +33 -0
  182. data/vendor/fssm/lib/fssm/backends/fsevents.rb +36 -0
  183. data/vendor/fssm/lib/fssm/backends/inotify.rb +26 -0
  184. data/vendor/fssm/lib/fssm/backends/polling.rb +25 -0
  185. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +131 -0
  186. data/vendor/fssm/lib/fssm/monitor.rb +26 -0
  187. data/vendor/fssm/lib/fssm/path.rb +91 -0
  188. data/vendor/fssm/lib/fssm/pathname.rb +502 -0
  189. data/vendor/fssm/lib/fssm/state/directory.rb +57 -0
  190. data/vendor/fssm/lib/fssm/state/file.rb +24 -0
  191. data/vendor/fssm/lib/fssm/support.rb +63 -0
  192. data/vendor/fssm/lib/fssm/tree.rb +176 -0
  193. data/vendor/fssm/profile/prof-cache.rb +40 -0
  194. data/vendor/fssm/profile/prof-fssm-pathname.html +1231 -0
  195. data/vendor/fssm/profile/prof-pathname.rb +68 -0
  196. data/vendor/fssm/profile/prof-plain-pathname.html +988 -0
  197. data/vendor/fssm/profile/prof.html +2379 -0
  198. data/vendor/fssm/spec/path_spec.rb +75 -0
  199. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  200. data/vendor/fssm/spec/root/file.css +0 -0
  201. data/vendor/fssm/spec/root/file.rb +0 -0
  202. data/vendor/fssm/spec/root/file.yml +0 -0
  203. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  204. data/vendor/fssm/spec/spec_helper.rb +14 -0
  205. metadata +297 -0
File without changes
File without changes
@@ -0,0 +1,254 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ require File.dirname(__FILE__) + '/../test_helper'
4
+ require 'sass/engine'
5
+
6
+ class SassScriptConversionTest < Test::Unit::TestCase
7
+ def test_bool
8
+ assert_renders "true"
9
+ assert_renders "false"
10
+ end
11
+
12
+ def test_color
13
+ assert_renders "#abcdef"
14
+ assert_renders "blue"
15
+ assert_renders "rgba(0, 1, 2, 0.2)"
16
+
17
+ assert_equal "#aabbcc", render("#abc")
18
+ assert_equal "blue", render("#0000ff")
19
+ end
20
+
21
+ def test_number
22
+ assert_renders "10"
23
+ assert_renders "10.35"
24
+ assert_renders "12px"
25
+ assert_renders "12.45px"
26
+
27
+ assert_equal "12.346", render("12.345678901")
28
+ end
29
+
30
+ def test_string
31
+ assert_renders '"foo"'
32
+ assert_renders '"bar baz"'
33
+ assert_equal '"baz bang"', render("'baz bang'")
34
+ end
35
+
36
+ def test_string_quotes
37
+ assert_equal "'quote\"quote'", render('"quote\\"quote"')
38
+ assert_equal '"quote\'quote"', render("'quote\\'quote'")
39
+ assert_renders '"quote\'quote\\"quote"'
40
+ assert_equal '"quote\'quote\\"quote"', render("'quote\\'quote\"quote'")
41
+ end
42
+
43
+ def test_string_escapes
44
+ assert_renders '"foo\\\\bar"'
45
+ end
46
+
47
+ def test_funcall
48
+ assert_renders "foo(true, blue)"
49
+ assert_renders "hsla(20deg, 30%, 50%, 0.3)"
50
+ assert_renders "blam()"
51
+
52
+ assert_renders "-\xC3\xBFoo(12px)"
53
+ assert_renders "-foo(12px)"
54
+ end
55
+
56
+ def test_url
57
+ assert_renders "url(foo.gif)"
58
+ assert_renders "url($var)"
59
+ assert_renders "url(\#{$var}/flip.gif)"
60
+ end
61
+
62
+ def test_variable
63
+ assert_renders "$foo-bar"
64
+ assert_renders "$flaznicate"
65
+ assert_warning(<<WARN) {assert_equal "$tumbly-wumbly", render("!tumbly-wumbly")}
66
+ DEPRECATION WARNING:
67
+ On line 1, character 1 of 'test_variable_inline.sass'
68
+ Variables with ! have been deprecated and will be removed in version 3.2.
69
+ Use "$tumbly-wumbly" instead.
70
+
71
+ You can use `sass-convert --in-place --from sass2 file.sass' to convert files automatically.
72
+ WARN
73
+ end
74
+
75
+ def test_important
76
+ assert_renders "!important"
77
+ assert_renders "$foo !important"
78
+ end
79
+
80
+ def test_comma_operator
81
+ assert_renders "$foo, $bar $baz"
82
+ assert_renders "$foo $bar, $baz"
83
+
84
+ assert_renders "($foo, $bar) $baz"
85
+ assert_renders "$foo ($bar, $baz)"
86
+
87
+ assert_equal "$foo, $bar $baz", render("$foo, ($bar $baz)")
88
+ assert_equal "$foo $bar, $baz", render("($foo $bar), $baz")
89
+ end
90
+
91
+ def test_concat_operator
92
+ assert_renders "$foo $bar or $baz"
93
+ assert_renders "$foo or $bar $baz"
94
+
95
+ assert_renders "($foo $bar) or $baz"
96
+ assert_renders "$foo or ($bar $baz)"
97
+
98
+ assert_equal "$foo $bar or $baz", render("$foo ($bar or $baz)")
99
+ assert_equal "$foo or $bar $baz", render("($foo or $bar) $baz")
100
+ end
101
+
102
+ def self.test_precedence(outer, inner)
103
+ op_outer = Sass::Script::Lexer::OPERATORS_REVERSE[outer]
104
+ op_inner = Sass::Script::Lexer::OPERATORS_REVERSE[inner]
105
+ class_eval <<RUBY
106
+ def test_precedence_#{outer}_#{inner}
107
+ assert_renders "$foo #{op_outer} $bar #{op_inner} $baz"
108
+ assert_renders "$foo #{op_inner} $bar #{op_outer} $baz"
109
+
110
+ assert_renders "($foo #{op_outer} $bar) #{op_inner} $baz"
111
+ assert_renders "$foo #{op_inner} ($bar #{op_outer} $baz)"
112
+
113
+ assert_equal "$foo #{op_outer} $bar #{op_inner} $baz",
114
+ render("$foo #{op_outer} ($bar #{op_inner} $baz)")
115
+ assert_equal "$foo #{op_inner} $bar #{op_outer} $baz",
116
+ render("($foo #{op_inner} $bar) #{op_outer} $baz")
117
+ end
118
+ RUBY
119
+ end
120
+
121
+ test_precedence :or, :and
122
+ test_precedence :and, :eq
123
+ test_precedence :and, :neq
124
+ test_precedence :eq, :gt
125
+ test_precedence :eq, :gte
126
+ test_precedence :eq, :lt
127
+ test_precedence :eq, :lte
128
+ test_precedence :gt, :plus
129
+ test_precedence :gt, :minus
130
+ test_precedence :plus, :times
131
+ test_precedence :plus, :div
132
+ test_precedence :plus, :mod
133
+
134
+ def test_unary_op
135
+ assert_renders "-12px"
136
+ assert_renders '/"foo"'
137
+ assert_renders 'not true'
138
+
139
+ assert_renders "-(foo(12px))"
140
+ assert_renders "-(-foo(12px))"
141
+ assert_renders "-(_foo(12px))"
142
+ assert_renders "-(\xC3\xBFoo(12px))"
143
+ assert_renders "-(blue)"
144
+
145
+ assert_equal 'not true or false', render('(not true) or false')
146
+ assert_equal 'not (true or false)', render('not (true or false)')
147
+ end
148
+
149
+ def test_interpolation
150
+ assert_renders "$foo\#{$bar}$baz"
151
+ assert_renders "$foo\#{$bar} $baz"
152
+ assert_renders "$foo \#{$bar}$baz"
153
+ assert_renders "$foo \#{$bar} $baz"
154
+ assert_renders "$foo \#{$bar}\#{$bang} $baz"
155
+ assert_renders "$foo \#{$bar} \#{$bang} $baz"
156
+ assert_renders "\#{$bar}$baz"
157
+ assert_renders "$foo\#{$bar}"
158
+ assert_renders "\#{$bar}"
159
+ end
160
+
161
+ def test_interpolation_in_function
162
+ assert_renders 'flabnabbit(#{1 + "foo"})'
163
+ assert_renders 'flabnabbit($foo #{1 + "foo"}$baz)'
164
+ assert_renders 'flabnabbit($foo #{1 + "foo"}#{2 + "bar"} $baz)'
165
+ end
166
+
167
+ def test_interpolation_near_operators
168
+ assert_renders '#{1 + 2} , #{3 + 4}'
169
+ assert_renders '#{1 + 2}, #{3 + 4}'
170
+ assert_renders '#{1 + 2} ,#{3 + 4}'
171
+ assert_renders '#{1 + 2},#{3 + 4}'
172
+
173
+ assert_renders '3 / #{3 + 4}'
174
+ assert_renders '3 /#{3 + 4}'
175
+ assert_renders '3/ #{3 + 4}'
176
+ assert_renders '3/#{3 + 4}'
177
+
178
+ assert_renders '#{1 + 2} * 7'
179
+ assert_renders '#{1 + 2}* 7'
180
+ assert_renders '#{1 + 2} *7'
181
+ assert_renders '#{1 + 2}*7'
182
+
183
+ assert_renders '-#{1 + 2}'
184
+ assert_renders '- #{1 + 2}'
185
+
186
+ assert_renders '5 + #{1 + 2} * #{3 + 4}'
187
+ assert_renders '5 +#{1 + 2} * #{3 + 4}'
188
+ assert_renders '5+#{1 + 2} * #{3 + 4}'
189
+ assert_renders '#{1 + 2} * #{3 + 4} + 5'
190
+ assert_renders '#{1 + 2} * #{3 + 4}+ 5'
191
+ assert_renders '#{1 + 2} * #{3 + 4}+5'
192
+
193
+ assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 / (#{1 + 2} + #{3 + 4})')
194
+ assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 /(#{1 + 2} + #{3 + 4})')
195
+ assert_equal '5 / #{1 + 2} + #{3 + 4}', render('5 /( #{1 + 2} + #{3 + 4} )')
196
+ assert_equal '#{1 + 2} + #{3 + 4} / 5', render('(#{1 + 2} + #{3 + 4}) / 5')
197
+ assert_equal '#{1 + 2} + #{3 + 4} / 5', render('(#{1 + 2} + #{3 + 4})/ 5')
198
+ assert_equal '#{1 + 2} + #{3 + 4} / 5', render('( #{1 + 2} + #{3 + 4} )/ 5')
199
+
200
+ assert_renders '#{1 + 2} + 2 + 3'
201
+ assert_renders '#{1 + 2} +2 + 3'
202
+ end
203
+
204
+ def test_string_interpolation
205
+ assert_renders '"foo#{$bar}baz"'
206
+ assert_renders '"foo #{$bar}baz"'
207
+ assert_renders '"foo#{$bar} baz"'
208
+ assert_renders '"foo #{$bar} baz"'
209
+ assert_renders '"foo #{$bar}#{$bang} baz"'
210
+ assert_renders '"foo #{$bar} #{$bang} baz"'
211
+ assert_renders '"#{$bar}baz"'
212
+ assert_renders '"foo#{$bar}"'
213
+ assert_equal '#{$bar}', render('"#{$bar}"')
214
+
215
+ assert_equal '"foo#{$bar}baz"', render("'foo\#{$bar}baz'")
216
+ end
217
+
218
+ def test_sass2_string_interpolation
219
+ assert_equal 'foo#{$bar}baz', render('"foo#{$bar}baz"', :context => :equals)
220
+ assert_equal '#{$bar}baz', render('"#{$bar}baz"', :context => :equals)
221
+ assert_equal 'foo#{$bar}', render('"foo#{$bar}"', :context => :equals)
222
+
223
+ assert_equal 'unquote(".foo#{$bar}.bar")', render('".foo#{$bar}.bar"', :context => :equals)
224
+ assert_equal 'unquote(".foo#{$bar}")', render('".foo#{$bar}"', :context => :equals)
225
+ assert_equal 'unquote("#{$bar}.bar")', render('"#{$bar}.bar"', :context => :equals)
226
+
227
+ assert_equal "unquote(\"f'o\#{$bar}b'z\")", render("'f\\'o\#{$bar}b\\'z'", :context => :equals)
228
+ assert_equal "unquote('f\"o\#{$bar}b\"z')", render("'f\\\"o\#{$bar}b\\\"z'", :context => :equals)
229
+ assert_equal "unquote(\"f'o\#{$bar}b\\\"z\")", render("'f\\'o\#{$bar}b\\\"z'", :context => :equals)
230
+ end
231
+
232
+ def test_sass2_urls
233
+ Sass::Util.silence_sass_warnings do
234
+ assert_equal 'url(foo/bar.gif)', render('url(foo/bar.gif)', :context => :equals)
235
+ assert_equal 'url("foo/bar.gif")', render('url("foo/bar.gif")', :context => :equals)
236
+
237
+ assert_equal 'url($var)', render('url(!var)', :context => :equals)
238
+ assert_equal 'url("#{$var}/flip.gif")', render('url("#{!var}/flip.gif")', :context => :equals)
239
+ end
240
+ end
241
+
242
+ private
243
+
244
+ def assert_renders(script, options = {})
245
+ assert_equal(script, render(script, options))
246
+ end
247
+
248
+ def render(script, options = {})
249
+ munge_filename(options)
250
+ node = Sass::Script.parse(script, 1, 0, options)
251
+ node.context = options[:context] if options[:context]
252
+ node.to_sass
253
+ end
254
+ end
@@ -0,0 +1,459 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'sass/engine'
4
+
5
+ module Sass::Script::Functions::UserFunctions
6
+ def assert_options(val)
7
+ val.options[:foo]
8
+ Sass::Script::String.new("Options defined!")
9
+ end
10
+ end
11
+
12
+ class SassScriptTest < Test::Unit::TestCase
13
+ include Sass::Script
14
+
15
+ def test_color_checks_input
16
+ assert_raise_message(Sass::SyntaxError, "Blue value must be between 0 and 255") {Color.new([1, 2, -1])}
17
+ assert_raise_message(Sass::SyntaxError, "Red value must be between 0 and 255") {Color.new([256, 2, 3])}
18
+ end
19
+
20
+ def test_color_checks_rgba_input
21
+ assert_raise_message(Sass::SyntaxError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
22
+ assert_raise_message(Sass::SyntaxError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
23
+ end
24
+
25
+ def test_string_escapes
26
+ assert_equal "'", resolve("\"'\"")
27
+ assert_equal '"', resolve("\"\\\"\"")
28
+ assert_equal "\\\\", resolve("\"\\\\\"")
29
+ assert_equal "\\02fa", resolve("\"\\02fa\"")
30
+
31
+ assert_equal "'", resolve("'\\''")
32
+ assert_equal '"', resolve("'\"'")
33
+ assert_equal "\\\\", resolve("'\\\\'")
34
+ assert_equal "\\02fa", resolve("'\\02fa'")
35
+ end
36
+
37
+ def test_string_interpolation
38
+ assert_equal "foo2bar", resolve('\'foo#{1 + 1}bar\'')
39
+ assert_equal "foo2bar", resolve('"foo#{1 + 1}bar"')
40
+ assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'')
41
+ end
42
+
43
+ def test_color_names
44
+ assert_equal "white", resolve("white")
45
+ assert_equal "white", resolve("#ffffff")
46
+ assert_equal "#fffffe", resolve("white - #000001")
47
+ end
48
+
49
+ def test_rgba_color_literals
50
+ assert_equal Sass::Script::Color.new([1, 2, 3, 0.75]), eval("rgba(1, 2, 3, 0.75)")
51
+ assert_equal "rgba(1, 2, 3, 0.75)", resolve("rgba(1, 2, 3, 0.75)")
52
+
53
+ assert_equal Sass::Script::Color.new([1, 2, 3, 0]), eval("rgba(1, 2, 3, 0)")
54
+ assert_equal "rgba(1, 2, 3, 0)", resolve("rgba(1, 2, 3, 0)")
55
+
56
+ assert_equal Sass::Script::Color.new([1, 2, 3]), eval("rgba(1, 2, 3, 1)")
57
+ assert_equal Sass::Script::Color.new([1, 2, 3, 1]), eval("rgba(1, 2, 3, 1)")
58
+ assert_equal "#010203", resolve("rgba(1, 2, 3, 1)")
59
+ assert_equal "white", resolve("rgba(255, 255, 255, 1)")
60
+ end
61
+
62
+ def test_rgba_color_math
63
+ assert_equal "rgba(50, 50, 100, 0.35)", resolve("rgba(1, 1, 2, 0.35) * rgba(50, 50, 50, 0.35)")
64
+ assert_equal "rgba(52, 52, 52, 0.25)", resolve("rgba(2, 2, 2, 0.25) + rgba(50, 50, 50, 0.25)")
65
+
66
+ assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)") do
67
+ resolve("rgba(1, 2, 3, 0.15) + rgba(50, 50, 50, 0.75)")
68
+ end
69
+ assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: #123456 * rgba(50, 50, 50, 0.75)") do
70
+ resolve("#123456 * rgba(50, 50, 50, 0.75)")
71
+ end
72
+ assert_raise_message(Sass::SyntaxError, "Alpha channels must be equal: rgba(50, 50, 50, 0.75) / #123456") do
73
+ resolve("rgba(50, 50, 50, 0.75) / #123456")
74
+ end
75
+ end
76
+
77
+ def test_rgba_number_math
78
+ assert_equal "rgba(49, 49, 49, 0.75)", resolve("rgba(50, 50, 50, 0.75) - 1")
79
+ assert_equal "rgba(100, 100, 100, 0.75)", resolve("rgba(50, 50, 50, 0.75) * 2")
80
+ end
81
+
82
+ def test_compressed_colors
83
+ assert_equal "#123456", resolve("#123456", :style => :compressed)
84
+ assert_equal "rgba(1, 2, 3, 0.5)", resolve("rgba(1, 2, 3, 0.5)", :style => :compressed)
85
+ assert_equal "#123", resolve("#112233", :style => :compressed)
86
+ assert_equal "#000", resolve("black", :style => :compressed)
87
+ assert_equal "red", resolve("#f00", :style => :compressed)
88
+ assert_equal "blue", resolve("#00f", :style => :compressed)
89
+ assert_equal "navy", resolve("#000080", :style => :compressed)
90
+ assert_equal "navy #fff", resolve("#000080 white", :style => :compressed)
91
+ assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed)
92
+ end
93
+
94
+ def test_implicit_strings
95
+ assert_equal Sass::Script::String.new("foo"), eval("foo")
96
+ assert_equal Sass::Script::String.new("foo bar"), eval("foo bar")
97
+ assert_equal Sass::Script::String.new("foo/bar"), eval("foo/bar")
98
+ end
99
+
100
+ def test_basic_interpolation
101
+ assert_equal "foo3bar", resolve("foo\#{1 + 2}bar")
102
+ assert_equal "foo3 bar", resolve("foo\#{1 + 2} bar")
103
+ assert_equal "foo 3bar", resolve("foo \#{1 + 2}bar")
104
+ assert_equal "foo 3 bar", resolve("foo \#{1 + 2} bar")
105
+ assert_equal "foo 35 bar", resolve("foo \#{1 + 2}\#{2 + 3} bar")
106
+ assert_equal "foo 3 5 bar", resolve("foo \#{1 + 2} \#{2 + 3} bar")
107
+ assert_equal "3bar", resolve("\#{1 + 2}bar")
108
+ assert_equal "foo3", resolve("foo\#{1 + 2}")
109
+ assert_equal "3", resolve("\#{1 + 2}")
110
+ end
111
+
112
+ def test_interpolation_in_function
113
+ assert_equal 'flabnabbit(1foo)', resolve('flabnabbit(#{1 + "foo"})')
114
+ assert_equal 'flabnabbit(foo 1foobaz)', resolve('flabnabbit(foo #{1 + "foo"}baz)')
115
+ assert_equal('flabnabbit(foo 1foo2bar baz)',
116
+ resolve('flabnabbit(foo #{1 + "foo"}#{2 + "bar"} baz)'))
117
+ end
118
+
119
+ def test_interpolation_near_operators
120
+ assert_equal '3 , 7', resolve('#{1 + 2} , #{3 + 4}')
121
+ assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
122
+ assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
123
+ assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
124
+
125
+ assert_equal '3 / 7', resolve('3 / #{3 + 4}')
126
+ assert_equal '3 /7', resolve('3 /#{3 + 4}')
127
+ assert_equal '3/ 7', resolve('3/ #{3 + 4}')
128
+ assert_equal '3/7', resolve('3/#{3 + 4}')
129
+
130
+ assert_equal '3 * 7', resolve('#{1 + 2} * 7')
131
+ assert_equal '3* 7', resolve('#{1 + 2}* 7')
132
+ assert_equal '3 *7', resolve('#{1 + 2} *7')
133
+ assert_equal '3*7', resolve('#{1 + 2}*7')
134
+
135
+ assert_equal '-3', resolve('-#{1 + 2}')
136
+ assert_equal '- 3', resolve('- #{1 + 2}')
137
+
138
+ assert_equal '5 + 3 * 7', resolve('5 + #{1 + 2} * #{3 + 4}')
139
+ assert_equal '5 +3 * 7', resolve('5 +#{1 + 2} * #{3 + 4}')
140
+ assert_equal '5+3 * 7', resolve('5+#{1 + 2} * #{3 + 4}')
141
+ assert_equal '3 * 7 + 5', resolve('#{1 + 2} * #{3 + 4} + 5')
142
+ assert_equal '3 * 7+ 5', resolve('#{1 + 2} * #{3 + 4}+ 5')
143
+ assert_equal '3 * 7+5', resolve('#{1 + 2} * #{3 + 4}+5')
144
+
145
+ assert_equal '5/3 + 7', resolve('5 / (#{1 + 2} + #{3 + 4})')
146
+ assert_equal '5/3 + 7', resolve('5 /(#{1 + 2} + #{3 + 4})')
147
+ assert_equal '5/3 + 7', resolve('5 /( #{1 + 2} + #{3 + 4} )')
148
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4}) / 5')
149
+ assert_equal '3 + 7/5', resolve('(#{1 + 2} + #{3 + 4})/ 5')
150
+ assert_equal '3 + 7/5', resolve('( #{1 + 2} + #{3 + 4} )/ 5')
151
+
152
+ assert_equal '3 + 5', resolve('#{1 + 2} + 2 + 3')
153
+ assert_equal '3 +5', resolve('#{1 + 2} +2 + 3')
154
+ end
155
+
156
+ def test_string_interpolation
157
+ assert_equal "foo bar, baz bang", resolve('"foo #{"bar"}, #{"baz"} bang"')
158
+ assert_equal "foo bar baz bang", resolve('"foo #{"#{"ba" + "r"} baz"} bang"')
159
+ assert_equal 'foo #{bar baz} bang', resolve('"foo \#{#{"ba" + "r"} baz} bang"')
160
+ assert_equal 'foo #{baz bang', resolve('"foo #{"\#{" + "baz"} bang"')
161
+ end
162
+
163
+ def test_rule_interpolation
164
+ assert_equal(<<CSS, render(<<SASS))
165
+ foo bar baz bang {
166
+ a: b; }
167
+ CSS
168
+ foo \#{"\#{"ba" + "r"} baz"} bang
169
+ a: b
170
+ SASS
171
+ assert_equal(<<CSS, render(<<SASS))
172
+ foo [bar="\#{bar baz}"] bang {
173
+ a: b; }
174
+ CSS
175
+ foo [bar="\\\#{\#{"ba" + "r"} baz}"] bang
176
+ a: b
177
+ SASS
178
+ assert_equal(<<CSS, render(<<SASS))
179
+ foo [bar="\#{baz"] bang {
180
+ a: b; }
181
+ CSS
182
+ foo [bar="\#{"\\\#{" + "baz"}"] bang
183
+ a: b
184
+ SASS
185
+ end
186
+
187
+ def test_inaccessible_functions
188
+ assert_equal "send(to_s)", resolve("send(to_s)", :line => 2)
189
+ assert_equal "public_instance_methods()", resolve("public_instance_methods()")
190
+ end
191
+
192
+ def test_default_functions
193
+ assert_equal "url(12)", resolve("url(12)")
194
+ assert_equal 'blam("foo")', resolve('blam("foo")')
195
+ end
196
+
197
+ def test_function_results_have_options
198
+ assert_equal "Options defined!", resolve("assert_options(abs(1))")
199
+ assert_equal "Options defined!", resolve("assert_options(round(1.2))")
200
+ end
201
+
202
+ def test_funcall_requires_no_whitespace_before_lparen
203
+ assert_equal "no-repeat 15px", resolve("no-repeat (7px + 8px)")
204
+ assert_equal "no-repeat(15px)", resolve("no-repeat(7px + 8px)")
205
+ end
206
+
207
+ def test_dynamic_url
208
+ assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => Sass::Script::String.new("foo-bar")))
209
+ assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => Sass::Script::String.new("foo-bar"), 'bar' => Sass::Script::String.new("baz")))
210
+ assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => Sass::Script::String.new("baz")))
211
+ assert_equal "url(foo bar)", resolve("url(foo bar)")
212
+ end
213
+
214
+ def test_url_with_interpolation
215
+ assert_equal "url(http://sass-lang.com/images/foo-bar)", resolve("url(http://sass-lang.com/images/\#{foo-bar})")
216
+ assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve("url('http://sass-lang.com/images/\#{foo-bar}')")
217
+ assert_equal 'url("http://sass-lang.com/images/foo-bar")', resolve('url("http://sass-lang.com/images/#{foo-bar}")')
218
+ assert_unquoted "url(http://sass-lang.com/images/\#{foo-bar})"
219
+ end
220
+
221
+ def test_hyphenated_variables
222
+ assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::String.new("a-b"))))
223
+ end
224
+
225
+ def test_ruby_equality
226
+ assert_equal eval('"foo"'), eval('"foo"')
227
+ assert_equal eval('1'), eval('1.0')
228
+ assert_not_equal eval('1'), eval('"1"')
229
+ end
230
+
231
+ def test_booleans
232
+ assert_equal "true", resolve("true")
233
+ assert_equal "false", resolve("false")
234
+ end
235
+
236
+ def test_boolean_ops
237
+ assert_equal "true", resolve("true and true")
238
+ assert_equal "true", resolve("false or true")
239
+ assert_equal "true", resolve("true or false")
240
+ assert_equal "true", resolve("true or true")
241
+ assert_equal "false", resolve("false or false")
242
+ assert_equal "false", resolve("false and true")
243
+ assert_equal "false", resolve("true and false")
244
+ assert_equal "false", resolve("false and false")
245
+
246
+ assert_equal "true", resolve("not false")
247
+ assert_equal "false", resolve("not true")
248
+ assert_equal "true", resolve("not not true")
249
+
250
+ assert_equal "1", resolve("false or 1")
251
+ assert_equal "false", resolve("false and 1")
252
+ assert_equal "2", resolve("2 or 3")
253
+ assert_equal "3", resolve("2 and 3")
254
+ end
255
+
256
+ def test_arithmetic_ops
257
+ assert_equal "2", resolve("1 + 1")
258
+ assert_equal "0", resolve("1 - 1")
259
+ assert_equal "8", resolve("2 * 4")
260
+ assert_equal "0.5", resolve("(2 / 4)")
261
+ assert_equal "2", resolve("(4 / 2)")
262
+
263
+ assert_equal "-1", resolve("-1")
264
+ end
265
+
266
+ def test_string_ops
267
+ assert_equal '"foo" "bar"', resolve('"foo" "bar"')
268
+ assert_equal "true 1", resolve('true 1')
269
+ assert_equal '"foo", "bar"', resolve("'foo' , 'bar'")
270
+ assert_equal "true, 1", resolve('true , 1')
271
+ assert_equal "foobar", resolve('"foo" + "bar"')
272
+ assert_equal "true1", resolve('true + 1')
273
+ assert_equal '"foo"-"bar"', resolve("'foo' - 'bar'")
274
+ assert_equal "true-1", resolve('true - 1')
275
+ assert_equal '"foo"/"bar"', resolve('"foo" / "bar"')
276
+ assert_equal "true/1", resolve('true / 1')
277
+
278
+ assert_equal '-"bar"', resolve("- 'bar'")
279
+ assert_equal "-true", resolve('- true')
280
+ assert_equal '/"bar"', resolve('/ "bar"')
281
+ assert_equal "/true", resolve('/ true')
282
+ end
283
+
284
+ def test_relational_ops
285
+ assert_equal "false", resolve("1 > 2")
286
+ assert_equal "false", resolve("2 > 2")
287
+ assert_equal "true", resolve("3 > 2")
288
+ assert_equal "false", resolve("1 >= 2")
289
+ assert_equal "true", resolve("2 >= 2")
290
+ assert_equal "true", resolve("3 >= 2")
291
+ assert_equal "true", resolve("1 < 2")
292
+ assert_equal "false", resolve("2 < 2")
293
+ assert_equal "false", resolve("3 < 2")
294
+ assert_equal "true", resolve("1 <= 2")
295
+ assert_equal "true", resolve("2 <= 2")
296
+ assert_equal "false", resolve("3 <= 2")
297
+ end
298
+
299
+ def test_equals
300
+ assert_equal("true", resolve('"foo" == $foo', {},
301
+ env("foo" => Sass::Script::String.new("foo"))))
302
+ assert_equal "true", resolve("1 == 1.0")
303
+ assert_equal "true", resolve("false != true")
304
+ assert_equal "false", resolve("1em == 1px")
305
+ assert_equal "false", resolve("12 != 12")
306
+ end
307
+
308
+ def test_operation_precedence
309
+ assert_equal "false true", resolve("true and false false or true")
310
+ assert_equal "true", resolve("false and true or true and true")
311
+ assert_equal "true", resolve("1 == 2 or 3 == 3")
312
+ assert_equal "true", resolve("1 < 2 == 3 >= 3")
313
+ assert_equal "true", resolve("1 + 3 > 4 - 2")
314
+ assert_equal "11", resolve("1 + 2 * 3 + 4")
315
+ end
316
+
317
+ def test_functions
318
+ assert_equal "#80ff80", resolve("hsl(120, 100%, 75%)")
319
+ assert_equal "#81ff81", resolve("hsl(120, 100%, 75%) + #010001")
320
+ end
321
+
322
+ def test_operator_unit_conversion
323
+ assert_equal "1.1cm", resolve("1cm + 1mm")
324
+ assert_equal "true", resolve("2mm < 1cm")
325
+ assert_equal "true", resolve("10mm == 1cm")
326
+ assert_equal "true", resolve("1 == 1cm")
327
+ assert_equal "true", resolve("1.1cm == 11mm")
328
+ end
329
+
330
+ def test_operations_have_options
331
+ assert_equal "Options defined!", resolve("assert_options(1 + 1)")
332
+ assert_equal "Options defined!", resolve("assert_options('bar' + 'baz')")
333
+ end
334
+
335
+ def test_slash_compiles_literally_when_left_alone
336
+ assert_equal "1px/2px", resolve("1px/2px")
337
+ assert_equal "1px/2px/3px/4px", resolve("1px/2px/3px/4px")
338
+
339
+ assert_equal "1px/2px redpx bluepx", resolve("1px/2px redpx bluepx")
340
+ assert_equal "foo 1px/2px/3px bar", resolve("foo 1px/2px/3px bar")
341
+ end
342
+
343
+ def test_slash_divides_with_parens
344
+ assert_equal "0.5", resolve("(1px/2px)")
345
+ assert_equal "0.5", resolve("(1px)/2px")
346
+ assert_equal "0.5", resolve("1px/(2px)")
347
+ end
348
+
349
+ def test_slash_divides_with_other_arithmetic
350
+ assert_equal "0.5px", resolve("1px*1px/2px")
351
+ assert_equal "0.5px", resolve("1px/2px*1px")
352
+ assert_equal "0.5", resolve("0+1px/2px")
353
+ assert_equal "0.5", resolve("1px/2px+0")
354
+ end
355
+
356
+ def test_slash_divides_with_variable
357
+ assert_equal "0.5", resolve("$var/2px", {}, env("var" => eval("1px")))
358
+ assert_equal "0.5", resolve("1px/$var", {}, env("var" => eval("2px")))
359
+ assert_equal "0.5", resolve("$var", {}, env("var" => eval("1px/2px")))
360
+ end
361
+
362
+ def test_colors_with_wrong_number_of_digits
363
+ assert_raise_message(Sass::SyntaxError,
364
+ "Colors must have either three or six digits: '#0'") {eval("#0")}
365
+ assert_raise_message(Sass::SyntaxError,
366
+ "Colors must have either three or six digits: '#12'") {eval("#12")}
367
+ assert_raise_message(Sass::SyntaxError,
368
+ "Colors must have either three or six digits: '#abcd'") {eval("#abcd")}
369
+ assert_raise_message(Sass::SyntaxError,
370
+ "Colors must have either three or six digits: '#abcdE'") {eval("#abcdE")}
371
+ assert_raise_message(Sass::SyntaxError,
372
+ "Colors must have either three or six digits: '#abcdEFA'") {eval("#abcdEFA")}
373
+ end
374
+
375
+ def test_case_insensitive_color_names
376
+ assert_equal "blue", resolve("BLUE")
377
+ assert_equal "red", resolve("rEd")
378
+ assert_equal "#7f4000", resolve("mix(GrEeN, ReD)")
379
+ end
380
+
381
+ # Regression Tests
382
+
383
+ def test_funcall_has_higher_precedence_than_color_name
384
+ assert_equal "teal(12)", resolve("teal(12)")
385
+ assert_equal "tealbang(12)", resolve("tealbang(12)")
386
+ assert_equal "teal-bang(12)", resolve("teal-bang(12)")
387
+ assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
388
+ end
389
+
390
+ def test_interpolation_after_hash
391
+ assert_equal "#2", resolve('"##{1 + 1}"')
392
+ end
393
+
394
+ def test_misplaced_comma_in_funcall
395
+ assert_raise_message(Sass::SyntaxError,
396
+ 'Invalid CSS after "foo(bar, ": expected function argument, was ")"') {eval('foo(bar, )')}
397
+ end
398
+
399
+ def test_color_prefixed_identifier
400
+ assert_equal "tealbang", resolve("tealbang")
401
+ assert_equal "teal-bang", resolve("teal-bang")
402
+ end
403
+
404
+ def test_op_prefixed_identifier
405
+ assert_equal "notbang", resolve("notbang")
406
+ assert_equal "not-bang", resolve("not-bang")
407
+ assert_equal "or-bang", resolve("or-bang")
408
+ assert_equal "and-bang", resolve("and-bang")
409
+ end
410
+
411
+ private
412
+
413
+ def resolve(str, opts = {}, environment = env)
414
+ munge_filename opts
415
+ val = eval(str, opts, environment)
416
+ val.is_a?(Sass::Script::String) ? val.value : val.to_s
417
+ end
418
+
419
+ def assert_unquoted(str, opts = {}, environment = env)
420
+ munge_filename opts
421
+ val = eval(str, opts, environment)
422
+ assert_kind_of Sass::Script::String, val
423
+ assert_equal :identifier, val.type
424
+ end
425
+
426
+ def assert_quoted(str, opts = {}, environment = env)
427
+ munge_filename opts
428
+ val = eval(str, opts, environment)
429
+ assert_kind_of Sass::Script::String, val
430
+ assert_equal :string, val.type
431
+ end
432
+
433
+ def eval(str, opts = {}, environment = env)
434
+ munge_filename opts
435
+ Sass::Script.parse(str, opts.delete(:line) || 1,
436
+ opts.delete(:offset) || 0, opts).perform(environment)
437
+ end
438
+
439
+ def render(sass, options = {})
440
+ munge_filename options
441
+ Sass::Engine.new(sass, options).render
442
+ end
443
+
444
+ def env(hash = {})
445
+ env = Sass::Environment.new
446
+ hash.each {|k, v| env.set_var(k, v)}
447
+ env
448
+ end
449
+
450
+ def test_number_printing
451
+ assert_equal "1", eval("1")
452
+ assert_equal "1", eval("1.0")
453
+ assert_equal "1.121", eval("1.1214")
454
+ assert_equal "1.122", eval("1.1215")
455
+ assert_equal "Infinity", eval("1.0/0.0")
456
+ assert_equal "-Infinity", eval("-1.0/0.0")
457
+ assert_equal "NaN", eval("0.0/0.0")
458
+ end
459
+ end