class Haml::Exec::SassConvert

The ‘sass-convert` executable.

def initialize(args)

Parameters:
  • args (Array) -- The command-line arguments
def initialize(args)
  super
  require 'sass'
  @options[:for_tree] = {}
  @options[:for_engine] = {:cache => false, :read_cache => true}
end

def process_directory

def process_directory
  unless input = @options[:input] = @args.shift
    raise "Error: directory required when using --recursive."
  end
  output = @options[:output] = @args.shift
  raise "Error: --from required when using --recursive." unless @options[:from]
  raise "Error: --to required when using --recursive." unless @options[:to]
  raise "Error: '#{@options[:input]}' is not a directory" unless File.directory?(@options[:input])
  if @options[:output] && File.exists?(@options[:output]) && !File.directory?(@options[:output])
    raise "Error: '#{@options[:output]}' is not a directory"
  end
  @options[:output] ||= @options[:input]
  from = @options[:from]
  from = :sass if from == :sass2
  if @options[:to] == @options[:from] && !@options[:in_place]
    fmt = @options[:from]
    raise "Error: converting from #{fmt} to #{fmt} without --in-place"
  end
  ext = @options[:from]
  ext = :sass if ext == :sass2
  Dir.glob("#{@options[:input]}/**/*.#{ext}") do |f|
    output =
      if @options[:in_place]
        f
      elsif @options[:output]
        output_name = f.gsub(/\.(c|sa|sc|le)ss$/, ".#{@options[:to]}")
        output_name[0...@options[:input].size] = @options[:output]
        output_name
      else
        f.gsub(/\.(c|sa|sc|le)ss$/, ".#{@options[:to]}")
      end
    unless File.directory?(File.dirname(output))
      puts_action :directory, :green, File.dirname(output)
      FileUtils.mkdir_p(File.dirname(output))
    end
    puts_action :convert, :green, f
    if File.exists?(output)
      puts_action :overwrite, :yellow, output
    else
      puts_action :create, :green, output
    end
    input = open_file(f)
    output = @options[:in_place] ? input : open_file(output, "w")
    process_file(input, output)
  end
end

def process_file(input, output)

def process_file(input, output)
  if input.is_a?(File)
    @options[:from] ||=
      case input.path
      when /\.scss$/; :scss
      when /\.sass$/; :sass
      when /\.less$/; :less
      when /\.css$/; :css
      end
  elsif @options[:in_place]
    raise "Error: the --in-place option requires a filename."
  end
  if output.is_a?(File)
    @options[:to] ||=
      case output.path
      when /\.scss$/; :scss
      when /\.sass$/; :sass
      end
  end
  if @options[:from] == :sass2
    @options[:from] = :sass
    @options[:for_engine][:sass2] = true
  end
  @options[:from] ||= :css
  @options[:to] ||= :sass
  @options[:for_engine][:syntax] = @options[:from]
  out =
    ::Haml::Util.silence_haml_warnings do
      if @options[:from] == :css
        require 'sass/css'
        ::Sass::CSS.new(input.read, @options[:for_tree]).render(@options[:to])
      elsif @options[:from] == :less
        require 'sass/less'
        try_less_note
        input = input.read if input.is_a?(IO) && !input.is_a?(File) # Less is dumb
        Less::Engine.new(input).to_tree.to_sass_tree.send("to_#{@options[:to]}", @options[:for_tree])
      else
        if input.is_a?(File)
          ::Sass::Files.tree_for(input.path, @options[:for_engine])
        else
          ::Sass::Engine.new(input.read, @options[:for_engine]).to_tree
        end.send("to_#{@options[:to]}", @options[:for_tree])
      end
    end
  output = File.open(input.path, 'w') if @options[:in_place]
  output.write(out)
rescue ::Sass::SyntaxError => 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

def process_result

and runs the CSS compiler appropriately.
Processes the options set by the command-line arguments,
def process_result
  require 'sass'
  if @options[:recursive]
    process_directory
    return
  end
  super
  input = @options[:input]
  raise "Error: '#{input.path}' is a directory (did you mean to use --recursive?)" if File.directory?(input)
  output = @options[:output]
  output = input if @options[:in_place]
  process_file(input, output)
end

def set_opts(opts)

Parameters:
  • opts (OptionParser) --
def set_opts(opts)
  opts.banner = <<END
 sass-convert [options] [INPUT] [OUTPUT]
ption:
erts between CSS, Sass, and SCSS files.
 converts from SCSS to Sass,
onverts from CSS to SCSS (adding appropriate nesting).
s:
  opts.on('-F', '--from FORMAT',
    'The format to convert from. Can be css, scss, sass, less, or sass2.',
    'sass2 is the same as sass, but updates more old syntax to new.',
    'By default, this is inferred from the input filename.',
    'If there is none, defaults to css.') do |name|
    @options[:from] = name.downcase.to_sym
    unless [:css, :scss, :sass, :less, :sass2].include?(@options[:from])
      raise "Unknown format for sass-convert --from: #{name}"
    end
    try_less_note if @options[:from] == :less
  end
  opts.on('-T', '--to FORMAT',
    'The format to convert to. Can be scss or sass.',
    'By default, this is inferred from the output filename.',
    'If there is none, defaults to sass.') do |name|
    @options[:to] = name.downcase.to_sym
    unless [:scss, :sass].include?(@options[:to])
      raise "Unknown format for sass-convert --to: #{name}"
    end
  end
  opts.on('-R', '--recursive',
    'Convert all the files in a directory. Requires --from and --to.') do
    @options[:recursive] = true
  end
  opts.on('-i', '--in-place',
    'Convert a file to its own syntax.',
    'This can be used to update some deprecated syntax.') do
    @options[:in_place] = true
  end
  opts.on('--dasherize', 'Convert underscores to dashes') do
    @options[:for_tree][:dasherize] = true
  end
  opts.on('--old', 'Output the old-style ":prop val" property syntax.',
                   'Only meaningful when generating Sass.') do
    @options[:for_tree][:old] = true
  end
  opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
    @options[:for_engine][:read_cache] = false
  end
  unless ::Haml::Util.ruby1_8?
    opts.on('-E encoding', 'Specify the default encoding for Sass and CSS files.') do |encoding|
      Encoding.default_external = encoding
    end
  end
  super
end

def try_less_note

def try_less_note
  return if @@less_note_printed
  @@less_note_printed = true
  warn <<NOTE
: Sass and Less are different languages, and they work differently.
 do my best to translate, but some features -- especially mixins --
ld be checked by hand.
end