class Emerald::PreProcessor

Preprocess the emerald code and add notion of indentation so it may be parsed by a context free grammar. Removes all whitespace and adds braces to denote indentation.

Public Class Methods

new() click to toggle source
# File lib/emerald/preprocessor.rb, line 14
def initialize
  reset
end

Public Instance Methods

check_and_enter_literal(line) click to toggle source
# File lib/emerald/preprocessor.rb, line 126
def check_and_enter_literal(line)
  if line.rstrip.end_with?('->')
    @in_literal = true
    @current_indent += 2
    @templateless_literal = false
    @preserve_html_literal = false
  elsif line.rstrip.end_with?('=>')
    @in_literal = true
    @current_indent += 2
    @templateless_literal = true
    @preserve_html_literal = false
  elsif line.rstrip.end_with?('~>')
    @in_literal = true
    @current_indent += 2
    @templateless_literal = true
    @preserve_html_literal = true
  end
end
check_new_indent(new_indent) click to toggle source

Compares the value of the new_indent with the old indentation. Invoked by: process_emerald

# File lib/emerald/preprocessor.rb, line 60
def check_new_indent(new_indent)
  if new_indent > @current_indent
    open_tags(new_indent)
  elsif new_indent < @current_indent
    close_tags(new_indent)
  end
end
close_entered_tags(new_indent) click to toggle source

Append closing braces if not in literal and new indent is less than old one

# File lib/emerald/preprocessor.rb, line 96
def close_entered_tags(new_indent)
  (1..((@current_indent - new_indent) / 2)).each do
    @output += "}\n"
    @b_count -= 1
  end
end
close_literal(new_indent) click to toggle source

Append closing braces if in literal and new indent is less than old one

# File lib/emerald/preprocessor.rb, line 85
def close_literal(new_indent)
  @output += "$\n"
  @in_literal = false

  (2..((@current_indent - new_indent) / 2)).each do
    @output += "}\n"
    @b_count -= 1
  end
end
close_tags(new_indent) click to toggle source
# File lib/emerald/preprocessor.rb, line 75
def close_tags(new_indent)
  if @in_literal
    close_literal(new_indent)
  else
    close_entered_tags(new_indent)
  end
  @current_indent = new_indent
end
open_tags(new_indent) click to toggle source
# File lib/emerald/preprocessor.rb, line 68
def open_tags(new_indent)
  return if @in_literal
  @output += "{\n"
  @b_count += 1
  @current_indent = new_indent
end
process_emerald(input) click to toggle source

Process the emerald to remove indentation and replace with brace convention for an easier time parsing with context free grammar

# File lib/emerald/preprocessor.rb, line 31
def process_emerald(input)
  input.each_line.with_index do |line, line_number|
    if @in_literal
      if line[0...-1].empty?
        new_indent = @current_indent
        line = " "*@current_indent + "\n"
      else
        new_indent = line.length - line.lstrip.length
      end
    else 
      next if line.lstrip.empty?
      new_indent = line.length - line.lstrip.length
    end

    check_new_indent(new_indent)
    @output += remove_indent_whitespace(line)
    @source_map[@output.lines.length] = {
      source_line: line_number + 1
    }
    check_and_enter_literal(line)
  end

  close_tags(0)

  [@output, @source_map]
end
remove_indent_whitespace(line) click to toggle source

Crop off only Emerald indent whitespace to preserve whitespace in the literal. Since $ is the end character, we need to escape it in the literal.

# File lib/emerald/preprocessor.rb, line 105
def remove_indent_whitespace(line)
  if @in_literal
    # Ignore indent whitespace, only count post-indent as the literal,
    # but keep any extra whitespace that might exist for literals
    cropped = line[@current_indent..-1] || ''
    if @templateless_literal
      # this is a fun one https://www.ruby-forum.com/topic/143645
      cropped = cropped.gsub("\\"){ "\\\\" }
    end

    unless @preserve_html_literal
      cropped = @encoder.encode cropped
    end

    # Escape $ since we use it as a terminator for literals, and encode HTML
    cropped.gsub('$', "\\$")
  else
    line.lstrip
  end
end
reset() click to toggle source

Reset class variables, used for testing

# File lib/emerald/preprocessor.rb, line 19
def reset
  @in_literal = false
  @templateless_literal = false
  @current_indent = 0
  @b_count = 0
  @output = ''
  @encoder = HTMLEntities.new
  @source_map = {}
end