gems.sass-3.2.8.lib.sass.exec.rb Maven / Gradle / Ivy
Go to download
Sass makes CSS fun again. Sass is an extension of CSS3, adding nested rules, variables, mixins, selector
inheritance, and more. It's translated to well-formatted, standard CSS using the command line tool or a
web-framework plugin.
This is a repackaged GEM in a JAR format of the sass-lang.gem package. The sass-gems package version
follows the sass-lang.gem versions located http://rubyforge.org/frs/?group_id=9702. Simply change
the version of this package to download and repackage the same GEM version.
require 'optparse'
require 'fileutils'
module Sass
# This module handles the various Sass executables (`sass` and `sass-convert`).
module Exec
# An abstract class that encapsulates the executable code for all three executables.
class Generic
# @param args [Array] The command-line arguments
def initialize(args)
@args = args
@options = {}
end
# Parses the command-line arguments and runs the executable.
# Calls `Kernel#exit` at the end, so it never returns.
#
# @see #parse
def parse!
begin
parse
rescue Exception => e
raise e if @options[:trace] || e.is_a?(SystemExit)
$stderr.print "#{e.class}: " unless e.class == RuntimeError
$stderr.puts "#{e.message}"
$stderr.puts " Use --trace for backtrace."
exit 1
end
exit 0
end
# Parses the command-line arguments and runs the executable.
# This does not handle exceptions or exit the program.
#
# @see #parse!
def parse
@opts = OptionParser.new(&method(:set_opts))
@opts.parse!(@args)
process_result
@options
end
# @return [String] A description of the executable
def to_s
@opts.to_s
end
protected
# Finds the line of the source template
# on which an exception was raised.
#
# @param exception [Exception] The exception
# @return [String] The line number
def get_line(exception)
# SyntaxErrors have weird line reporting
# when there's trailing whitespace
return (exception.message.scan(/:(\d+)/).first || ["??"]).first if exception.is_a?(::SyntaxError)
(exception.backtrace[0].scan(/:(\d+)/).first || ["??"]).first
end
# Tells optparse how to parse the arguments
# available for all executables.
#
# This is meant to be overridden by subclasses
# so they can add their own options.
#
# @param opts [OptionParser]
def set_opts(opts)
opts.on('-s', '--stdin', :NONE, 'Read input from standard input instead of an input file') do
@options[:input] = $stdin
end
opts.on('--trace', :NONE, 'Show a full traceback on error') do
@options[:trace] = true
end
opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do
@options[:unix_newlines] = true if ::Sass::Util.windows?
end
opts.on_tail("-?", "-h", "--help", "Show this message") do
puts opts
exit
end
opts.on_tail("-v", "--version", "Print version") do
puts("Sass #{::Sass.version[:string]}")
exit
end
end
# Processes the options set by the command-line arguments.
# In particular, sets `@options[:input]` and `@options[:output]`
# to appropriate IO streams.
#
# This is meant to be overridden by subclasses
# so they can run their respective programs.
def process_result
input, output = @options[:input], @options[:output]
args = @args.dup
input ||=
begin
filename = args.shift
@options[:filename] = filename
open_file(filename) || $stdin
end
output ||= args.shift || $stdout
@options[:input], @options[:output] = input, output
end
COLORS = { :red => 31, :green => 32, :yellow => 33 }
# Prints a status message about performing the given action,
# colored using the given color (via terminal escapes) if possible.
#
# @param name [#to_s] A short name for the action being performed.
# Shouldn't be longer than 11 characters.
# @param color [Symbol] The name of the color to use for this action.
# Can be `:red`, `:green`, or `:yellow`.
def puts_action(name, color, arg)
return if @options[:for_engine][:quiet]
printf color(color, "%11s %s\n"), name, arg
STDOUT.flush
end
# Same as \{Kernel.puts}, but doesn't print anything if the `--quiet` option is set.
#
# @param args [Array] Passed on to \{Kernel.puts}
def puts(*args)
return if @options[:for_engine][:quiet]
Kernel.puts(*args)
end
# Wraps the given string in terminal escapes
# causing it to have the given color.
# If terminal esapes aren't supported on this platform,
# just returns the string instead.
#
# @param color [Symbol] The name of the color to use.
# Can be `:red`, `:green`, or `:yellow`.
# @param str [String] The string to wrap in the given color.
# @return [String] The wrapped string.
def color(color, str)
raise "[BUG] Unrecognized color #{color}" unless COLORS[color]
# Almost any real Unix terminal will support color,
# so we just filter for Windows terms (which don't set TERM)
# and not-real terminals, which aren't ttys.
return str if ENV["TERM"].nil? || ENV["TERM"].empty? || !STDOUT.tty?
return "\e[#{COLORS[color]}m#{str}\e[0m"
end
def write_output(text, destination)
if destination.is_a?(String)
File.open(destination, 'w') {|file| file.write(text)}
else
destination.write(text)
end
end
private
def open_file(filename, flag = 'r')
return if filename.nil?
flag = 'wb' if @options[:unix_newlines] && flag == 'w'
File.open(filename, flag)
end
def handle_load_error(err)
dep = err.message[/^no such file to load -- (.*)/, 1]
raise err if @options[:trace] || dep.nil? || dep.empty?
$stderr.puts <] The command-line arguments
def initialize(args)
super
@options[:for_engine] = {
:load_paths => ['.'] + (ENV['SASSPATH'] || '').split(File::PATH_SEPARATOR)
}
@default_syntax = :sass
end
protected
# Tells optparse how to parse the arguments.
#
# @param opts [OptionParser]
def set_opts(opts)
super
opts.banner = < e
raise e if @options[:trace]
raise e.sass_backtrace_str("standard input")
end
end
private
def load_compass
begin
require 'compass'
rescue LoadError
require 'rubygems'
begin
require 'compass'
rescue LoadError
puts "ERROR: Cannot load compass."
exit 1
end
end
Compass.add_project_configuration
Compass.configuration.project_path ||= Dir.pwd
@options[:for_engine][:load_paths] += Compass.configuration.sass_load_paths
end
def interactive
require 'sass/repl'
::Sass::Repl.new(@options).run
end
def watch_or_update
require 'sass/plugin'
::Sass::Plugin.options.merge! @options[:for_engine]
::Sass::Plugin.options[:unix_newlines] = @options[:unix_newlines]
::Sass::Plugin.options[:poll] = @options[:poll]
if @options[:force]
raise "The --force flag may only be used with --update." unless @options[:update]
::Sass::Plugin.options[:always_update] = true
end
raise <>> Sass is watching for changes. Press Ctrl-C to stop."
::Sass::Plugin.on_template_modified do |template|
puts ">>> Change detected to: #{template}"
STDOUT.flush
end
::Sass::Plugin.on_template_created do |template|
puts ">>> New template detected: #{template}"
STDOUT.flush
end
::Sass::Plugin.on_template_deleted do |template|
puts ">>> Deleted template detected: #{template}"
STDOUT.flush
end
::Sass::Plugin.watch(files)
end
def colon_path?(path)
!split_colon_path(path)[1].nil?
end
def split_colon_path(path)
one, two = path.split(':', 2)
if one && two && ::Sass::Util.windows? &&
one =~ /\A[A-Za-z]\Z/ && two =~ /\A[\/\\]/
# If we're on Windows and we were passed a drive letter path,
# don't split on that colon.
one2, two = two.split(':', 2)
one = one + ':' + one2
end
return one, two
end
# Whether path is likely to be meant as the destination
# in a source:dest pair.
def probably_dest_dir?(path)
return false unless path
return false if colon_path?(path)
return ::Sass::Util.glob(File.join(path, "*.s[ca]ss")).empty?
end
end
class Scss < Sass
# @param args [Array] The command-line arguments
def initialize(args)
super
@default_syntax = :scss
end
end
# The `sass-convert` executable.
class SassConvert < Generic
# @param args [Array] The command-line arguments
def initialize(args)
super
require 'sass'
@options[:for_tree] = {}
@options[:for_engine] = {:cache => false, :read_cache => true}
end
# Tells optparse how to parse the arguments.
#
# @param opts [OptionParser]
def set_opts(opts)
opts.banner = < e
raise e if @options[:trace]
file = " of #{e.sass_filename}" if e.sass_filename
raise "Error on line #{e.sass_line}#{file}: #{e.message}\n Use --trace for backtrace"
rescue LoadError => err
handle_load_error(err)
end
end
end
end