sass 3.1.0 → 3.3.0

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 (260) hide show
  1. checksums.yaml +7 -0
  2. data/CONTRIBUTING +1 -1
  3. data/MIT-LICENSE +2 -2
  4. data/README.md +29 -17
  5. data/Rakefile +43 -9
  6. data/VERSION +1 -1
  7. data/VERSION_DATE +1 -0
  8. data/VERSION_NAME +1 -1
  9. data/bin/sass +6 -1
  10. data/bin/sass-convert +6 -1
  11. data/bin/scss +6 -1
  12. data/ext/mkrf_conf.rb +27 -0
  13. data/lib/sass/cache_stores/base.rb +7 -3
  14. data/lib/sass/cache_stores/chain.rb +3 -2
  15. data/lib/sass/cache_stores/filesystem.rb +5 -7
  16. data/lib/sass/cache_stores/memory.rb +1 -1
  17. data/lib/sass/cache_stores/null.rb +2 -2
  18. data/lib/sass/callbacks.rb +2 -1
  19. data/lib/sass/css.rb +168 -53
  20. data/lib/sass/engine.rb +502 -174
  21. data/lib/sass/environment.rb +151 -111
  22. data/lib/sass/error.rb +7 -7
  23. data/lib/sass/exec.rb +176 -60
  24. data/lib/sass/features.rb +40 -0
  25. data/lib/sass/importers/base.rb +46 -7
  26. data/lib/sass/importers/deprecated_path.rb +51 -0
  27. data/lib/sass/importers/filesystem.rb +113 -30
  28. data/lib/sass/importers.rb +1 -0
  29. data/lib/sass/logger/base.rb +30 -0
  30. data/lib/sass/logger/log_level.rb +45 -0
  31. data/lib/sass/logger.rb +12 -0
  32. data/lib/sass/media.rb +213 -0
  33. data/lib/sass/plugin/compiler.rb +194 -104
  34. data/lib/sass/plugin/configuration.rb +18 -25
  35. data/lib/sass/plugin/merb.rb +1 -1
  36. data/lib/sass/plugin/staleness_checker.rb +37 -11
  37. data/lib/sass/plugin.rb +10 -13
  38. data/lib/sass/railtie.rb +2 -1
  39. data/lib/sass/repl.rb +5 -6
  40. data/lib/sass/script/css_lexer.rb +8 -4
  41. data/lib/sass/script/css_parser.rb +5 -2
  42. data/lib/sass/script/functions.rb +1547 -618
  43. data/lib/sass/script/lexer.rb +122 -72
  44. data/lib/sass/script/parser.rb +304 -135
  45. data/lib/sass/script/tree/funcall.rb +306 -0
  46. data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
  47. data/lib/sass/script/tree/list_literal.rb +77 -0
  48. data/lib/sass/script/tree/literal.rb +45 -0
  49. data/lib/sass/script/tree/map_literal.rb +64 -0
  50. data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
  51. data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
  52. data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
  53. data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
  54. data/lib/sass/script/tree/variable.rb +57 -0
  55. data/lib/sass/script/tree.rb +15 -0
  56. data/lib/sass/script/value/arg_list.rb +36 -0
  57. data/lib/sass/script/value/base.rb +238 -0
  58. data/lib/sass/script/value/bool.rb +40 -0
  59. data/lib/sass/script/{color.rb → value/color.rb} +256 -74
  60. data/lib/sass/script/value/deprecated_false.rb +55 -0
  61. data/lib/sass/script/value/helpers.rb +155 -0
  62. data/lib/sass/script/value/list.rb +128 -0
  63. data/lib/sass/script/value/map.rb +70 -0
  64. data/lib/sass/script/value/null.rb +49 -0
  65. data/lib/sass/script/{number.rb → value/number.rb} +115 -62
  66. data/lib/sass/script/{string.rb → value/string.rb} +9 -11
  67. data/lib/sass/script/value.rb +12 -0
  68. data/lib/sass/script.rb +35 -9
  69. data/lib/sass/scss/css_parser.rb +2 -12
  70. data/lib/sass/scss/parser.rb +657 -230
  71. data/lib/sass/scss/rx.rb +17 -12
  72. data/lib/sass/scss/static_parser.rb +37 -6
  73. data/lib/sass/scss.rb +0 -1
  74. data/lib/sass/selector/abstract_sequence.rb +35 -3
  75. data/lib/sass/selector/comma_sequence.rb +29 -14
  76. data/lib/sass/selector/sequence.rb +371 -74
  77. data/lib/sass/selector/simple.rb +28 -13
  78. data/lib/sass/selector/simple_sequence.rb +163 -36
  79. data/lib/sass/selector.rb +138 -36
  80. data/lib/sass/shared.rb +3 -5
  81. data/lib/sass/source/map.rb +196 -0
  82. data/lib/sass/source/position.rb +39 -0
  83. data/lib/sass/source/range.rb +41 -0
  84. data/lib/sass/stack.rb +126 -0
  85. data/lib/sass/supports.rb +228 -0
  86. data/lib/sass/tree/at_root_node.rb +82 -0
  87. data/lib/sass/tree/comment_node.rb +34 -29
  88. data/lib/sass/tree/content_node.rb +9 -0
  89. data/lib/sass/tree/css_import_node.rb +60 -0
  90. data/lib/sass/tree/debug_node.rb +3 -3
  91. data/lib/sass/tree/directive_node.rb +33 -3
  92. data/lib/sass/tree/each_node.rb +9 -9
  93. data/lib/sass/tree/extend_node.rb +20 -6
  94. data/lib/sass/tree/for_node.rb +6 -6
  95. data/lib/sass/tree/function_node.rb +12 -4
  96. data/lib/sass/tree/if_node.rb +2 -15
  97. data/lib/sass/tree/import_node.rb +11 -5
  98. data/lib/sass/tree/media_node.rb +27 -11
  99. data/lib/sass/tree/mixin_def_node.rb +15 -4
  100. data/lib/sass/tree/mixin_node.rb +27 -7
  101. data/lib/sass/tree/node.rb +69 -35
  102. data/lib/sass/tree/prop_node.rb +47 -31
  103. data/lib/sass/tree/return_node.rb +4 -3
  104. data/lib/sass/tree/root_node.rb +20 -4
  105. data/lib/sass/tree/rule_node.rb +37 -26
  106. data/lib/sass/tree/supports_node.rb +38 -0
  107. data/lib/sass/tree/trace_node.rb +33 -0
  108. data/lib/sass/tree/variable_node.rb +10 -4
  109. data/lib/sass/tree/visitors/base.rb +5 -8
  110. data/lib/sass/tree/visitors/check_nesting.rb +67 -52
  111. data/lib/sass/tree/visitors/convert.rb +134 -53
  112. data/lib/sass/tree/visitors/cssize.rb +245 -51
  113. data/lib/sass/tree/visitors/deep_copy.rb +102 -0
  114. data/lib/sass/tree/visitors/extend.rb +68 -0
  115. data/lib/sass/tree/visitors/perform.rb +331 -105
  116. data/lib/sass/tree/visitors/set_options.rb +125 -0
  117. data/lib/sass/tree/visitors/to_css.rb +259 -95
  118. data/lib/sass/tree/warn_node.rb +3 -3
  119. data/lib/sass/tree/while_node.rb +3 -3
  120. data/lib/sass/util/cross_platform_random.rb +19 -0
  121. data/lib/sass/util/multibyte_string_scanner.rb +157 -0
  122. data/lib/sass/util/normalized_map.rb +130 -0
  123. data/lib/sass/util/ordered_hash.rb +192 -0
  124. data/lib/sass/util/subset_map.rb +11 -2
  125. data/lib/sass/util/test.rb +9 -0
  126. data/lib/sass/util.rb +565 -39
  127. data/lib/sass/version.rb +27 -15
  128. data/lib/sass.rb +39 -4
  129. data/test/sass/cache_test.rb +15 -0
  130. data/test/sass/compiler_test.rb +223 -0
  131. data/test/sass/conversion_test.rb +901 -107
  132. data/test/sass/css2sass_test.rb +94 -0
  133. data/test/sass/engine_test.rb +1059 -164
  134. data/test/sass/exec_test.rb +86 -0
  135. data/test/sass/extend_test.rb +933 -837
  136. data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
  137. data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
  138. data/test/sass/functions_test.rb +995 -136
  139. data/test/sass/importer_test.rb +338 -18
  140. data/test/sass/logger_test.rb +58 -0
  141. data/test/sass/more_results/more_import.css +2 -2
  142. data/test/sass/plugin_test.rb +114 -30
  143. data/test/sass/results/cached_import_option.css +3 -0
  144. data/test/sass/results/filename_fn.css +3 -0
  145. data/test/sass/results/import.css +2 -2
  146. data/test/sass/results/import_charset.css +1 -0
  147. data/test/sass/results/import_charset_1_8.css +1 -0
  148. data/test/sass/results/import_charset_ibm866.css +1 -0
  149. data/test/sass/results/import_content.css +1 -0
  150. data/test/sass/results/script.css +1 -1
  151. data/test/sass/results/scss_import.css +2 -2
  152. data/test/sass/results/units.css +2 -2
  153. data/test/sass/script_conversion_test.rb +43 -1
  154. data/test/sass/script_test.rb +380 -36
  155. data/test/sass/scss/css_test.rb +257 -75
  156. data/test/sass/scss/scss_test.rb +2322 -110
  157. data/test/sass/source_map_test.rb +887 -0
  158. data/test/sass/templates/_cached_import_option_partial.scss +1 -0
  159. data/test/sass/templates/_double_import_loop2.sass +1 -0
  160. data/test/sass/templates/_filename_fn_import.scss +11 -0
  161. data/test/sass/templates/_imported_content.sass +3 -0
  162. data/test/sass/templates/_same_name_different_partiality.scss +1 -0
  163. data/test/sass/templates/bork5.sass +3 -0
  164. data/test/sass/templates/cached_import_option.scss +3 -0
  165. data/test/sass/templates/double_import_loop1.sass +1 -0
  166. data/test/sass/templates/filename_fn.scss +18 -0
  167. data/test/sass/templates/import_charset.sass +2 -0
  168. data/test/sass/templates/import_charset_1_8.sass +2 -0
  169. data/test/sass/templates/import_charset_ibm866.sass +2 -0
  170. data/test/sass/templates/import_content.sass +4 -0
  171. data/test/sass/templates/same_name_different_ext.sass +2 -0
  172. data/test/sass/templates/same_name_different_ext.scss +1 -0
  173. data/test/sass/templates/same_name_different_partiality.scss +1 -0
  174. data/test/sass/templates/single_import_loop.sass +1 -0
  175. data/test/sass/templates/subdir/import_up1.scss +1 -0
  176. data/test/sass/templates/subdir/import_up2.scss +1 -0
  177. data/test/sass/test_helper.rb +1 -1
  178. data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
  179. data/test/sass/util/normalized_map_test.rb +51 -0
  180. data/test/sass/util_test.rb +183 -0
  181. data/test/sass/value_helpers_test.rb +181 -0
  182. data/test/test_helper.rb +45 -5
  183. data/vendor/listen/CHANGELOG.md +228 -0
  184. data/vendor/listen/CONTRIBUTING.md +38 -0
  185. data/vendor/listen/Gemfile +30 -0
  186. data/vendor/listen/Guardfile +8 -0
  187. data/vendor/{fssm → listen}/LICENSE +1 -1
  188. data/vendor/listen/README.md +315 -0
  189. data/vendor/listen/Rakefile +47 -0
  190. data/vendor/listen/Vagrantfile +96 -0
  191. data/vendor/listen/lib/listen/adapter.rb +214 -0
  192. data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
  193. data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
  194. data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
  195. data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
  196. data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
  197. data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
  198. data/vendor/listen/lib/listen/directory_record.rb +371 -0
  199. data/vendor/listen/lib/listen/listener.rb +225 -0
  200. data/vendor/listen/lib/listen/multi_listener.rb +143 -0
  201. data/vendor/listen/lib/listen/turnstile.rb +28 -0
  202. data/vendor/listen/lib/listen/version.rb +3 -0
  203. data/vendor/listen/lib/listen.rb +40 -0
  204. data/vendor/listen/listen.gemspec +22 -0
  205. data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
  206. data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
  207. data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
  208. data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
  209. data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
  210. data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
  211. data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
  212. data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
  213. data/vendor/listen/spec/listen/listener_spec.rb +169 -0
  214. data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
  215. data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
  216. data/vendor/listen/spec/listen_spec.rb +73 -0
  217. data/vendor/listen/spec/spec_helper.rb +21 -0
  218. data/vendor/listen/spec/support/adapter_helper.rb +629 -0
  219. data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
  220. data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
  221. data/vendor/listen/spec/support/listeners_helper.rb +156 -0
  222. data/vendor/listen/spec/support/platform_helper.rb +15 -0
  223. metadata +344 -271
  224. data/lib/sass/less.rb +0 -382
  225. data/lib/sass/script/bool.rb +0 -18
  226. data/lib/sass/script/funcall.rb +0 -162
  227. data/lib/sass/script/list.rb +0 -76
  228. data/lib/sass/script/literal.rb +0 -245
  229. data/lib/sass/script/variable.rb +0 -54
  230. data/lib/sass/scss/sass_parser.rb +0 -11
  231. data/test/sass/less_conversion_test.rb +0 -653
  232. data/vendor/fssm/README.markdown +0 -55
  233. data/vendor/fssm/Rakefile +0 -59
  234. data/vendor/fssm/VERSION.yml +0 -5
  235. data/vendor/fssm/example.rb +0 -9
  236. data/vendor/fssm/fssm.gemspec +0 -77
  237. data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
  238. data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
  239. data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
  240. data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
  241. data/vendor/fssm/lib/fssm/monitor.rb +0 -26
  242. data/vendor/fssm/lib/fssm/path.rb +0 -91
  243. data/vendor/fssm/lib/fssm/pathname.rb +0 -502
  244. data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
  245. data/vendor/fssm/lib/fssm/state/file.rb +0 -24
  246. data/vendor/fssm/lib/fssm/support.rb +0 -63
  247. data/vendor/fssm/lib/fssm/tree.rb +0 -176
  248. data/vendor/fssm/lib/fssm.rb +0 -33
  249. data/vendor/fssm/profile/prof-cache.rb +0 -40
  250. data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
  251. data/vendor/fssm/profile/prof-pathname.rb +0 -68
  252. data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
  253. data/vendor/fssm/profile/prof.html +0 -2379
  254. data/vendor/fssm/spec/path_spec.rb +0 -75
  255. data/vendor/fssm/spec/root/duck/quack.txt +0 -0
  256. data/vendor/fssm/spec/root/file.css +0 -0
  257. data/vendor/fssm/spec/root/file.rb +0 -0
  258. data/vendor/fssm/spec/root/file.yml +0 -0
  259. data/vendor/fssm/spec/root/moo/cow.txt +0 -0
  260. data/vendor/fssm/spec/spec_helper.rb +0 -14
@@ -5,21 +5,29 @@ require 'sass/engine'
5
5
  module Sass::Script::Functions::UserFunctions
6
6
  def assert_options(val)
7
7
  val.options[:foo]
8
- Sass::Script::String.new("Options defined!")
8
+ Sass::Script::Value::String.new("Options defined!")
9
9
  end
10
+
11
+ def arg_error
12
+ assert_options
13
+ end
14
+ end
15
+
16
+ module Sass::Script::Functions
17
+ include Sass::Script::Functions::UserFunctions
10
18
  end
11
19
 
12
20
  class SassScriptTest < Test::Unit::TestCase
13
21
  include Sass::Script
14
22
 
15
23
  def test_color_checks_input
16
- assert_raise_message(ArgumentError, "Blue value must be between 0 and 255") {Color.new([1, 2, -1])}
17
- assert_raise_message(ArgumentError, "Red value must be between 0 and 255") {Color.new([256, 2, 3])}
24
+ assert_raise_message(ArgumentError, "Blue value -1 must be between 0 and 255") {Sass::Script::Value::Color.new([1, 2, -1])}
25
+ assert_raise_message(ArgumentError, "Red value 256 must be between 0 and 255") {Sass::Script::Value::Color.new([256, 2, 3])}
18
26
  end
19
27
 
20
28
  def test_color_checks_rgba_input
21
- assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, 1.1])}
22
- assert_raise_message(ArgumentError, "Alpha channel must be between 0 and 1") {Color.new([1, 2, 3, -0.1])}
29
+ assert_raise_message(ArgumentError, "Alpha channel 1.1 must be between 0 and 1") {Sass::Script::Value::Color.new([1, 2, 3, 1.1])}
30
+ assert_raise_message(ArgumentError, "Alpha channel -0.1 must be between 0 and 1") {Sass::Script::Value::Color.new([1, 2, 3, -0.1])}
23
31
  end
24
32
 
25
33
  def test_string_escapes
@@ -34,27 +42,23 @@ class SassScriptTest < Test::Unit::TestCase
34
42
  assert_equal "\\02fa", resolve("'\\02fa'")
35
43
  end
36
44
 
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
45
  def test_color_names
44
46
  assert_equal "white", resolve("white")
45
47
  assert_equal "white", resolve("#ffffff")
46
48
  assert_equal "#fffffe", resolve("white - #000001")
49
+ assert_equal "transparent", resolve("transparent")
50
+ assert_equal "transparent", resolve("rgba(0, 0, 0, 0)")
47
51
  end
48
52
 
49
53
  def test_rgba_color_literals
50
- assert_equal Sass::Script::Color.new([1, 2, 3, 0.75]), eval("rgba(1, 2, 3, 0.75)")
54
+ assert_equal Sass::Script::Value::Color.new([1, 2, 3, 0.75]), eval("rgba(1, 2, 3, 0.75)")
51
55
  assert_equal "rgba(1, 2, 3, 0.75)", resolve("rgba(1, 2, 3, 0.75)")
52
56
 
53
- assert_equal Sass::Script::Color.new([1, 2, 3, 0]), eval("rgba(1, 2, 3, 0)")
57
+ assert_equal Sass::Script::Value::Color.new([1, 2, 3, 0]), eval("rgba(1, 2, 3, 0)")
54
58
  assert_equal "rgba(1, 2, 3, 0)", resolve("rgba(1, 2, 3, 0)")
55
59
 
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)")
60
+ assert_equal Sass::Script::Value::Color.new([1, 2, 3]), eval("rgba(1, 2, 3, 1)")
61
+ assert_equal Sass::Script::Value::Color.new([1, 2, 3, 1]), eval("rgba(1, 2, 3, 1)")
58
62
  assert_equal "#010203", resolve("rgba(1, 2, 3, 1)")
59
63
  assert_equal "white", resolve("rgba(255, 255, 255, 1)")
60
64
  end
@@ -80,7 +84,7 @@ class SassScriptTest < Test::Unit::TestCase
80
84
  end
81
85
 
82
86
  def test_rgba_rounding
83
- assert_equal "rgba(10, 1, 0, 0.123)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)")
87
+ assert_equal "rgba(10, 1, 0, 0.12346)", resolve("rgba(10.0, 1.23456789, 0.0, 0.1234567)")
84
88
  end
85
89
 
86
90
  def test_compressed_colors
@@ -93,6 +97,7 @@ class SassScriptTest < Test::Unit::TestCase
93
97
  assert_equal "navy", resolve("#000080", :style => :compressed)
94
98
  assert_equal "navy #fff", resolve("#000080 white", :style => :compressed)
95
99
  assert_equal "This color is #fff", resolve('"This color is #{ white }"', :style => :compressed)
100
+ assert_equal "transparent", resolve("rgba(0, 0, 0, 0)", :style => :compressed)
96
101
  end
97
102
 
98
103
  def test_compressed_comma
@@ -102,8 +107,8 @@ class SassScriptTest < Test::Unit::TestCase
102
107
  end
103
108
 
104
109
  def test_implicit_strings
105
- assert_equal Sass::Script::String.new("foo"), eval("foo")
106
- assert_equal Sass::Script::String.new("foo/bar"), eval("foo/bar")
110
+ assert_equal Sass::Script::Value::String.new("foo"), eval("foo")
111
+ assert_equal Sass::Script::Value::String.new("foo/bar"), eval("foo/bar")
107
112
  end
108
113
 
109
114
  def test_basic_interpolation
@@ -130,6 +135,9 @@ class SassScriptTest < Test::Unit::TestCase
130
135
  assert_equal '3, 7', resolve('#{1 + 2}, #{3 + 4}')
131
136
  assert_equal '3 ,7', resolve('#{1 + 2} ,#{3 + 4}')
132
137
  assert_equal '3,7', resolve('#{1 + 2},#{3 + 4}')
138
+ assert_equal '3, 7, 11', resolve('#{1 + 2}, #{3 + 4}, #{5 + 6}')
139
+ assert_equal '3, 7, 11', resolve('3, #{3 + 4}, 11')
140
+ assert_equal '3, 7, 11', resolve('3, 7, #{5 + 6}')
133
141
 
134
142
  assert_equal '3 / 7', resolve('3 / #{3 + 4}')
135
143
  assert_equal '3 /7', resolve('3 /#{3 + 4}')
@@ -167,6 +175,9 @@ class SassScriptTest < Test::Unit::TestCase
167
175
  assert_equal "foo bar baz bang", resolve('"foo #{"#{"ba" + "r"} baz"} bang"')
168
176
  assert_equal 'foo #{bar baz} bang', resolve('"foo \#{#{"ba" + "r"} baz} bang"')
169
177
  assert_equal 'foo #{baz bang', resolve('"foo #{"\#{" + "baz"} bang"')
178
+ assert_equal "foo2bar", resolve('\'foo#{1 + 1}bar\'')
179
+ assert_equal "foo2bar", resolve('"foo#{1 + 1}bar"')
180
+ assert_equal "foo1bar5baz4bang", resolve('\'foo#{1 + "bar#{2 + 3}baz" + 4}bang\'')
170
181
  end
171
182
 
172
183
  def test_rule_interpolation
@@ -221,9 +232,9 @@ SASS
221
232
  end
222
233
 
223
234
  def test_dynamic_url
224
- assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => Sass::Script::String.new("foo-bar")))
225
- assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => Sass::Script::String.new("foo-bar"), 'bar' => Sass::Script::String.new("baz")))
226
- assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => Sass::Script::String.new("baz")))
235
+ assert_equal "url(foo-bar)", resolve("url($foo)", {}, env('foo' => Sass::Script::Value::String.new("foo-bar")))
236
+ assert_equal "url(foo-bar baz)", resolve("url($foo $bar)", {}, env('foo' => Sass::Script::Value::String.new("foo-bar"), 'bar' => Sass::Script::Value::String.new("baz")))
237
+ assert_equal "url(foo baz)", resolve("url(foo $bar)", {}, env('bar' => Sass::Script::Value::String.new("baz")))
227
238
  assert_equal "url(foo bar)", resolve("url(foo bar)")
228
239
  end
229
240
 
@@ -235,7 +246,7 @@ SASS
235
246
  end
236
247
 
237
248
  def test_hyphenated_variables
238
- assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::String.new("a-b"))))
249
+ assert_equal("a-b", resolve("$a-b", {}, env("a-b" => Sass::Script::Value::String.new("a-b"))))
239
250
  end
240
251
 
241
252
  def test_ruby_equality
@@ -253,6 +264,10 @@ SASS
253
264
  assert_equal "false", resolve("false")
254
265
  end
255
266
 
267
+ def test_null
268
+ assert_equal "", resolve("null")
269
+ end
270
+
256
271
  def test_boolean_ops
257
272
  assert_equal "true", resolve("true and true")
258
273
  assert_equal "true", resolve("false or true")
@@ -271,6 +286,18 @@ SASS
271
286
  assert_equal "false", resolve("false and 1")
272
287
  assert_equal "2", resolve("2 or 3")
273
288
  assert_equal "3", resolve("2 and 3")
289
+
290
+ assert_equal "true", resolve("null or true")
291
+ assert_equal "true", resolve("true or null")
292
+ assert_equal "", resolve("null or null")
293
+ assert_equal "", resolve("null and true")
294
+ assert_equal "", resolve("true and null")
295
+ assert_equal "", resolve("null and null")
296
+
297
+ assert_equal "true", resolve("not null")
298
+
299
+ assert_equal "1", resolve("null or 1")
300
+ assert_equal "", resolve("null and 1")
274
301
  end
275
302
 
276
303
  def test_arithmetic_ops
@@ -316,9 +343,40 @@ SASS
316
343
  assert_equal "false", resolve("3 <= 2")
317
344
  end
318
345
 
346
+ def test_null_ops
347
+ assert_raise_message(Sass::SyntaxError,
348
+ 'Invalid null operation: "null plus 1".') {eval("null + 1")}
349
+ assert_raise_message(Sass::SyntaxError,
350
+ 'Invalid null operation: "null minus 1".') {eval("null - 1")}
351
+ assert_raise_message(Sass::SyntaxError,
352
+ 'Invalid null operation: "null times 1".') {eval("null * 1")}
353
+ assert_raise_message(Sass::SyntaxError,
354
+ 'Invalid null operation: "null div 1".') {eval("null / 1")}
355
+ assert_raise_message(Sass::SyntaxError,
356
+ 'Invalid null operation: "null mod 1".') {eval("null % 1")}
357
+ assert_raise_message(Sass::SyntaxError,
358
+ 'Invalid null operation: "1 plus null".') {eval("1 + null")}
359
+ assert_raise_message(Sass::SyntaxError,
360
+ 'Invalid null operation: "1 minus null".') {eval("1 - null")}
361
+ assert_raise_message(Sass::SyntaxError,
362
+ 'Invalid null operation: "1 times null".') {eval("1 * null")}
363
+ assert_raise_message(Sass::SyntaxError,
364
+ 'Invalid null operation: "1 div null".') {eval("1 / null")}
365
+ assert_raise_message(Sass::SyntaxError,
366
+ 'Invalid null operation: "1 mod null".') {eval("1 % null")}
367
+ assert_raise_message(Sass::SyntaxError,
368
+ 'Invalid null operation: "1 gt null".') {eval("1 > null")}
369
+ assert_raise_message(Sass::SyntaxError,
370
+ 'Invalid null operation: "null lt 1".') {eval("null < 1")}
371
+ assert_raise_message(Sass::SyntaxError,
372
+ 'Invalid null operation: "null plus null".') {eval("null + null")}
373
+ assert_raise_message(Sass::SyntaxError,
374
+ 'Invalid null operation: ""foo" plus null".') {eval("foo + null")}
375
+ end
376
+
319
377
  def test_equals
320
378
  assert_equal("true", resolve('"foo" == $foo', {},
321
- env("foo" => Sass::Script::String.new("foo"))))
379
+ env("foo" => Sass::Script::Value::String.new("foo"))))
322
380
  assert_equal "true", resolve("1 == 1.0")
323
381
  assert_equal "true", resolve("false != true")
324
382
  assert_equal "false", resolve("1em == 1px")
@@ -331,6 +389,22 @@ SASS
331
389
  assert_equal "false", resolve('(1 (2 3)) == (1 2 3)')
332
390
  assert_equal "false", resolve('((1, 2) (3, 4)) == (1, 2 3, 4)')
333
391
  assert_equal "false", resolve('(1 2 3) == (1, 2, 3)')
392
+
393
+ assert_equal "true", resolve('null == null')
394
+ assert_equal "false", resolve('"null" == null')
395
+ assert_equal "false", resolve('0 == null')
396
+ assert_equal "false", resolve('() == null')
397
+
398
+ assert_equal "false", resolve('null != null')
399
+ assert_equal "true", resolve('"null" != null')
400
+ assert_equal "true", resolve('0 != null')
401
+ assert_equal "true", resolve('() != null')
402
+ end
403
+
404
+ def test_mod
405
+ assert_equal "5", resolve("29 % 12")
406
+ assert_equal "5px", resolve("29px % 12")
407
+ assert_equal "5px", resolve("29px % 12px")
334
408
  end
335
409
 
336
410
  def test_operation_precedence
@@ -349,6 +423,7 @@ SASS
349
423
 
350
424
  def test_operator_unit_conversion
351
425
  assert_equal "1.1cm", resolve("1cm + 1mm")
426
+ assert_equal "2in", resolve("1in + 96px")
352
427
  assert_equal "true", resolve("2mm < 1cm")
353
428
  assert_equal "true", resolve("10mm == 1cm")
354
429
  assert_equal "true", resolve("1 == 1cm")
@@ -414,8 +489,235 @@ SASS
414
489
  assert_raise_message(Sass::SyntaxError, "() isn't a valid CSS value.") {resolve("nth(append((), ()), 1)")}
415
490
  end
416
491
 
492
+ def test_list_with_nulls
493
+ assert_equal "1, 2, 3", resolve("1, 2, null, 3")
494
+ assert_equal "1 2 3", resolve("1 2 null 3")
495
+ assert_equal "1, 2, 3", resolve("1, 2, 3, null")
496
+ assert_equal "1 2 3", resolve("1 2 3 null")
497
+ assert_equal "1, 2, 3", resolve("null, 1, 2, 3")
498
+ assert_equal "1 2 3", resolve("null 1 2 3")
499
+ end
500
+
501
+ def test_map_can_have_trailing_comma
502
+ assert_equal("(foo: 1, bar: 2)", eval("(foo: 1, bar: 2,)").to_sass)
503
+ end
504
+
505
+ def test_list_can_have_trailing_comma
506
+ assert_equal("1, 2, 3", resolve("1, 2, 3,"))
507
+ end
508
+
509
+ def test_trailing_comma_defines_singleton_list
510
+ assert_equal("1 2 3", resolve("nth((1 2 3,), 1)"))
511
+ end
512
+
513
+ def test_map_cannot_have_duplicate_keys
514
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, foo: baz).') do
515
+ eval("(foo: bar, foo: baz)")
516
+ end
517
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, fo + o: baz).') do
518
+ eval("(foo: bar, fo + o: baz)")
519
+ end
520
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key "foo" in map (foo: bar, "foo": baz).') do
521
+ eval("(foo: bar, 'foo': baz)")
522
+ end
523
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key 2px in map (2px: bar, 1px + 1px: baz).') do
524
+ eval("(2px: bar, 1px + 1px: baz)")
525
+ end
526
+ assert_raise_message(Sass::SyntaxError, 'Duplicate key #0000ff in map (blue: bar, blue: baz).') do
527
+ eval("(blue: bar, #00f: baz)")
528
+ end
529
+ end
530
+
531
+ def test_non_duplicate_map_keys
532
+ # These shouldn't throw errors
533
+ eval("(foo: foo, bar: bar)")
534
+ eval("(2px: foo, 2: bar)")
535
+ eval("(2px: foo, 2em: bar)")
536
+ eval("('2px': foo, 2px: bar)")
537
+ end
538
+
539
+ def test_map_syntax_errors
540
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo:": expected expression (e.g. 1px, bold), was ")"') do
541
+ eval("(foo:)")
542
+ end
543
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(": expected ")", was ":bar)"') do
544
+ eval("(:bar)")
545
+ end
546
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo, bar": expected ")", was ": baz)"') do
547
+ eval("(foo, bar: baz)")
548
+ end
549
+ assert_raise_message(Sass::SyntaxError, 'Invalid CSS after "(foo: bar, baz": expected ":", was ")"') do
550
+ eval("(foo: bar, baz)")
551
+ end
552
+ end
553
+
554
+ def test_deep_argument_error_not_unwrapped
555
+ # JRuby (as of 1.6.7.2) offers no way of distinguishing between
556
+ # argument errors caused by programming errors in a function and
557
+ # argument errors explicitly thrown within that function.
558
+ return if RUBY_PLATFORM =~ /java/
559
+
560
+ # Don't validate the message; it's different on Rubinius.
561
+ assert_raise(ArgumentError) {resolve("arg-error()")}
562
+ end
563
+
564
+ def test_shallow_argument_error_unwrapped
565
+ assert_raise_message(Sass::SyntaxError, "wrong number of arguments (1 for 0) for `arg-error'") {resolve("arg-error(1)")}
566
+ end
567
+
568
+ def test_boolean_ops_short_circuit
569
+ assert_equal "false", resolve("$ie and $ie <= 7", {}, env('ie' => Sass::Script::Value::Bool.new(false)))
570
+ assert_equal "true", resolve("$ie or $undef", {}, env('ie' => Sass::Script::Value::Bool.new(true)))
571
+ end
572
+
573
+ def test_setting_global_variable_locally_warns
574
+ assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
575
+ DEPRECATION WARNING on line 4 of test_setting_global_variable_locally_warns_inline.scss:
576
+ Assigning to global variable "$var" by default is deprecated.
577
+ In future versions of Sass, this will create a new local variable.
578
+ If you want to assign to the global variable, use "$var: x !global" instead.
579
+ Note that this will be incompatible with Sass 3.2.
580
+ WARNING
581
+ .foo {
582
+ a: x; }
583
+
584
+ .bar {
585
+ b: x; }
586
+ CSS
587
+ $var: 1;
588
+
589
+ .foo {
590
+ $var: x;
591
+ a: $var;
592
+ }
593
+
594
+ .bar {
595
+ b: $var;
596
+ }
597
+ SCSS
598
+ end
599
+
600
+ def test_setting_global_variable_locally_warns_only_once
601
+ assert_warning(<<WARNING) {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
602
+ DEPRECATION WARNING on line 3 of test_setting_global_variable_locally_warns_only_once_inline.scss:
603
+ Assigning to global variable "$var" by default is deprecated.
604
+ In future versions of Sass, this will create a new local variable.
605
+ If you want to assign to the global variable, use "$var: x !global" instead.
606
+ Note that this will be incompatible with Sass 3.2.
607
+ WARNING
608
+ CSS
609
+ $var: 1;
610
+
611
+ @mixin foo {$var: x}
612
+ @include foo;
613
+ @include foo;
614
+ @include foo;
615
+ SCSS
616
+ end
617
+
618
+ def test_setting_global_variable_globally
619
+ assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
620
+ .foo {
621
+ a: 1; }
622
+
623
+ .bar {
624
+ b: 2; }
625
+ CSS
626
+ $var: 1;
627
+
628
+ .foo {
629
+ a: $var;
630
+ }
631
+
632
+ $var: 2;
633
+
634
+ .bar {
635
+ b: $var;
636
+ }
637
+ SCSS
638
+ end
639
+
640
+ def test_setting_global_variable_with_flag
641
+ assert_no_warning {assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))}
642
+ .bar {
643
+ a: x;
644
+ b: y;
645
+ c: z; }
646
+ CSS
647
+ $var1: 1;
648
+ $var3: 3;
649
+
650
+ .foo {
651
+ $var1: x !global;
652
+ $var2: y !global;
653
+ @each $var3 in _ {
654
+ $var3: z !global;
655
+ }
656
+ }
657
+
658
+ .bar {
659
+ a: $var1;
660
+ b: $var2;
661
+ c: $var3;
662
+ }
663
+ SCSS
664
+ end
665
+
666
+ def test_setting_global_variable_with_flag_and_default
667
+ assert_equal(<<CSS, render(<<SCSS, :syntax => :scss))
668
+ .bar {
669
+ a: 1;
670
+ b: y;
671
+ c: z; }
672
+ CSS
673
+ $var1: 1;
674
+
675
+ .foo {
676
+ $var1: x !global !default;
677
+ $var2: y !global !default;
678
+ @each $var3 in _ {
679
+ $var3: z !global !default;
680
+ }
681
+ }
682
+
683
+ .bar {
684
+ a: $var1;
685
+ b: $var2;
686
+ c: $var3;
687
+ }
688
+ SCSS
689
+ end
690
+
417
691
  # Regression Tests
418
692
 
693
+ def test_minus_without_whitespace
694
+ assert_equal "5px", resolve("15px-10px")
695
+ end
696
+
697
+ def test_user_defined_function_forces_division
698
+ assert_equal(<<CSS, render(<<SASS))
699
+ a {
700
+ b: 10px; }
701
+ CSS
702
+ @function foo()
703
+ @return 20px
704
+
705
+ a
706
+ b: (foo() / 2)
707
+ SASS
708
+
709
+ assert_equal(<<CSS, render(<<SASS))
710
+ a {
711
+ b: 10px; }
712
+ CSS
713
+ @function foo()
714
+ @return 20px
715
+
716
+ a
717
+ b: foo() / 2
718
+ SASS
719
+ end
720
+
419
721
  def test_funcall_has_higher_precedence_than_color_name
420
722
  assert_equal "teal(12)", resolve("teal(12)")
421
723
  assert_equal "tealbang(12)", resolve("tealbang(12)")
@@ -423,6 +725,13 @@ SASS
423
725
  assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
424
726
  end
425
727
 
728
+ def test_funcall_has_higher_precedence_than_true_false_null
729
+ assert_equal "teal(12)", resolve("teal(12)")
730
+ assert_equal "tealbang(12)", resolve("tealbang(12)")
731
+ assert_equal "teal-bang(12)", resolve("teal-bang(12)")
732
+ assert_equal "teal\\+bang(12)", resolve("teal\\+bang(12)")
733
+ end
734
+
426
735
  def test_interpolation_after_hash
427
736
  assert_equal "#2", resolve('"##{1 + 1}"')
428
737
  end
@@ -444,33 +753,68 @@ SASS
444
753
  assert_equal "and-bang", resolve("and-bang")
445
754
  end
446
755
 
756
+ def test_number_initialization
757
+ assert_equal Sass::Script::Value::Number.new(10, ["px"]), Sass::Script::Value::Number.new(10, "px")
758
+ assert_equal Sass::Script::Value::Number.new(10, ["px"], ["em"]), Sass::Script::Value::Number.new(10, "px", "em")
759
+ end
760
+
761
+ def test_is_unit
762
+ assert Sass::Script::Value::Number.new(10, "px").is_unit?("px")
763
+ assert Sass::Script::Value::Number.new(10).is_unit?(nil)
764
+ assert !Sass::Script::Value::Number.new(10, "px", "em").is_unit?("px")
765
+ assert !Sass::Script::Value::Number.new(10, [], "em").is_unit?("em")
766
+ assert !Sass::Script::Value::Number.new(10, ["px", "em"]).is_unit?("px")
767
+ end
768
+
769
+ def test_rename_redirect
770
+ assert_no_warning do
771
+ assert_equal Sass::Script::Value::Base, Sass::Script::Literal
772
+ assert_equal Sass::Script::Tree::Node, Sass::Script::Node
773
+ assert_equal Sass::Script::Tree::Operation, Sass::Script::Operation
774
+ assert_equal Sass::Script::Value::String, Sass::Script::String
775
+ end
776
+ end
777
+
778
+ def test_number_printing
779
+ assert_equal "1", resolve("1")
780
+ assert_equal "1", resolve("1.0")
781
+ assert_equal "1000000000", resolve("1000000000")
782
+ assert_equal "0.00001", resolve("0.00001")
783
+ assert_equal "1.12121", resolve("1.121214")
784
+ assert_equal "1.12122", resolve("1.121215")
785
+ assert_equal "Infinity", resolve("(1.0/0.0)")
786
+ assert_equal "-Infinity", resolve("(-1.0/0.0)")
787
+ assert_equal "NaN", resolve("(0.0/0.0)")
788
+ end
789
+
447
790
  private
448
791
 
449
792
  def resolve(str, opts = {}, environment = env)
450
793
  munge_filename opts
451
794
  val = eval(str, opts, environment)
452
- val.is_a?(Sass::Script::String) ? val.value : val.to_s
795
+ assert_kind_of Sass::Script::Value::Base, val
796
+ val.is_a?(Sass::Script::Value::String) ? val.value : val.to_s
453
797
  end
454
798
 
455
799
  def assert_unquoted(str, opts = {}, environment = env)
456
800
  munge_filename opts
457
801
  val = eval(str, opts, environment)
458
- assert_kind_of Sass::Script::String, val
802
+ assert_kind_of Sass::Script::Value::String, val
459
803
  assert_equal :identifier, val.type
460
804
  end
461
805
 
462
806
  def assert_quoted(str, opts = {}, environment = env)
463
807
  munge_filename opts
464
808
  val = eval(str, opts, environment)
465
- assert_kind_of Sass::Script::String, val
809
+ assert_kind_of Sass::Script::Value::String, val
466
810
  assert_equal :string, val.type
467
811
  end
468
812
 
469
813
  def eval(str, opts = {}, environment = env)
470
814
  munge_filename opts
471
- environment.options = opts
472
815
  Sass::Script.parse(str, opts.delete(:line) || 1,
473
- opts.delete(:offset) || 0, opts).perform(environment)
816
+ opts.delete(:offset) || 0, opts).
817
+ perform(Sass::Environment.new(environment, opts))
474
818
  end
475
819
 
476
820
  def render(sass, options = {})
@@ -484,13 +828,13 @@ SASS
484
828
  env
485
829
  end
486
830
 
487
- def test_number_printing
488
- assert_equal "1", eval("1")
489
- assert_equal "1", eval("1.0")
490
- assert_equal "1.121", eval("1.1214")
491
- assert_equal "1.122", eval("1.1215")
492
- assert_equal "Infinity", eval("1.0/0.0")
493
- assert_equal "-Infinity", eval("-1.0/0.0")
494
- assert_equal "NaN", eval("0.0/0.0")
831
+ def selector(str)
832
+ parser = Sass::SCSS::StaticParser.new(
833
+ str, filename_for_test, Sass::Importers::Filesystem.new('.'))
834
+ parser.parse_selector
835
+ end
836
+
837
+ def test_null_is_a_singleton
838
+ assert_same Sass::Script::Value::Null.new, Sass::Script::Value::Null.new
495
839
  end
496
840
  end