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.
- 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'
|