html2haml-1.0.1/0000755000175000017500000000000012147506116012422 5ustar gwolfgwolfhtml2haml-1.0.1/bin/0000755000175000017500000000000012147506116013172 5ustar gwolfgwolfhtml2haml-1.0.1/bin/html2haml0000755000175000017500000000023412147506116015007 0ustar gwolfgwolf#!/usr/bin/env ruby require File.dirname(__FILE__) + '/../lib/html2haml' require 'html2haml/exec' opts = Html2haml::Exec::HTML2Haml.new(ARGV) opts.parse! html2haml-1.0.1/lib/0000755000175000017500000000000012147506116013170 5ustar gwolfgwolfhtml2haml-1.0.1/lib/html2haml/0000755000175000017500000000000012147506116015060 5ustar gwolfgwolfhtml2haml-1.0.1/lib/html2haml/html/0000755000175000017500000000000012147506116016024 5ustar gwolfgwolfhtml2haml-1.0.1/lib/html2haml/html/erb.rb0000644000175000017500000001276212147506116017131 0ustar gwolfgwolfrequire 'cgi' require 'erubis' require 'ruby_parser' module Haml class HTML # A class for converting ERB code into a format that's easier # for the {Haml::HTML} Hpricot-based parser to understand. # # Uses [Erubis](http://www.kuwata-lab.com/erubis)'s extensible parsing powers # to parse the ERB in a reliable way, # and [ruby_parser](http://parsetree.rubyforge.org/)'s Ruby knowledge # to figure out whether a given chunk of Ruby code starts a block or not. # # The ERB tags are converted to HTML tags in the following way. # `<% ... %>` is converted into ` ... `. # `<%= ... %>` is converted into ` ... `. # Finally, if either of these opens a Ruby block, # ` ... ` will wrap the entire contents of the block - # that is, everything that should be indented beneath the previous silent or loud tag. class ERB < Erubis::Basic::Engine # Compiles an ERB template into a HTML document containing `haml:` tags. # # @param template [String] The ERB template # @return [String] The output document # @see Haml::HTML::ERB def self.compile(template) new(template).src end # `html2haml` doesn't support HTML-escaped expressions. def escaped_expr(code) raise Haml::Error.new("html2haml doesn't support escaped expressions.") end # The ERB-to-Hamlized-HTML conversion has no preamble. def add_preamble(src); end # The ERB-to-Hamlized-HTML conversion has no postamble. def add_postamble(src); end # Concatenates the text onto the source buffer. # # @param src [String] The source buffer # @param text [String] The raw text to add to the buffer def add_text(src, text) src << text end # Concatenates a silent Ruby statement onto the source buffer. # This uses the `` tag, # and may close and/or open a Ruby block with the `` tag. # # In particular, a block is closed if this statement is some form of `end`, # opened if it's a block opener like `do`, `if`, or `begin`, # and both closed and opened if it's a mid-block keyword # like `else` or `when`. # # @param src [String] The source buffer # @param code [String] The Ruby statement to add to the buffer def add_stmt(src, code) src << '' if block_closer?(code) || mid_block?(code) src << '' << h(code) << '' unless code.strip == "end" src << '' if block_opener?(code) || mid_block?(code) end # Concatenates a Ruby expression that's printed to the document # onto the source buffer. # This uses the `` tag, # and may open a Ruby block with the `` tag. # An expression never closes a block. # # @param src [String] The source buffer # @param code [String] The Ruby expression to add to the buffer def add_expr_literal(src, code) src << '' << h(code) << '' src << '' if block_opener?(code) end # `html2haml` doesn't support debugging expressions. def add_expr_debug(src, code) raise Haml::Error.new("html2haml doesn't support debugging expressions.") end private # HTML-escaped some text (in practice, always Ruby code). # A utility method. # # @param text [String] The text to escape # @return [String] The escaped text def h(text) CGI.escapeHTML(text) end # Returns whether the code is valid Ruby code on its own. # # @param code [String] Ruby code to check # @return [Boolean] def valid_ruby?(code) RubyParser.new.parse(code) rescue Racc::ParseError, RubyParser::SyntaxError false end # Returns whether the code has any content # This is used to test whether lines have been removed by erubis, such as comments # # @param code [String] Ruby code to check # @return [Boolean] def has_code?(code) code != "\n" end # Checks if a string of Ruby code opens a block. # This could either be something like `foo do |a|` # or a keyword that requires a matching `end` # like `if`, `begin`, or `case`. # # @param code [String] Ruby code to check # @return [Boolean] def block_opener?(code) return unless has_code?(code) valid_ruby?(code + "\nend") || valid_ruby?(code + "\nwhen foo\nend") end # Checks if a string of Ruby code closes a block. # This is always `end` followed optionally by some method calls. # # @param code [String] Ruby code to check # @return [Boolean] def block_closer?(code) return unless has_code?(code) valid_ruby?("begin\n" + code) end # Checks if a string of Ruby code comes in the middle of a block. # This could be a keyword like `else`, `rescue`, or `when`, # or even `end` with a method call that takes a block. # # @param code [String] Ruby code to check # @return [Boolean] def mid_block?(code) return unless has_code?(code) return if valid_ruby?(code) valid_ruby?("if foo\n#{code}\nend") || # else, elsif valid_ruby?("begin\n#{code}\nend") || # rescue, ensure valid_ruby?("case foo\n#{code}\nend") # when end end end end html2haml-1.0.1/lib/html2haml/exec.rb0000644000175000017500000002024412147506116016333 0ustar gwolfgwolfrequire 'optparse' require 'fileutils' require 'rbconfig' module Html2haml # This module handles the various Haml executables (`haml` and `haml-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 = {:for_engine => {}} 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, # 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 # 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 # Note that this is the preferred way to check for Windows, since # JRuby and Rubinius also run there. if RbConfig::CONFIG['host_os'] =~ /mswin|windows|mingw/i @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("html2haml #{::Html2haml::VERSION}") 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 ||= open_file(args.shift, 'w') || $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 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 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 @module_opts = {} end # Tells optparse how to parse the arguments. # # @param opts [OptionParser] def set_opts(opts) opts.banner = < e raise "#{e.is_a?(::Haml::SyntaxError) ? "Syntax error" : "Error"} on line " + "#{get_line e}: #{e.message}" rescue LoadError => err handle_load_error(err) end end end end html2haml-1.0.1/lib/html2haml/html.rb0000644000175000017500000003262312147506116016357 0ustar gwolfgwolfrequire 'cgi' require 'hpricot' require 'html2haml/html/erb' # Haml monkeypatches various Hpricot classes # to add methods for conversion to Haml. # @private module Hpricot # @see Hpricot module Node # Whether this node has already been converted to Haml. # Only used for text nodes and elements. # # @return [Boolean] attr_accessor :converted_to_haml # Returns the Haml representation of the given node. # # @param tabs [Fixnum] The indentation level of the resulting Haml. # @option options (see Haml::HTML#initialize) def to_haml(tabs, options) return "" if converted_to_haml || to_s.strip.empty? text = uninterp(self.to_s) node = next_node while node.is_a?(::Hpricot::Elem) && node.name == "haml:loud" node.converted_to_haml = true text << '#{' << CGI.unescapeHTML(node.inner_text).gsub(/\n\s*/, ' ').strip << '}' if node.next_node.is_a?(::Hpricot::Text) node = node.next_node text << uninterp(node.to_s) node.converted_to_haml = true end node = node.next_node end return parse_text_with_interpolation(text, tabs) end private def erb_to_interpolation(text, options) return text unless options[:erb] text = CGI.escapeHTML(uninterp(text)) %w[ ].each {|str| text.gsub!(CGI.escapeHTML(str), str)} ::Hpricot::XML(text).children.inject("") do |str, elem| if elem.is_a?(::Hpricot::Text) str + CGI.unescapeHTML(elem.to_s) else # element str + '#{' + CGI.unescapeHTML(elem.innerText.strip) + '}' end end end def tabulate(tabs) ' ' * tabs end def uninterp(text) text.gsub('#{', '\#{') #' end def attr_hash attributes.to_hash end def parse_text(text, tabs) parse_text_with_interpolation(uninterp(text), tabs) end def parse_text_with_interpolation(text, tabs) text.strip! return "" if text.empty? text.split("\n").map do |line| line.strip! "#{tabulate(tabs)}#{'\\' if Haml::Parser::SPECIAL_CHARACTERS.include?(line[0])}#{line}\n" end.join end end end # @private HAML_TAGS = %w[haml:block haml:loud haml:silent] HAML_TAGS.each do |t| Hpricot::ElementContent[t] = {} Hpricot::ElementContent.keys.each do |key| Hpricot::ElementContent[t][key.hash] = true end end Hpricot::ElementContent.keys.each do |k| HAML_TAGS.each do |el| val = Hpricot::ElementContent[k] val[el.hash] = true if val.is_a?(Hash) end end module Haml # Converts HTML documents into Haml templates. # Depends on [Hpricot](http://github.com/whymirror/hpricot) for HTML parsing. # If ERB conversion is being used, also depends on # [Erubis](http://www.kuwata-lab.com/erubis) to parse the ERB # and [ruby_parser](http://parsetree.rubyforge.org/) to parse the Ruby code. # # Example usage: # # Haml::HTML.new("Blat").render # #=> "%a{:href => 'http://google.com'} Blat" class HTML # @param template [String, Hpricot::Node] The HTML template to convert # @option options :erb [Boolean] (false) Whether or not to parse # ERB's `<%= %>` and `<% %>` into Haml's `=` and `-` # @option options :xhtml [Boolean] (false) Whether or not to parse # the HTML strictly as XHTML def initialize(template, options = {}) @options = options if template.is_a? Hpricot::Node @template = template else if template.is_a? IO template = template.read end template = Haml::Util.check_encoding(template) {|msg, line| raise Haml::Error.new(msg, line)} if @options[:erb] require 'html2haml/html/erb' template = ERB.compile(template) end method = @options[:xhtml] ? Hpricot.method(:XML) : method(:Hpricot) @template = method.call(template.gsub('&', '&')) end end # Processes the document and returns the result as a string # containing the Haml template. def render @template.to_haml(0, @options) end alias_method :to_haml, :render TEXT_REGEXP = /^(\s*).*$/ # @see Hpricot # @private class ::Hpricot::Doc # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) (children || []).inject('') {|s, c| s << c.to_haml(0, options)} end end # @see Hpricot # @private class ::Hpricot::XMLDecl # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) "#{tabulate(tabs)}!!! XML\n" end end # @see Hpricot # @private class ::Hpricot::CData # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) content = parse_text_with_interpolation( erb_to_interpolation(self.content, options), tabs + 1) "#{tabulate(tabs)}:cdata\n#{content}" end end # @see Hpricot # @private class ::Hpricot::DocType # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) attrs = public_id.nil? ? ["", "", ""] : public_id.scan(/DTD\s+([^\s]+)\s*([^\s]*)\s*([^\s]*)\s*\/\//)[0] raise Haml::SyntaxError.new("Invalid doctype") if attrs == nil type, version, strictness = attrs.map { |a| a.downcase } if type == "html" version = "" strictness = "strict" if strictness == "" end if version == "1.0" || version.empty? version = nil end if strictness == 'transitional' || strictness.empty? strictness = nil end version = " #{version.capitalize}" if version strictness = " #{strictness.capitalize}" if strictness "#{tabulate(tabs)}!!!#{version}#{strictness}\n" end end # @see Hpricot # @private class ::Hpricot::Comment # @see Haml::HTML::Node#to_haml def to_haml(tabs, options) content = self.content if content =~ /\A(\[[^\]]+\])>(.*) 1 # Multiline script block # Normalize the indentation so that the last line is the base indent_str = lines.last[/^[ \t]*/] indent_re = /^[ \t]{0,#{indent_str.count(" ") + 8 * indent_str.count("\t")}}/ lines.map! {|s| s.gsub!(indent_re, '')} # Add an extra " " to make it indented relative to "= " lines[1..-1].each {|s| s.gsub!(/^/, " ")} # Add | at the end, properly aligned length = lines.map {|s| s.size}.max + 1 lines.map! {|s| "%#{-length}s|" % s} if next_sibling && next_sibling.is_a?(Hpricot::Elem) && next_sibling.name == "haml:loud" && next_sibling.inner_text.split("\n").reject {|s| s.strip.empty?}.size > 1 lines << "-#" end end return lines.map {|s| output + s + "\n"}.join when "silent" return CGI.unescapeHTML(inner_text).split("\n").map do |line| next "" if line.strip.empty? "#{output}- #{line.strip}\n" end.join when "block" return render_children("", tabs, options) end end if self.next && self.next.text? && self.next.content =~ /\A[^\s]/ if self.previous.nil? || self.previous.text? && (self.previous.content =~ /[^\s]\Z/ || self.previous.content =~ /\A\s*\Z/ && self.previous.previous.nil?) nuke_outer_whitespace = true else output << "= succeed #{self.next.content.slice!(/\A[^\s]+/).dump} do\n" tabs += 1 output << tabulate(tabs) end end output << "%#{name}" unless name == 'div' && (static_id?(options) || static_classname?(options) && attr_hash['class'].split(' ').any?(&method(:haml_css_attr?))) if attr_hash if static_id?(options) output << "##{attr_hash['id']}" remove_attribute('id') end if static_classname?(options) leftover = attr_hash['class'].split(' ').reject do |c| next unless haml_css_attr?(c) output << ".#{c}" end remove_attribute('class') set_attribute('class', leftover.join(' ')) unless leftover.empty? end output << haml_attributes(options) if attr_hash.length > 0 end output << ">" if nuke_outer_whitespace output << "/" if empty? && !etag if children && children.size == 1 child = children.first if child.is_a?(::Hpricot::Text) if !child.to_s.include?("\n") text = child.to_haml(tabs + 1, options) return output + " " + text.lstrip.gsub(/^\\/, '') unless text.chomp.include?("\n") || text.empty? return output + "\n" + text elsif ["pre", "textarea"].include?(name) || (name == "code" && parent.is_a?(::Hpricot::Elem) && parent.name == "pre") return output + "\n#{tabulate(tabs + 1)}:preserve\n" + innerText.gsub(/^/, tabulate(tabs + 2)) end elsif child.is_a?(::Hpricot::Elem) && child.name == "haml:loud" return output + child.to_haml(tabs + 1, options).lstrip end end render_children(output + "\n", tabs, options) end private def render_children(so_far, tabs, options) (self.children || []).inject(so_far) do |output, child| output + child.to_haml(tabs + 1, options) end end def dynamic_attributes @dynamic_attributes ||= begin Hash[attr_hash.map do |name, value| next if value.empty? full_match = nil ruby_value = value.gsub(%r{\s*(.+?)\s*}) do full_match = $`.empty? && $'.empty? CGI.unescapeHTML(full_match ? $1: "\#{#{$1}}") end next if ruby_value == value [name, full_match ? ruby_value : %("#{ruby_value}")] end] end end def to_haml_filter(filter, tabs, options) content = if children.first.is_a?(::Hpricot::CData) children.first.content else CGI.unescapeHTML(self.innerText) end content = erb_to_interpolation(content, options) content.gsub!(/\A\s*\n(\s*)/, '\1') original_indent = content[/\A(\s*)/, 1] if content.split("\n").all? {|l| l.strip.empty? || l =~ /^#{original_indent}/} content.gsub!(/^#{original_indent}/, tabulate(tabs + 1)) else # Indentation is inconsistent. Strip whitespace from start and indent all # to ensure valid Haml. content.lstrip! content.gsub!(/^/, tabulate(tabs + 1)) end content.rstrip! content << "\n" "#{tabulate(tabs)}:#{filter}\n#{content}" end def static_attribute?(name, options) attr_hash[name] && !dynamic_attribute?(name, options) end def dynamic_attribute?(name, options) options[:erb] and dynamic_attributes.key?(name) end def static_id?(options) static_attribute?('id', options) && haml_css_attr?(attr_hash['id']) end def static_classname?(options) static_attribute?('class', options) end def haml_css_attr?(attr) attr =~ /^[-:\w]+$/ end # Returns a string representation of an attributes hash # that's prettier than that produced by Hash#inspect def haml_attributes(options) attrs = attr_hash.sort.map do |name, value| haml_attribute_pair(name, value, options) end if options[:html_style_attributes] "(#{attrs.join(' ')})" else "{#{attrs.join(', ')}}" end end # Returns the string representation of a single attribute key value pair def haml_attribute_pair(name, value, options) value = dynamic_attribute?(name, options) ? dynamic_attributes[name] : value.inspect if options[:html_style_attributes] "#{name}=#{value}" else name = name.index(/\W/) ? name.inspect : ":#{name}" "#{name} => #{value}" end end end end end html2haml-1.0.1/lib/html2haml/version.rb0000644000175000017500000000005112147506116017066 0ustar gwolfgwolfmodule Html2haml VERSION = "1.0.1" end html2haml-1.0.1/lib/html2haml.rb0000644000175000017500000000032112147506116015401 0ustar gwolfgwolfrequire "rubygems" gem "haml", ">= 3.2" require File.expand_path("../html2haml/version", __FILE__) require "haml/util" require "haml/parser" require "haml/error" require "html2haml/html" module Html2haml end html2haml-1.0.1/test/0000755000175000017500000000000012147506116013401 5ustar gwolfgwolfhtml2haml-1.0.1/test/html2haml_test.rb0000644000175000017500000002013512147506116016656 0ustar gwolfgwolfrequire 'test_helper' class Html2HamlTest < MiniTest::Unit::TestCase def test_empty_render_should_remain_empty assert_equal '', render('') end def test_doctype assert_equal '!!!', render("") assert_equal '!!! 1.1', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!! Mobile 1.2', render('') assert_equal '!!! Basic 1.1', render('') assert_equal '!!!', render('') assert_equal '!!! Strict', render('') assert_equal '!!! Frameset', render('') assert_equal '!!!', render('') end def test_id_and_class_should_be_removed_from_hash assert_equal '%span#foo.bar', render(' ') end def test_no_tag_name_for_div_if_class_or_id_is_present assert_equal '#foo', render('
') assert_equal '.foo', render('
') end def test_multiple_class_names assert_equal '.foo.bar.baz', render('
') end def test_should_have_pretty_attributes assert_equal('%input{:name => "login", :type => "text"}/', render('')) assert_equal('%meta{:content => "text/html", "http-equiv" => "Content-Type"}/', render('')) end def test_should_have_html_style_attributes assert_equal('%input(name="login" type="text")/', render('', :html_style_attributes => true)) assert_equal('%meta(content="text/html" http-equiv="Content-Type")/', render('', :html_style_attributes => true)) end def test_class_with_dot_and_hash assert_equal('%div{:class => "foo.bar"}', render("
")) assert_equal('%div{:class => "foo#bar"}', render("
")) assert_equal('.foo.bar{:class => "foo#bar foo.bar"}', render("
")) end def test_id_with_dot_and_hash assert_equal('%div{:id => "foo.bar"}', render("
")) assert_equal('%div{:id => "foo#bar"}', render("
")) end def test_interpolation assert_equal('Foo \#{bar} baz', render('Foo #{bar} baz')) end def test_interpolation_in_attrs assert_equal('%p{:foo => "\#{bar} baz"}', render('

')) end def test_cdata assert_equal(<
flop
HAML

flop
]]>

HTML end def test_self_closing_tag assert_equal("%foo/", render("")) end def test_inline_text assert_equal("%p foo", render("

foo

")) end def test_inline_comment assert_equal("/ foo", render("")) assert_equal(<

bar

HTML end def test_non_inline_comment assert_equal(< HTML end def test_non_inline_text assert_equal(< foo

HTML assert_equal(< foo

HTML assert_equal(<foo

HTML end def test_script_tag assert_equal(< function foo() { return "12" & "13"; } HTML end def test_script_tag_with_cdata assert_equal(< HTML end def test_pre assert_equal(<foo bar baz HTML end def test_pre_code assert_equal(<foo bar baz HTML end def test_code_without_pre assert_equal(<foo bar baz HTML end def test_conditional_comment assert_equal(< bar baz HTML end def test_style_to_css_filter assert_equal(< foo { bar: baz; } HTML end def test_style_to_css_filter_with_following_content assert_equal(< Hello HTML end def test_filter_with_inconsistent_indentation assert_equal(< foo { badly: indented; } HTML end def test_inline_conditional_comment assert_equal(< bar baz HTML end def test_minus_in_tag assert_equal("%p - foo bar -", render("

- foo bar -

")) end def test_equals_in_tag assert_equal("%p = foo bar =", render("

= foo bar =

")) end def test_hash_in_tag assert_equal("%p # foo bar #", render("

# foo bar #

")) end def test_comma_post_tag assert_equal(< Foo , %span bar Foo %span> bar , %span baz HAML
Foo, bar Foobar, baz
HTML end def test_comma_post_tag_with_text_before assert_equal(< Batch Foo, Bar HTML end def test_haml_tags_should_be_on_new_line_after_tag_with_blank_content xml = " \n102" haml = "%weight\n%pages 102" assert_equal haml, render(xml) end # Encodings unless RUBY_VERSION < "1.9" def test_encoding_error render("foo\nbar\nb\xFEaz".force_encoding("utf-8")) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-8 character "\xFE"', e.message) end def test_ascii_incompatible_encoding_error template = "foo\nbar\nb_z".encode("utf-16le") template[9] = "\xFE".force_encoding("utf-16le") render(template) assert(false, "Expected exception") rescue Haml::Error => e assert_equal(3, e.line) assert_equal('Invalid UTF-16LE character "\xFE"', e.message) end end # Regression Tests def test_xhtml_strict_doctype assert_equal('!!! Strict', render(< HTML end end html2haml-1.0.1/test/erb_test.rb0000644000175000017500000002141212147506116015535 0ustar gwolfgwolfrequire 'test_helper' class ErbTest < MiniTest::Unit::TestCase def test_erb assert_equal '- foo = bar', render_erb('<% foo = bar %>') assert_equal '- foo = bar', render_erb('<% foo = bar -%>') assert_equal '= h @item.title', render_erb('<%=h @item.title %>') assert_equal '= h @item.title', render_erb('<%=h @item.title -%>') end def test_inline_erb assert_equal("%p= foo", render_erb("

<%= foo %>

")) end def test_non_inline_erb assert_equal(< <%= foo %>

HTML assert_equal(< <%= foo %>

HTML assert_equal(<<%= foo %>

HTML end def test_erb_in_cdata assert_equal(< baz]]> HTML end def test_erb_in_script assert_equal(< function foo() { return <%= foo.to_json %>; } HTML end def test_erb_in_style assert_equal(< foo { bar: <%= "baz" %>; } HTML end def test_erb_in_line assert_equal 'foo bar #{baz}', render_erb('foo bar <%= baz %>') assert_equal 'foo bar #{baz}! Bang.', render_erb('foo bar <%= baz %>! Bang.') end def test_erb_multi_in_line assert_equal('foo bar #{baz}! Bang #{bop}.', render_erb('foo bar <%= baz %>! Bang <%= bop %>.')) assert_equal('foo bar #{baz}#{bop}!', render_erb('foo bar <%= baz %><%= bop %>!')) end def test_erb_with_html_special_chars assert_equal '= 3 < 5 ? "OK" : "Your computer is b0rken"', render_erb('<%= 3 < 5 ? "OK" : "Your computer is b0rken" %>') end def test_erb_in_class_attribute assert_equal "%div{:class => dyna_class} I have a dynamic attribute", render_erb('
I have a dynamic attribute
') end def test_erb_in_id_attribute assert_equal "%div{:id => dyna_id} I have a dynamic attribute", render_erb('
I have a dynamic attribute
') end def test_erb_in_attribute_results_in_string_interpolation assert_equal('%div{:id => "item_#{i}"} Ruby string interpolation FTW', render_erb('
Ruby string interpolation FTW
')) end def test_erb_in_attribute_with_trailing_content assert_equal('%div{:class => "#{12}!"} Bang!', render_erb('
Bang!
')) end def test_erb_in_html_escaped_attribute assert_equal '%div{:class => "foo"} Bang!', render_erb('
">Bang!
') end def test_erb_in_attribute_to_multiple_interpolations assert_equal('%div{:class => "#{12} + #{13}"} Math is super', render_erb('
Math is super
')) end def test_whitespace_eating_erb_tags assert_equal '- form_for', render_erb('<%- form_for -%>') end def test_interpolation_in_erb assert_equal('= "Foo #{bar} baz"', render_erb('<%= "Foo #{bar} baz" %>')) end def test_interpolation_in_erb_attrs assert_equal('%p{:foo => "#{bar} baz"}', render_erb('

">

')) end def test_multiline_erb_silent_script assert_equal(< <% foo bar baz %>

foo

ERB end def test_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_weirdly_indented_multiline_erb_loud_script assert_equal(< <%= foo + bar.baz.bang + baz %>

foo

ERB end def test_two_multiline_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar do bang end %>

foo

ERB end def test_multiline_then_single_line_erb_loud_scripts assert_equal(< <%= foo + bar.baz.bang + baz %> <%= foo.bar %>

foo

ERB end def test_multiline_erb_but_really_single_line assert_equal(< <%= foo %>

foo

ERB end ### Block Parsing def test_block_parsing assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_args assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_equals assert_equal(<

bar

<% end %> ERB end def test_block_parsing_with_modified_end assert_equal(< blah <% end.bip %> ERB end def test_block_parsing_with_modified_end_with_block assert_equal(< blah <% end.bip do %> brang <% end %> ERB end def test_multiline_block_opener assert_equal(< foo <% end %> ERB end def test_if_elsif_else_parsing assert_equal(<

bar

<% elsif bar.foo("zip") %>
baz
<% else %> bibble <% end %> ERB end def test_case_when_parsing assert_equal(< <% when "bip" %>

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB assert_equal(<

bip

<% when "bop" %>

BOP

<% when bizzle.bang.boop.blip %> BIZZLE BANG BOOP BLIP <% end %> ERB end def test_begin_rescue_ensure assert_equal(< e %p b - ensure %p c HAML <% begin %>

a

<% rescue FooException => e %>

b

<% ensure %>

c

<% end %> ERB end # Regression def test_tag_inside_block assert_equal(< <% foo.each do %> <% end %> ERB end def test_silent_inside_block_inside_tag assert_equal(< <% foo.each do %> <% haml_puts "foo" %> <% end %> ERB end def test_commented_erb_should_not_cause_indentation assert_equal(< html2haml and multiline titles <%=# stylesheet_link_tag :first %> <%#= stylesheet_link_tag :second %> <%# stylesheet_link_tag :third %> <%= stylesheet_link_tag 'another file' %> ERB end def test_can_parse_ruby_19_hashes_as_arguments erb = "<%= foobar 'foo', {bar: 'baz'} %>" begin Haml::HTML::ERB.new(erb) rescue flunk "should not raise an error" end end def test_should_wrap_in_silent assert_equal(< some_variable_or_function \n
HTML <% some_variable_or_function %> ERB end #comment content is removed by erubis def test_should_wrap_process_comments_as_empty_lines assert_equal(<\n
HTML <%# some_variable_or_function %> ERB end end html2haml-1.0.1/test/test_helper.rb0000644000175000017500000000062412147506116016246 0ustar gwolfgwolfrequire "rubygems" if ENV["COVERAGE"] require "simplecov" SimpleCov.start end require "bundler/setup" require "minitest/autorun" require "html2haml" require 'html2haml/html' require 'html2haml/html/erb' class MiniTest::Unit::TestCase protected def render(text, options = {}) Haml::HTML.new(text, options).render.rstrip end def render_erb(text) render(text, :erb => true) end end html2haml-1.0.1/MIT-LICENSE0000644000175000017500000000211312147506116014053 0ustar gwolfgwolfCopyright (c) 2006-2013 Hampton Catlin, Nathan Weizenbaum and Norman Clarke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.html2haml-1.0.1/README.md0000644000175000017500000000455212147506116013707 0ustar gwolfgwolf# Html2haml Converts HTML to Haml. ## Installation Add this line to your application's Gemfile: gem 'html2haml' And then execute: $ bundle Or install it yourself as: $ gem install html2haml ## Usage See `html2haml --help`: Usage: html2haml [options] [INPUT] [OUTPUT] Description: Transforms an HTML file into corresponding Haml code. Options: -e, --erb Parse ERb tags. --no-erb Don't parse ERb tags. -r, --rhtml Deprecated; same as --erb. --no-rhtml Deprecated; same as --no-erb. -x, --xhtml Parse the input using the more strict XHTML parser. --html-attributes Use HTML style attributes instead of Ruby hash style. -E ex[:in] Specify the default external and internal character encodings. -s, --stdin Read input from standard input instead of an input file --trace Show a full traceback on error --unix-newlines Use Unix-style newlines in written files. -?, -h, --help Show this message -v, --version Print version ## License Copyright (c) 2006-2013 Hampton Catlin, Nathan Weizenbaum and Norman Clarke Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. html2haml-1.0.1/Rakefile0000644000175000017500000000105612147506116014071 0ustar gwolfgwolfrequire "rake/clean" require "rake/testtask" require "rubygems/package_task" task :default => :test CLEAN.replace %w(pkg doc coverage .yardoc) Rake::TestTask.new do |t| t.libs << 'lib' << 'test' t.test_files = Dir["test/**/*_test.rb"] t.verbose = true end task :set_coverage_env do ENV["COVERAGE"] = "true" end desc "Run Simplecov (only works on 1.9)" task :coverage => [:set_coverage_env, :test] gemspec = File.expand_path("../html2haml.gemspec", __FILE__) if File.exist? gemspec Gem::PackageTask.new(eval(File.read(gemspec))) { |pkg| } end html2haml-1.0.1/Changelog.markdown0000644000175000017500000000034312147506116016055 0ustar gwolfgwolf# HTML2Haml Changelog ## 1.0.1 Rescue from `RubyParser::SyntaxError` in check for valid ruby. ## 1.0.0 * Extracted from Haml and released as an independent gem. For changes from previous versions, see the Haml changelog. html2haml-1.0.1/.gitignore0000644000175000017500000000011712147506116014411 0ustar gwolfgwolf/.yardoc /coverage /doc /pkg *.rbc .rbenv-version Gemfile.lock .rvmrc .rbx tmp html2haml-1.0.1/.travis.yml0000644000175000017500000000022012147506116014525 0ustar gwolfgwolfrvm: - 1.8.7 - 1.9.3 - jruby-18mode - rbx-18mode gemfile: - Gemfile branches: only: - master script: "bundle exec rake test" html2haml-1.0.1/Gemfile0000644000175000017500000000005012147506116013710 0ustar gwolfgwolfsource 'https://rubygems.org' gemspec html2haml-1.0.1/metadata.yml0000644000175000017500000000705512147506116014734 0ustar gwolfgwolf--- !ruby/object:Gem::Specification name: html2haml version: !ruby/object:Gem::Version prerelease: false segments: - 1 - 0 - 1 version: 1.0.1 platform: ruby authors: - Norman Clarke autorequire: bindir: bin cert_chain: [] date: 2013-02-16 00:00:00 -03:00 default_executable: dependencies: - !ruby/object:Gem::Dependency name: hpricot prerelease: false requirement: &id001 !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version segments: - 0 - 8 - 6 version: 0.8.6 type: :runtime version_requirements: *id001 - !ruby/object:Gem::Dependency name: erubis prerelease: false requirement: &id002 !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version segments: - 2 - 7 - 0 version: 2.7.0 type: :runtime version_requirements: *id002 - !ruby/object:Gem::Dependency name: ruby_parser prerelease: false requirement: &id003 !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version segments: - 3 - 1 - 1 version: 3.1.1 type: :runtime version_requirements: *id003 - !ruby/object:Gem::Dependency name: haml prerelease: false requirement: &id004 !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version segments: - 4 - 0 - 0 - rc - 1 version: 4.0.0.rc.1 type: :runtime version_requirements: *id004 - !ruby/object:Gem::Dependency name: simplecov prerelease: false requirement: &id005 !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version segments: - 0 - 7 - 1 version: 0.7.1 type: :development version_requirements: *id005 - !ruby/object:Gem::Dependency name: minitest prerelease: false requirement: &id006 !ruby/object:Gem::Requirement requirements: - - ~> - !ruby/object:Gem::Version segments: - 4 - 4 - 0 version: 4.4.0 type: :development version_requirements: *id006 - !ruby/object:Gem::Dependency name: rake prerelease: false requirement: &id007 !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version segments: - 0 version: "0" type: :development version_requirements: *id007 description: Converts HTML into Haml email: - norman@njclarke.com executables: - html2haml extensions: [] extra_rdoc_files: [] files: - .gitignore - .travis.yml - Changelog.markdown - Gemfile - MIT-LICENSE - README.md - Rakefile - bin/html2haml - html2haml.gemspec - lib/html2haml.rb - lib/html2haml/exec.rb - lib/html2haml/html.rb - lib/html2haml/html/erb.rb - lib/html2haml/version.rb - test/erb_test.rb - test/html2haml_test.rb - test/test_helper.rb has_rdoc: true homepage: http://haml.info licenses: [] post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version segments: - 0 version: "0" required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version segments: - 0 version: "0" requirements: [] rubyforge_project: rubygems_version: 1.3.6 signing_key: specification_version: 3 summary: Converts HTML into Haml test_files: - test/erb_test.rb - test/html2haml_test.rb - test/test_helper.rb html2haml-1.0.1/html2haml.gemspec0000644000175000017500000000172212147506116015661 0ustar gwolfgwolf# -*- encoding: utf-8 -*- require File.expand_path('../lib/html2haml/version', __FILE__) Gem::Specification.new do |gem| gem.authors = ["Norman Clarke"] gem.email = ["norman@njclarke.com"] gem.description = %q{Converts HTML into Haml} gem.summary = %q{Converts HTML into Haml} gem.homepage = "http://haml.info" gem.files = `git ls-files`.split($\) gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) gem.name = "html2haml" gem.require_paths = ["lib"] gem.version = Html2haml::VERSION gem.add_dependency 'hpricot', '~> 0.8.6' gem.add_dependency 'erubis', '~> 2.7.0' gem.add_dependency 'ruby_parser', '~> 3.1.1' gem.add_dependency 'haml', '>= 4.0.0.rc.1' gem.add_development_dependency 'simplecov', '~> 0.7.1' gem.add_development_dependency 'minitest', '~> 4.4.0' gem.add_development_dependency 'rake' end