lib/temple/html/pretty.rb
module Temple module HTML # @api public class Pretty < Fast define_options :indent => ' ', :pretty => true, :indent_tags => %w(article aside audio base body datalist dd div dl dt fieldset figure footer form head h1 h2 h3 h4 h5 h6 header hgroup hr html li link meta nav ol option p rp rt ruby section script style table tbody td tfoot th thead tr ul video doctype).freeze, :pre_tags => %w(code pre textarea).freeze def initialize(opts = {}) super @last = nil @indent = 0 @pretty = options[:pretty] @pre_tags = Regexp.new(options[:pre_tags].map {|t| "<#{t}" }.join('|')) end def call(exp) @pretty ? [:multi, preamble, compile(exp)] : super end def on_static(content) if @pretty if @pre_tags !~ content content = content.sub(/\A\s*\n?/, "\n") if options[:indent_tags].include?(@last) content = content.gsub("\n", indent) end @last = :static end [:static, content] end def on_dynamic(code) if @pretty tmp = unique_name indent_code = '' indent_code << "#{tmp} = #{tmp}.sub(/\\A\\s*\\n?/, \"\\n\"); " if options[:indent_tags].include?(@last) indent_code << "#{tmp} = #{tmp}.gsub(\"\\n\", #{indent.inspect}); " if ''.respond_to?(:html_safe) safe = unique_name # we have to first save if the string was html_safe # otherwise the gsub operation will lose that knowledge indent_code = "#{safe} = #{tmp}.html_safe?; #{indent_code}#{tmp} = #{tmp}.html_safe if #{safe}; " end @last = :dynamic [:multi, [:code, "#{tmp} = (#{code}).to_s"], [:code, "if #{@pre_tags_name} !~ #{tmp}; #{indent_code}end"], [:dynamic, tmp]] else [:dynamic, code] end end def on_html_doctype(type) return super unless @pretty [:multi, [:static, tag_indent('doctype')], super] end def on_html_comment(content) return super unless @pretty result = [:multi, [:static, tag_indent('comment')], super] @last = :comment result end def on_html_tag(name, attrs, content = nil) return super unless @pretty name = name.to_s closed = !content || (empty_exp?(content) && options[:autoclose].include?(name)) @pretty = false result = [:multi, [:static, "#{tag_indent(name)}<#{name}"], compile(attrs)] result << [:static, (closed && xhtml? ? ' /' : '') + '>'] @pretty = !options[:pre_tags].include?(name) if content @indent += 1 result << compile(content) @indent -= 1 end result << [:static, "#{content && !empty_exp?(content) ? tag_indent(name) : ''}</#{name}>"] unless closed @pretty = true result end protected def preamble @pre_tags_name = unique_name [:code, "#{@pre_tags_name} = /#{@pre_tags.source}/"] end def indent "\n" + (options[:indent] || '') * @indent end # Return indentation before tag def tag_indent(name) result = @last && (options[:indent_tags].include?(@last) || options[:indent_tags].include?(name)) ? indent : '' @last = name result end end end end