Extracted html2haml to its own gem.
This commit is contained in:
parent
c94794f149
commit
8030deb1fb
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
## 3.2.0 (Unreleased)
|
## 3.2.0 (Unreleased)
|
||||||
|
|
||||||
|
* HTML2Haml has been extracted to a separate gem, creatively named "html2haml".
|
||||||
|
|
||||||
* Haml now supports only Rails 3 and above, and Ruby 1.8.7 and above. If you
|
* Haml now supports only Rails 3 and above, and Ruby 1.8.7 and above. If you
|
||||||
still need support for Rails 2 and Ruby 1.8.6, please use Haml 3.1.x which
|
still need support for Rails 2 and Ruby 1.8.6, please use Haml 3.1.x which
|
||||||
will continue to be maintained for bug fixes.
|
will continue to be maintained for bug fixes.
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
#!/usr/bin/env ruby
|
|
||||||
|
|
||||||
require File.dirname(__FILE__) + '/../lib/haml'
|
|
||||||
require 'haml/exec'
|
|
||||||
|
|
||||||
opts = Haml::Exec::HTML2Haml.new(ARGV)
|
|
||||||
opts.parse!
|
|
|
@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
|
||||||
spec.email = ['haml@googlegroups.com', 'norman@njclarke.com']
|
spec.email = ['haml@googlegroups.com', 'norman@njclarke.com']
|
||||||
|
|
||||||
readmes = Dir['*'].reject{ |x| x =~ /(^|[^.a-z])[a-z]+/ || x == "TODO" }
|
readmes = Dir['*'].reject{ |x| x =~ /(^|[^.a-z])[a-z]+/ || x == "TODO" }
|
||||||
spec.executables = ['haml', 'html2haml']
|
spec.executables = ['haml']
|
||||||
spec.files = Dir['rails/init.rb', 'lib/**/*', 'bin/*', 'test/**/*',
|
spec.files = Dir['rails/init.rb', 'lib/**/*', 'bin/*', 'test/**/*',
|
||||||
'extra/**/*', 'Rakefile', 'init.rb', '.yardopts'] + readmes
|
'extra/**/*', 'Rakefile', 'init.rb', '.yardopts'] + readmes
|
||||||
spec.homepage = 'http://haml.info/'
|
spec.homepage = 'http://haml.info/'
|
||||||
|
@ -20,9 +20,7 @@ Gem::Specification.new do |spec|
|
||||||
|
|
||||||
spec.add_development_dependency 'yard', '>= 0.5.3'
|
spec.add_development_dependency 'yard', '>= 0.5.3'
|
||||||
spec.add_development_dependency 'maruku', '>= 0.5.9'
|
spec.add_development_dependency 'maruku', '>= 0.5.9'
|
||||||
spec.add_development_dependency 'hpricot'
|
|
||||||
spec.add_development_dependency 'rails', '>= 3.0.0'
|
spec.add_development_dependency 'rails', '>= 3.0.0'
|
||||||
spec.add_development_dependency 'ruby_parser'
|
|
||||||
spec.add_development_dependency 'rbench'
|
spec.add_development_dependency 'rbench'
|
||||||
spec.add_development_dependency 'minitest'
|
spec.add_development_dependency 'minitest'
|
||||||
spec.add_development_dependency 'json'
|
spec.add_development_dependency 'json'
|
||||||
|
|
|
@ -298,82 +298,5 @@ END
|
||||||
output.close() if output.is_a? File
|
output.close() if output.is_a? File
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# The `html2haml` executable.
|
|
||||||
class HTML2Haml < Generic
|
|
||||||
# @param args [Array<String>] 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 = <<END
|
|
||||||
Usage: html2haml [options] [INPUT] [OUTPUT]
|
|
||||||
|
|
||||||
Description: Transforms an HTML file into corresponding Haml code.
|
|
||||||
|
|
||||||
Options:
|
|
||||||
END
|
|
||||||
|
|
||||||
opts.on('-e', '--erb', 'Parse ERb tags.') do
|
|
||||||
@module_opts[:erb] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--no-erb', "Don't parse ERb tags.") do
|
|
||||||
@options[:no_erb] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-r', '--rhtml', 'Deprecated; same as --erb.') do
|
|
||||||
@module_opts[:erb] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('--no-rhtml', "Deprecated; same as --no-erb.") do
|
|
||||||
@options[:no_erb] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on('-x', '--xhtml', 'Parse the input using the more strict XHTML parser.') do
|
|
||||||
@module_opts[:xhtml] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
opts.on("--html-attributes", "Use HTML style attributes instead of Ruby hash style.") do
|
|
||||||
@module_opts[:html_style_attributes] = true
|
|
||||||
end
|
|
||||||
|
|
||||||
unless RUBY_VERSION < "1.9"
|
|
||||||
opts.on('-E ex[:in]', 'Specify the default external and internal character encodings.') do |encoding|
|
|
||||||
external, internal = encoding.split(':')
|
|
||||||
Encoding.default_external = external if external && !external.empty?
|
|
||||||
Encoding.default_internal = internal if internal && !internal.empty?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
super
|
|
||||||
end
|
|
||||||
|
|
||||||
# Processes the options set by the command-line arguments,
|
|
||||||
# and runs the HTML compiler appropriately.
|
|
||||||
def process_result
|
|
||||||
super
|
|
||||||
|
|
||||||
require 'haml/html'
|
|
||||||
|
|
||||||
input = @options[:input]
|
|
||||||
output = @options[:output]
|
|
||||||
|
|
||||||
@module_opts[:erb] ||= input.respond_to?(:path) && input.path =~ /\.(rhtml|erb)$/
|
|
||||||
@module_opts[:erb] &&= @options[:no_erb] != false
|
|
||||||
|
|
||||||
output.write(::Haml::HTML.new(input, @module_opts).render)
|
|
||||||
rescue ::Haml::Error => 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
|
||||||
end
|
end
|
||||||
|
|
425
lib/haml/html.rb
425
lib/haml/html.rb
|
@ -1,425 +0,0 @@
|
||||||
require File.dirname(__FILE__) + '/../haml'
|
|
||||||
|
|
||||||
require 'haml/engine'
|
|
||||||
require 'rubygems'
|
|
||||||
require 'cgi'
|
|
||||||
require 'hpricot'
|
|
||||||
|
|
||||||
# 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[<haml:loud> </haml:loud>].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 # <haml:loud> 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("<a href='http://google.com'>Blat</a>").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 'haml/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(\[[^\]]+\])>(.*)<!\[endif\]\z/m
|
|
||||||
condition = $1
|
|
||||||
content = $2
|
|
||||||
end
|
|
||||||
|
|
||||||
if content.include?("\n")
|
|
||||||
"#{tabulate(tabs)}/#{condition}\n#{parse_text(content, tabs + 1)}"
|
|
||||||
else
|
|
||||||
"#{tabulate(tabs)}/#{condition} #{content.strip}\n"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# @see Hpricot
|
|
||||||
# @private
|
|
||||||
class ::Hpricot::Elem
|
|
||||||
# @see Haml::HTML::Node#to_haml
|
|
||||||
def to_haml(tabs, options)
|
|
||||||
return "" if converted_to_haml
|
|
||||||
if name == "script" &&
|
|
||||||
(attr_hash['type'].nil? || attr_hash['type'] == "text/javascript") &&
|
|
||||||
(attr_hash.keys - ['type']).empty?
|
|
||||||
return to_haml_filter(:javascript, tabs, options)
|
|
||||||
elsif name == "style" &&
|
|
||||||
(attr_hash['type'].nil? || attr_hash['type'] == "text/css") &&
|
|
||||||
(attr_hash.keys - ['type']).empty?
|
|
||||||
return to_haml_filter(:css, tabs, options)
|
|
||||||
end
|
|
||||||
|
|
||||||
output = tabulate(tabs)
|
|
||||||
if options[:erb] && name[0...5] == 'haml:'
|
|
||||||
case name[5..-1]
|
|
||||||
when "loud"
|
|
||||||
lines = CGI.unescapeHTML(inner_text).split("\n").
|
|
||||||
map {|s| s.rstrip}.reject {|s| s.strip.empty?}
|
|
||||||
lines.first.gsub!(/^[ \t]*/, "= ")
|
|
||||||
|
|
||||||
if lines.size > 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")
|
|
||||||
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{<haml:loud>\s*(.+?)\s*</haml:loud>}) 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))
|
|
||||||
end
|
|
||||||
|
|
||||||
"#{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
|
|
|
@ -1,141 +0,0 @@
|
||||||
require '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 `<haml:silent> ... </haml:silent>`.
|
|
||||||
# `<%= ... %>` is converted into `<haml:loud> ... </haml:loud>`.
|
|
||||||
# Finally, if either of these opens a Ruby block,
|
|
||||||
# `<haml:block> ... </haml: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 `<haml:silent>` tag,
|
|
||||||
# and may close and/or open a Ruby block with the `<haml:block>` 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 << '</haml:block>' if block_closer?(code) || mid_block?(code)
|
|
||||||
src << '<haml:silent>' << h(code) << '</haml:silent>' unless code.strip == "end"
|
|
||||||
src << '<haml:block>' 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 `<haml:silent>` tag,
|
|
||||||
# and may open a Ruby block with the `<haml:block>` 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 << '<haml:loud>' << h(code) << '</haml:loud>'
|
|
||||||
src << '<haml:block>' 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
|
|
||||||
false
|
|
||||||
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)
|
|
||||||
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)
|
|
||||||
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 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
|
|
|
@ -1,440 +0,0 @@
|
||||||
module ErbTests
|
|
||||||
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("<p><%= foo %></p>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_non_inline_erb
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
%p
|
|
||||||
= foo
|
|
||||||
HAML
|
|
||||||
<p>
|
|
||||||
<%= foo %>
|
|
||||||
</p>
|
|
||||||
HTML
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
%p
|
|
||||||
= foo
|
|
||||||
HAML
|
|
||||||
<p>
|
|
||||||
<%= foo %></p>
|
|
||||||
HTML
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
%p
|
|
||||||
= foo
|
|
||||||
HAML
|
|
||||||
<p><%= foo %>
|
|
||||||
</p>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_cdata
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
:cdata
|
|
||||||
Foo \#{bar} baz
|
|
||||||
HAML
|
|
||||||
<![CDATA[Foo <%= bar %> baz]]>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_script
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
:javascript
|
|
||||||
function foo() {
|
|
||||||
return \#{foo.to_json};
|
|
||||||
}
|
|
||||||
HAML
|
|
||||||
<script type="text/javascript">
|
|
||||||
function foo() {
|
|
||||||
return <%= foo.to_json %>;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_style
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<HTML))
|
|
||||||
:css
|
|
||||||
foo {
|
|
||||||
bar: \#{"baz"};
|
|
||||||
}
|
|
||||||
HAML
|
|
||||||
<style type="text/css">
|
|
||||||
foo {
|
|
||||||
bar: <%= "baz" %>;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
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('<div class="<%= dyna_class %>">I have a dynamic attribute</div>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_id_attribute
|
|
||||||
assert_equal "%div{:id => dyna_id} I have a dynamic attribute",
|
|
||||||
render_erb('<div id="<%= dyna_id %>">I have a dynamic attribute</div>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_attribute_results_in_string_interpolation
|
|
||||||
assert_equal('%div{:id => "item_#{i}"} Ruby string interpolation FTW',
|
|
||||||
render_erb('<div id="item_<%= i %>">Ruby string interpolation FTW</div>'))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_attribute_with_trailing_content
|
|
||||||
assert_equal('%div{:class => "#{12}!"} Bang!',
|
|
||||||
render_erb('<div class="<%= 12 %>!">Bang!</div>'))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_html_escaped_attribute
|
|
||||||
assert_equal '%div{:class => "foo"} Bang!',
|
|
||||||
render_erb('<div class="<%= "foo" %>">Bang!</div>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_erb_in_attribute_to_multiple_interpolations
|
|
||||||
assert_equal('%div{:class => "#{12} + #{13}"} Math is super',
|
|
||||||
render_erb('<div class="<%= 12 %> + <%= 13 %>">Math is super</div>'))
|
|
||||||
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('<p foo="<%= "#{bar} baz" %>"></p>'))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiline_erb_silent_script
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
- foo
|
|
||||||
- bar
|
|
||||||
- baz
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
%>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiline_erb_loud_script
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
= foo + |
|
|
||||||
bar.baz.bang + |
|
|
||||||
baz |
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%=
|
|
||||||
foo +
|
|
||||||
bar.baz.bang +
|
|
||||||
baz
|
|
||||||
%>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_weirdly_indented_multiline_erb_loud_script
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
= foo + |
|
|
||||||
bar.baz.bang + |
|
|
||||||
baz |
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%=
|
|
||||||
foo +
|
|
||||||
bar.baz.bang +
|
|
||||||
baz
|
|
||||||
%>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_two_multiline_erb_loud_scripts
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
= foo + |
|
|
||||||
bar.baz.bang + |
|
|
||||||
baz |
|
|
||||||
-#
|
|
||||||
= foo.bar do |
|
|
||||||
bang |
|
|
||||||
end |
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%=
|
|
||||||
foo +
|
|
||||||
bar.baz.bang +
|
|
||||||
baz
|
|
||||||
%>
|
|
||||||
<%= foo.bar do
|
|
||||||
bang
|
|
||||||
end %>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiline_then_single_line_erb_loud_scripts
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
= foo + |
|
|
||||||
bar.baz.bang + |
|
|
||||||
baz |
|
|
||||||
= foo.bar
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%=
|
|
||||||
foo +
|
|
||||||
bar.baz.bang +
|
|
||||||
baz
|
|
||||||
%>
|
|
||||||
<%= foo.bar %>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiline_erb_but_really_single_line
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
.blah
|
|
||||||
= foo
|
|
||||||
%p foo
|
|
||||||
HAML
|
|
||||||
<div class="blah">
|
|
||||||
<%=
|
|
||||||
foo
|
|
||||||
%>
|
|
||||||
<p>foo</p>
|
|
||||||
</div>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
### Block Parsing
|
|
||||||
|
|
||||||
def test_block_parsing
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- foo do
|
|
||||||
%p bar
|
|
||||||
HAML
|
|
||||||
<% foo do %>
|
|
||||||
<p>bar</p>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_block_parsing_with_args
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- foo do |a, b, c|
|
|
||||||
%p bar
|
|
||||||
HAML
|
|
||||||
<% foo do |a, b, c| %>
|
|
||||||
<p>bar</p>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_block_parsing_with_equals
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
= foo do
|
|
||||||
%p bar
|
|
||||||
HAML
|
|
||||||
<%= foo do %>
|
|
||||||
<p>bar</p>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_block_parsing_with_modified_end
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- foo do
|
|
||||||
blah
|
|
||||||
- end.bip
|
|
||||||
HAML
|
|
||||||
<% foo do %>
|
|
||||||
blah
|
|
||||||
<% end.bip %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_block_parsing_with_modified_end_with_block
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- foo do
|
|
||||||
blah
|
|
||||||
- end.bip do
|
|
||||||
brang
|
|
||||||
HAML
|
|
||||||
<% foo do %>
|
|
||||||
blah
|
|
||||||
<% end.bip do %>
|
|
||||||
brang
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiline_block_opener
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- foo bar
|
|
||||||
- baz bang
|
|
||||||
- biddle do
|
|
||||||
foo
|
|
||||||
HAML
|
|
||||||
<% foo bar
|
|
||||||
baz bang
|
|
||||||
biddle do %>
|
|
||||||
foo
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_if_elsif_else_parsing
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- if foo
|
|
||||||
%p bar
|
|
||||||
- elsif bar.foo("zip")
|
|
||||||
#bang baz
|
|
||||||
- else
|
|
||||||
%strong bibble
|
|
||||||
HAML
|
|
||||||
<% if foo %>
|
|
||||||
<p>bar</p>
|
|
||||||
<% elsif bar.foo("zip") %>
|
|
||||||
<div id="bang">baz</div>
|
|
||||||
<% else %>
|
|
||||||
<strong>bibble</strong>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_case_when_parsing
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- case foo.bar
|
|
||||||
- when "bip"
|
|
||||||
%p bip
|
|
||||||
- when "bop"
|
|
||||||
%p BOP
|
|
||||||
- when bizzle.bang.boop.blip
|
|
||||||
%em BIZZLE BANG BOOP BLIP
|
|
||||||
HAML
|
|
||||||
<% case foo.bar %>
|
|
||||||
<% when "bip" %>
|
|
||||||
<p>bip</p>
|
|
||||||
<% when "bop" %>
|
|
||||||
<p>BOP</p>
|
|
||||||
<% when bizzle.bang.boop.blip %>
|
|
||||||
<em>BIZZLE BANG BOOP BLIP</em>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- case foo.bar
|
|
||||||
- when "bip"
|
|
||||||
%p bip
|
|
||||||
- when "bop"
|
|
||||||
%p BOP
|
|
||||||
- when bizzle.bang.boop.blip
|
|
||||||
%em BIZZLE BANG BOOP BLIP
|
|
||||||
HAML
|
|
||||||
<% case foo.bar
|
|
||||||
when "bip" %>
|
|
||||||
<p>bip</p>
|
|
||||||
<% when "bop" %>
|
|
||||||
<p>BOP</p>
|
|
||||||
<% when bizzle.bang.boop.blip %>
|
|
||||||
<em>BIZZLE BANG BOOP BLIP</em>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_begin_rescue_ensure
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
- begin
|
|
||||||
%p a
|
|
||||||
- rescue FooException => e
|
|
||||||
%p b
|
|
||||||
- ensure
|
|
||||||
%p c
|
|
||||||
HAML
|
|
||||||
<% begin %>
|
|
||||||
<p>a</p>
|
|
||||||
<% rescue FooException => e %>
|
|
||||||
<p>b</p>
|
|
||||||
<% ensure %>
|
|
||||||
<p>c</p>
|
|
||||||
<% end %>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
# Regression
|
|
||||||
|
|
||||||
def test_tag_inside_block
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
%table
|
|
||||||
- foo.each do
|
|
||||||
%tr
|
|
||||||
HAML
|
|
||||||
<table>
|
|
||||||
<% foo.each do %>
|
|
||||||
<tr></tr>
|
|
||||||
<% end %>
|
|
||||||
</table>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_silent_inside_block_inside_tag
|
|
||||||
assert_equal(<<HAML.rstrip, render_erb(<<ERB))
|
|
||||||
%table
|
|
||||||
- foo.each do
|
|
||||||
- haml_puts "foo"
|
|
||||||
HAML
|
|
||||||
<table>
|
|
||||||
<% foo.each do %>
|
|
||||||
<% haml_puts "foo" %>
|
|
||||||
<% end %>
|
|
||||||
</table>
|
|
||||||
ERB
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -1,342 +0,0 @@
|
||||||
require 'test_helper'
|
|
||||||
require 'html2haml/erb_tests'
|
|
||||||
require 'haml/html'
|
|
||||||
|
|
||||||
class Html2HamlTest < MiniTest::Unit::TestCase
|
|
||||||
def test_empty_render_should_remain_empty
|
|
||||||
assert_equal '', render('')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_doctype
|
|
||||||
assert_equal '!!!', render("<!DOCTYPE html>")
|
|
||||||
assert_equal '!!! 1.1', render('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">')
|
|
||||||
assert_equal '!!! Strict', render('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">')
|
|
||||||
assert_equal '!!! Frameset', render('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">')
|
|
||||||
assert_equal '!!! Mobile 1.2', render('<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">')
|
|
||||||
assert_equal '!!! Basic 1.1', render('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">')
|
|
||||||
assert_equal '!!!', render('<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">')
|
|
||||||
assert_equal '!!! Strict', render('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">')
|
|
||||||
assert_equal '!!! Frameset', render('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">')
|
|
||||||
assert_equal '!!!', render('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id_and_class_should_be_removed_from_hash
|
|
||||||
assert_equal '%span#foo.bar', render('<span id="foo" class="bar"> </span>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_no_tag_name_for_div_if_class_or_id_is_present
|
|
||||||
assert_equal '#foo', render('<div id="foo"> </div>')
|
|
||||||
assert_equal '.foo', render('<div class="foo"> </div>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_multiple_class_names
|
|
||||||
assert_equal '.foo.bar.baz', render('<div class=" foo bar baz "> </div>')
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_have_pretty_attributes
|
|
||||||
assert_equal('%input{:name => "login", :type => "text"}/',
|
|
||||||
render('<input type="text" name="login" />'))
|
|
||||||
assert_equal('%meta{:content => "text/html", "http-equiv" => "Content-Type"}/',
|
|
||||||
render('<meta http-equiv="Content-Type" content="text/html" />'))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_should_have_html_style_attributes
|
|
||||||
assert_equal('%input(name="login" type="text")/',
|
|
||||||
render('<input type="text" name="login" />', :html_style_attributes => true))
|
|
||||||
assert_equal('%meta(content="text/html" http-equiv="Content-Type")/',
|
|
||||||
render('<meta http-equiv="Content-Type" content="text/html" />', :html_style_attributes => true))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_class_with_dot_and_hash
|
|
||||||
assert_equal('%div{:class => "foo.bar"}', render("<div class='foo.bar'></div>"))
|
|
||||||
assert_equal('%div{:class => "foo#bar"}', render("<div class='foo#bar'></div>"))
|
|
||||||
assert_equal('.foo.bar{:class => "foo#bar foo.bar"}', render("<div class='foo foo#bar bar foo.bar'></div>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_id_with_dot_and_hash
|
|
||||||
assert_equal('%div{:id => "foo.bar"}', render("<div id='foo.bar'></div>"))
|
|
||||||
assert_equal('%div{:id => "foo#bar"}', render("<div id='foo#bar'></div>"))
|
|
||||||
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('<p foo="#{bar} baz"></p>'))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_cdata
|
|
||||||
assert_equal(<<HAML.strip, render(<<HTML))
|
|
||||||
%p
|
|
||||||
:cdata
|
|
||||||
<a foo="bar" baz="bang">
|
|
||||||
<div id="foo">flop</div>
|
|
||||||
</a>
|
|
||||||
HAML
|
|
||||||
<p><![CDATA[
|
|
||||||
<a foo="bar" baz="bang">
|
|
||||||
<div id="foo">flop</div>
|
|
||||||
</a>
|
|
||||||
]]></p>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_self_closing_tag
|
|
||||||
assert_equal("%foo/", render("<foo />"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_inline_text
|
|
||||||
assert_equal("%p foo", render("<p>foo</p>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_inline_comment
|
|
||||||
assert_equal("/ foo", render("<!-- foo -->"))
|
|
||||||
assert_equal(<<HAML.strip, render(<<HTML))
|
|
||||||
/ foo
|
|
||||||
%p bar
|
|
||||||
HAML
|
|
||||||
<!-- foo -->
|
|
||||||
<p>bar</p>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_non_inline_comment
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
/
|
|
||||||
Foo
|
|
||||||
Bar
|
|
||||||
HAML
|
|
||||||
<!-- Foo
|
|
||||||
Bar -->
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_non_inline_text
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%p
|
|
||||||
foo
|
|
||||||
HAML
|
|
||||||
<p>
|
|
||||||
foo
|
|
||||||
</p>
|
|
||||||
HTML
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%p
|
|
||||||
foo
|
|
||||||
HAML
|
|
||||||
<p>
|
|
||||||
foo</p>
|
|
||||||
HTML
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%p
|
|
||||||
foo
|
|
||||||
HAML
|
|
||||||
<p>foo
|
|
||||||
</p>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_script_tag
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
:javascript
|
|
||||||
function foo() {
|
|
||||||
return "12" & "13";
|
|
||||||
}
|
|
||||||
HAML
|
|
||||||
<script type="text/javascript">
|
|
||||||
function foo() {
|
|
||||||
return "12" & "13";
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_script_tag_with_cdata
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
:javascript
|
|
||||||
function foo() {
|
|
||||||
return "&";
|
|
||||||
}
|
|
||||||
HAML
|
|
||||||
<script type="text/javascript">
|
|
||||||
<![CDATA[
|
|
||||||
function foo() {
|
|
||||||
return "&";
|
|
||||||
}
|
|
||||||
]]>
|
|
||||||
</script>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_pre
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%pre
|
|
||||||
:preserve
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
HAML
|
|
||||||
<pre>foo
|
|
||||||
bar
|
|
||||||
baz</pre>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_pre_code
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%pre
|
|
||||||
%code
|
|
||||||
:preserve
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
HAML
|
|
||||||
<pre><code>foo
|
|
||||||
bar
|
|
||||||
baz</code></pre>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_code_without_pre
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
%code
|
|
||||||
foo
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
HAML
|
|
||||||
<code>foo
|
|
||||||
bar
|
|
||||||
baz</code>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_conditional_comment
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
/[if foo]
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
HAML
|
|
||||||
<!--[if foo]>
|
|
||||||
bar
|
|
||||||
baz
|
|
||||||
<![endif]-->
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_style_to_css_filter
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
:css
|
|
||||||
foo {
|
|
||||||
bar: baz;
|
|
||||||
}
|
|
||||||
HAML
|
|
||||||
<style type="text/css">
|
|
||||||
foo {
|
|
||||||
bar: baz;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_inline_conditional_comment
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
/[if foo] bar baz
|
|
||||||
HAML
|
|
||||||
<!--[if foo]> bar baz <![endif]-->
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_minus_in_tag
|
|
||||||
assert_equal("%p - foo bar -", render("<p>- foo bar -</p>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_equals_in_tag
|
|
||||||
assert_equal("%p = foo bar =", render("<p>= foo bar =</p>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_hash_in_tag
|
|
||||||
assert_equal("%p # foo bar #", render("<p># foo bar #</p>"))
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_comma_post_tag
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
#foo
|
|
||||||
%span> Foo
|
|
||||||
,
|
|
||||||
%span bar
|
|
||||||
Foo
|
|
||||||
%span> bar
|
|
||||||
,
|
|
||||||
%span baz
|
|
||||||
HAML
|
|
||||||
<div id="foo">
|
|
||||||
<span>Foo</span>, <span>bar</span>
|
|
||||||
Foo<span>bar</span>, <span>baz</span>
|
|
||||||
</div>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
def test_comma_post_tag_with_text_before
|
|
||||||
assert_equal(<<HAML.rstrip, render(<<HTML))
|
|
||||||
#foo
|
|
||||||
Batch
|
|
||||||
= succeed "," do
|
|
||||||
%span Foo
|
|
||||||
%span Bar
|
|
||||||
HAML
|
|
||||||
<div id="foo">
|
|
||||||
Batch
|
|
||||||
<span>Foo</span>, <span>Bar</span>
|
|
||||||
</div>
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
begin
|
|
||||||
require 'haml/html/erb'
|
|
||||||
include ErbTests
|
|
||||||
rescue LoadError => e
|
|
||||||
puts "\n** Couldn't require #{e.message[/-- (.*)$/, 1]}, skipping some tests"
|
|
||||||
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))
|
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
|
||||||
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
|
||||||
HTML
|
|
||||||
end
|
|
||||||
|
|
||||||
protected
|
|
||||||
|
|
||||||
def render(text, options = {})
|
|
||||||
Haml::HTML.new(text, options).render.rstrip
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_erb(text)
|
|
||||||
render(text, :erb => true)
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -11,7 +11,6 @@ require 'minitest/autorun'
|
||||||
require 'action_pack'
|
require 'action_pack'
|
||||||
require 'action_controller'
|
require 'action_controller'
|
||||||
require 'action_view'
|
require 'action_view'
|
||||||
require 'hpricot'
|
|
||||||
|
|
||||||
require 'rails'
|
require 'rails'
|
||||||
class TestApp < Rails::Application
|
class TestApp < Rails::Application
|
||||||
|
|
Loading…
Reference in New Issue