Module: Sass::Plugin

Extended by:
Plugin
Includes:
Haml::Util, Callbacks
Included in:
Plugin
Defined in:
lib/sass/plugin.rb,
lib/sass/plugin/rack.rb,
lib/sass/plugin/configuration.rb,
lib/sass/plugin/staleness_checker.rb

Overview

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 automatically activated for Rails and Merb. Other frameworks must enable it explicitly; see 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.

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

Examples:

Using a callback

Defined Under Namespace

Classes: MerbBootLoader, Rack, StalenessChecker

Constant Summary

Constants included from Haml::Util

Haml::Util::CHARSET_REGEXPS, Haml::Util::ENCODINGS_TO_CHECK, Haml::Util::RUBY_VERSION

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Callbacks

#define_callback

Methods included from Haml::Util

#ap_geq?, #ap_geq_3?, #assert_html_safe!, #av_template_class, #caller_info, #check_encoding, #check_haml_encoding, #check_sass_encoding, #def_static_method, #enum_cons, #enum_slice, #enum_with_index, #flatten, #haml_warn, #has?, #html_safe, #intersperse, #lcs, #map_hash, #map_keys, #map_vals, #merge_adjacent_strings, #ord, #paths, #powerset, #rails_env, #rails_root, #rails_safe_buffer_class, #rails_xss_safe?, #restrict, #ruby1_8?, #ruby1_8_6?, #scope, #set_eql?, #set_hash, #silence_haml_warnings, #silence_warnings, #static_method_name, #strip_string_array, #substitute, #to_hash, #windows?

Instance Attribute Details

#checked_for_updatesBoolean (readonly)

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

Returns:

  • (Boolean)


40
41
42
# File 'lib/sass/plugin.rb', line 40

def checked_for_updates
  @checked_for_updates
end

#options{Symbol => Object}

An options hash. See the Sass options documentation.

Returns:

  • ({Symbol => Object})


126
127
128
# File 'lib/sass/plugin/configuration.rb', line 126

def options
  @options
end

Instance Method Details

#add_template_location(template_location, css_location = )

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

Parameters:

  • template_location (String)

    The location where Sass/SCSS files will be.

  • css_location (String) (defaults to: )

    The location where compiled CSS files will go.



161
162
163
164
# File 'lib/sass/plugin/configuration.rb', line 161

def add_template_location(template_location, css_location = options[:css_location])
  normalize_template_location!
  template_location_array << [template_location, css_location]
end

#check_for_updates

Same as #update_stylesheets, but respects #checked_for_updates and the :always_update and :always_check options.



47
48
49
50
51
# File 'lib/sass/plugin.rb', line 47

def check_for_updates
  return unless !Sass::Plugin.checked_for_updates ||
      Sass::Plugin.options[:always_update] || Sass::Plugin.options[:always_check]
  update_stylesheets
end

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

Non-destructively modifies #options so that default values are properly set.

Parameters:

  • additional_options ({Symbol => Object}) (defaults to: {})

    An options hash with which to merge #options

Returns:

  • ({Symbol => Object})

    The modified options hash



140
141
142
143
144
# File 'lib/sass/plugin/configuration.rb', line 140

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

#force_update_stylesheets(individual_files = [])

Updates all stylesheets, even those that aren't out-of-date. Ignores the cache.

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.

See Also:



103
104
105
106
107
108
109
110
111
112
# File 'lib/sass/plugin.rb', line 103

def force_update_stylesheets(individual_files = [])
  old_options = options
  self.options = options.dup
  options[:never_update] = false
  options[:always_update] = true
  options[:cache] = false
  update_stylesheets(individual_files)
ensure
  self.options = old_options
end

#remove_template_location(template_location, css_location = ) ⇒ Boolean

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

Parameters:

  • template_location (String)

    The location where Sass/SCSS files were, which is now going to be ignored.

  • css_location (String) (defaults to: )

    The location where compiled CSS files went, but will no longer go.

Returns:

  • (Boolean)

    Non-nil if the given mapping already existed and was removed, or nil if nothing was changed.



187
188
189
190
# File 'lib/sass/plugin/configuration.rb', line 187

def remove_template_location(template_location, css_location = options[:css_location])
  normalize_template_location!
  template_location_array.delete([template_location, css_location])
end

#template_location_arrayArray<(String, String)>

Returns the template locations configured for Sass as an array of [template_location, css_location] pairs. See the :template_location option for details.

Returns:

  • (Array<(String, String)>)

    An array of [template_location, css_location] pairs.



199
200
201
202
203
204
205
# File 'lib/sass/plugin/configuration.rb', line 199

def template_location_array
  old_template_location = options[:template_location]
  normalize_template_location!
  options[:template_location]
ensure
  options[:template_location] = old_template_location
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.



66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/sass/plugin.rb', line 66

def update_stylesheets(individual_files = [])
  return if options[:never_update]

  run_updating_stylesheets individual_files

  individual_files.each {|t, c| update_stylesheet(t, c)}

  @checked_for_updates = true
  staleness_checker = StalenessChecker.new

  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.sub(/\/*$/, '/'), "")
      css = css_filename(name, css_location)

      next if forbid_update?(name)
      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.



138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
# File 'lib/sass/plugin.rb', line 138

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

  begin
    require 'fssm'
  rescue LoadError => e
    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
  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'
    Haml::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