Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: rtomayko/tilt
base: master
...
head fork: rtomayko/tilt
compare: precomp-procs
Checking mergeability… Don’t worry, you can still create the pull request.
  • 5 commits
  • 2 files changed
  • 0 commit comments
  • 2 contributors
Commits on Mar 03, 2010
@josh josh Cached compiled erb templates in procs 75a75f3
@rtomayko cache template procs on locals.keys so values can GC 6cf50bd
@rtomayko move proc compilation to Template base class so everyone wins e4024f0
@rtomayko failing test case for different locals w/ same template proc
The problem here is that the cached template proc closes over the
locals variable when the proc is created and not when the proc is
instance eval'd. Caching the proc on the entire locals Hash (instead
of just the keys) fixes this but holds references to all locals
values and has really poor cache hit characteristics.
6e1ce25
@rtomayko use instance_exec to overcome locals problem (>= 1.8.7 only)
Falls back to evaluating template source each time when
instance_exec is not available.
79de592
Showing with 30 additions and 12 deletions.
  1. +23 −12 lib/tilt.rb
  2. +7 −0 test/tilt_erbtemplate_test.rb
View
35 lib/tilt.rb
@@ -78,6 +78,7 @@ def initialize(file=nil, line=1, options={}, &block)
@options = options || {}
@reader = block || lambda { |t| File.read(file) }
@data = nil
+ @procs = {}
if !self.class.engine_initialized
initialize_engine
@@ -93,7 +94,6 @@ def initialize_engine
@engine_initialized = false
class << self ; attr_accessor :engine_initialized ; end
-
# Load template source and compile the template. The template is
# loaded and compiled the first time this method is called; subsequent
# calls are no-ops.
@@ -138,20 +138,35 @@ def compile!
end
# Process the template and return the result. Subclasses should override
- # this method unless they implement the #template_source.
+ # this method unless they implement either the #template_source or
+ # template_proc method.
def evaluate(scope, locals, &block)
- source, offset = local_assignment_code(locals)
- source = [source, template_source].join("\n")
- scope.instance_eval source, eval_file, line - offset
+ if scope.respond_to?(:instance_exec)
+ scope.instance_exec(locals, &template_proc(locals))
+ else
+ source, offset = local_assignment_code(locals)
+ source = [source, template_source].join("\n")
+ scope.instance_eval(source, eval_file, line - offset)
+ end
end
# Return a string containing the (Ruby) source code for the template. The
- # default Template#evaluate implementation requires this method be
- # defined.
+ # default Template#evaluate implementation requires either this method or
+ # #template_proc be implemented.
def template_source
raise NotImplementedError
end
+ # Return a compiled template source Proc for the given locals Hash. The
+ # proc returned must be suitable for instance_eval in the context object.
+ def template_proc(locals)
+ @procs[locals.keys] ||= begin
+ source, offset = local_assignment_code(locals)
+ source = [source, template_source].join("\n")
+ instance_eval("proc { |locals| #{source} }", eval_file, line - offset)
+ end
+ end
+
private
def local_assignment_code(locals)
return ['', 1] if locals.empty?
@@ -223,14 +238,11 @@ def template_source
end
def evaluate(scope, locals, &block)
- source, offset = local_assignment_code(locals)
- source = [source, template_source].join("\n")
-
original_out_buf =
scope.instance_variables.any? { |var| var.to_sym == :@_out_buf } &&
scope.instance_variable_get(:@_out_buf)
- scope.instance_eval source, eval_file, line - offset
+ super
output = scope.instance_variable_get(:@_out_buf)
scope.instance_variable_set(:@_out_buf, original_out_buf)
@@ -239,7 +251,6 @@ def evaluate(scope, locals, &block)
end
private
-
# ERB generates a line to specify the character coding of the generated
# source in 1.9. Account for this in the line offset.
if RUBY_VERSION >= '1.9.0'
View
7 test/tilt_erbtemplate_test.rb
@@ -22,6 +22,13 @@ class ERBTemplateTest < Test::Unit::TestCase
assert_equal "Hey Joe!", template.render(Object.new, :name => 'Joe')
end
+ test "rendering same template with different locals" do
+ template = Tilt::ERBTemplate.new { 'Hey <%= name %>!' }
+ assert_equal "Hey Joe!", template.render(Object.new, :name => 'Joe')
+ assert_equal "Hey Jane!", template.render(Object.new, :name => 'Jane')
+ assert_equal "Hey Billy!", template.render(Object.new, :name => 'Billy', :x => 5)
+ end
+
test "evaluating in an object scope" do
template = Tilt::ERBTemplate.new { 'Hey <%= @name %>!' }
scope = Object.new

No commit comments for this range

Something went wrong with that request. Please try again.