sass 3.1.0 → 3.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CONTRIBUTING +1 -1
- data/MIT-LICENSE +2 -2
- data/README.md +29 -17
- data/Rakefile +43 -9
- data/VERSION +1 -1
- data/VERSION_DATE +1 -0
- data/VERSION_NAME +1 -1
- data/bin/sass +6 -1
- data/bin/sass-convert +6 -1
- data/bin/scss +6 -1
- data/ext/mkrf_conf.rb +27 -0
- data/lib/sass/cache_stores/base.rb +7 -3
- data/lib/sass/cache_stores/chain.rb +3 -2
- data/lib/sass/cache_stores/filesystem.rb +5 -7
- data/lib/sass/cache_stores/memory.rb +1 -1
- data/lib/sass/cache_stores/null.rb +2 -2
- data/lib/sass/callbacks.rb +2 -1
- data/lib/sass/css.rb +168 -53
- data/lib/sass/engine.rb +502 -174
- data/lib/sass/environment.rb +151 -111
- data/lib/sass/error.rb +7 -7
- data/lib/sass/exec.rb +176 -60
- data/lib/sass/features.rb +40 -0
- data/lib/sass/importers/base.rb +46 -7
- data/lib/sass/importers/deprecated_path.rb +51 -0
- data/lib/sass/importers/filesystem.rb +113 -30
- data/lib/sass/importers.rb +1 -0
- data/lib/sass/logger/base.rb +30 -0
- data/lib/sass/logger/log_level.rb +45 -0
- data/lib/sass/logger.rb +12 -0
- data/lib/sass/media.rb +213 -0
- data/lib/sass/plugin/compiler.rb +194 -104
- data/lib/sass/plugin/configuration.rb +18 -25
- data/lib/sass/plugin/merb.rb +1 -1
- data/lib/sass/plugin/staleness_checker.rb +37 -11
- data/lib/sass/plugin.rb +10 -13
- data/lib/sass/railtie.rb +2 -1
- data/lib/sass/repl.rb +5 -6
- data/lib/sass/script/css_lexer.rb +8 -4
- data/lib/sass/script/css_parser.rb +5 -2
- data/lib/sass/script/functions.rb +1547 -618
- data/lib/sass/script/lexer.rb +122 -72
- data/lib/sass/script/parser.rb +304 -135
- data/lib/sass/script/tree/funcall.rb +306 -0
- data/lib/sass/script/{interpolation.rb → tree/interpolation.rb} +43 -13
- data/lib/sass/script/tree/list_literal.rb +77 -0
- data/lib/sass/script/tree/literal.rb +45 -0
- data/lib/sass/script/tree/map_literal.rb +64 -0
- data/lib/sass/script/{node.rb → tree/node.rb} +30 -12
- data/lib/sass/script/{operation.rb → tree/operation.rb} +33 -21
- data/lib/sass/script/{string_interpolation.rb → tree/string_interpolation.rb} +14 -4
- data/lib/sass/script/{unary_operation.rb → tree/unary_operation.rb} +21 -9
- data/lib/sass/script/tree/variable.rb +57 -0
- data/lib/sass/script/tree.rb +15 -0
- data/lib/sass/script/value/arg_list.rb +36 -0
- data/lib/sass/script/value/base.rb +238 -0
- data/lib/sass/script/value/bool.rb +40 -0
- data/lib/sass/script/{color.rb → value/color.rb} +256 -74
- data/lib/sass/script/value/deprecated_false.rb +55 -0
- data/lib/sass/script/value/helpers.rb +155 -0
- data/lib/sass/script/value/list.rb +128 -0
- data/lib/sass/script/value/map.rb +70 -0
- data/lib/sass/script/value/null.rb +49 -0
- data/lib/sass/script/{number.rb → value/number.rb} +115 -62
- data/lib/sass/script/{string.rb → value/string.rb} +9 -11
- data/lib/sass/script/value.rb +12 -0
- data/lib/sass/script.rb +35 -9
- data/lib/sass/scss/css_parser.rb +2 -12
- data/lib/sass/scss/parser.rb +657 -230
- data/lib/sass/scss/rx.rb +17 -12
- data/lib/sass/scss/static_parser.rb +37 -6
- data/lib/sass/scss.rb +0 -1
- data/lib/sass/selector/abstract_sequence.rb +35 -3
- data/lib/sass/selector/comma_sequence.rb +29 -14
- data/lib/sass/selector/sequence.rb +371 -74
- data/lib/sass/selector/simple.rb +28 -13
- data/lib/sass/selector/simple_sequence.rb +163 -36
- data/lib/sass/selector.rb +138 -36
- data/lib/sass/shared.rb +3 -5
- data/lib/sass/source/map.rb +196 -0
- data/lib/sass/source/position.rb +39 -0
- data/lib/sass/source/range.rb +41 -0
- data/lib/sass/stack.rb +126 -0
- data/lib/sass/supports.rb +228 -0
- data/lib/sass/tree/at_root_node.rb +82 -0
- data/lib/sass/tree/comment_node.rb +34 -29
- data/lib/sass/tree/content_node.rb +9 -0
- data/lib/sass/tree/css_import_node.rb +60 -0
- data/lib/sass/tree/debug_node.rb +3 -3
- data/lib/sass/tree/directive_node.rb +33 -3
- data/lib/sass/tree/each_node.rb +9 -9
- data/lib/sass/tree/extend_node.rb +20 -6
- data/lib/sass/tree/for_node.rb +6 -6
- data/lib/sass/tree/function_node.rb +12 -4
- data/lib/sass/tree/if_node.rb +2 -15
- data/lib/sass/tree/import_node.rb +11 -5
- data/lib/sass/tree/media_node.rb +27 -11
- data/lib/sass/tree/mixin_def_node.rb +15 -4
- data/lib/sass/tree/mixin_node.rb +27 -7
- data/lib/sass/tree/node.rb +69 -35
- data/lib/sass/tree/prop_node.rb +47 -31
- data/lib/sass/tree/return_node.rb +4 -3
- data/lib/sass/tree/root_node.rb +20 -4
- data/lib/sass/tree/rule_node.rb +37 -26
- data/lib/sass/tree/supports_node.rb +38 -0
- data/lib/sass/tree/trace_node.rb +33 -0
- data/lib/sass/tree/variable_node.rb +10 -4
- data/lib/sass/tree/visitors/base.rb +5 -8
- data/lib/sass/tree/visitors/check_nesting.rb +67 -52
- data/lib/sass/tree/visitors/convert.rb +134 -53
- data/lib/sass/tree/visitors/cssize.rb +245 -51
- data/lib/sass/tree/visitors/deep_copy.rb +102 -0
- data/lib/sass/tree/visitors/extend.rb +68 -0
- data/lib/sass/tree/visitors/perform.rb +331 -105
- data/lib/sass/tree/visitors/set_options.rb +125 -0
- data/lib/sass/tree/visitors/to_css.rb +259 -95
- data/lib/sass/tree/warn_node.rb +3 -3
- data/lib/sass/tree/while_node.rb +3 -3
- data/lib/sass/util/cross_platform_random.rb +19 -0
- data/lib/sass/util/multibyte_string_scanner.rb +157 -0
- data/lib/sass/util/normalized_map.rb +130 -0
- data/lib/sass/util/ordered_hash.rb +192 -0
- data/lib/sass/util/subset_map.rb +11 -2
- data/lib/sass/util/test.rb +9 -0
- data/lib/sass/util.rb +565 -39
- data/lib/sass/version.rb +27 -15
- data/lib/sass.rb +39 -4
- data/test/sass/cache_test.rb +15 -0
- data/test/sass/compiler_test.rb +223 -0
- data/test/sass/conversion_test.rb +901 -107
- data/test/sass/css2sass_test.rb +94 -0
- data/test/sass/engine_test.rb +1059 -164
- data/test/sass/exec_test.rb +86 -0
- data/test/sass/extend_test.rb +933 -837
- data/test/sass/fixtures/test_staleness_check_across_importers.css +1 -0
- data/test/sass/fixtures/test_staleness_check_across_importers.scss +1 -0
- data/test/sass/functions_test.rb +995 -136
- data/test/sass/importer_test.rb +338 -18
- data/test/sass/logger_test.rb +58 -0
- data/test/sass/more_results/more_import.css +2 -2
- data/test/sass/plugin_test.rb +114 -30
- data/test/sass/results/cached_import_option.css +3 -0
- data/test/sass/results/filename_fn.css +3 -0
- data/test/sass/results/import.css +2 -2
- data/test/sass/results/import_charset.css +1 -0
- data/test/sass/results/import_charset_1_8.css +1 -0
- data/test/sass/results/import_charset_ibm866.css +1 -0
- data/test/sass/results/import_content.css +1 -0
- data/test/sass/results/script.css +1 -1
- data/test/sass/results/scss_import.css +2 -2
- data/test/sass/results/units.css +2 -2
- data/test/sass/script_conversion_test.rb +43 -1
- data/test/sass/script_test.rb +380 -36
- data/test/sass/scss/css_test.rb +257 -75
- data/test/sass/scss/scss_test.rb +2322 -110
- data/test/sass/source_map_test.rb +887 -0
- data/test/sass/templates/_cached_import_option_partial.scss +1 -0
- data/test/sass/templates/_double_import_loop2.sass +1 -0
- data/test/sass/templates/_filename_fn_import.scss +11 -0
- data/test/sass/templates/_imported_content.sass +3 -0
- data/test/sass/templates/_same_name_different_partiality.scss +1 -0
- data/test/sass/templates/bork5.sass +3 -0
- data/test/sass/templates/cached_import_option.scss +3 -0
- data/test/sass/templates/double_import_loop1.sass +1 -0
- data/test/sass/templates/filename_fn.scss +18 -0
- data/test/sass/templates/import_charset.sass +2 -0
- data/test/sass/templates/import_charset_1_8.sass +2 -0
- data/test/sass/templates/import_charset_ibm866.sass +2 -0
- data/test/sass/templates/import_content.sass +4 -0
- data/test/sass/templates/same_name_different_ext.sass +2 -0
- data/test/sass/templates/same_name_different_ext.scss +1 -0
- data/test/sass/templates/same_name_different_partiality.scss +1 -0
- data/test/sass/templates/single_import_loop.sass +1 -0
- data/test/sass/templates/subdir/import_up1.scss +1 -0
- data/test/sass/templates/subdir/import_up2.scss +1 -0
- data/test/sass/test_helper.rb +1 -1
- data/test/sass/util/multibyte_string_scanner_test.rb +147 -0
- data/test/sass/util/normalized_map_test.rb +51 -0
- data/test/sass/util_test.rb +183 -0
- data/test/sass/value_helpers_test.rb +181 -0
- data/test/test_helper.rb +45 -5
- data/vendor/listen/CHANGELOG.md +228 -0
- data/vendor/listen/CONTRIBUTING.md +38 -0
- data/vendor/listen/Gemfile +30 -0
- data/vendor/listen/Guardfile +8 -0
- data/vendor/{fssm → listen}/LICENSE +1 -1
- data/vendor/listen/README.md +315 -0
- data/vendor/listen/Rakefile +47 -0
- data/vendor/listen/Vagrantfile +96 -0
- data/vendor/listen/lib/listen/adapter.rb +214 -0
- data/vendor/listen/lib/listen/adapters/bsd.rb +112 -0
- data/vendor/listen/lib/listen/adapters/darwin.rb +85 -0
- data/vendor/listen/lib/listen/adapters/linux.rb +113 -0
- data/vendor/listen/lib/listen/adapters/polling.rb +67 -0
- data/vendor/listen/lib/listen/adapters/windows.rb +87 -0
- data/vendor/listen/lib/listen/dependency_manager.rb +126 -0
- data/vendor/listen/lib/listen/directory_record.rb +371 -0
- data/vendor/listen/lib/listen/listener.rb +225 -0
- data/vendor/listen/lib/listen/multi_listener.rb +143 -0
- data/vendor/listen/lib/listen/turnstile.rb +28 -0
- data/vendor/listen/lib/listen/version.rb +3 -0
- data/vendor/listen/lib/listen.rb +40 -0
- data/vendor/listen/listen.gemspec +22 -0
- data/vendor/listen/spec/listen/adapter_spec.rb +183 -0
- data/vendor/listen/spec/listen/adapters/bsd_spec.rb +36 -0
- data/vendor/listen/spec/listen/adapters/darwin_spec.rb +37 -0
- data/vendor/listen/spec/listen/adapters/linux_spec.rb +47 -0
- data/vendor/listen/spec/listen/adapters/polling_spec.rb +68 -0
- data/vendor/listen/spec/listen/adapters/windows_spec.rb +30 -0
- data/vendor/listen/spec/listen/dependency_manager_spec.rb +107 -0
- data/vendor/listen/spec/listen/directory_record_spec.rb +1225 -0
- data/vendor/listen/spec/listen/listener_spec.rb +169 -0
- data/vendor/listen/spec/listen/multi_listener_spec.rb +174 -0
- data/vendor/listen/spec/listen/turnstile_spec.rb +56 -0
- data/vendor/listen/spec/listen_spec.rb +73 -0
- data/vendor/listen/spec/spec_helper.rb +21 -0
- data/vendor/listen/spec/support/adapter_helper.rb +629 -0
- data/vendor/listen/spec/support/directory_record_helper.rb +55 -0
- data/vendor/listen/spec/support/fixtures_helper.rb +29 -0
- data/vendor/listen/spec/support/listeners_helper.rb +156 -0
- data/vendor/listen/spec/support/platform_helper.rb +15 -0
- metadata +344 -271
- data/lib/sass/less.rb +0 -382
- data/lib/sass/script/bool.rb +0 -18
- data/lib/sass/script/funcall.rb +0 -162
- data/lib/sass/script/list.rb +0 -76
- data/lib/sass/script/literal.rb +0 -245
- data/lib/sass/script/variable.rb +0 -54
- data/lib/sass/scss/sass_parser.rb +0 -11
- data/test/sass/less_conversion_test.rb +0 -653
- data/vendor/fssm/README.markdown +0 -55
- data/vendor/fssm/Rakefile +0 -59
- data/vendor/fssm/VERSION.yml +0 -5
- data/vendor/fssm/example.rb +0 -9
- data/vendor/fssm/fssm.gemspec +0 -77
- data/vendor/fssm/lib/fssm/backends/fsevents.rb +0 -36
- data/vendor/fssm/lib/fssm/backends/inotify.rb +0 -26
- data/vendor/fssm/lib/fssm/backends/polling.rb +0 -25
- data/vendor/fssm/lib/fssm/backends/rubycocoa/fsevents.rb +0 -131
- data/vendor/fssm/lib/fssm/monitor.rb +0 -26
- data/vendor/fssm/lib/fssm/path.rb +0 -91
- data/vendor/fssm/lib/fssm/pathname.rb +0 -502
- data/vendor/fssm/lib/fssm/state/directory.rb +0 -57
- data/vendor/fssm/lib/fssm/state/file.rb +0 -24
- data/vendor/fssm/lib/fssm/support.rb +0 -63
- data/vendor/fssm/lib/fssm/tree.rb +0 -176
- data/vendor/fssm/lib/fssm.rb +0 -33
- data/vendor/fssm/profile/prof-cache.rb +0 -40
- data/vendor/fssm/profile/prof-fssm-pathname.html +0 -1231
- data/vendor/fssm/profile/prof-pathname.rb +0 -68
- data/vendor/fssm/profile/prof-plain-pathname.html +0 -988
- data/vendor/fssm/profile/prof.html +0 -2379
- data/vendor/fssm/spec/path_spec.rb +0 -75
- data/vendor/fssm/spec/root/duck/quack.txt +0 -0
- data/vendor/fssm/spec/root/file.css +0 -0
- data/vendor/fssm/spec/root/file.rb +0 -0
- data/vendor/fssm/spec/root/file.yml +0 -0
- data/vendor/fssm/spec/root/moo/cow.txt +0 -0
- data/vendor/fssm/spec/spec_helper.rb +0 -14
data/lib/sass/plugin/compiler.rb
CHANGED
@@ -7,7 +7,6 @@ require 'sass/plugin/configuration'
|
|
7
7
|
require 'sass/plugin/staleness_checker'
|
8
8
|
|
9
9
|
module Sass::Plugin
|
10
|
-
|
11
10
|
# The Compiler class handles compilation of multiple files and/or directories,
|
12
11
|
# including checking which CSS files are out-of-date and need to be updated
|
13
12
|
# and calling Sass to perform the compilation on those files.
|
@@ -26,19 +25,18 @@ module Sass::Plugin
|
|
26
25
|
# * `:never_update`
|
27
26
|
# * `:always_check`
|
28
27
|
class Compiler
|
29
|
-
include Sass::Util
|
30
28
|
include Configuration
|
31
29
|
extend Sass::Callbacks
|
32
30
|
|
33
31
|
# Creates a new compiler.
|
34
32
|
#
|
35
|
-
# @param
|
33
|
+
# @param opts [{Symbol => Object}]
|
36
34
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
37
|
-
def initialize(
|
38
|
-
|
35
|
+
def initialize(opts = {})
|
36
|
+
options.merge!(opts)
|
39
37
|
end
|
40
38
|
|
41
|
-
# Register a callback to be run
|
39
|
+
# Register a callback to be run after stylesheets are mass-updated.
|
42
40
|
# This is run whenever \{#update\_stylesheets} is called,
|
43
41
|
# unless the \{file:SASS_REFERENCE.md#never_update-option `:never_update` option}
|
44
42
|
# is enabled.
|
@@ -51,8 +49,8 @@ module Sass::Plugin
|
|
51
49
|
# the second is the target CSS file.
|
52
50
|
define_callback :updating_stylesheets
|
53
51
|
|
54
|
-
# Register a callback to be run
|
55
|
-
# The callback is only run if the stylesheet is
|
52
|
+
# Register a callback to be run after a single stylesheet is updated.
|
53
|
+
# The callback is only run if the stylesheet is really updated;
|
56
54
|
# if the CSS file is fresh, this won't be run.
|
57
55
|
#
|
58
56
|
# Even if the \{file:SASS_REFERENCE.md#full_exception-option `:full_exception` option}
|
@@ -60,12 +58,14 @@ module Sass::Plugin
|
|
60
58
|
# when an exception CSS file is being written.
|
61
59
|
# To run an action for those files, use \{#on\_compilation\_error}.
|
62
60
|
#
|
63
|
-
# @yield [template, css]
|
61
|
+
# @yield [template, css, sourcemap]
|
64
62
|
# @yieldparam template [String]
|
65
63
|
# The location of the Sass/SCSS file being updated.
|
66
64
|
# @yieldparam css [String]
|
67
65
|
# The location of the CSS file being generated.
|
68
|
-
|
66
|
+
# @yieldparam sourcemap [String]
|
67
|
+
# The location of the sourcemap being generated, if any.
|
68
|
+
define_callback :updated_stylesheet
|
69
69
|
|
70
70
|
# Register a callback to be run when Sass decides not to update a stylesheet.
|
71
71
|
# In particular, the callback is run when Sass finds that
|
@@ -146,9 +146,18 @@ module Sass::Plugin
|
|
146
146
|
# The location of the CSS file that was deleted.
|
147
147
|
define_callback :deleting_css
|
148
148
|
|
149
|
+
# Register a callback to be run when Sass deletes a sourcemap file.
|
150
|
+
# This happens when the corresponding Sass/SCSS file has been deleted.
|
151
|
+
#
|
152
|
+
# @yield [filename]
|
153
|
+
# @yieldparam filename [String]
|
154
|
+
# The location of the sourcemap file that was deleted.
|
155
|
+
define_callback :deleting_sourcemap
|
156
|
+
|
149
157
|
# Updates out-of-date stylesheets.
|
150
158
|
#
|
151
|
-
# Checks each Sass/SCSS file in
|
159
|
+
# Checks each Sass/SCSS file in
|
160
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
152
161
|
# to see if it's been modified more recently than the corresponding CSS file
|
153
162
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
154
163
|
# If it has, it updates the CSS file.
|
@@ -160,28 +169,26 @@ module Sass::Plugin
|
|
160
169
|
# The first string in each pair is the location of the Sass/SCSS file,
|
161
170
|
# the second is the location of the CSS file that it should be compiled to.
|
162
171
|
def update_stylesheets(individual_files = [])
|
163
|
-
|
172
|
+
individual_files = individual_files.dup
|
164
173
|
Sass::Plugin.checked_for_updates = true
|
165
174
|
staleness_checker = StalenessChecker.new(engine_options)
|
166
175
|
|
167
|
-
individual_files.each do |t, c|
|
168
|
-
if options[:always_update] || staleness_checker.stylesheet_needs_update?(c, t)
|
169
|
-
update_stylesheet(t, c)
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
176
|
template_location_array.each do |template_location, css_location|
|
174
|
-
|
175
|
-
Dir.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
|
177
|
+
Sass::Util.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
|
176
178
|
# Get the relative path to the file
|
177
179
|
name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
|
178
180
|
css = css_filename(name, css_location)
|
181
|
+
sourcemap = Sass::Util.sourcemap_name(css) if engine_options[:sourcemap]
|
182
|
+
individual_files << [file, css, sourcemap]
|
183
|
+
end
|
184
|
+
end
|
179
185
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
186
|
+
individual_files.each do |file, css, sourcemap|
|
187
|
+
# TODO: Does staleness_checker need to check the sourcemap file as well?
|
188
|
+
if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
|
189
|
+
update_stylesheet(file, css, sourcemap)
|
190
|
+
else
|
191
|
+
run_not_updating_stylesheet(file, css, sourcemap)
|
185
192
|
end
|
186
193
|
end
|
187
194
|
end
|
@@ -198,10 +205,10 @@ module Sass::Plugin
|
|
198
205
|
#
|
199
206
|
# Before the watching starts in earnest, `watch` calls \{#update\_stylesheets}.
|
200
207
|
#
|
201
|
-
# Note that `watch` uses the [
|
208
|
+
# Note that `watch` uses the [Listen](http://github.com/guard/listen) library
|
202
209
|
# to monitor the filesystem for changes.
|
203
|
-
#
|
204
|
-
# The version of
|
210
|
+
# Listen isn't loaded until `watch` is run.
|
211
|
+
# The version of Listen distributed with Sass is loaded by default,
|
205
212
|
# but if another version has already been loaded that will be used instead.
|
206
213
|
#
|
207
214
|
# @param individual_files [Array<(String, String)>]
|
@@ -213,79 +220,78 @@ module Sass::Plugin
|
|
213
220
|
def watch(individual_files = [])
|
214
221
|
update_stylesheets(individual_files)
|
215
222
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
dir = Sass::Util.scope("vendor/fssm/lib")
|
220
|
-
if $LOAD_PATH.include?(dir)
|
221
|
-
e.message << "\n" <<
|
222
|
-
if File.exists?(scope(".git"))
|
223
|
-
'Run "git submodule update --init" to get the recommended version.'
|
224
|
-
else
|
225
|
-
'Run "gem install fssm" to get it.'
|
226
|
-
end
|
227
|
-
raise e
|
228
|
-
else
|
229
|
-
$LOAD_PATH.unshift dir
|
230
|
-
retry
|
231
|
-
end
|
232
|
-
end
|
233
|
-
|
234
|
-
unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
|
235
|
-
# As of FSSM 0.1.4, it doesn't support FSevents on individual files,
|
236
|
-
# but it also isn't smart enough to switch to polling itself.
|
237
|
-
require 'fssm/backends/polling'
|
238
|
-
Sass::Util.silence_warnings do
|
239
|
-
FSSM::Backends.const_set(:Default, FSSM::Backends::Polling)
|
240
|
-
end
|
223
|
+
directories = watched_paths
|
224
|
+
individual_files.each do |(source, _, _)|
|
225
|
+
directories << File.dirname(File.expand_path(source))
|
241
226
|
end
|
227
|
+
directories = remove_redundant_directories(directories)
|
242
228
|
|
243
229
|
# TODO: Keep better track of what depends on what
|
244
230
|
# so we don't have to run a global update every time anything changes.
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
231
|
+
listener_args = directories + [{:relative_paths => false}]
|
232
|
+
|
233
|
+
# The native windows listener is much slower than the polling option, according to
|
234
|
+
# https://github.com/nex3/sass/commit/a3031856b22bc834a5417dedecb038b7be9b9e3e
|
235
|
+
poll = @options[:poll] || Sass::Util.windows?
|
236
|
+
if poll && Sass::Util.listen_geq_2?
|
237
|
+
# In Listen 2.0.0 and on, :force_polling is an option. In earlier
|
238
|
+
# versions, it's a method on the listener (called below).
|
239
|
+
listener_args.last[:force_polling] = true
|
240
|
+
end
|
254
241
|
|
255
|
-
|
256
|
-
|
257
|
-
update_stylesheets(individual_files)
|
258
|
-
end
|
242
|
+
listener = create_listener(*listener_args) do |modified, added, removed|
|
243
|
+
recompile_required = false
|
259
244
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
update_stylesheets(individual_files)
|
265
|
-
end
|
266
|
-
end
|
245
|
+
modified.uniq.each do |f|
|
246
|
+
next unless watched_file?(f)
|
247
|
+
recompile_required = true
|
248
|
+
run_template_modified(relative_to_pwd(f))
|
267
249
|
end
|
268
250
|
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
end
|
275
|
-
|
276
|
-
path.create do
|
277
|
-
run_template_created template
|
278
|
-
update_stylesheets(individual_files)
|
279
|
-
end
|
251
|
+
added.uniq.each do |f|
|
252
|
+
next unless watched_file?(f)
|
253
|
+
recompile_required = true
|
254
|
+
run_template_created(relative_to_pwd(f))
|
255
|
+
end
|
280
256
|
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
257
|
+
removed.uniq.each do |f|
|
258
|
+
if (files = individual_files.find {|(source, _, _)| File.expand_path(source) == f})
|
259
|
+
recompile_required = true
|
260
|
+
# This was a file we were watching explicitly and compiling to a particular location.
|
261
|
+
# Delete the corresponding file.
|
262
|
+
try_delete_css files[1]
|
263
|
+
else
|
264
|
+
next unless watched_file?(f)
|
265
|
+
recompile_required = true
|
266
|
+
# Look for the sass directory that contained the sass file
|
267
|
+
# And try to remove the css file that corresponds to it
|
268
|
+
template_location_array.each do |(sass_dir, css_dir)|
|
269
|
+
sass_dir = File.expand_path(sass_dir)
|
270
|
+
if child_of_directory?(sass_dir, f)
|
271
|
+
remainder = f[(sass_dir.size + 1)..-1]
|
272
|
+
try_delete_css(css_filename(remainder, css_dir))
|
273
|
+
break
|
274
|
+
end
|
285
275
|
end
|
286
276
|
end
|
277
|
+
run_template_deleted(relative_to_pwd(f))
|
278
|
+
end
|
279
|
+
|
280
|
+
if recompile_required
|
281
|
+
# In case a file we're watching is removed and then recreated we
|
282
|
+
# prune out the non-existant files here.
|
283
|
+
watched_files_remaining = individual_files.select {|(source, _, _)| File.exists?(source)}
|
284
|
+
update_stylesheets(watched_files_remaining)
|
287
285
|
end
|
288
286
|
end
|
287
|
+
|
288
|
+
if poll && !Sass::Util.listen_geq_2?
|
289
|
+
# In Listen 2.0.0 and on, :force_polling is an option (set above). In
|
290
|
+
# earlier versions, it's a method on the listener.
|
291
|
+
listener.force_polling(true)
|
292
|
+
end
|
293
|
+
|
294
|
+
listen_to(listener)
|
289
295
|
end
|
290
296
|
|
291
297
|
# Non-destructively modifies \{#options} so that default values are properly set,
|
@@ -306,7 +312,46 @@ module Sass::Plugin
|
|
306
312
|
|
307
313
|
private
|
308
314
|
|
309
|
-
def
|
315
|
+
def create_listener(*args, &block)
|
316
|
+
require 'listen'
|
317
|
+
if Sass::Util.listen_geq_2?
|
318
|
+
Listen.to(*args, &block)
|
319
|
+
else
|
320
|
+
Listen::Listener.new(*args, &block)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
|
324
|
+
def listen_to(listener)
|
325
|
+
if Sass::Util.listen_geq_2?
|
326
|
+
listener.start
|
327
|
+
listener.thread.join
|
328
|
+
listener.stop # Partially work around guard/listen#146
|
329
|
+
else
|
330
|
+
begin
|
331
|
+
listener.start!
|
332
|
+
rescue Interrupt
|
333
|
+
# Squelch Interrupt for clean exit from Listen::Listener
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def remove_redundant_directories(directories)
|
339
|
+
dedupped = []
|
340
|
+
directories.each do |new_directory|
|
341
|
+
# no need to add a directory that is already watched.
|
342
|
+
next if dedupped.any? do |existing_directory|
|
343
|
+
child_of_directory?(existing_directory, new_directory)
|
344
|
+
end
|
345
|
+
# get rid of any sub directories of this new directory
|
346
|
+
dedupped.reject! do |existing_directory|
|
347
|
+
child_of_directory?(new_directory, existing_directory)
|
348
|
+
end
|
349
|
+
dedupped << new_directory
|
350
|
+
end
|
351
|
+
dedupped
|
352
|
+
end
|
353
|
+
|
354
|
+
def update_stylesheet(filename, css, sourcemap)
|
310
355
|
dir = File.dirname(css)
|
311
356
|
unless File.exists?(dir)
|
312
357
|
run_creating_directory dir
|
@@ -315,28 +360,61 @@ module Sass::Plugin
|
|
315
360
|
|
316
361
|
begin
|
317
362
|
File.read(filename) unless File.readable?(filename) # triggers an error for handling
|
318
|
-
engine_opts = engine_options(:css_filename => css,
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
363
|
+
engine_opts = engine_options(:css_filename => css,
|
364
|
+
:filename => filename,
|
365
|
+
:sourcemap_filename => sourcemap)
|
366
|
+
mapping = nil
|
367
|
+
engine = Sass::Engine.for_file(filename, engine_opts)
|
368
|
+
if sourcemap
|
369
|
+
rendered, mapping = engine.render_with_sourcemap(File.basename(sourcemap))
|
370
|
+
else
|
371
|
+
rendered = engine.render
|
372
|
+
end
|
373
|
+
rescue StandardError => e
|
374
|
+
compilation_error_occured = true
|
375
|
+
run_compilation_error e, filename, css, sourcemap
|
376
|
+
rendered = Sass::SyntaxError.exception_to_css(e, options)
|
325
377
|
end
|
326
378
|
|
327
|
-
|
379
|
+
write_file(css, rendered)
|
380
|
+
if mapping
|
381
|
+
write_file(sourcemap, mapping.to_json(:css_path => css, :sourcemap_path => sourcemap))
|
382
|
+
end
|
383
|
+
run_updated_stylesheet(filename, css, sourcemap) unless compilation_error_occured
|
384
|
+
end
|
385
|
+
|
386
|
+
def write_file(fileName, content)
|
328
387
|
flag = 'w'
|
329
388
|
flag = 'wb' if Sass::Util.windows? && options[:unix_newlines]
|
330
|
-
File.open(
|
331
|
-
file.set_encoding(
|
332
|
-
file.print(
|
389
|
+
File.open(fileName, flag) do |file|
|
390
|
+
file.set_encoding(content.encoding) unless Sass::Util.ruby1_8?
|
391
|
+
file.print(content)
|
333
392
|
end
|
334
393
|
end
|
335
394
|
|
336
395
|
def try_delete_css(css)
|
337
|
-
|
338
|
-
|
339
|
-
|
396
|
+
if File.exists?(css)
|
397
|
+
run_deleting_css css
|
398
|
+
File.delete css
|
399
|
+
end
|
400
|
+
map = Sass::Util.sourcemap_name(css)
|
401
|
+
if File.exists?(map)
|
402
|
+
run_deleting_sourcemap map
|
403
|
+
File.delete map
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
def watched_file?(file)
|
408
|
+
normalized_load_paths.find {|lp| lp.watched_file?(file)}
|
409
|
+
end
|
410
|
+
|
411
|
+
def watched_paths
|
412
|
+
@watched_paths ||= normalized_load_paths.map {|lp| lp.directories_to_watch}.compact.flatten
|
413
|
+
end
|
414
|
+
|
415
|
+
def normalized_load_paths
|
416
|
+
@normalized_load_paths ||=
|
417
|
+
Sass::Engine.normalize_options(:load_paths => load_paths)[:load_paths]
|
340
418
|
end
|
341
419
|
|
342
420
|
def load_paths(opts = options)
|
@@ -352,7 +430,19 @@ module Sass::Plugin
|
|
352
430
|
end
|
353
431
|
|
354
432
|
def css_filename(name, path)
|
355
|
-
"#{path}
|
433
|
+
"#{path}#{File::SEPARATOR unless path.end_with?(File::SEPARATOR)}#{name}".
|
434
|
+
gsub(/\.s[ac]ss$/, '.css')
|
435
|
+
end
|
436
|
+
|
437
|
+
def relative_to_pwd(f)
|
438
|
+
Sass::Util.pathname(f).relative_path_from(Sass::Util.pathname(Dir.pwd)).to_s
|
439
|
+
rescue ArgumentError # when a relative path cannot be computed
|
440
|
+
f
|
441
|
+
end
|
442
|
+
|
443
|
+
def child_of_directory?(parent, child)
|
444
|
+
parent_dir = parent.end_with?(File::SEPARATOR) ? parent : (parent + File::SEPARATOR)
|
445
|
+
child.start_with?(parent_dir) || parent == child
|
356
446
|
end
|
357
447
|
end
|
358
448
|
end
|
@@ -1,11 +1,9 @@
|
|
1
|
-
# We keep configuration in its own self-contained file
|
2
|
-
# so that we can load it independently in Rails 3,
|
3
|
-
# where the full plugin stuff is lazy-loaded.
|
4
|
-
|
5
1
|
module Sass
|
6
2
|
module Plugin
|
3
|
+
# We keep configuration in its own self-contained file
|
4
|
+
# so that we can load it independently in Rails 3,
|
5
|
+
# where the full plugin stuff is lazy-loaded.
|
7
6
|
module Configuration
|
8
|
-
|
9
7
|
# Returns the default options for a {Sass::Plugin::Compiler}.
|
10
8
|
#
|
11
9
|
# @return [{Symbol => Object}]
|
@@ -19,7 +17,8 @@ module Sass
|
|
19
17
|
}.freeze
|
20
18
|
end
|
21
19
|
|
22
|
-
# Resets the options and
|
20
|
+
# Resets the options and
|
21
|
+
# {Sass::Callbacks::InstanceMethods#clear_callbacks! clears all callbacks}.
|
23
22
|
def reset!
|
24
23
|
@options = nil
|
25
24
|
clear_callbacks!
|
@@ -31,26 +30,14 @@ module Sass
|
|
31
30
|
# @return [{Symbol => Object}]
|
32
31
|
def options
|
33
32
|
@options ||= default_options.dup
|
34
|
-
@options[:cache_store] ||= Sass::CacheStores::Filesystem.new(@options[:cache_location])
|
35
|
-
@options
|
36
|
-
end
|
37
|
-
|
38
|
-
# Sets the options hash.
|
39
|
-
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
40
|
-
# See {Sass::Plugin::Configuration#reset!}
|
41
|
-
# @deprecated Instead, modify the options hash in-place.
|
42
|
-
# @param value [{Symbol => Object}] The options hash
|
43
|
-
def options=(value)
|
44
|
-
Sass::Util.sass_warn("Setting Sass::Plugin.options is deprecated " +
|
45
|
-
"and will be removed in a future release.")
|
46
|
-
options.merge!(value)
|
47
33
|
end
|
48
34
|
|
49
35
|
# Adds a new template-location/css-location mapping.
|
50
36
|
# This means that Sass/SCSS files in `template_location`
|
51
37
|
# will be compiled to CSS files in `css_location`.
|
52
38
|
#
|
53
|
-
# This is preferred over manually manipulating the
|
39
|
+
# This is preferred over manually manipulating the
|
40
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
|
54
41
|
# since the option can be in multiple formats.
|
55
42
|
#
|
56
43
|
# Note that this method will change `options[:template_location]`
|
@@ -70,7 +57,8 @@ module Sass
|
|
70
57
|
# This means that Sass/SCSS files in `template_location`
|
71
58
|
# will no longer be compiled to CSS files in `css_location`.
|
72
59
|
#
|
73
|
-
# This is preferred over manually manipulating the
|
60
|
+
# This is preferred over manually manipulating the
|
61
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location` option}
|
74
62
|
# since the option can be in multiple formats.
|
75
63
|
#
|
76
64
|
# Note that this method will change `options[:template_location]`
|
@@ -114,10 +102,15 @@ module Sass
|
|
114
102
|
options[:template_location] =
|
115
103
|
case options[:template_location]
|
116
104
|
when nil
|
117
|
-
options[:css_location]
|
118
|
-
[[File.join(options[:css_location], 'sass'), options[:css_location]]]
|
119
|
-
|
120
|
-
|
105
|
+
if options[:css_location]
|
106
|
+
[[File.join(options[:css_location], 'sass'), options[:css_location]]]
|
107
|
+
else
|
108
|
+
[]
|
109
|
+
end
|
110
|
+
when String
|
111
|
+
[[options[:template_location], options[:css_location]]]
|
112
|
+
else
|
113
|
+
options[:template_location].to_a
|
121
114
|
end
|
122
115
|
end
|
123
116
|
end
|
data/lib/sass/plugin/merb.rb
CHANGED
@@ -5,7 +5,7 @@ unless defined?(Sass::MERB_LOADED)
|
|
5
5
|
# Different default options in a m envirionment.
|
6
6
|
def default_options
|
7
7
|
@default_options ||= begin
|
8
|
-
version = Merb::VERSION.split('.').map {
|
8
|
+
version = Merb::VERSION.split('.').map {|n| n.to_i}
|
9
9
|
if version[0] <= 0 && version[1] < 5
|
10
10
|
root = MERB_ROOT
|
11
11
|
env = MERB_ENV
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
1
3
|
module Sass
|
2
4
|
module Plugin
|
3
5
|
# The class handles `.s[ca]ss` file staleness checks via their mtime timestamps.
|
@@ -24,11 +26,13 @@ module Sass
|
|
24
26
|
# as its instance-level caches are never explicitly expired.
|
25
27
|
class StalenessChecker
|
26
28
|
@dependencies_cache = {}
|
29
|
+
@dependency_cache_mutex = Mutex.new
|
27
30
|
|
28
31
|
class << self
|
29
32
|
# TODO: attach this to a compiler instance.
|
30
33
|
# @private
|
31
34
|
attr_accessor :dependencies_cache
|
35
|
+
attr_reader :dependency_cache_mutex
|
32
36
|
end
|
33
37
|
|
34
38
|
# Creates a new StalenessChecker
|
@@ -37,11 +41,13 @@ module Sass
|
|
37
41
|
# @param options [{Symbol => Object}]
|
38
42
|
# See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.
|
39
43
|
def initialize(options)
|
40
|
-
|
44
|
+
# URIs that are being actively checked for staleness. Protects against
|
45
|
+
# import loops.
|
46
|
+
@actively_checking = Set.new
|
41
47
|
|
42
48
|
# Entries in the following instance-level caches are never explicitly expired.
|
43
|
-
# Instead they are supposed to automaticaly go out of scope when a series of staleness
|
44
|
-
# (this instance of StalenessChecker was created for) is finished.
|
49
|
+
# Instead they are supposed to automaticaly go out of scope when a series of staleness
|
50
|
+
# checks (this instance of StalenessChecker was created for) is finished.
|
45
51
|
@mtimes, @dependencies_stale, @parse_trees = {}, {}, {}
|
46
52
|
@options = Sass::Engine.normalize_options(options)
|
47
53
|
end
|
@@ -127,7 +133,7 @@ module Sass
|
|
127
133
|
begin
|
128
134
|
mtime = importer.mtime(uri, @options)
|
129
135
|
if mtime.nil?
|
130
|
-
|
136
|
+
with_dependency_cache {|cache| cache.delete([uri, importer])}
|
131
137
|
nil
|
132
138
|
else
|
133
139
|
mtime
|
@@ -136,22 +142,31 @@ module Sass
|
|
136
142
|
end
|
137
143
|
|
138
144
|
def dependencies(uri, importer)
|
139
|
-
stored_mtime, dependencies =
|
145
|
+
stored_mtime, dependencies =
|
146
|
+
with_dependency_cache {|cache| Sass::Util.destructure(cache[[uri, importer]])}
|
140
147
|
|
141
148
|
if !stored_mtime || stored_mtime < mtime(uri, importer)
|
142
149
|
dependencies = compute_dependencies(uri, importer)
|
143
|
-
|
150
|
+
with_dependency_cache do |cache|
|
151
|
+
cache[[uri, importer]] = [mtime(uri, importer), dependencies]
|
152
|
+
end
|
144
153
|
end
|
145
154
|
|
146
155
|
dependencies
|
147
156
|
end
|
148
157
|
|
149
158
|
def dependency_updated?(css_mtime)
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
159
|
+
proc do |uri, importer|
|
160
|
+
next true if @actively_checking.include?(uri)
|
161
|
+
begin
|
162
|
+
@actively_checking << uri
|
163
|
+
sass_mtime = mtime(uri, importer)
|
164
|
+
!sass_mtime ||
|
165
|
+
sass_mtime > css_mtime ||
|
166
|
+
dependencies_stale?(uri, importer, css_mtime)
|
167
|
+
ensure
|
168
|
+
@actively_checking.delete uri
|
169
|
+
end
|
155
170
|
end
|
156
171
|
end
|
157
172
|
|
@@ -168,6 +183,17 @@ module Sass
|
|
168
183
|
def tree(uri, importer)
|
169
184
|
@parse_trees[[uri, importer]] ||= importer.find(uri, @options).to_tree
|
170
185
|
end
|
186
|
+
|
187
|
+
# Get access to the global dependency cache in a threadsafe manner.
|
188
|
+
# Inside the block, no other thread can access the dependency cache.
|
189
|
+
#
|
190
|
+
# @yieldparam cache [Hash] The hash that is the global dependency cache
|
191
|
+
# @return The value returned by the block to which this method yields
|
192
|
+
def with_dependency_cache
|
193
|
+
StalenessChecker.dependency_cache_mutex.synchronize do
|
194
|
+
yield StalenessChecker.dependencies_cache
|
195
|
+
end
|
196
|
+
end
|
171
197
|
end
|
172
198
|
end
|
173
199
|
end
|
data/lib/sass/plugin.rb
CHANGED
@@ -11,7 +11,8 @@ module Sass
|
|
11
11
|
# This module is used as the primary interface with Sass
|
12
12
|
# when it's used as a plugin for various frameworks.
|
13
13
|
# All Rack-enabled frameworks are supported out of the box.
|
14
|
-
# The plugin is
|
14
|
+
# The plugin is
|
15
|
+
# {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}.
|
15
16
|
# Other frameworks must enable it explicitly; see {Sass::Plugin::Rack}.
|
16
17
|
#
|
17
18
|
# This module has a large set of callbacks available
|
@@ -32,7 +33,6 @@ module Sass
|
|
32
33
|
# #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css
|
33
34
|
# @see Sass::Plugin::Compiler
|
34
35
|
module Plugin
|
35
|
-
include Sass::Util
|
36
36
|
extend self
|
37
37
|
|
38
38
|
@checked_for_updates = false
|
@@ -65,7 +65,8 @@ module Sass
|
|
65
65
|
|
66
66
|
# Updates out-of-date stylesheets.
|
67
67
|
#
|
68
|
-
# Checks each Sass/SCSS file in
|
68
|
+
# Checks each Sass/SCSS file in
|
69
|
+
# {file:SASS_REFERENCE.md#template_location-option `:template_location`}
|
69
70
|
# to see if it's been modified more recently than the corresponding CSS file
|
70
71
|
# in {file:SASS_REFERENCE.md#css_location-option `:css_location`}.
|
71
72
|
# If it has, it updates the CSS file.
|
@@ -92,14 +93,10 @@ module Sass
|
|
92
93
|
# the second is the location of the CSS file that it should be compiled to.
|
93
94
|
# @see #update_stylesheets
|
94
95
|
def force_update_stylesheets(individual_files = [])
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
options[:cache] = false
|
100
|
-
update_stylesheets(individual_files)
|
101
|
-
ensure
|
102
|
-
self.options = old_options
|
96
|
+
Compiler.new(options.dup.merge(
|
97
|
+
:never_update => false,
|
98
|
+
:always_update => true,
|
99
|
+
:cache => false)).update_stylesheets(individual_files)
|
103
100
|
end
|
104
101
|
|
105
102
|
# All other method invocations are proxied to the \{#compiler}.
|
@@ -123,11 +120,11 @@ module Sass
|
|
123
120
|
def options
|
124
121
|
compiler.options
|
125
122
|
end
|
126
|
-
|
127
123
|
end
|
128
124
|
end
|
129
125
|
|
130
|
-
|
126
|
+
# On Rails 3+ the rails plugin is loaded at the right time in railtie.rb
|
127
|
+
if defined?(ActionController) && !Sass::Util.ap_geq_3?
|
131
128
|
require 'sass/plugin/rails'
|
132
129
|
elsif defined?(Merb::Plugins)
|
133
130
|
require 'sass/plugin/merb'
|