Module Sass::Plugin
In: lib/sass/plugin/rack.rb
lib/sass/plugin/staleness_checker.rb
lib/sass/plugin/configuration.rb
lib/sass/plugin.rb
Haml::Util Engine Color SyntaxError UnitConversionError StandardError AbstractSequence CommaSequence Sequence SimpleSequence Simple Parent Universal Class SelectorPseudoClass Id Pseudo Attribute Interpolation Element Node Operation Literal UnaryOperation StringInterpolation Funcall Interpolation Variable Lexer CssLexer Number Bool String Parser Parser CssParser EvaluationContext StaticParser SassParser CssParser Node DebugNode IfNode CommentNode ForNode PropNode MixinNode CharsetNode DirectiveNode VariableNode WarnNode ExtendNode RootNode WhileNode MixinDefNode RuleNode Enumerable ImportNode Merb::BootLoader MerbBootLoader Repl CSS Environment Rack StalenessChecker lib/sass/repl.rb lib/sass/css.rb lib/sass/environment.rb lib/sass/error.rb lib/sass/engine.rb lib/sass/selector/simple_sequence.rb lib/sass/selector/abstract_sequence.rb lib/sass/selector/sequence.rb lib/sass/selector/comma_sequence.rb lib/sass/selector/simple.rb lib/sass/selector.rb Selector lib/sass/script/css_parser.rb lib/sass/script/lexer.rb lib/sass/script/color.rb lib/sass/script/string.rb lib/sass/script/unary_operation.rb lib/sass/script/variable.rb lib/sass/script/funcall.rb lib/sass/script/string_interpolation.rb lib/sass/script/operation.rb lib/sass/script/bool.rb lib/sass/script/parser.rb lib/sass/script/node.rb lib/sass/script/literal.rb lib/sass/script/interpolation.rb lib/sass/script/css_lexer.rb lib/sass/script/number.rb lib/sass/script/functions.rb Functions Script lib/sass/scss/sass_parser.rb lib/sass/scss/static_parser.rb lib/sass/scss/parser.rb lib/sass/scss/css_parser.rb ScriptLexer ScriptParser RX SCSS Callbacks Files lib/sass/tree/while_node.rb lib/sass/tree/if_node.rb lib/sass/tree/mixin_def_node.rb lib/sass/tree/debug_node.rb lib/sass/tree/root_node.rb lib/sass/tree/for_node.rb lib/sass/tree/import_node.rb lib/sass/tree/prop_node.rb lib/sass/tree/node.rb lib/sass/tree/comment_node.rb lib/sass/tree/extend_node.rb lib/sass/tree/charset_node.rb lib/sass/tree/mixin_node.rb lib/sass/tree/warn_node.rb lib/sass/tree/directive_node.rb lib/sass/tree/rule_node.rb lib/sass/tree/variable_node.rb Tree lib/sass/plugin/rack.rb lib/sass/plugin/staleness_checker.rb lib/sass/plugin/merb.rb Plugin Sass dot/m_86_0.png

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

Methods

Included Modules

Sass::Callbacks Haml::Util

Classes and Modules

Class Sass::Plugin::MerbBootLoader
Class Sass::Plugin::Rack
Class Sass::Plugin::StalenessChecker

Attributes

checked_for_updates  [R]  Whether or not Sass has *ever* checked if the stylesheets need to be updated (in this Ruby instance).

@return [Boolean]

options  [R]  An options hash. See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.

@return [{Symbol => Object}]

Public Instance methods

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.

[Source]

     # 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

[Source]

    # 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

[Source]

     # 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

[Source]

     # 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

Sets the options hash. See {file:SASS_REFERENCE.md#sass_options the Sass options documentation}.

@param value [{Symbol => Object}] The options hash

[Source]

     # File lib/sass/plugin/configuration.rb, line 132
132:     def options=(value)
133:       @options.merge!(value)
134:     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.

[Source]

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

[Source]

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

[Source]

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

[Source]

     # 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

Private Instance methods

[Source]

     # File lib/sass/plugin.rb, line 258
258:     def css_filename(name, path)
259:       "#{path}/#{name}".gsub(/\.s[ac]ss$/, '.css')
260:     end

[Source]

     # File lib/sass/plugin.rb, line 254
254:     def css_locations
255:       template_location_array.to_a.map {|l| l.last}
256:     end

[Source]

     # File lib/sass/plugin.rb, line 262
262:     def forbid_update?(name)
263:       name.sub(/^.*\//, '')[0] == ?_
264:     end

[Source]

     # File lib/sass/plugin.rb, line 246
246:     def load_paths(opts = options)
247:       (opts[:load_paths] || []) + template_locations
248:     end

[Source]

     # 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

[Source]

     # 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

[Source]

     # File lib/sass/plugin.rb, line 250
250:     def template_locations
251:       template_location_array.to_a.map {|l| l.first}
252:     end

[Source]

     # 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

[Source]

     # 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

[Validate]