require File.dirname(__FILE__) + '/../haml' require 'optparse' 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: def initialize(args) @args = args @options = {} end def parse! begin @opts = OptionParser.new(&method(:set_opts)) @opts.parse!(@args) process_result @options rescue Exception => e raise e if e.is_a? SystemExit $stderr.print "#{e.class} on line #{get_line e}: " if @options[:trace] $stderr.puts e.message e.backtrace[1..-1].each { |t| $stderr.puts " #{t}" } if @options[:trace] exit 1 end exit 0 end def to_s @opts.to_s end protected def get_line(exception) exception.backtrace[0].scan(/:(\d+)/)[0] end private 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_tail("-?", "-h", "--help", "Show this message") do puts opts exit end opts.on_tail("-v", "--version", "Print version") do puts("Haml " + File.read(File.dirname(__FILE__) + '/../../VERSION')) exit end end def process_result input, output = @options[:input], @options[:output] input_file, output_file = if input [nil, open_file(ARGV[0], 'w')] else [open_file(ARGV[0]), open_file(ARGV[1], 'w')] end input ||= input_file output ||= output_file input ||= $stdin output ||= $stdout @options[:input], @options[:output] = input, output end def open_file(filename, flag = 'r') return if filename.nil? File.open(filename, flag) end end # A class encapsulating the executable functionality # specific to Haml and Sass. class HamlSass < Generic # :nodoc: def initialize(args) super @options[:for_engine] = {} end private def set_opts(opts) opts.banner = < 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: def initialize(args) super @name = "Haml" end def process_result super input = @options[:input] output = @options[:output] template = input.read() input.close() if input.is_a? File begin engine = ::Haml::Engine.new(template, @options[:for_engine]) if @options[:check_syntax] puts "Syntax OK" return end result = engine.to_html rescue Exception => e raise e if @options[:trace] case e when ::Haml::SyntaxError; raise "Syntax error on line #{get_line e}: #{e.message}" when ::Haml::HamlError; raise "Haml error on line #{get_line e}: #{e.message}" else raise "Exception on line #{get_line e}: #{e.message}\n Use --trace for backtrace." end end 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: 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!" exit 1 end end def set_opts(opts) opts.banner = <