Skip to content

Loading…

Support for Erector templates #110

Closed
wants to merge 3 commits into from

3 participants

@maca

I've implemented support for templates written in Erector with a file extension .erector.
Erector hasn't got a lot of support from the community but is a neat DSL for html generation, and I've been using it lately for a sinatra extension. Author claims it is faster than markaby and nearly as fast as haml and erb.

@judofyr
Collaborator

Any reason Erector can't include the template itself?

@judofyr judofyr modified the milestone: 2.1, 2.0.2
@judofyr judofyr added the planned label
@judofyr
Collaborator

I'm not a big fan of the builder_class. Maybe there's a cleaner way to implement this in the latest Erector version?

@judofyr judofyr modified the milestone: 2.0.3, 2.0.2
@judofyr
Collaborator

Closing this because of no activity. Comment or reopen if you want to see it added.

@judofyr judofyr closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
View
1 .gitignore
@@ -3,3 +3,4 @@
/Gemfile.lock
/vendor
/.bundle
+.sass-cache
View
1 README.md
@@ -46,6 +46,7 @@ Support for these template engines is included with the package:
Creole (Wiki markup) .wiki, .creole creole
WikiCloth (Wiki markup) .wiki, .mediawiki, .mw wikicloth
Yajl .yajl yajl-ruby
+ Erector .erector erector
These template engines ship with their own Tilt integration:
View
3 lib/tilt.rb
@@ -187,4 +187,7 @@ def clear
require 'tilt/yajl'
register YajlTemplate, 'yajl'
+
+ require 'tilt/erector'
+ register ErectorTemplate, 'erector'
end
View
61 lib/tilt/erector.rb
@@ -0,0 +1,61 @@
+require 'tilt/template'
+
+module Tilt
+ # Erector
+ # http://github.com/erector/erector
+ class ErectorTemplate < Template
+ def self.builder_class
+ @builder_class ||= Class.new(Erector::InlineWidget) do
+ def scope= object
+ @_parent = object
+ end
+
+ def method_missing(name, *args, &block)
+ instance_variable_get("@#{name}") || @_parent.send(name, *args, &block)
+ end
+
+ def capture(&block)
+ original, @_output = output, Erector::Output.new
+ instance_eval &block
+ original.widgets.concat(output.widgets)
+ output.to_s
+ ensure
+ @_output = original
+ end
+
+ def content
+ block ? template_content{ text capture(&block) } : template_content
+ end
+ end
+ end
+
+ def self.engine_initialized?
+ defined? ::Erector
+ end
+
+ def initialize_engine
+ require_template_library 'erector'
+ end
+
+ def prepare
+ end
+
+ def evaluate(scope, locals, &block)
+ builder = self.class.builder_class.new(locals, &block)
+ builder.scope = scope
+
+ if data.kind_of? Proc
+ (class << builder; self end).send(:define_method, :template_content, &data)
+ else
+ builder.instance_eval <<-CODE, __FILE__, __LINE__
+ def template_content
+ #{data}
+ end
+ CODE
+ end
+
+ builder.to_html
+ end
+ end
+end
+
View
1 test/erector/erector.erector
@@ -0,0 +1 @@
+text "hello from erector!"
View
1 test/erector/erector_other_static.erector
@@ -0,0 +1 @@
+text "_why?"
View
1 test/erector/locals.erector
@@ -0,0 +1 @@
+li foo
View
1 test/erector/render_twice.erector
@@ -0,0 +1 @@
+text "foo"
View
1 test/erector/scope.erector
@@ -0,0 +1 @@
+li foo
View
2 test/erector/yielding.erector
@@ -0,0 +1,2 @@
+text("Hey ")
+yield
View
90 test/tilt_erector_test.rb
@@ -0,0 +1,90 @@
+require 'contest'
+require 'tilt'
+
+begin
+ require 'erector'
+ require 'erector'
+
+ class ErectorTiltTest < Test::Unit::TestCase
+ def setup
+ @block = lambda do |t|
+ File.read(File.dirname(__FILE__) + "/#{t.file}")
+ end
+ end
+
+ test "should be able to render a erector template with static html" do
+ tilt = Tilt::ErectorTemplate.new("erector/erector.erector", &@block)
+ assert_equal "hello from erector!", tilt.render
+ end
+
+ test "should use the contents of the template" do
+ tilt = ::Tilt::ErectorTemplate.new("erector/erector_other_static.erector", &@block)
+ assert_equal "_why?", tilt.render
+ end
+
+ test "should render from a string (given as data)" do
+ tilt = ::Tilt::ErectorTemplate.new { "html do; end" }
+ assert_equal "<html></html>", tilt.render
+ end
+
+ test "can be rendered more than once" do
+ tilt = ::Tilt::ErectorTemplate.new { "html do; end" }
+ 3.times { assert_equal "<html></html>", tilt.render }
+ end
+
+ test "should evaluate a template file in the scope given" do
+ scope = Object.new
+ def scope.foo
+ "bar"
+ end
+
+ tilt = ::Tilt::ErectorTemplate.new("erector/scope.erector", &@block)
+ assert_equal "<li>bar</li>", tilt.render(scope)
+ end
+
+ test "should pass locals to the template" do
+ tilt = ::Tilt::ErectorTemplate.new("erector/locals.erector", &@block)
+ assert_equal "<li>bar</li>", tilt.render(Object.new, { :foo => "bar" })
+ end
+
+ test "should pass locals to the template when key is string" do
+ tilt = ::Tilt::ErectorTemplate.new("erector/locals.erector", &@block)
+ assert_equal "<li>bar</li>", tilt.render(Object.new, { 'foo' => "bar" })
+ end
+
+ test "should yield to the block given" do
+ tilt = ::Tilt::ErectorTemplate.new("erector/yielding.erector", &@block)
+ output = tilt.render(Object.new, {}) do
+ text("Joe")
+ end
+ assert_equal "Hey Joe", output
+ end
+
+ test "should be able to render two templates in a row" do
+ tilt = ::Tilt::ErectorTemplate.new("erector/render_twice.erector", &@block)
+ assert_equal "foo", tilt.render
+ assert_equal "foo", tilt.render
+ end
+
+ test "should retrieve a Tilt::ErectorTemplate when calling Tilt['hello.erector']" do
+ assert_equal Tilt::ErectorTemplate, ::Tilt['./erector/erector.erector']
+ end
+
+ test "should return a new instance of the implementation class (when calling Tilt.new)" do
+ assert ::Tilt.new(File.dirname(__FILE__) + "/erector/erector.erector").kind_of?(Tilt::ErectorTemplate)
+ end
+
+ test "should be able to evaluate block style templates" do
+ tilt = Tilt::ErectorTemplate.new { |t| lambda { h1 "Hello World!" }}
+ assert_equal "<h1>Hello World!</h1>", tilt.render
+ end
+
+ test "should pass locals to block style templates" do
+ tilt = Tilt::ErectorTemplate.new { |t| lambda { h1 "Hello #{name}!" }}
+ assert_equal "<h1>Hello _why!</h1>", tilt.render(nil, :name => "_why")
+ end
+ end
+
+rescue LoadError => boom
+ warn "Tilt::ErectorTemplate (disabled)"
+end
View
1 tilt.gemspec
@@ -99,6 +99,7 @@ Gem::Specification.new do |s|
s.add_development_dependency 'sass'
s.add_development_dependency 'wikicloth'
s.add_development_dependency 'yajl-ruby'
+ s.add_development_dependency 'erector'
s.homepage = "http://github.com/rtomayko/tilt/"
s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tilt", "--main", "Tilt"]
Something went wrong with that request. Please try again.