Class: Sass::Plugin::Compiler

Inherits:
Object
  • Object
show all
Extended by:
Callbacks
Includes:
Configuration, Util
Defined in:
lib/sass/plugin/compiler.rb

Overview

The Compiler class handles compilation of multiple files and/or directories, including checking which CSS files are out-of-date and need to be updated and calling Sass to perform the compilation on those files.

Sass::Plugin uses this class to update stylesheets for a single application. Unlike Sass::Plugin, though, the Compiler class has no global state, and so multiple instances may be created and used independently.

If you need to compile a Sass string into CSS, please see the Engine class.

Unlike Sass::Plugin, this class doesn't keep track of whether or how many times a stylesheet should be updated. Therefore, the following Sass::Plugin options are ignored by the Compiler:

  • :never_update
  • :always_check

Constant Summary

Constants included from Util

Util::CHARSET_REGEXPS, Util::ENCODINGS_TO_CHECK, Util::RUBY_ENGINE, Util::RUBY_VERSION

Instance Method Summary collapse

Methods included from Callbacks

define_callback, extended

Methods included from Configuration

#add_template_location, #default_options, #options, #options=, #remove_template_location, #reset!, #template_location_array

Methods included from Util

#abstract, #ap_geq?, #ap_geq_3?, #av_template_class, #caller_info, #check_encoding, #check_sass_encoding, #enum_cons, #enum_slice, #enum_with_index, #flatten, #has?, #inspect_obj, #intersperse, #ironruby?, #lcs, #map_hash, #map_keys, #map_vals, #merge_adjacent_strings, #ord, #paths, #powerset, #rails_env, #rails_root, #restrict, #ruby1_8?, #ruby1_8_6?, #sass_warn, #scope, #set_eql?, #set_hash, #silence_sass_warnings, #silence_warnings, #strip_string_array, #substitute, #to_hash, #version_geq, #version_gt, #windows?

Constructor Details

#initialize(options = {}) ⇒ Compiler

Creates a new compiler.

Parameters:



37
38
39
# File 'lib/sass/plugin/compiler.rb', line 37

def initialize(options = {})
  self.options.merge!(options)
end

Instance Method Details

#engine_options(additional_options = {}) ⇒ {Symbol => Object}

Non-destructively modifies Sass::Plugin::Configuration#options so that default values are properly set, and returns the result.

Parameters:

Returns:

  • ({Symbol => Object})

    The modified options hash



296
297
298
299
300
# File 'lib/sass/plugin/compiler.rb', line 296

def engine_options(additional_options = {})
  opts = options.merge(additional_options)
  opts[:load_paths] = load_paths(opts)
  opts
end

#stylesheet_needs_update?(css_file, template_file) ⇒ Boolean

Compass expects this to exist

Returns:

  • (Boolean)


303
304
305
# File 'lib/sass/plugin/compiler.rb', line 303

def stylesheet_needs_update?(css_file, template_file)
  StalenessChecker.stylesheet_needs_update?(css_file, template_file)
end

#update_stylesheets(individual_files = [])

Updates out-of-date stylesheets.

Checks each Sass/SCSS file in :template_location to see if it's been modified more recently than the corresponding CSS file in :css_location. If it has, it updates the CSS file.

Parameters:

  • individual_files (Array<(String, String)>) (defaults to: [])

    A list of files to check for updates in addition to those specified by the :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.



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/sass/plugin/compiler.rb', line 162

def update_stylesheets(individual_files = [])
  run_updating_stylesheets individual_files
  Sass::Plugin.checked_for_updates = true
  staleness_checker = StalenessChecker.new(engine_options)

  individual_files.each do |t, c|
    if options[:always_update] || staleness_checker.stylesheet_needs_update?(c, t)
      update_stylesheet(t, c)
    end
  end

  template_location_array.each do |template_location, css_location|

    Dir.glob(File.join(template_location, "**", "[^_]*.s[ca]ss")).sort.each do |file|
      # Get the relative path to the file
      name = file.sub(template_location.to_s.sub(/\/*$/, '/'), "")
      css = css_filename(name, css_location)

      if options[:always_update] || staleness_checker.stylesheet_needs_update?(css, file)
        update_stylesheet file, css
      else
        run_not_updating_stylesheet file, css
      end
    end
  end
end

#watch(individual_files = [])

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 :template_location, the corresponding CSS file in :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 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.

Parameters:

  • individual_files (Array<(String, String)>) (defaults to: [])

    A list of files to watch for updates in addition to those specified by the :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.



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
# File 'lib/sass/plugin/compiler.rb', line 213

def watch(individual_files = [])
  update_stylesheets(individual_files)

  begin
    require 'fssm'
  rescue LoadError => e
    dir = Sass::Util.scope("vendor/fssm/lib")
    if $LOAD_PATH.include?(dir)
      e.message << "\n" <<
        if File.exists?(scope(".git"))
          'Run "git submodule update --init" to get the recommended version.'
        else
          'Run "gem install fssm" to get it.'
        end
      raise e
    else
      $LOAD_PATH.unshift dir
      retry
    end
  end

  unless individual_files.empty? && FSSM::Backends::Default.name == "FSSM::Backends::FSEvents"
    # As of FSSM 0.1.4, it doesn't support FSevents on individual files,
    # but it also isn't smart enough to switch to polling itself.
    require 'fssm/backends/polling'
    Sass::Util.silence_warnings do
      FSSM::Backends.const_set(:Default, FSSM::Backends::Polling)
    end
  end

  # TODO: Keep better track of what depends on what
  # so we don't have to run a global update every time anything changes.
  FSSM.monitor do |mon|
    template_location_array.each do |template_location, css_location|
      mon.path template_location do |path|
        path.glob '**/*.s[ac]ss'

        path.update do |base, relative|
          run_template_modified File.join(base, relative)
          update_stylesheets(individual_files)
        end

        path.create do |base, relative|
          run_template_created File.join(base, relative)
          update_stylesheets(individual_files)
        end

        path.delete do |base, relative|
          run_template_deleted File.join(base, relative)
          css = File.join(css_location, relative.gsub(/\.s[ac]ss$/, '.css'))
          try_delete_css css
          update_stylesheets(individual_files)
        end
      end
    end

    individual_files.each do |template, css|
      mon.file template do |path|
        path.update do
          run_template_modified template
          update_stylesheets(individual_files)
        end

        path.create do
          run_template_created template
          update_stylesheets(individual_files)
        end

        path.delete do
          run_template_deleted template
          try_delete_css css
          update_stylesheets(individual_files)
        end
      end
    end
  end
end