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
@@ -1,34 +1,57 @@
1
1
  #!/usr/bin/env ruby
2
2
  require File.dirname(__FILE__) + '/../test_helper'
3
3
  require File.dirname(__FILE__) + '/test_helper'
4
+ require 'mock_importer'
5
+ require 'sass/plugin'
4
6
 
5
7
  class ImporterTest < Test::Unit::TestCase
6
-
8
+
7
9
  class FruitImporter < Sass::Importers::Base
8
10
  def find(name, context = nil)
9
- if name =~ %r{fruits/(\w+)(\.s[ac]ss)?}
10
- fruit = $1
11
- color = case $1
12
- when "apple"
13
- "red"
14
- when "orange"
15
- "orange"
16
- else
17
- "blue"
18
- end
19
- contents = %Q{
20
- $#{fruit}-color: #{color} !default;
21
- @mixin #{fruit} {
22
- color: $#{fruit}-color;
23
- }
24
- }
25
- Sass::Engine.new(contents, :filename => name, :syntax => :scss, :importer => self)
11
+ fruit = parse(name)
12
+ return unless fruit
13
+ color = case fruit
14
+ when "apple"
15
+ "red"
16
+ when "orange"
17
+ "orange"
18
+ else
19
+ "blue"
26
20
  end
21
+ contents = %Q{
22
+ $#{fruit}-color: #{color} !default;
23
+ @mixin #{fruit} {
24
+ color: $#{fruit}-color;
25
+ }
26
+ }
27
+ Sass::Engine.new(contents, :filename => name, :syntax => :scss, :importer => self)
27
28
  end
28
29
 
29
30
  def key(name, context)
30
31
  [self.class.name, name]
31
32
  end
33
+
34
+ def public_url(name, sourcemap_directory = nil)
35
+ "http://#{parse(name)}.example.com/style.scss"
36
+ end
37
+
38
+ private
39
+
40
+ def parse(name)
41
+ name[%r{fruits/(\w+)(\.s[ac]ss)?}, 1]
42
+ end
43
+ end
44
+
45
+ class NoPublicUrlImporter < FruitImporter
46
+ def public_url(name, sourcemap_directory = nil)
47
+ nil
48
+ end
49
+
50
+ private
51
+
52
+ def parse(name)
53
+ name[%r{ephemeral/(\w+)(\.s[ac]ss)?}, 1]
54
+ end
32
55
  end
33
56
 
34
57
  # This class proves that you can override the extension scheme for importers
@@ -38,6 +61,72 @@ class ImporterTest < Test::Unit::TestCase
38
61
  end
39
62
  end
40
63
 
64
+ # This importer maps one import to another import
65
+ # based on the mappings passed to importer's constructor.
66
+ class IndirectImporter < Sass::Importers::Base
67
+ def initialize(mappings, mtimes)
68
+ @mappings = mappings
69
+ @mtimes = mtimes
70
+ end
71
+ def find_relative(uri, base, options)
72
+ nil
73
+ end
74
+ def find(name, options)
75
+ if @mappings.has_key?(name)
76
+ Sass::Engine.new(
77
+ %Q[@import "#{@mappings[name]}";],
78
+ options.merge(
79
+ :filename => name,
80
+ :syntax => :scss,
81
+ :importer => self
82
+ )
83
+ )
84
+ end
85
+ end
86
+ def mtime(uri, options)
87
+ @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
88
+ end
89
+ def key(uri, options)
90
+ [self.class.name, uri]
91
+ end
92
+ def to_s
93
+ "IndirectImporter(#{@mappings.keys.join(", ")})"
94
+ end
95
+ end
96
+
97
+ # This importer maps the import to single class
98
+ # based on the mappings passed to importer's constructor.
99
+ class ClassImporter < Sass::Importers::Base
100
+ def initialize(mappings, mtimes)
101
+ @mappings = mappings
102
+ @mtimes = mtimes
103
+ end
104
+ def find_relative(uri, base, options)
105
+ nil
106
+ end
107
+ def find(name, options)
108
+ if @mappings.has_key?(name)
109
+ Sass::Engine.new(
110
+ %Q[.#{name}{#{@mappings[name]}}],
111
+ options.merge(
112
+ :filename => name,
113
+ :syntax => :scss,
114
+ :importer => self
115
+ )
116
+ )
117
+ end
118
+ end
119
+ def mtime(uri, options)
120
+ @mtimes.fetch(uri, @mtimes.has_key?(uri) ? Time.now : nil)
121
+ end
122
+ def key(uri, options)
123
+ [self.class.name, uri]
124
+ end
125
+ def to_s
126
+ "ClassImporter(#{@mappings.keys.join(", ")})"
127
+ end
128
+ end
129
+
41
130
  def test_can_resolve_generated_imports
42
131
  scss_file = %Q{
43
132
  $pear-color: green;
@@ -79,4 +168,235 @@ CSS
79
168
  ensure
80
169
  FileUtils.rm_rf(absolutize("tmp"))
81
170
  end
171
+
172
+ def test_staleness_check_across_importers
173
+ file_system_importer = Sass::Importers::Filesystem.new(fixture_dir)
174
+ # Make sure the first import is older
175
+ indirect_importer = IndirectImporter.new({"apple" => "pear"}, {"apple" => Time.now - 1})
176
+ # Make css file is newer so the dependencies are the only way for the css file to be out of date.
177
+ FileUtils.touch(fixture_file("test_staleness_check_across_importers.css"))
178
+ # Make sure the first import is older
179
+ class_importer = ClassImporter.new({"pear" => %Q{color: green;}}, {"pear" => Time.now + 1})
180
+
181
+ options = {
182
+ :style => :compact,
183
+ :filename => fixture_file("test_staleness_check_across_importers.scss"),
184
+ :importer => file_system_importer,
185
+ :load_paths => [file_system_importer, indirect_importer, class_importer],
186
+ :syntax => :scss
187
+ }
188
+
189
+ assert_equal File.read(fixture_file("test_staleness_check_across_importers.css")),
190
+ Sass::Engine.new(File.read(fixture_file("test_staleness_check_across_importers.scss")), options).render
191
+
192
+ checker = Sass::Plugin::StalenessChecker.new(options)
193
+
194
+ assert checker.stylesheet_needs_update?(
195
+ fixture_file("test_staleness_check_across_importers.css"),
196
+ fixture_file("test_staleness_check_across_importers.scss"),
197
+ file_system_importer
198
+ )
199
+ end
200
+
201
+ def test_source_map_with_only_css_uri_supports_public_url_imports
202
+ fruit_importer = FruitImporter.new
203
+
204
+ options = {
205
+ :filename => 'fruits/orange',
206
+ :importer => fruit_importer,
207
+ :syntax => :scss
208
+ }
209
+
210
+ engine = Sass::Engine.new(<<SCSS, options)
211
+ .orchard {
212
+ color: blue;
213
+ }
214
+ SCSS
215
+
216
+ _, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
217
+ assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => 'css_uri')
218
+ {
219
+ "version": 3,
220
+ "mappings": "AAAA,QAAS;EACP,KAAK,EAAE,IAAI",
221
+ "sources": ["http://orange.example.com/style.scss"],
222
+ "names": [],
223
+ "file": "css_uri"
224
+ }
225
+ JSON
226
+ end
227
+
228
+ def test_source_map_with_only_css_uri_can_have_no_public_url_without_warning
229
+ ephemeral_importer = NoPublicUrlImporter.new
230
+ mock_importer = MockImporter.new
231
+ def mock_importer.public_url(name, sourcemap_directory = nil)
232
+ "css_uri"
233
+ end
234
+
235
+ options = {
236
+ :filename => filename_for_test,
237
+ :sourcemap_filename => sourcemap_filename_for_test,
238
+ :importer => mock_importer,
239
+ :syntax => :scss,
240
+ :load_paths => [ephemeral_importer],
241
+ :cache => false
242
+ }
243
+
244
+ engine = Sass::Engine.new(<<SCSS, options)
245
+ @import "ephemeral/orange";
246
+ .orange {
247
+ @include orange;
248
+ }
249
+ SCSS
250
+
251
+ assert_warning("") do
252
+ css_output, sourcemap = engine.render_with_sourcemap('sourcemap_uri')
253
+ assert_equal <<CSS.strip, css_output.strip
254
+ .orange {
255
+ color: orange; }
256
+
257
+ /*# sourceMappingURL=sourcemap_uri */
258
+ CSS
259
+ map = sourcemap.to_json(:css_uri => 'css_uri')
260
+ assert_equal <<JSON.strip, map
261
+ {
262
+ "version": 3,
263
+ "mappings": "AACA,OAAQ",
264
+ "sources": ["css_uri"],
265
+ "names": [],
266
+ "file": "css_uri"
267
+ }
268
+ JSON
269
+ end
270
+ end
271
+
272
+ def test_source_map_with_only_css_uri_doesnt_support_filesystem_importer
273
+ file_system_importer = Sass::Importers::Filesystem.new('.')
274
+ options = {
275
+ :filename => filename_for_test(:scss),
276
+ :sourcemap_filename => sourcemap_filename_for_test,
277
+ :importer => file_system_importer,
278
+ :syntax => :scss
279
+ }
280
+
281
+ engine = Sass::Engine.new(<<SCSS, options)
282
+ .foo {a: b}
283
+ SCSS
284
+
285
+ _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
286
+
287
+ assert_warning(<<WARNING) {sourcemap.to_json(:css_uri => 'css_uri')}
288
+ WARNING: Couldn't determine public URL for "#{filename_for_test(:scss)}" while generating sourcemap.
289
+ Without a public URL, there's nothing for the source map to link to.
290
+ WARNING
291
+ end
292
+
293
+ def test_source_map_with_css_uri_and_css_path_doesnt_support_filesystem_importer
294
+ file_system_importer = Sass::Importers::Filesystem.new('.')
295
+ options = {
296
+ :filename => filename_for_test(:scss),
297
+ :sourcemap_filename => sourcemap_filename_for_test,
298
+ :importer => file_system_importer,
299
+ :syntax => :scss
300
+ }
301
+
302
+ engine = Sass::Engine.new(<<SCSS, options)
303
+ .foo {a: b}
304
+ SCSS
305
+
306
+ _, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
307
+
308
+ assert_warning(<<WARNING) {sourcemap.to_json(:css_uri => 'css_uri', :css_path => 'css_path')}
309
+ WARNING: Couldn't determine public URL for "#{filename_for_test(:scss)}" while generating sourcemap.
310
+ Without a public URL, there's nothing for the source map to link to.
311
+ WARNING
312
+ end
313
+
314
+ def test_source_map_with_css_uri_and_sourcemap_path_supports_filesystem_importer
315
+ file_system_importer = Sass::Importers::Filesystem.new('.')
316
+ css_uri = 'css_uri'
317
+ sourcemap_path = 'map/style.map'
318
+ options = {
319
+ :filename => 'sass/style.scss',
320
+ :sourcemap_filename => sourcemap_path,
321
+ :importer => file_system_importer,
322
+ :syntax => :scss
323
+ }
324
+
325
+ engine = Sass::Engine.new(<<SCSS, options)
326
+ .foo {a: b}
327
+ SCSS
328
+
329
+ rendered, sourcemap = engine.render_with_sourcemap('http://1.example.com/style.map')
330
+
331
+
332
+ rendered, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
333
+ assert_equal <<JSON.strip, sourcemap.to_json(:css_uri => css_uri, :sourcemap_path => sourcemap_path)
334
+ {
335
+ "version": 3,
336
+ "mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
337
+ "sources": ["../sass/style.scss"],
338
+ "names": [],
339
+ "file": "css_uri"
340
+ }
341
+ JSON
342
+ end
343
+
344
+ def test_source_map_with_css_path_and_sourcemap_path_supports_file_system_importer
345
+ file_system_importer = Sass::Importers::Filesystem.new('.')
346
+ sass_path = 'sass/style.scss'
347
+ css_path = 'static/style.css'
348
+ sourcemap_path = 'map/style.map'
349
+ options = {
350
+ :filename => sass_path,
351
+ :sourcemap_filename => sourcemap_path,
352
+ :importer => file_system_importer,
353
+ :syntax => :scss
354
+ }
355
+
356
+ engine = Sass::Engine.new(<<SCSS, options)
357
+ .foo {a: b}
358
+ SCSS
359
+
360
+ _, sourcemap = engine.render_with_sourcemap('http://map.example.com/map/style.map')
361
+ assert_equal <<JSON.strip, sourcemap.to_json(:css_path => css_path, :sourcemap_path => sourcemap_path)
362
+ {
363
+ "version": 3,
364
+ "mappings": "AAAA,IAAK;EAAC,CAAC,EAAE,CAAC",
365
+ "sources": ["../sass/style.scss"],
366
+ "names": [],
367
+ "file": "../static/style.css"
368
+ }
369
+ JSON
370
+ end
371
+
372
+ def test_render_with_sourcemap_requires_filename
373
+ file_system_importer = Sass::Importers::Filesystem.new('.')
374
+ engine = Sass::Engine.new(".foo {a: b}", :syntax => :scss, :importer => file_system_importer)
375
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE) {engine.render_with_sourcemap('sourcemap_url')}
376
+ Error generating source map: couldn't determine public URL for the source stylesheet.
377
+ No filename is available so there's nothing for the source map to link to.
378
+ MESSAGE
379
+ end
380
+
381
+ def test_render_with_sourcemap_requires_importer_with_public_url
382
+ class_importer = ClassImporter.new({"pear" => "color: green;"}, {"pear" => Time.now})
383
+ assert_raise_message(Sass::SyntaxError, <<MESSAGE) {class_importer.find("pear", {}).render_with_sourcemap('sourcemap_url')}
384
+ Error generating source map: couldn't determine public URL for "pear".
385
+ Without a public URL, there's nothing for the source map to link to.
386
+ Custom importers should define the #public_url method.
387
+ MESSAGE
388
+ end
389
+
390
+ def fixture_dir
391
+ File.join(File.dirname(__FILE__), "fixtures")
392
+ end
393
+
394
+ def fixture_file(path)
395
+ File.join(fixture_dir, path)
396
+ end
397
+
398
+ def test_absolute_files_across_template_locations
399
+ importer = Sass::Importers::Filesystem.new(absolutize 'templates')
400
+ assert_not_nil importer.mtime(absolutize('more_templates/more1.sass'), {})
401
+ end
82
402
  end
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env ruby
2
+ require File.dirname(__FILE__) + '/../test_helper'
3
+ require 'pathname'
4
+
5
+ class LoggerTest < Test::Unit::TestCase
6
+
7
+ class InterceptedLogger < Sass::Logger::Base
8
+
9
+ attr_accessor :messages
10
+
11
+ def initialize(*args)
12
+ super
13
+ self.messages = []
14
+ end
15
+
16
+ def reset!
17
+ self.messages = []
18
+ end
19
+
20
+ def _log(*args)
21
+ messages << [args]
22
+ end
23
+
24
+ end
25
+
26
+ def test_global_sass_logger_instance_exists
27
+ assert Sass.logger.respond_to?(:warn)
28
+ end
29
+
30
+ def test_log_level_orders
31
+ logged_levels = {
32
+ :trace => [ [], [:trace, :debug, :info, :warn, :error]],
33
+ :debug => [ [:trace], [:debug, :info, :warn, :error]],
34
+ :info => [ [:trace, :debug], [:info, :warn, :error]],
35
+ :warn => [ [:trace, :debug, :info], [:warn, :error]],
36
+ :error => [ [:trace, :debug, :info, :warn], [:error]]
37
+ }
38
+ logged_levels.each do |level, (should_not_be_logged, should_be_logged)|
39
+ logger = Sass::Logger::Base.new(level)
40
+ should_not_be_logged.each do |should_level|
41
+ assert !logger.logging_level?(should_level)
42
+ end
43
+ should_be_logged.each do |should_level|
44
+ assert logger.logging_level?(should_level)
45
+ end
46
+ end
47
+ end
48
+
49
+ def test_logging_can_be_disabled
50
+ logger = InterceptedLogger.new
51
+ logger.error("message #1")
52
+ assert_equal 1, logger.messages.size
53
+ logger.reset!
54
+ logger.disabled = true
55
+ logger.error("message #2")
56
+ assert_equal 0, logger.messages.size
57
+ end
58
+ end
@@ -1,3 +1,5 @@
1
+ @import url(basic.css);
2
+ @import url(../results/complex.css);
1
3
  imported { otherconst: hello; myconst: goodbye; pre-mixin: here; }
2
4
 
3
5
  body { font: Arial; background: blue; }
@@ -22,8 +24,6 @@ body { font: Arial; background: blue; }
22
24
  #content.user.show #container.top #column.right { width: 600px; }
23
25
  #content.user.show #container.bottom { background: brown; }
24
26
 
25
- @import url(basic.css);
26
- @import url(../results/complex.css);
27
27
  #foo { background-color: #bbaaff; }
28
28
 
29
29
  nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }
@@ -4,11 +4,24 @@ require File.dirname(__FILE__) + '/test_helper'
4
4
  require 'sass/plugin'
5
5
  require 'fileutils'
6
6
 
7
+ module Sass::Script::Functions
8
+ def filename
9
+ filename = options[:filename].gsub(%r{.*((/[^/]+){4})}, '\1')
10
+ Sass::Script::Value::String.new(filename)
11
+ end
12
+
13
+ def whatever
14
+ custom = options[:custom]
15
+ whatever = custom && custom[:whatever]
16
+ Sass::Script::Value::String.new(whatever || "incorrect")
17
+ end
18
+ end
19
+
7
20
  class SassPluginTest < Test::Unit::TestCase
8
21
  @@templates = %w{
9
22
  complex script parent_ref import scss_import alt
10
23
  subdir/subdir subdir/nested_subdir/nested_subdir
11
- options
24
+ options import_content filename_fn
12
25
  }
13
26
  @@templates += %w[import_charset import_charset_ibm866] unless Sass::Util.ruby1_8?
14
27
  @@templates << 'import_charset_1_8' if Sass::Util.ruby1_8?
@@ -110,6 +123,61 @@ CSS
110
123
  File.delete(tempfile_loc('bork1'))
111
124
  end
112
125
 
126
+ def test_full_exception_with_block_comment
127
+ File.delete(tempfile_loc('bork5'))
128
+ check_for_updates!
129
+ File.open(tempfile_loc('bork5')) do |file|
130
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...7].join("\n"))
131
+ /*
132
+ Syntax error: Undefined variable: "$bork".
133
+ on line 3 of #{template_loc('bork5')}
134
+
135
+ 1: bork
136
+ 2: /* foo *\\/
137
+ 3: :bork $bork
138
+ CSS
139
+ end
140
+ File.delete(tempfile_loc('bork1'))
141
+ end
142
+
143
+ def test_single_level_import_loop
144
+ File.delete(tempfile_loc('single_import_loop'))
145
+ check_for_updates!
146
+ File.open(tempfile_loc('single_import_loop')) do |file|
147
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...2].join("\n"))
148
+ /*
149
+ Syntax error: An @import loop has been found: #{template_loc('single_import_loop')} imports itself
150
+ CSS
151
+ end
152
+ end
153
+
154
+ def test_double_level_import_loop
155
+ File.delete(tempfile_loc('double_import_loop1'))
156
+ check_for_updates!
157
+ File.open(tempfile_loc('double_import_loop1')) do |file|
158
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...4].join("\n"))
159
+ /*
160
+ Syntax error: An @import loop has been found:
161
+ #{template_loc('double_import_loop1')} imports #{template_loc('_double_import_loop2')}
162
+ #{template_loc('_double_import_loop2')} imports #{template_loc('double_import_loop1')}
163
+ CSS
164
+ end
165
+ end
166
+
167
+ def test_import_name_cleanup
168
+ File.delete(tempfile_loc('subdir/import_up1'))
169
+ check_for_updates!
170
+ File.open(tempfile_loc('subdir/import_up1')) do |file|
171
+ assert_equal(<<CSS.strip, file.read.split("\n")[0...5].join("\n"))
172
+ /*
173
+ Syntax error: File to import not found or unreadable: ../subdir/import_up3.scss.
174
+ Load path: #{template_loc}
175
+ on line 1 of #{template_loc 'subdir/import_up2'}
176
+ from line 1 of #{template_loc 'subdir/import_up1'}
177
+ CSS
178
+ end
179
+ end
180
+
113
181
  def test_nonfull_exception_handling
114
182
  old_full_exception = Sass::Plugin.options[:full_exception]
115
183
  Sass::Plugin.options[:full_exception] = false
@@ -179,42 +247,39 @@ CSS
179
247
  assert_needs_update "basic"
180
248
  end
181
249
 
182
- # Callbacks
183
-
184
- def test_updating_stylesheets_callback
185
- # Should run even when there's nothing to update
186
- assert_callback :updating_stylesheets, []
187
- end
188
-
189
- def test_updating_stylesheets_callback_with_individual_files
190
- files = [[template_loc("basic"), tempfile_loc("basic")]]
191
- assert_callback(:updating_stylesheets, files) {Sass::Util.silence_sass_warnings{Sass::Plugin.update_stylesheets(files)}}
250
+ def test_import_same_name
251
+ assert_warning <<WARNING do
252
+ WARNING: In #{template_loc}:
253
+ There are multiple files that match the name "same_name_different_partiality.scss":
254
+ _same_name_different_partiality.scss
255
+ same_name_different_partiality.scss
256
+ WARNING
257
+ touch "_same_name_different_partiality"
258
+ assert_needs_update "same_name_different_partiality"
259
+ end
192
260
  end
193
261
 
194
- def test_updating_stylesheets_callback_with_never_update
195
- Sass::Plugin.options[:never_update] = true
196
- assert_no_callback :updating_stylesheets
197
- end
262
+ # Callbacks
198
263
 
199
- def test_updating_stylesheet_callback_for_updated_template
264
+ def test_updated_stylesheet_callback_for_updated_template
200
265
  Sass::Plugin.options[:always_update] = false
201
266
  touch 'basic'
202
- assert_no_callback :updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
267
+ assert_no_callback :updated_stylesheet, template_loc("complex"), tempfile_loc("complex") do
203
268
  assert_callbacks(
204
- [:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")],
205
- [:updating_stylesheet, template_loc("import"), tempfile_loc("import")])
269
+ [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
270
+ [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
206
271
  end
207
272
  end
208
273
 
209
- def test_updating_stylesheet_callback_for_fresh_template
274
+ def test_updated_stylesheet_callback_for_fresh_template
210
275
  Sass::Plugin.options[:always_update] = false
211
- assert_no_callback :updating_stylesheet
276
+ assert_no_callback :updated_stylesheet
212
277
  end
213
278
 
214
- def test_updating_stylesheet_callback_for_error_template
279
+ def test_updated_stylesheet_callback_for_error_template
215
280
  Sass::Plugin.options[:always_update] = false
216
281
  touch 'bork1'
217
- assert_no_callback :updating_stylesheet
282
+ assert_no_callback :updated_stylesheet
218
283
  end
219
284
 
220
285
  def test_not_updating_stylesheet_callback_for_fresh_template
@@ -226,8 +291,8 @@ CSS
226
291
  Sass::Plugin.options[:always_update] = false
227
292
  assert_callback :not_updating_stylesheet, template_loc("complex"), tempfile_loc("complex") do
228
293
  assert_no_callbacks(
229
- [:updating_stylesheet, template_loc("basic"), tempfile_loc("basic")],
230
- [:updating_stylesheet, template_loc("import"), tempfile_loc("import")])
294
+ [:updated_stylesheet, template_loc("basic"), tempfile_loc("basic")],
295
+ [:updated_stylesheet, template_loc("import"), tempfile_loc("import")])
231
296
  end
232
297
  end
233
298
 
@@ -301,7 +366,24 @@ CSS
301
366
  check_for_updates!
302
367
  assert_renders_correctly 'if'
303
368
  ensure
304
- set_plugin_opts :cache_store => @@cache_store
369
+ set_plugin_opts
370
+ end
371
+
372
+ def test_cached_import_option
373
+ set_plugin_opts :custom => {:whatever => "correct"}
374
+ check_for_updates!
375
+ assert_renders_correctly "cached_import_option"
376
+
377
+ @@cache_store.reset!
378
+ set_plugin_opts :custom => nil, :always_update => false
379
+ check_for_updates!
380
+ assert_renders_correctly "cached_import_option"
381
+
382
+ set_plugin_opts :custom => {:whatever => "correct"}, :always_update => true
383
+ check_for_updates!
384
+ assert_renders_correctly "cached_import_option"
385
+ ensure
386
+ set_plugin_opts :custom => nil
305
387
  end
306
388
 
307
389
  private
@@ -347,19 +429,21 @@ CSS
347
429
 
348
430
  def assert_callback(name, *expected_args)
349
431
  run = false
432
+ received_args = nil
350
433
  Sass::Plugin.send("on_#{name}") do |*args|
351
- run ||= expected_args.zip(args).all? do |ea, a|
352
- ea.respond_to?(:call) ? ea.call(a) : ea == a
434
+ received_args = args
435
+ run ||= expected_args.zip(received_args).all? do |ea, ra|
436
+ ea.respond_to?(:call) ? ea.call(ra) : ea == ra
353
437
  end
354
438
  end
355
439
 
356
440
  if block_given?
357
- yield
441
+ Sass::Util.silence_sass_warnings {yield}
358
442
  else
359
443
  check_for_updates!
360
444
  end
361
445
 
362
- assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}"
446
+ assert run, "Expected #{name} callback to be run with arguments:\n #{expected_args.inspect}\nHowever, it got:\n #{received_args.inspect}"
363
447
  end
364
448
 
365
449
  def assert_no_callback(name, *unexpected_args)
@@ -0,0 +1,3 @@
1
+ partial { value: correct; }
2
+
3
+ main { value: correct; }
@@ -0,0 +1,3 @@
1
+ filename { imported: /test/sass/templates/_filename_fn_import.scss; }
2
+
3
+ filename { local: /test/sass/templates/filename_fn.scss; local-mixin: /test/sass/templates/filename_fn.scss; local-function: /test/sass/templates/filename_fn.scss; imported-mixin: /test/sass/templates/_filename_fn_import.scss; imported-function: /test/sass/templates/_filename_fn_import.scss; }
@@ -1,3 +1,5 @@
1
+ @import url(basic.css);
2
+ @import url(../results/complex.css);
1
3
  imported { otherconst: hello; myconst: goodbye; pre-mixin: here; }
2
4
 
3
5
  body { font: Arial; background: blue; }
@@ -24,8 +26,6 @@ body { font: Arial; background: blue; }
24
26
  #content.user.show #container.top #column.right { width: 600px; }
25
27
  #content.user.show #container.bottom { background: brown; }
26
28
 
27
- @import url(basic.css);
28
- @import url(../results/complex.css);
29
29
  #foo { background-color: #bbaaff; }
30
30
 
31
31
  nonimported { myconst: hello; otherconst: goodbye; post-mixin: here; }