You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
64 lines
1.5 KiB
Ruby
64 lines
1.5 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require_relative 'util'
|
|
|
|
require 'ostruct'
|
|
|
|
module Template
|
|
REGEX = %r{(?://\$([^\n]*(?:\n|$))|/\*\$(.*?)\*/)}
|
|
|
|
@cache = {}
|
|
@template_stack = []
|
|
def self.template inp, vals = nil, c = nil
|
|
raise ArgumentError, 'Input is nil' if inp.nil?
|
|
return inp unless inp =~ REGEX
|
|
raise ArgumentError, 'No vals' if vals.nil? && @template_stack.empty?
|
|
|
|
@cache[inp] ||= begin
|
|
code = +'::Kernel.proc{__tmpl_out = ::String.new;'
|
|
prev_pos = 0
|
|
|
|
while m = inp.match(REGEX, prev_pos)
|
|
cur_pos = m.begin 0
|
|
unless prev_pos == cur_pos
|
|
code << "__tmpl_out << #{inp[prev_pos...cur_pos].inspect};"
|
|
end
|
|
|
|
snip = m.match(1) || m.match(2)
|
|
if snip.start_with? '='
|
|
code << "__tmpl_out << (#{snip[1..]}).to_s;"
|
|
else
|
|
code << "#{snip};"
|
|
end
|
|
|
|
prev_pos = cur_pos + m.match(0).size
|
|
end
|
|
|
|
unless prev_pos == inp.size
|
|
code << "__tmpl_out << #{inp[prev_pos..].inspect};"
|
|
end
|
|
|
|
code << '__tmpl_out}'
|
|
eval code
|
|
end
|
|
|
|
|
|
begin
|
|
if vals.nil?
|
|
@template_stack[-1].instance_eval &@cache[inp]
|
|
else
|
|
os_vals = OpenStruct.new vals
|
|
@template_stack << os_vals
|
|
begin
|
|
return os_vals.instance_eval &@cache[inp]
|
|
ensure
|
|
@template_stack.pop
|
|
end
|
|
end
|
|
rescue
|
|
Util.print_error "Invalid template #{inp.inspect}: #{$!.full_message}", c
|
|
return ''
|
|
end
|
|
end
|
|
end
|