module Haml::Util

def balance(scanner, start, finish, count = 0)

Returns:
  • ((String, String)) - The string matched within the balanced pair

Parameters:
  • count (Fixnum) -- The number of opening characters matched
  • finish (String) -- The character closing the balanced pair.
  • start (String) -- The character opening the balanced pair.
  • scanner (StringScanner) -- The string scanner to move
def balance(scanner, start, finish, count = 0)
  str = ''.dup
  scanner = StringScanner.new(scanner) unless scanner.is_a? StringScanner
  regexp = Regexp.new("(.*?)[\\#{start.chr}\\#{finish.chr}]", Regexp::MULTILINE)
  while scanner.scan(regexp)
    str << scanner.matched
    count += 1 if scanner.matched[-1] == start
    count -= 1 if scanner.matched[-1] == finish
    return [str.strip, scanner.rest] if count == 0
  end
end

def check_encoding(str)

Returns:
  • (String) - `str`, potentially with encoding gotchas like BOMs removed

Other tags:
    Yieldparam: msg - The error message to be raised

Other tags:
    Yield: - A block in which an encoding error can be raised.

Parameters:
  • str (String) -- The string of which to check the encoding
def check_encoding(str)
  if str.valid_encoding?
    # Get rid of the Unicode BOM if possible
    # Shortcut for UTF-8 which might be the majority case
    if str.encoding == Encoding::UTF_8
      return str.gsub(/\A\uFEFF/, '')
    elsif str.encoding.name =~ /^UTF-(16|32)(BE|LE)?$/
      return str.gsub(Regexp.new("\\A\uFEFF".encode(str.encoding)), '')
    else
      return str
    end
  end
  encoding = str.encoding
  newlines = Regexp.new("\r\n|\r|\n".encode(encoding).force_encoding(Encoding::ASCII_8BIT))
  str.force_encoding(Encoding::ASCII_8BIT).split(newlines).each_with_index do |line, i|
    begin
      line.encode(encoding)
    rescue Encoding::UndefinedConversionError => e
      yield <<MSG.rstrip, i + 1
lid #{encoding.name} character #{e.error_char.dump}
    end
  end
  return str
end

def check_haml_encoding(str, &block)

Raises:
  • (ArgumentError) - if the document declares an unknown encoding

Returns:
  • (String) - The original string encoded properly

Other tags:
    Yieldparam: msg - The error message to be raised

Other tags:
    Yield: - A block in which an encoding error can be raised.

Parameters:
  • str (String) -- The Haml template of which to check the encoding
def check_haml_encoding(str, &block)
  str = str.dup if str.frozen?
  bom, encoding = parse_haml_magic_comment(str)
  if encoding; str.force_encoding(encoding)
  elsif bom; str.force_encoding(Encoding::UTF_8)
  end
  return check_encoding(str, &block)
end

def contains_interpolation?(str)

def contains_interpolation?(str)
  /#[\{$@]/ === str
end

def handle_interpolation(str)

Returns:
  • (String) - The text remaining in the scanner after all `#{`s have been processed

Other tags:
    Yieldparam: scan - The scanner scanning through the string
def handle_interpolation(str)
  scan = StringScanner.new(str)
  yield scan while scan.scan(/(.*?)(\\*)#([\{@$])/)
  scan.rest
end

def html_safe(text)

Returns:
  • (String, nil) - `text`, marked as HTML-safe

Parameters:
  • text (String, nil) --
def html_safe(text)
  return unless text
  text.html_safe
end

def human_indentation(indentation)

Returns:
  • (String) - The name of the indentation (e.g. `"12 spaces"`, `"1 tab"`)

Parameters:
  • indentation (String) -- The string used for indentation
def human_indentation(indentation)
  if !indentation.include?(?\t)
    noun = 'space'
  elsif !indentation.include?(?\s)
    noun = 'tab'
  else
    return indentation.inspect
  end
  singular = indentation.length == 1
  "#{indentation.length} #{noun}#{'s' unless singular}"
end

def inspect_obj(obj)

Returns:
  • (String) -

Parameters:
  • obj (Object) --
def inspect_obj(obj)
  case obj
  when String
    %Q!"#{obj.gsub(/[\x00-\x7F]+/) {|s| s.dump[1...-1]}}"!
  when Symbol
    ":#{inspect_obj(obj.to_s)}"
  else
    obj.inspect
  end
end

def parse_haml_magic_comment(str)

Returns:
  • ((Boolean, String or nil)) -
def parse_haml_magic_comment(str)
  scanner = StringScanner.new(str.dup.force_encoding(Encoding::ASCII_8BIT))
  bom = scanner.scan(/\xEF\xBB\xBF/n)
  return bom unless scanner.scan(/-\s*#\s*/n)
  if (coding = try_parse_haml_emacs_magic_comment(scanner))
    return bom, coding
  end
  return bom unless scanner.scan(/.*?coding[=:]\s*([\w-]+)/in)
  return bom, scanner[1]
end

def rails_xss_safe?; true; end

def rails_xss_safe?; true; end

def rails_xss_safe?

Returns:
  • (Boolean) -
def rails_xss_safe?
  false
end

def silence_warnings

Other tags:
    Yield: - A block in which no output will be printed to STDERR
def silence_warnings
  the_real_stderr, $stderr = $stderr, StringIO.new
  yield
ensure
  $stderr = the_real_stderr
end

def try_parse_haml_emacs_magic_comment(scanner)

def try_parse_haml_emacs_magic_comment(scanner)
  pos = scanner.pos
  return unless scanner.scan(/.*?-\*-\s*/n)
  # From Ruby's parse.y
  return unless scanner.scan(/([^\s'":;]+)\s*:\s*("(?:\\.|[^"])*"|[^"\s;]+?)[\s;]*-\*-/n)
  name, val = scanner[1], scanner[2]
  return unless name =~ /(en)?coding/in
  val = $1 if val =~ /^"(.*)"$/n
  return val
ensure
  scanner.pos = pos
end

def unescape_interpolation(str, escape_html = nil)

def unescape_interpolation(str, escape_html = nil)
  res = ''.dup
  rest = Haml::Util.handle_interpolation str.dump do |scan|
    escapes = (scan[2].size - 1) / 2
    char = scan[3] # '{', '@' or '$'
    res << scan.matched[0...-3 - escapes]
    if escapes % 2 == 1
      res << "\##{char}"
    else
      interpolated = if char == '{'
        balance(scan, ?{, ?}, 1)[0][0...-1]
      else
        scan.scan(/\w+/)
      end
      content = eval("\"#{interpolated}\"")
      content.prepend(char) if char == '@' || char == '$'
      content = "Haml::Helpers.html_escape((#{content}))" if escape_html
      res << "\#{#{content}}"
    end
  end
  res + rest
end