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
@@ -0,0 +1,51 @@
1
+ module Sass
2
+ module Importers
3
+ # This importer emits a deprecation warning the first time it is used to
4
+ # import a file. It is used to deprecate the current working
5
+ # directory from the list of automatic sass load paths.
6
+ class DeprecatedPath < Filesystem
7
+ # @param root [String] The absolute, expanded path to the folder that is deprecated.
8
+ def initialize(root)
9
+ @specified_root = root
10
+ @warning_given = false
11
+ super
12
+ end
13
+
14
+ # @see Sass::Importers::Base#find
15
+ def find(*args)
16
+ found = super
17
+ if found && !@warning_given
18
+ @warning_given = true
19
+ Sass::Util.sass_warn deprecation_warning
20
+ end
21
+ found
22
+ end
23
+
24
+ # @see Base#directories_to_watch
25
+ def directories_to_watch
26
+ # The current working directory was not watched in Sass 3.2,
27
+ # so we continue not to watch it while it's deprecated.
28
+ []
29
+ end
30
+
31
+ # @see Sass::Importers::Base#to_s
32
+ def to_s
33
+ "#{@root} (DEPRECATED)"
34
+ end
35
+
36
+ protected
37
+
38
+ # @return [String] The deprecation warning that will be printed the first
39
+ # time an import occurs.
40
+ def deprecation_warning
41
+ path = @specified_root == "." ? "the current working directory" : @specified_root
42
+ <<WARNING
43
+ DEPRECATION WARNING: Importing from #{path} will not be
44
+ automatic in future versions of Sass. To avoid future errors, you can add it
45
+ to your environment explicitly by setting `SASS_PATH=#{@specified_root}`, by using the -I command
46
+ line option, or by changing your Sass configuration options.
47
+ WARNING
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,11 +1,10 @@
1
- require 'pathname'
1
+ require 'set'
2
2
 
3
3
  module Sass
4
4
  module Importers
5
5
  # The default importer, used for any strings found in the load path.
6
6
  # Simply loads Sass files from the filesystem using the default logic.
7
7
  class Filesystem < Base
8
-
9
8
  attr_accessor :root
10
9
 
11
10
  # Creates a new filesystem importer that imports files relative to a given path.
@@ -13,7 +12,8 @@ module Sass
13
12
  # @param root [String] The root path.
14
13
  # This importer will import files relative to this path.
15
14
  def initialize(root)
16
- @root = root
15
+ @root = File.expand_path(root)
16
+ @same_name_warnings = Set.new
17
17
  end
18
18
 
19
19
  # @see Base#find_relative
@@ -28,7 +28,7 @@ module Sass
28
28
 
29
29
  # @see Base#mtime
30
30
  def mtime(name, options)
31
- file, s = find_real_file(@root, name)
31
+ file, _ = Sass::Util.destructure(find_real_file(@root, name, options))
32
32
  File.mtime(file) if file
33
33
  rescue Errno::ENOENT
34
34
  nil
@@ -37,7 +37,7 @@ module Sass
37
37
  # @see Base#key
38
38
  def key(name, options)
39
39
  [self.class.name + ":" + File.dirname(File.expand_path(name)),
40
- File.basename(name)]
40
+ File.basename(name)]
41
41
  end
42
42
 
43
43
  # @see Base#to_s
@@ -45,14 +45,47 @@ module Sass
45
45
  @root
46
46
  end
47
47
 
48
+ def hash
49
+ @root.hash
50
+ end
51
+
52
+ def eql?(other)
53
+ root.eql?(other.root)
54
+ end
55
+
56
+ # @see Base#directories_to_watch
57
+ def directories_to_watch
58
+ [root]
59
+ end
60
+
61
+ # @see Base#watched_file?
62
+ def watched_file?(filename)
63
+ filename =~ /\.s[ac]ss$/ &&
64
+ filename.start_with?(root + File::SEPARATOR)
65
+ end
66
+
67
+ def public_url(name, sourcemap_directory = nil)
68
+ if sourcemap_directory.nil?
69
+ warn_about_public_url(name)
70
+ else
71
+ file_pathname = Sass::Util.pathname(Sass::Util.absolute_path(name, @root)).cleanpath
72
+ sourcemap_pathname = Sass::Util.pathname(sourcemap_directory).cleanpath
73
+ begin
74
+ file_pathname.relative_path_from(sourcemap_pathname).to_s
75
+ rescue ArgumentError # when a relative path cannot be constructed
76
+ warn_about_public_url(name)
77
+ nil
78
+ end
79
+ end
80
+ end
81
+
48
82
  protected
49
83
 
50
84
  # If a full uri is passed, this removes the root from it
51
85
  # otherwise returns the name unchanged
52
86
  def remove_root(name)
53
- root = @root.end_with?('/') ? @root : @root + '/'
54
- if name.index(root) == 0
55
- name[root.length..-1]
87
+ if name.index(@root + "/") == 0
88
+ name[(@root.length + 1)..-1]
56
89
  else
57
90
  name
58
91
  end
@@ -77,31 +110,77 @@ module Sass
77
110
  # The first element of each pair is a filename to look for;
78
111
  # the second element is the syntax that file would be in (`:sass` or `:scss`).
79
112
  def possible_files(name)
113
+ name = escape_glob_characters(name)
80
114
  dirname, basename, extname = split(name)
81
115
  sorted_exts = extensions.sort
82
116
  syntax = extensions[extname]
83
117
 
84
- return [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]] if syntax
85
- sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
118
+ if syntax
119
+ ret = [["#{dirname}/{_,}#{basename}.#{extensions.invert[syntax]}", syntax]]
120
+ else
121
+ ret = sorted_exts.map {|ext, syn| ["#{dirname}/{_,}#{basename}.#{ext}", syn]}
122
+ end
123
+
124
+ # JRuby chokes when trying to import files from JARs when the path starts with './'.
125
+ ret.map {|f, s| [f.sub(/^\.\//, ''), s]}
86
126
  end
87
127
 
128
+ def escape_glob_characters(name)
129
+ name.gsub(/[\*\[\]\{\}\?]/) do |char|
130
+ "\\#{char}"
131
+ end
132
+ end
88
133
 
89
- REDUNDANT_DIRECTORY = %r{#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}}
134
+ REDUNDANT_DIRECTORY = /#{Regexp.escape(File::SEPARATOR)}\.#{Regexp.escape(File::SEPARATOR)}/
90
135
  # Given a base directory and an `@import`ed name,
91
136
  # finds an existant file that matches the name.
92
137
  #
93
138
  # @param dir [String] The directory relative to which to search.
94
139
  # @param name [String] The filename to search for.
95
140
  # @return [(String, Symbol)] A filename-syntax pair.
96
- def find_real_file(dir, name)
97
- for (f,s) in possible_files(remove_root(name))
98
- path = (dir == ".") ? f : "#{dir}/#{f}"
99
- if full_path = Dir[path].first
100
- full_path.gsub!(REDUNDANT_DIRECTORY,File::SEPARATOR)
101
- return full_path, s
141
+ def find_real_file(dir, name, options)
142
+ # on windows 'dir' can be in native File::ALT_SEPARATOR form
143
+ dir = dir.gsub(File::ALT_SEPARATOR, File::SEPARATOR) unless File::ALT_SEPARATOR.nil?
144
+
145
+ found = possible_files(remove_root(name)).map do |f, s|
146
+ path = (dir == "." || Sass::Util.pathname(f).absolute?) ? f :
147
+ "#{escape_glob_characters(dir)}/#{f}"
148
+ Dir[path].map do |full_path|
149
+ full_path.gsub!(REDUNDANT_DIRECTORY, File::SEPARATOR)
150
+ [Sass::Util.pathname(full_path).cleanpath.to_s, s]
102
151
  end
103
152
  end
104
- nil
153
+ found = Sass::Util.flatten(found, 1)
154
+ return if found.empty?
155
+
156
+ if found.size > 1 && !@same_name_warnings.include?(found.first.first)
157
+ found.each {|(f, _)| @same_name_warnings << f}
158
+ relative_to = Sass::Util.pathname(dir)
159
+ if options[:_from_import_node]
160
+ # If _line exists, we're here due to an actual import in an
161
+ # import_node and we want to print a warning for a user writing an
162
+ # ambiguous import.
163
+ candidates = found.map do |(f, _)|
164
+ " " + Sass::Util.pathname(f).relative_path_from(relative_to).to_s
165
+ end.join("\n")
166
+ raise Sass::SyntaxError.new(<<MESSAGE)
167
+ It's not clear which file to import for '@import "#{name}"'.
168
+ Candidates:
169
+ #{candidates}
170
+ Please delete or rename all but one of these files.
171
+ MESSAGE
172
+ else
173
+ # Otherwise, we're here via StalenessChecker, and we want to print a
174
+ # warning for a user running `sass --watch` with two ambiguous files.
175
+ candidates = found.map {|(f, _)| " " + File.basename(f)}.join("\n")
176
+ Sass::Util.sass_warn <<WARNING
177
+ WARNING: In #{File.dirname(name)}:
178
+ There are multiple files that match the name "#{File.basename(name)}":
179
+ #{candidates}
180
+ WARNING
181
+ end
182
+ end
183
+ found.first
105
184
  end
106
185
 
107
186
  # Splits a filename into three parts, a directory part, a basename, and an extension
@@ -109,25 +188,33 @@ module Sass
109
188
  def split(name)
110
189
  extension = nil
111
190
  dirname, basename = File.dirname(name), File.basename(name)
112
- if basename =~ /^(.*)\.(#{extensions.keys.map{|e| Regexp.escape(e)}.join('|')})$/
191
+ if basename =~ /^(.*)\.(#{extensions.keys.map {|e| Regexp.escape(e)}.join('|')})$/
113
192
  basename = $1
114
193
  extension = $2
115
194
  end
116
195
  [dirname, basename, extension]
117
196
  end
118
197
 
119
- def hash
120
- @root.hash
121
- end
122
-
123
- def eql?(other)
124
- root.eql?(other.root)
198
+ # Issues a warning about being unable to determine a public url.
199
+ #
200
+ # @param uri [String] A URI known to be valid for this importer.
201
+ # @return [NilClass] nil
202
+ def warn_about_public_url(uri)
203
+ @warnings_issued ||= Set.new
204
+ unless @warnings_issued.include?(uri)
205
+ Sass::Util.sass_warn <<WARNING
206
+ WARNING: Couldn't determine public URL for "#{uri}" while generating sourcemap.
207
+ Without a public URL, there's nothing for the source map to link to.
208
+ WARNING
209
+ @warnings_issued << uri
210
+ end
211
+ nil
125
212
  end
126
213
 
127
214
  private
128
215
 
129
216
  def _find(dir, name, options)
130
- full_filename, syntax = find_real_file(dir, name)
217
+ full_filename, syntax = Sass::Util.destructure(find_real_file(dir, name, options))
131
218
  return unless full_filename && File.readable?(full_filename)
132
219
 
133
220
  options[:syntax] = syntax
@@ -135,10 +222,6 @@ module Sass
135
222
  options[:importer] = self
136
223
  Sass::Engine.new(File.read(full_filename), options)
137
224
  end
138
-
139
- def join(base, path)
140
- Pathname.new(base).join(path).to_s
141
- end
142
225
  end
143
226
  end
144
227
  end
@@ -20,3 +20,4 @@ end
20
20
 
21
21
  require 'sass/importers/base'
22
22
  require 'sass/importers/filesystem'
23
+ require 'sass/importers/deprecated_path'
@@ -0,0 +1,30 @@
1
+ require 'sass/logger/log_level'
2
+
3
+ class Sass::Logger::Base
4
+ include Sass::Logger::LogLevel
5
+
6
+ attr_accessor :log_level
7
+ attr_accessor :disabled
8
+
9
+ log_level :trace
10
+ log_level :debug
11
+ log_level :info
12
+ log_level :warn
13
+ log_level :error
14
+
15
+ def initialize(log_level = :debug)
16
+ self.log_level = log_level
17
+ end
18
+
19
+ def logging_level?(level)
20
+ !disabled && self.class.log_level?(level, log_level)
21
+ end
22
+
23
+ def log(level, message)
24
+ _log(level, message) if logging_level?(level)
25
+ end
26
+
27
+ def _log(level, message)
28
+ Kernel.warn(message)
29
+ end
30
+ end
@@ -0,0 +1,45 @@
1
+ module Sass
2
+ module Logger
3
+ module LogLevel
4
+ def self.included(base)
5
+ base.extend(ClassMethods)
6
+ end
7
+
8
+ module ClassMethods
9
+ def inherited(subclass)
10
+ subclass.log_levels = subclass.superclass.log_levels.dup
11
+ end
12
+
13
+ attr_writer :log_levels
14
+
15
+ def log_levels
16
+ @log_levels ||= {}
17
+ end
18
+
19
+ def log_level?(level, min_level)
20
+ log_levels[level] >= log_levels[min_level]
21
+ end
22
+
23
+ def log_level(name, options = {})
24
+ if options[:prepend]
25
+ level = log_levels.values.min
26
+ level = level.nil? ? 0 : level - 1
27
+ else
28
+ level = log_levels.values.max
29
+ level = level.nil? ? 0 : level + 1
30
+ end
31
+ log_levels.update(name => level)
32
+ define_logger(name)
33
+ end
34
+
35
+ def define_logger(name, options = {})
36
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
37
+ def #{name}(message)
38
+ #{options.fetch(:to, :log)}(#{name.inspect}, message)
39
+ end
40
+ RUBY
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,12 @@
1
+ module Sass::Logger; end
2
+
3
+ require "sass/logger/log_level"
4
+ require "sass/logger/base"
5
+
6
+ module Sass
7
+ class << self
8
+ attr_accessor :logger
9
+ end
10
+
11
+ self.logger = Sass::Logger::Base.new
12
+ end
data/lib/sass/media.rb ADDED
@@ -0,0 +1,213 @@
1
+ # A namespace for the `@media` query parse tree.
2
+ module Sass::Media
3
+ # A comma-separated list of queries.
4
+ #
5
+ # media_query [ ',' S* media_query ]*
6
+ class QueryList
7
+ # The queries contained in this list.
8
+ #
9
+ # @return [Array<Query>]
10
+ attr_accessor :queries
11
+
12
+ # @param queries [Array<Query>] See \{#queries}
13
+ def initialize(queries)
14
+ @queries = queries
15
+ end
16
+
17
+ # Merges this query list with another. The returned query list
18
+ # queries for the intersection between the two inputs.
19
+ #
20
+ # Both query lists should be resolved.
21
+ #
22
+ # @param other [QueryList]
23
+ # @return [QueryList?] The merged list, or nil if there is no intersection.
24
+ def merge(other)
25
+ new_queries = queries.map {|q1| other.queries.map {|q2| q1.merge(q2)}}.flatten.compact
26
+ return if new_queries.empty?
27
+ QueryList.new(new_queries)
28
+ end
29
+
30
+ # Returns the CSS for the media query list.
31
+ #
32
+ # @return [String]
33
+ def to_css
34
+ queries.map {|q| q.to_css}.join(', ')
35
+ end
36
+
37
+ # Returns the Sass/SCSS code for the media query list.
38
+ #
39
+ # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
40
+ # @return [String]
41
+ def to_src(options)
42
+ queries.map {|q| q.to_src(options)}.join(', ')
43
+ end
44
+
45
+ # Returns a representation of the query as an array of strings and
46
+ # potentially {Sass::Script::Tree::Node}s (if there's interpolation in it).
47
+ # When the interpolation is resolved and the strings are joined together,
48
+ # this will be the string representation of this query.
49
+ #
50
+ # @return [Array<String, Sass::Script::Tree::Node>]
51
+ def to_a
52
+ Sass::Util.intersperse(queries.map {|q| q.to_a}, ', ').flatten
53
+ end
54
+
55
+ # Returns a deep copy of this query list and all its children.
56
+ #
57
+ # @return [QueryList]
58
+ def deep_copy
59
+ QueryList.new(queries.map {|q| q.deep_copy})
60
+ end
61
+ end
62
+
63
+ # A single media query.
64
+ #
65
+ # [ [ONLY | NOT]? S* media_type S* | expression ] [ AND S* expression ]*
66
+ class Query
67
+ # The modifier for the query.
68
+ #
69
+ # When parsed as Sass code, this contains strings and SassScript nodes. When
70
+ # parsed as CSS, it contains a single string (accessible via
71
+ # \{#resolved_modifier}).
72
+ #
73
+ # @return [Array<String, Sass::Script::Tree::Node>]
74
+ attr_accessor :modifier
75
+
76
+ # The type of the query (e.g. `"screen"` or `"print"`).
77
+ #
78
+ # When parsed as Sass code, this contains strings and SassScript nodes. When
79
+ # parsed as CSS, it contains a single string (accessible via
80
+ # \{#resolved_type}).
81
+ #
82
+ # @return [Array<String, Sass::Script::Tree::Node>]
83
+ attr_accessor :type
84
+
85
+ # The trailing expressions in the query.
86
+ #
87
+ # When parsed as Sass code, each expression contains strings and SassScript
88
+ # nodes. When parsed as CSS, each one contains a single string.
89
+ #
90
+ # @return [Array<Array<String, Sass::Script::Tree::Node>>]
91
+ attr_accessor :expressions
92
+
93
+ # @param modifier [Array<String, Sass::Script::Tree::Node>] See \{#modifier}
94
+ # @param type [Array<String, Sass::Script::Tree::Node>] See \{#type}
95
+ # @param expressions [Array<Array<String, Sass::Script::Tree::Node>>] See \{#expressions}
96
+ def initialize(modifier, type, expressions)
97
+ @modifier = modifier
98
+ @type = type
99
+ @expressions = expressions
100
+ end
101
+
102
+ # See \{#modifier}.
103
+ # @return [String]
104
+ def resolved_modifier
105
+ # modifier should contain only a single string
106
+ modifier.first || ''
107
+ end
108
+
109
+ # See \{#type}.
110
+ # @return [String]
111
+ def resolved_type
112
+ # type should contain only a single string
113
+ type.first || ''
114
+ end
115
+
116
+ # Merges this query with another. The returned query queries for
117
+ # the intersection between the two inputs.
118
+ #
119
+ # Both queries should be resolved.
120
+ #
121
+ # @param other [Query]
122
+ # @return [Query?] The merged query, or nil if there is no intersection.
123
+ def merge(other)
124
+ m1, t1 = resolved_modifier.downcase, resolved_type.downcase
125
+ m2, t2 = other.resolved_modifier.downcase, other.resolved_type.downcase
126
+ t1 = t2 if t1.empty?
127
+ t2 = t1 if t2.empty?
128
+ if (m1 == 'not') ^ (m2 == 'not')
129
+ return if t1 == t2
130
+ type = m1 == 'not' ? t2 : t1
131
+ mod = m1 == 'not' ? m2 : m1
132
+ elsif m1 == 'not' && m2 == 'not'
133
+ # CSS has no way of representing "neither screen nor print"
134
+ return unless t1 == t2
135
+ type = t1
136
+ mod = 'not'
137
+ elsif t1 != t2
138
+ return
139
+ else # t1 == t2, neither m1 nor m2 are "not"
140
+ type = t1
141
+ mod = m1.empty? ? m2 : m1
142
+ end
143
+ Query.new([mod], [type], other.expressions + expressions)
144
+ end
145
+
146
+ # Returns the CSS for the media query.
147
+ #
148
+ # @return [String]
149
+ def to_css
150
+ css = ''
151
+ css << resolved_modifier
152
+ css << ' ' unless resolved_modifier.empty?
153
+ css << resolved_type
154
+ css << ' and ' unless resolved_type.empty? || expressions.empty?
155
+ css << expressions.map do |e|
156
+ # It's possible for there to be script nodes in Expressions even when
157
+ # we're converting to CSS in the case where we parsed the document as
158
+ # CSS originally (as in css_test.rb).
159
+ e.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.to_sass : c.to_s}.join
160
+ end.join(' and ')
161
+ css
162
+ end
163
+
164
+ # Returns the Sass/SCSS code for the media query.
165
+ #
166
+ # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
167
+ # @return [String]
168
+ def to_src(options)
169
+ src = ''
170
+ src << Sass::Media._interp_to_src(modifier, options)
171
+ src << ' ' unless modifier.empty?
172
+ src << Sass::Media._interp_to_src(type, options)
173
+ src << ' and ' unless type.empty? || expressions.empty?
174
+ src << expressions.map do |e|
175
+ Sass::Media._interp_to_src(e, options)
176
+ end.join(' and ')
177
+ src
178
+ end
179
+
180
+ # @see \{MediaQuery#to\_a}
181
+ def to_a
182
+ res = []
183
+ res += modifier
184
+ res << ' ' unless modifier.empty?
185
+ res += type
186
+ res << ' and ' unless type.empty? || expressions.empty?
187
+ res += Sass::Util.intersperse(expressions, ' and ').flatten
188
+ res
189
+ end
190
+
191
+ # Returns a deep copy of this query and all its children.
192
+ #
193
+ # @return [Query]
194
+ def deep_copy
195
+ Query.new(
196
+ modifier.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c},
197
+ type.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c},
198
+ expressions.map {|e| e.map {|c| c.is_a?(Sass::Script::Tree::Node) ? c.deep_copy : c}})
199
+ end
200
+ end
201
+
202
+ # Converts an interpolation array to source.
203
+ #
204
+ # @param interp [Array<String, Sass::Script::Tree::Node>] The interpolation array to convert.
205
+ # @param options [{Symbol => Object}] An options hash (see {Sass::CSS#initialize}).
206
+ # @return [String]
207
+ def self._interp_to_src(interp, options)
208
+ interp.map do |r|
209
+ next r if r.is_a?(String)
210
+ "\#{#{r.to_sass(options)}}"
211
+ end.join
212
+ end
213
+ end