summary refs log tree commit diff
path: root/vendor/htemplate.rb
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/htemplate.rb')
-rw-r--r--vendor/htemplate.rb68
1 files changed, 68 insertions, 0 deletions
diff --git a/vendor/htemplate.rb b/vendor/htemplate.rb
new file mode 100644
index 0000000..5a429a1
--- /dev/null
+++ b/vendor/htemplate.rb
@@ -0,0 +1,68 @@
+require 'strscan'
+
+class HTemplate
+  def initialize(source, filename=nil)
+    @source = source
+    @filename = filename
+    compile
+  end
+
+  if defined? Rack::Utils
+    def escape_html(s)
+      Rack::Utils.escape_html s
+    end
+  else
+    require 'cgi'
+    def escape_html(s)
+      CGI.escapeHTML s
+    end
+  end
+
+  def expand(data, output="", escape=nil, &block)
+    escape ||= lambda { |v|
+      escape_html v.to_s
+    }
+    @code.call(output, data, block, escape)
+    output
+  end
+
+  def compile
+    code = "lambda { |output, data, block, __escape| data.instance_eval {\n"
+
+    scanner = StringScanner.new(@source)
+
+    until scanner.eos?
+      if scanner.bol? and scanner.scan(/\s*\$ (.*\n)/)
+                                           # raw line of code, $ if bla
+        code << scanner[1]
+      elsif scanner.scan(/\$(:?)(\{(.*?)\}|(@?[\w.!?]+))/)
+                                           # expression, ${foo} or $foo.bar
+        expr = scanner[3] || scanner[4]
+
+        if scanner[1] == ":"               # disable escaping?
+          code << %Q{output << (#{expr}).to_s;}
+        else
+          code << %Q{output << __escape[#{expr}];}
+        end
+      elsif scanner.scan(/\$\$/)           # plain $
+        code << %Q{output << '$';}
+      elsif scanner.scan(/\$#.*?(?:#\$|$\n?)/)  # comment $#...#$ or $#...
+        # nothing
+      elsif scanner.scan(/([^\n$]+\n?)|([^\n$]*\n)/)   # text
+        if scanner.matched =~ /\\$/ && scanner.bol?
+          code << %Q{output << #{scanner.matched.chop.chop.dump};}
+        else
+          code << %Q{output << #{scanner.matched.dump};}
+        end
+
+        code << "\n"  if scanner.bol?
+      else
+        raise "can't parse template: #{scanner.rest[0..20].dump}"
+      end
+    end
+
+    code << "}}"
+
+    @code = eval(code, nil, @filename || '(template)', 0)
+  end
+end