Skip to content

Loading…

Add Etanni Templating Engine #131

Merged
merged 1 commit into from

4 participants

@manveru

It's been part of Ramaze/Innate for years, time to provide it to the tilt folks as well.

@mig-hub

That would be nice.
I like the way Etanni looks like an extension of interpolated strings.

@rkh rkh closed this
@rkh rkh reopened this
@rkh rkh merged commit fe912ce into rtomayko:master

1 check passed

Details default The Travis build passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 26, 2012
  1. @manveru

    Adding Etanni templating

    manveru committed
Showing with 203 additions and 0 deletions.
  1. +3 −0 lib/tilt.rb
  2. +27 −0 lib/tilt/etanni.rb
  3. +173 −0 test/tilt_etannitemplate_test.rb
View
3 lib/tilt.rb
@@ -142,6 +142,9 @@ def clear
register ERBTemplate, 'erb', 'rhtml'
register ErubisTemplate, 'erb', 'rhtml', 'erubis'
+ require 'tilt/etanni'
+ register EtanniTemplate, 'etn', 'etanni'
+
require 'tilt/haml'
register HamlTemplate, 'haml'
View
27 lib/tilt/etanni.rb
@@ -0,0 +1,27 @@
+require 'tilt/template'
+
+module Tilt
+ class EtanniTemplate < Template
+ def prepare
+ separator = data.hash.abs
+ chomp = "<<#{separator}.chomp!"
+ start = "\n_out_ << #{chomp}\n"
+ stop = "\n#{separator}\n"
+ replacement = "#{stop}\\1#{start}"
+
+ temp = data.strip
+ temp.gsub!(/<\?r\s+(.*?)\s+\?>/m, replacement)
+
+ @code = "_out_ = [<<#{separator}.chomp!]\n#{temp}#{stop}_out_.join"
+ end
+
+ def precompiled_template(locals)
+ @code
+ end
+
+ def precompiled(locals)
+ source, offset = super
+ [source, offset + 1]
+ end
+ end
+end
View
173 test/tilt_etannitemplate_test.rb
@@ -0,0 +1,173 @@
+require 'contest'
+require 'tilt'
+
+class EtanniTemplateTest < Test::Unit::TestCase
+ test "registered for '.etn' files" do
+ assert_equal Tilt::EtanniTemplate, Tilt['test.etn']
+ end
+
+ test "registered for '.etanni' files" do
+ assert_equal Tilt::EtanniTemplate, Tilt['test.etanni']
+ end
+
+ test "loading and evaluating templates on #render" do
+ template = Tilt::EtanniTemplate.new { |t| "Hello World!" }
+ assert_equal "Hello World!", template.render
+ end
+
+ test "can be rendered more than once" do
+ template = Tilt::EtanniTemplate.new { |t| "Hello World!" }
+ 3.times { assert_equal "Hello World!", template.render }
+ end
+
+ test "passing locals" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{name}!' }
+ assert_equal "Hey Joe!", template.render(Object.new, :name => 'Joe')
+ end
+
+ test "evaluating in an object scope" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{@name}!' }
+ scope = Object.new
+ scope.instance_variable_set :@name, 'Joe'
+ assert_equal "Hey Joe!", template.render(scope)
+ end
+
+ test "passing a block for yield" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{yield}!' }
+ assert_equal "Hey Joe!", template.render { 'Joe' }
+ assert_equal "Hey Moe!", template.render { 'Moe' }
+ end
+
+ test "multiline templates" do
+ template = Tilt::EtanniTemplate.new { "Hello\nWorld!\n" }
+ assert_equal "Hello\nWorld!", template.render
+ end
+
+ test "backtrace file and line reporting without locals" do
+ data = File.read(__FILE__).split("\n__END__\n").last
+ fail unless data[0] == ?<
+ template = Tilt::EtanniTemplate.new('test.etn', 11) { data }
+ begin
+ template.render
+ fail 'should have raised an exception'
+ rescue => boom
+ assert_kind_of NameError, boom
+ line = boom.backtrace.grep(/^test\.etn:/).first
+ assert line, "Backtrace didn't contain test.etn"
+ file, line, meth = line.split(":")
+ assert_equal '13', line
+ end
+ end
+
+ test "backtrace file and line reporting with locals" do
+ data = File.read(__FILE__).split("\n__END__\n").last
+ fail unless data[0] == ?<
+ template = Tilt::EtanniTemplate.new('test.etn', 1) { data }
+ begin
+ template.render(nil, :name => 'Joe', :foo => 'bar')
+ fail 'should have raised an exception'
+ rescue => boom
+ assert_kind_of RuntimeError, boom
+ line = boom.backtrace.first
+ file, line, meth = line.split(":")
+ assert_equal 'test.etn', file
+ assert_equal '6', line
+ end
+ end
+end
+
+
+class CompiledEtanniTemplateTest < Test::Unit::TestCase
+ def teardown
+ GC.start
+ end
+
+ class Scope
+ end
+
+ test "compiling template source to a method" do
+ template = Tilt::EtanniTemplate.new { |t| "Hello World!" }
+ template.render(Scope.new)
+ method = template.send(:compiled_method, [])
+ assert_kind_of UnboundMethod, method
+ end
+
+ test "loading and evaluating templates on #render" do
+ template = Tilt::EtanniTemplate.new { |t| "Hello World!" }
+ assert_equal "Hello World!", template.render(Scope.new)
+ end
+
+ test "passing locals" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{name}!' }
+ assert_equal "Hey Joe!", template.render(Scope.new, :name => 'Joe')
+ assert_equal "Hey Moe!", template.render(Scope.new, :name => 'Moe')
+ end
+
+ test "evaluating in an object scope" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{@name}!' }
+ scope = Scope.new
+ scope.instance_variable_set :@name, 'Joe'
+ assert_equal "Hey Joe!", template.render(scope)
+ scope.instance_variable_set :@name, 'Moe'
+ assert_equal "Hey Moe!", template.render(scope)
+ end
+
+ test "passing a block for yield" do
+ template = Tilt::EtanniTemplate.new { 'Hey #{yield}!' }
+ assert_equal "Hey Joe!", template.render(Scope.new) { 'Joe' }
+ assert_equal "Hey Moe!", template.render(Scope.new) { 'Moe' }
+ end
+
+ test "multiline templates" do
+ template = Tilt::EtanniTemplate.new { "Hello\nWorld!\n" }
+ assert_equal "Hello\nWorld!", template.render(Scope.new)
+ end
+
+ test "template with '}'" do
+ template = Tilt::EtanniTemplate.new { "Hello }" }
+ assert_equal "Hello }", template.render
+ end
+
+ test "backtrace file and line reporting without locals" do
+ data = File.read(__FILE__).split("\n__END__\n").last
+ fail unless data[0] == ?<
+ template = Tilt::EtanniTemplate.new('test.etn', 11) { data }
+ begin
+ template.render(Scope.new)
+ fail 'should have raised an exception'
+ rescue => boom
+ assert_kind_of NameError, boom
+ line = boom.backtrace.first
+ line = boom.backtrace.grep(/^test\.etn:/).first
+ assert line, "Backtrace didn't contain test.etn"
+ file, line, meth = line.split(":")
+ assert_equal '13', line
+ end
+ end
+
+ test "backtrace file and line reporting with locals" do
+ data = File.read(__FILE__).split("\n__END__\n").last
+ fail unless data[0] == ?<
+ template = Tilt::EtanniTemplate.new('test.etn') { data }
+ begin
+ template.render(Scope.new, :name => 'Joe', :foo => 'bar')
+ fail 'should have raised an exception'
+ rescue => boom
+ assert_kind_of RuntimeError, boom
+ line = boom.backtrace.first
+ file, line, meth = line.split(":")
+ assert_equal 'test.etn', file
+ assert_equal '6', line
+ end
+ end
+end
+
+__END__
+<html>
+<body>
+ <h1>Hey #{name}!</h1>
+
+
+ <p>#{fail}</p>
+</body>
+</html>
Something went wrong with that request. Please try again.