module Semplice::TemplateParser

Public Class Methods

parse(content, names=[]) click to toggle source
# File lib/semplice.rb, line 38
def self.parse(content, names=[])
  tpl = parse_content(content.split(TPL_PATTERN))
  context_vars = names.map{|name| "%s = __params[%p]" % [name, name]}.join(';')
  render_code = tpl[:methods].map{|name, code|
    "def __block_#{name}(__params);#{context_vars};__out = [];#{code};__out.join;end"
  }

  unless tpl[:base]
    render_code << "def __render(__params)"
    render_code <<   context_vars
    render_code <<   "__out = [super(__params)]"
    render_code <<   tpl[:code].join("\n")
    render_code <<   "__out.join.chomp"
    render_code << "end"
  end

  cls = Class.new(tpl[:base] ? template(tpl[:base], names) : Semplice::Template)
  cls.class_eval(render_code.join("\n"))
  cls
end
template(path, names) click to toggle source
# File lib/semplice.rb, line 59
def self.template(path, names)
  cache[path] ||= parse(content_for(path), names)
end

Private Class Methods

cache() click to toggle source
# File lib/semplice.rb, line 122
def self.cache
  Thread.current[:simplex_cache] ||= {}
end
content_for(path) click to toggle source
# File lib/semplice.rb, line 65
def self.content_for(path)
  unless File.exists?(path)
    path = @@template_dirs.map{|l|
      File.join(l, path)
    }.select{|p|
      File.exists?(p)
    }.first
  end
           
  File.read(path)
end
parse_content(tokens, content: nil, stopwords: []) click to toggle source
# File lib/semplice.rb, line 81
def self.parse_content(tokens, content: nil, stopwords: [])
  content ||= {code: [], methods: {}, base: nil}

  while token = tokens.shift
    case token
    when '{%' then
      sub_token = tokens.shift
      case sub_token
      when /^\bblock\b/
        block_name = /^block (?<name>.*)$/.match(sub_token)[:name]
        block_content = parse_content(tokens, stopwords: ['end'])
        content[:methods].merge!(block_content[:methods])
        content[:methods][block_name.to_sym] = block_content[:code].join("\n")
        content[:code] << "__out << __block_#{block_name}(__params)"
      when /\bextends\b/
        content[:base] = /^extends\s+["'](?<tpl>.*)["']$/.match(sub_token)[:tpl]
      when /\binclude\b/
        path = /^include\s+["'](?<tpl>.*)["']$/.match(sub_token)[:tpl]
        content[:code] << "__out << include(\"#{path}\", __params)"
      when /\bend\b/
        return content if stopwords.include?('end')
        content[:code] << 'end'
      else
        content[:code] << sub_token
      end
    when '{{' then # output value
      content[:code] << "__out << (h(#{tokens.shift})).to_s"
    when '{!' then # output value
      content[:code] << "__out << (#{tokens.shift}).to_s"
    when '{-' then # suppress output
      content[:code] << "(#{tokens.shift}).to_s"
    when '{#' then # igore comments
      tokens.shift
    else
      content[:code] << "__out << #{token.dump}" if token != ''
    end
  end

  content
end
template_dirs(dirs = []) click to toggle source
# File lib/semplice.rb, line 77
def self.template_dirs(dirs = [])
  @@template_dirs = dirs
end