Skip to content

Commit

Permalink
Extend existing sass filesystem import to track dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
josh committed Jan 10, 2012
1 parent 19a8796 commit d9ba0d4
Show file tree
Hide file tree
Showing 4 changed files with 17 additions and 101 deletions.
104 changes: 15 additions & 89 deletions lib/sprockets/sass_importer.rb
@@ -1,103 +1,29 @@
require 'sass'

module Sprockets
# This custom importer adds sprockets dependency tracking on to Sass
# `@import` statements. This makes the Sprockets and Sass caching
# systems work together.
class SassImporter
attr_reader :context

def initialize(context)
class SassImporter < Sass::Importers::Filesystem
def initialize(context, root)
@context = context
super root.to_s
end

def evaluate(pathname, options)
# Mark pathname as a dependency for cache tracking
context.depend_on_asset(pathname)

options = options.merge(:filename => pathname.to_s, :syntax => :scss)
syntax = pathname.extname[/\w+$/].to_sym

case syntax
when :sass, :scss
# `foo.sass` and `foo.scss` can be read directly by sass.
::Sass::Engine.new(pathname.read, options.merge(:syntax => syntax))
else
# If the file something else like a `foo.css.erb`, have
# sprockets process it first before handing it off to sass.
::Sass::Engine.new(context.evaluate(pathname), options)
end
end

# Find relative path to asset in load path and return its Pathname.
def resolve_relative(path, basepath)
dirname, basename = File.split(path)

# Ensure resolve is always called with a leading "./" to force a
# relative lookup.
if dirname == '.'
resolve("./_#{basename}", :base_path => basepath) ||
resolve("./#{basename}", :base_path => basepath)
else
resolve("./#{dirname}/_#{basename}", :base_path => basepath) ||
resolve("./#{dirname}/#{basename}", :base_path => basepath)
end
end

# Find full path to asset in load path and return its Pathname.
def resolve_loadpath(path)
return if path.to_s =~ /^\.\.?\//
dirname, basename = File.split(path)

# Strip any leading "./" to force a load path lookup.
if dirname == '.'
resolve("_#{basename}") || resolve("#{basename}")
else
resolve("#{dirname}/_#{basename}") || resolve("#{dirname}/#{basename}")
end
end

def resolve(path, options = {})
context.resolve(path, {:content_type => :self}.merge(options))
rescue Sprockets::FileNotFound
nil
end

# Find asset relative to the current file and return a `Sass::Engine`.
def find_relative(path, base, options)
if pathname = resolve_relative(path, :base_path => File.dirname(base))
evaluate(pathname, options)
end
end

# Find asset in Sprockets load path and return a `Sass::Engine`.
def find(path, options)
if pathname = resolve_loadpath(path)
evaluate(pathname, options)
def find_relative(*args)
engine = super
if engine && (filename = engine.options[:filename])
@context.depend_on_asset(filename)
end
engine
end

# Return mtime for path.
#
# (This method doesn't seem to ever be called)
def mtime(path, options)
if pathname = resolve_loadpath(path)
pathname.mtime
def find(*args)
engine = super
if engine && (filename = engine.options[:filename])
@context.depend_on_asset(filename)
end
end

# Return cache key for Sass's cache system.
def key(name, options)
["Sprockets:" + File.dirname(File.expand_path(name)), File.basename(name)]
end

# Pretty inspect
def inspect
"#<#{self.class}:0x#{object_id.to_s(16)} " +
"logical_path=#{context.logical_path.to_s.inspect}" +
">"
end

def to_s
inspect
engine
end
end
end
5 changes: 2 additions & 3 deletions lib/sprockets/sass_template.rb
Expand Up @@ -27,16 +27,15 @@ def syntax

def evaluate(context, locals, &block)
# Use custom importer that knows about Sprockets Caching
importer = SassImporter.new(context)
cache_store = SassCacheStore.new(context.environment)

options = {
:filename => eval_file,
:line => line,
:syntax => syntax,
:cache_store => cache_store,
:importer => importer,
:load_paths => [importer]
:importer => SassImporter.new(context, context.pathname),
:load_paths => context.environment.paths.map { |path| SassImporter.new(context, path) }
}

::Sass::Engine.new(data, options).render
Expand Down
1 change: 0 additions & 1 deletion test/fixtures/sass/import_css.scss

This file was deleted.

8 changes: 0 additions & 8 deletions test/test_sass.rb
Expand Up @@ -228,12 +228,4 @@ def render(path)
@env[path].to_s
end
end

# For some reason Sass doesn't like importing other css files
test "@import css from scss" do
assert_equal <<-EOS, render('sass/import_css.scss')
article, aside, details, figcaption, figure,\nfooter, header, hgroup, menu, nav, section {
display: block; }
EOS
end
end

0 comments on commit d9ba0d4

Please sign in to comment.