Skip to content
Permalink
Browse files

Fix warning when using yield in templates on ruby 2.7

Take the class of the scope, and pass it through the
compilation methods.  Call class_eval on the scope's
class so that constant lookup works, and switch the
singleton class opening to instance_exec.

This radically simplifies the compiled template method
code, and I would guess it speeds it up significantly
as well.  However, this approach can cause a memory
leak if you are creating anonymous classes at runtime
and then passing instances of those classes as the scope
of the render.
  • Loading branch information...
jeremyevans authored and judofyr committed May 31, 2019
1 parent a7e0018 commit dbb4df94e5bc6e533fc2ed09b2fd70df39c049c3
Showing with 7 additions and 12 deletions.
  1. +7 −12 lib/tilt/template.rb
@@ -166,7 +166,7 @@ def prepare
def evaluate(scope, locals, &block)
locals_keys = locals.keys
locals_keys.sort!{|x, y| x.to_s <=> y.to_s}
method = compiled_method(locals_keys)
method = compiled_method(locals_keys, scope.class)
method.bind(scope).call(locals, &block)
end

@@ -231,9 +231,9 @@ def read_template_file
end

# The compiled method for the locals keys provided.
def compiled_method(locals_keys)
def compiled_method(locals_keys, scope_class=nil)
LOCK.synchronize do
@compiled_method[locals_keys] ||= compile_template_method(locals_keys)
@compiled_method[[scope_class, locals_keys]] ||= compile_template_method(locals_keys, scope_class)
end
end

@@ -247,7 +247,7 @@ def local_extraction(local_keys)
end.join("\n")
end

def compile_template_method(local_keys)
def compile_template_method(local_keys, scope_class=nil)
source, offset = precompiled(local_keys)
local_code = local_extraction(local_keys)

@@ -261,17 +261,12 @@ def compile_template_method(local_keys)
method_source << <<-RUBY
TOPOBJECT.class_eval do
def #{method_name}(locals)
Thread.current[:tilt_vars] = [self, locals]
class << self
this, locals = Thread.current[:tilt_vars]
locals = locals
this.instance_eval do
#{local_code}
#{local_code}
RUBY
offset += method_source.count("\n")
method_source << source
method_source << "\nend;end;end;end"
Object.class_eval(method_source, eval_file, line - offset)
method_source << "\nend;end;"
(scope_class || Object).class_eval(method_source, eval_file, line - offset)
unbind_compiled_method(method_name)
end

0 comments on commit dbb4df9

Please sign in to comment.
You can’t perform that action at this time.