middleman/middleman-core/lib/middleman-core/renderers/sass.rb
2014-07-20 18:57:22 -07:00

130 lines
3.6 KiB
Ruby

require 'sass'
require 'compass/import-once'
GLOB = /\*|\[.+\]/
# Hack around broken sass globs when combined with import-once
# Targets compass-import-once 1.0.4
# Tracking issue: https://github.com/chriseppstein/compass/issues/1529
module Compass
module ImportOnce
module Importer
def find_relative(uri, base, options, *args)
if uri =~ GLOB
force_import = true
else
uri, force_import = handle_force_import(uri)
end
maybe_replace_with_dummy_engine(super(uri, base, options, *args), options, force_import)
end
def find(uri, options, *args)
if uri =~ GLOB
force_import = true
else
uri, force_import = handle_force_import(uri)
end
maybe_replace_with_dummy_engine(super(uri, options, *args), options, force_import)
end
end
end
end
module Middleman
module Renderers
# Sass renderer
class Sass < ::Middleman::Extension
# Setup extension
def initialize(app, options={}, &block)
super
app.files.ignore :sass_cache, :source, /(^|\/)\.sass-cache\//
opts = { output_style: :nested }
opts[:line_comments] = false if ENV['TEST']
# Default sass options
app.config.define_setting :sass, opts, 'Sass engine options'
app.config.define_setting :sass_assets_paths, [], 'Paths to extra SASS/SCSS files'
# Tell Tilt to use it as well (for inline sass blocks)
::Tilt.register 'sass', SassPlusCSSFilenameTemplate
::Tilt.prefer(SassPlusCSSFilenameTemplate)
# Tell Tilt to use it as well (for inline scss blocks)
::Tilt.register 'scss', ScssPlusCSSFilenameTemplate
::Tilt.prefer(ScssPlusCSSFilenameTemplate)
::Compass::ImportOnce.activate!
require 'middleman-core/renderers/sass_functions'
end
# A SassTemplate for Tilt which outputs debug messages
class SassPlusCSSFilenameTemplate < ::Tilt::SassTemplate
def initialize(*args, &block)
super
@context = @options[:context] if @options.key?(:context)
end
# Define the expected syntax for the template
# @return [Symbol]
def syntax
:sass
end
def prepare; end
# Add exception messaging
# @param [Class] context
# @return [String]
def evaluate(context, _)
@context ||= context
@engine = ::Sass::Engine.new(data, sass_options)
begin
@engine.render
rescue ::Sass::SyntaxError => e
::Sass::SyntaxError.exception_to_css(e, full_exception: true)
end
end
# Change Sass path, for url functions, to the build folder if we're building
# @return [Hash]
def sass_options
ctx = if defined?(::Middleman::Renderers::Haml)
::Middleman::Renderers::Haml.last_haml_scope || @context
else
@context
end
more_opts = {
load_paths: ctx.config[:sass_assets_paths],
filename: eval_file,
line: line,
syntax: syntax,
custom: { middleman_context: ctx.app }
}
if ctx.is_a?(::Middleman::TemplateContext) && file
more_opts[:css_filename] = file.sub(/\.s[ac]ss$/, '')
end
options.merge(more_opts)
end
end
# SCSS version of the above template
class ScssPlusCSSFilenameTemplate < SassPlusCSSFilenameTemplate
# Define the expected syntax for the template
# @return [Symbol]
def syntax
:scss
end
end
end
end
end