| Module | Sass::Plugin |
| In: |
lib/sass/plugin/rack.rb
lib/sass/plugin/staleness_checker.rb lib/sass/plugin/configuration.rb lib/sass/plugin.rb |
This module handles the compilation of Sass/SCSS files. It provides global options and checks whether CSS files need to be updated.
This module is used as the primary interface with Sass when it‘s used as a plugin for various frameworks. All Rack-enabled frameworks are supported out of the box. The plugin is {file:SASS_REFERENCE.md#rails_merb_plugin automatically activated for Rails and Merb}. Other frameworks must enable it explicitly; see {Sass::Plugin::Rack}.
This module has a large set of callbacks available to allow users to run code (such as logging) when certain things happen. All callback methods are of the form `on_#{name}`, and they all take a block that‘s called when the given action occurs.
@example Using a callback Sass::Plugin.on_updating_stylesheet do |template, css|
puts "Compiling #{template} to #{css}"
end Sass::Plugin.update_stylesheets
#=> Compiling app/sass/screen.scss to public/stylesheets/screen.css #=> Compiling app/sass/print.scss to public/stylesheets/print.css #=> Compiling app/sass/ie.scss to public/stylesheets/ie.css
Adds a new template-location/css-location mapping. This means that Sass/SCSS files in `template_location` will be compiled to CSS files in `css_location`.
This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option} since the option can be in multiple formats.
Note that this method will change `options[:template_location]` to be in the Array format. This means that even if `options[:template_location]` had previously been a Hash or a String, it will now be an Array.
@param template_location [String] The location where Sass/SCSS files will be. @param css_location [String] The location where compiled CSS files will go.
# File lib/sass/plugin/configuration.rb, line 161
161: def add_template_location(template_location, css_location = options[:css_location])
162: normalize_template_location!
163: template_location_array << [template_location, css_location]
164: end
Same as \{update_stylesheets}, but respects \{checked_for_updates} and the {file:SASS_REFERENCE.md#always_update-option `:always_update`} and {file:SASS_REFERENCE.md#always_check-option `:always_check`} options.
@see update_stylesheets
# File lib/sass/plugin.rb, line 47
47: def check_for_updates
48: return unless !Sass::Plugin.checked_for_updates ||
49: Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
50: update_stylesheets
51: end
Non-destructively modifies \{options} so that default values are properly set.
@param additional_options [{Symbol => Object}] An options hash with which to merge \{options} @return [{Symbol => Object}] The modified options hash
# File lib/sass/plugin/configuration.rb, line 140
140: def engine_options(additional_options = {})
141: opts = options.dup.merge(additional_options)
142: opts[:load_paths] = load_paths(opts)
143: opts
144: end
Updates all stylesheets, even those that aren‘t out-of-date. Ignores the cache.
@param individual_files [Array<(String, String)>]
A list of files to check for updates
**in addition to those specified by the
{file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
The first string in each pair is the location of the Sass/SCSS file,
the second is the location of the CSS file that it should be compiled to.
@see update_stylesheets
# File lib/sass/plugin.rb, line 106
106: def force_update_stylesheets(individual_files = [])
107: old_options = options
108: self.options = options.dup
109: options[:never_update] = false
110: options[:always_update] = true
111: options[:cache] = false
112: update_stylesheets(individual_files)
113: ensure
114: self.options = old_options
115: end
Removes a template-location/css-location mapping. This means that Sass/SCSS files in `template_location` will no longer be compiled to CSS files in `css_location`.
This is preferred over manually manipulating the {file:SASS_REFERENCE.md#template_location-option `:template_location` option} since the option can be in multiple formats.
Note that this method will change `options[:template_location]` to be in the Array format. This means that even if `options[:template_location]` had previously been a Hash or a String, it will now be an Array.
@param template_location [String]
The location where Sass/SCSS files were, which is now going to be ignored.
@param css_location [String]
The location where compiled CSS files went, but will no longer go.
@return [Boolean]
Non-`nil` if the given mapping already existed and was removed, or `nil` if nothing was changed.
# File lib/sass/plugin/configuration.rb, line 187
187: def remove_template_location(template_location, css_location = options[:css_location])
188: normalize_template_location!
189: template_location_array.delete([template_location, css_location])
190: end
Returns the template locations configured for Sass as an array of `[template_location, css_location]` pairs. See the {file:SASS_REFERENCE.md#template_location-option `:template_location` option} for details.
@return [Array<(String, String)>]
An array of `[template_location, css_location]` pairs.
# File lib/sass/plugin/configuration.rb, line 199
199: def template_location_array
200: old_template_location = options[:template_location]
201: normalize_template_location!
202: options[:template_location]
203: ensure
204: options[:template_location] = old_template_location
205: end
Updates out-of-date stylesheets.
Checks each Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`} to see if it‘s been modified more recently than the corresponding CSS file in {file:SASS_REFERENCE.md#css_location-option `:css_location`}. If it has, it updates the CSS file.
@param individual_files [Array<(String, String)>]
A list of files to check for updates
**in addition to those specified by the
{file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
The first string in each pair is the location of the Sass/SCSS file,
the second is the location of the CSS file that it should be compiled to.
# File lib/sass/plugin.rb, line 66
66: def update_stylesheets(individual_files = [])
67: return if options[:never_update]
68:
69: run_updating_stylesheets individual_files
70: @checked_for_updates = true
71: staleness_checker = StalenessChecker.new
72:
73: individual_files.each do |t, c|
74: if options[:always_update] || staleness_checker.stylesheet_needs_update?(c, t)
75: update_stylesheet(t, c)
76: end
77: end
78:
79: template_location_array.each do |template_location, css_location|
80:
81: Dir.glob(File.join(template_location, "**", "*.s[ca]ss")).sort.each do |file|
82: # Get the relative path to the file
83: name = file.sub(template_location.sub(/\/*$/, '/'), "")
84: css = css_filename(name, css_location)
85:
86: next if forbid_update?(name)
87: if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
88: update_stylesheet file, css
89: else
90: run_not_updating_stylesheet file, css
91: end
92: end
93: end
94: end
Watches the template directory (or directories) and updates the CSS files whenever the related Sass/SCSS files change. `watch` never returns.
Whenever a change is detected to a Sass/SCSS file in {file:SASS_REFERENCE.md#template_location-option `:template_location`}, the corresponding CSS file in {file:SASS_REFERENCE.md#css_location-option `:css_location`} will be recompiled. The CSS files of any Sass/SCSS files that import the changed file will also be recompiled.
Before the watching starts in earnest, `watch` calls \{update_stylesheets}.
Note that `watch` uses the [FSSM](github.com/ttilley/fssm) library to monitor the filesystem for changes. FSSM isn‘t loaded until `watch` is run. The version of FSSM distributed with Sass is loaded by default, but if another version has already been loaded that will be used instead.
@param individual_files [Array<(String, String)>]
A list of files to watch for updates
**in addition to those specified by the
{file:SASS_REFERENCE.md#template_location-option `:template_location` option}.**
The first string in each pair is the location of the Sass/SCSS file,
the second is the location of the CSS file that it should be compiled to.
# File lib/sass/plugin.rb, line 141
141: def watch(individual_files = [])
142: update_stylesheets(individual_files)
143:
144: begin
145: require 'fssm'
146: rescue LoadError => e
147: e.message << "\n" <<
148: if File.exists?(scope(".git"))
149: 'Run "git submodule update --init" to get the recommended version.'
150: else
151: 'Run "gem install fssm" to get it.'
152: end
153: raise e
154: end
155:
156: unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
157: # As of FSSM 0.1.4, it doesn't support FSevents on individual files,
158: # but it also isn't smart enough to switch to polling itself.
159: require 'fssm/backends/polling'
160: Haml::Util.silence_warnings do
161: FSSM::Backends.const_set(:Default, FSSM::Backends::Polling)
162: end
163: end
164:
165: # TODO: Keep better track of what depends on what
166: # so we don't have to run a global update every time anything changes.
167: FSSM.monitor do |mon|
168: template_location_array.each do |template_location, css_location|
169: mon.path template_location do |path|
170: path.glob '**/*.s[ac]ss'
171:
172: path.update do |base, relative|
173: run_template_modified File.join(base, relative)
174: update_stylesheets(individual_files)
175: end
176:
177: path.create do |base, relative|
178: run_template_created File.join(base, relative)
179: update_stylesheets(individual_files)
180: end
181:
182: path.delete do |base, relative|
183: run_template_deleted File.join(base, relative)
184: css = File.join(css_location, relative.gsub(/\.s[ac]ss$/, '.css'))
185: try_delete_css css
186: update_stylesheets(individual_files)
187: end
188: end
189: end
190:
191: individual_files.each do |template, css|
192: mon.file template do |path|
193: path.update do
194: run_template_modified template
195: update_stylesheets(individual_files)
196: end
197:
198: path.create do
199: run_template_created template
200: update_stylesheets(individual_files)
201: end
202:
203: path.delete do
204: run_template_deleted template
205: try_delete_css css
206: update_stylesheets(individual_files)
207: end
208: end
209: end
210: end
211: end
# File lib/sass/plugin.rb, line 258
258: def css_filename(name, path)
259: "#{path}/#{name}".gsub(/\.s[ac]ss$/, '.css')
260: end
# File lib/sass/plugin.rb, line 254
254: def css_locations
255: template_location_array.to_a.map {|l| l.last}
256: end
# File lib/sass/plugin.rb, line 262
262: def forbid_update?(name)
263: name.sub(/^.*\//, '')[0] == ?_
264: end
# File lib/sass/plugin.rb, line 246
246: def load_paths(opts = options)
247: (opts[:load_paths] || []) + template_locations
248: end
# File lib/sass/plugin/configuration.rb, line 209
209: def normalize_template_location!
210: return if options[:template_location].is_a?(Array)
211: options[:template_location] =
212: case options[:template_location]
213: when nil
214: css_location = options[:css_location] || './public/stylesheets'
215: [[File.join(css_location, 'sass'), css_location]]
216: when String; [[options[:template_location], options[:css_location]]]
217: else; options[:template_location].to_a
218: end
219: end
Compass expects this to exist
# File lib/sass/plugin.rb, line 267
267: def stylesheet_needs_update?(css_file, template_file)
268: StalenessChecker.stylesheet_needs_update?(css_file, template_file)
269: end
# File lib/sass/plugin.rb, line 250
250: def template_locations
251: template_location_array.to_a.map {|l| l.first}
252: end
# File lib/sass/plugin.rb, line 240
240: def try_delete_css(css)
241: return unless File.exists?(css)
242: run_deleting_css css
243: File.delete css
244: end
# File lib/sass/plugin.rb, line 215
215: def update_stylesheet(filename, css)
216: dir = File.dirname(css)
217: unless File.exists?(dir)
218: run_creating_directory dir
219: FileUtils.mkdir_p dir
220: end
221:
222: begin
223: result = Sass::Files.tree_for(filename, engine_options(:css_filename => css, :filename => filename)).render
224: rescue Exception => e
225: run_compilation_error e, filename, css
226: result = Sass::SyntaxError.exception_to_css(e, options)
227: else
228: run_updating_stylesheet filename, css
229: end
230:
231: # Finally, write the file
232: flag = 'w'
233: flag = 'wb' if Haml::Util.windows? && options[:unix_newlines]
234: File.open(css, flag) do |file|
235: file.set_encoding(result.encoding) unless Haml::Util.ruby1_8?
236: file.print(result)
237: end
238: end