vendor/plugins/haml/lib/haml/exec.rb in radiant-0.8.2 vs vendor/plugins/haml/lib/haml/exec.rb in radiant-0.9.0.rc2
- old
+ new
@@ -1,22 +1,22 @@
require 'optparse'
require 'fileutils'
+require 'rbconfig'
module Haml
- # This module contains code for working with the
- # haml, sass, and haml2html executables,
- # such as command-line parsing stuff.
- # It shouldn't need to be invoked by client code.
- module Exec # :nodoc:
- # A class that encapsulates the executable code
- # for all three executables.
- class Generic # :nodoc:
+ # This module handles the various Haml executables (`haml`, `sass`, `css2sass`, etc).
+ module Exec
+ # An abstract class that encapsulates the executable code for all three executables.
+ class Generic
+ # @param args [Array<String>] 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.
def parse!
begin
@opts = OptionParser.new(&method(:set_opts))
@opts.parse!(@args)
@@ -30,78 +30,113 @@
exit 1
end
exit 0
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,
# which there is for Haml documents.
return exception.message.scan(/:(\d+)/).first.first if exception.is_a?(::SyntaxError)
exception.backtrace[0].scan(/:(\d+)/).first.first
end
- private
-
+ # 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
+ if RbConfig::CONFIG['host_os'] =~ /mswin|windows/i
+ opts.on('--unix-newlines', 'Use Unix-style newlines in written files.') do
+ @options[:unix_newlines] = true
+ end
+ end
+
opts.on_tail("-?", "-h", "--help", "Show this message") do
puts opts
exit
end
opts.on_tail("-v", "--version", "Print version") do
- puts("Haml #{::Haml.version[:string]}")
+ puts("Haml/Sass #{::Haml.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]
input_file, output_file = if input
- [nil, open_file(ARGV[0], 'w')]
+ [nil, open_file(@args[0], 'w')]
else
- [open_file(ARGV[0]), open_file(ARGV[1], 'w')]
+ @options[:filename] = @args[0]
+ [open_file(@args[0]), open_file(@args[1], 'w')]
end
input ||= input_file
output ||= output_file
input ||= $stdin
output ||= $stdout
@options[:input], @options[:output] = input, output
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
end
- # A class encapsulating the executable functionality
- # specific to Haml and Sass.
- class HamlSass < Generic # :nodoc:
+ # An abstrac class that encapsulates the code
+ # specific to the `haml` and `sass` executables.
+ class HamlSass < Generic
+ # @param args [Array<String>] The command-line arguments
def initialize(args)
super
@options[:for_engine] = {}
end
- private
+ protected
+ # Tells optparse how to parse the arguments
+ # available for the `haml` and `sass` executables.
+ #
+ # This is meant to be overridden by subclasses
+ # so they can add their own options.
+ #
+ # @param opts [OptionParser]
def set_opts(opts)
opts.banner = <<END
Usage: #{@name.downcase} [options] [INPUT] [OUTPUT]
Description:
@@ -135,11 +170,10 @@
puts "Cannot create #{dir}"
exit
end
File.open(File.join(dir, 'init.rb'), 'w') do |file|
- file.puts "require 'rubygems'"
file << File.read(File.dirname(__FILE__) + "/../../init.rb")
end
puts "Haml plugin added to #{original_dir}"
exit
@@ -152,66 +186,113 @@
end
super
end
+ # Processes the options set by the command-line arguments.
+ # In particular, sets `@options[:for_engine][:filename]` to the input filename
+ # and requires the appropriate file.
+ #
+ # This is meant to be overridden by subclasses
+ # so they can run their respective programs.
def process_result
super
+ @options[:for_engine][:filename] = @options[:filename] if @options[:filename]
require File.dirname(__FILE__) + "/../#{@name.downcase}"
end
end
- # A class encapsulating executable functionality
- # specific to Sass.
- class Sass < HamlSass # :nodoc:
+ # The `sass` executable.
+ class Sass < HamlSass
+ # @param args [Array<String>] The command-line arguments
def initialize(args)
super
@name = "Sass"
+ @options[:for_engine][:load_paths] = ['.'] + (ENV['SASSPATH'] || '').split(File::PATH_SEPARATOR)
end
+ protected
+
+ # Tells optparse how to parse the arguments.
+ #
+ # @param opts [OptionParser]
def set_opts(opts)
super
opts.on('-t', '--style NAME',
'Output style. Can be nested (default), compact, compressed, or expanded.') do |name|
@options[:for_engine][:style] = name.to_sym
end
+ opts.on('-l', '--line-numbers', '--line-comments',
+ 'Emit comments in the generated CSS indicating the corresponding sass line.') do
+ @options[:for_engine][:line_numbers] = true
+ end
+ opts.on('-i', '--interactive',
+ 'Run an interactive SassScript shell.') do
+ @options[:interactive] = true
+ end
+ opts.on('-I', '--load-path PATH', 'Add a sass import path.') do |path|
+ @options[:for_engine][:load_paths] << path
+ end
+ opts.on('--cache-location PATH', 'The path to put cached Sass files. Defaults to .sass-cache.') do |loc|
+ @options[:for_engine][:cache_location] = loc
+ end
+ opts.on('-C', '--no-cache', "Don't cache to sassc files.") do
+ @options[:for_engine][:cache] = false
+ end
end
+ # Processes the options set by the command-line arguments,
+ # and runs the Sass compiler appropriately.
def process_result
+ if @options[:interactive]
+ require 'sass'
+ require 'sass/repl'
+ ::Sass::Repl.new(@options).run
+ return
+ end
+
super
- input = @options[:input]
- output = @options[:output]
- template = input.read()
- input.close() if input.is_a? File
-
begin
- # We don't need to do any special handling of @options[:check_syntax] here,
- # because the Sass syntax checking happens alongside evaluation
- # and evaluation doesn't actually evaluate any code anyway.
- result = ::Sass::Engine.new(template, @options[:for_engine]).render
+ input = @options[:input]
+ output = @options[:output]
+
+ tree =
+ if input.is_a?(File) && !@options[:check_syntax]
+ ::Sass::Files.tree_for(input.path, @options[:for_engine])
+ else
+ # We don't need to do any special handling of @options[:check_syntax] here,
+ # because the Sass syntax checking happens alongside evaluation
+ # and evaluation doesn't actually evaluate any code anyway.
+ ::Sass::Engine.new(input.read(), @options[:for_engine]).to_tree
+ end
+
+ input.close() if input.is_a?(File)
+
+ output.write(tree.render)
+ output.close() if output.is_a? File
rescue ::Sass::SyntaxError => e
raise e if @options[:trace]
raise "Syntax error on line #{get_line e}: #{e.message}"
end
-
- output.write(result)
- output.close() if output.is_a? File
end
end
- # A class encapsulating executable functionality
- # specific to Haml.
- class Haml < HamlSass # :nodoc:
+ # The `haml` executable.
+ class Haml < HamlSass
+ # @param args [Array<String>] The command-line arguments
def initialize(args)
super
@name = "Haml"
@options[:requires] = []
@options[:load_paths] = []
end
+ # Tells optparse how to parse the arguments.
+ #
+ # @param opts [OptionParser]
def set_opts(opts)
super
opts.on('-t', '--style NAME',
'Output style. Can be indented (default) or ugly.') do |name|
@@ -239,10 +320,12 @@
opts.on('--debug', "Print out the precompiled Ruby source.") do
@options[:debug] = true
end
end
+ # Processes the options set by the command-line arguments,
+ # and runs the Haml compiler appropriately.
def process_result
super
input = @options[:input]
output = @options[:output]
@@ -278,27 +361,31 @@
output.write(result)
output.close() if output.is_a? File
end
end
- # A class encapsulating executable functionality
- # specific to the html2haml executable.
- class HTML2Haml < Generic # :nodoc:
+ # The `html2haml` executable.
+ class HTML2Haml < Generic
+ # @param args [Array<String>] The command-line arguments
def initialize(args)
super
@module_opts = {}
begin
require 'haml/html'
rescue LoadError => err
dep = err.message.scan(/^no such file to load -- (.*)/)[0]
- puts "Required dependency #{dep} not found!"
+ raise err if @options[:trace] || dep.nil? || dep.empty?
+ $stderr.puts "Required dependency #{dep} not found!\n Use --trace for backtrace."
exit 1
end
end
+ # Tells optparse how to parse the arguments.
+ #
+ # @param opts [OptionParser]
def set_opts(opts)
opts.banner = <<END
Usage: html2haml [options] [INPUT] [OUTPUT]
Description: Transforms an HTML file into corresponding Haml code.
@@ -319,10 +406,12 @@
end
super
end
+ # Processes the options set by the command-line arguments,
+ # and runs the HTML compiler appropriately.
def process_result
super
input = @options[:input]
output = @options[:output]
@@ -332,36 +421,43 @@
output.write(::Haml::HTML.new(input, @module_opts).render)
end
end
- # A class encapsulating executable functionality
- # specific to the css2sass executable.
- class CSS2Sass < Generic # :nodoc:
+ # The `css2sass` executable.
+ class CSS2Sass < Generic
+ # @param args [Array<String>] The command-line arguments
def initialize(args)
super
@module_opts = {}
require 'sass/css'
end
+ # Tells optparse how to parse the arguments.
+ #
+ # @param opts [OptionParser]
def set_opts(opts)
opts.banner = <<END
Usage: css2sass [options] [INPUT] [OUTPUT]
Description: Transforms a CSS file into corresponding Sass code.
Options:
END
- opts.on('-a', '--alternate', 'Output using alternative Sass syntax (margin: 1px)') do
- @module_opts[:alternate] = true
+ opts.on('--old', 'Output the old-style ":prop val" property syntax') do
+ @module_opts[:old] = true
end
+ opts.on_tail('-a', '--alternate', 'Ignored') {}
+
super
end
+ # Processes the options set by the command-line arguments,
+ # and runs the CSS compiler appropriately.
def process_result
super
input = @options[:input]
output = @options[:output]