module Guff class Template getter :string def initialize(@string : String) @tokens = scan(@string) @has_keys = @tokens.select { |t| t.type == :key }.size > 0 end def run(args : Nil) : String raise_missing if @has_keys # return literal string @string end def run( args = {} of String => String : Hash(String, String) ) : String if @has_keys # check template args raise_missing if args.size == 0 # build result String.build do |r| @tokens.each do |t| r << t.get(args) end end else # no keys, return literal string @string end end private def raise_missing raise "missing template args: %s" % [@tokens.select { |t| t.type == :key }.map { |t| t.value }.sort.join(", ")] end SCAN_RE = %r{ # match key (?:%\{(?[^\}]+)\}) | # match literal value (?[^%]+) | # match literal percent (?%) }mx private def scan(s : String) r = [] of TemplateToken s.scan(SCAN_RE) do |md| if md["key"]? r << TemplateToken.new(:key, md["key"].strip) elsif md["val"]? r << TemplateToken.new(:val, md["val"]) elsif md["pct"]? r << TemplateToken.new(:val, "%") else # never reached raise "unknown match: #{md}" end end # return result r end end end