A little more tweaking of Engine#compile.

git-svn-id: svn://hamptoncatlin.com/haml/trunk@643 7063305b-7217-0410-af8c-cdc13e5119b9
This commit is contained in:
nex3 2007-11-23 12:14:02 +00:00
parent a56175f37a
commit 3e91e60400
2 changed files with 34 additions and 9 deletions

View File

@ -72,6 +72,26 @@ module Haml
end
# Processes the template and returns the result as a string.
#
# +scope+ is the context in which the template is evaluated.
# If it's a Binding or Proc object,
# Haml uses it as the second argument to Kernel#eval;
# otherwise, Haml just uses its #instance_eval context.
# Note that Haml modifies the context,
# extending it with Haml::Helpers
# and performing various other modifications.
#
# If a block is passed to render,
# that block is run when +yield+ is called
# within the template.
#
# Note that due to some Ruby quirks,
# if scope is a Binding or Proc object and a block is given,
# the evaluation context may not be quite what the user expects.
# In particular, it's equivalent to passing <tt>eval("self", scope)</tt> as scope.
# This won't have an effect in most cases,
# but if you're relying on local variables defined in the context of scope,
# they won't work.
def render(scope = Object.new, &block)
@buffer = Haml::Buffer.new(@options)
compile scope, &block
@ -86,13 +106,18 @@ module Haml
# The code in <tt>@precompiled</tt> populates
# <tt>@buffer</tt> with the compiled XHTML code.
def compile(scope, &block)
if Binding === scope
if scope.is_a?(Binding) || scope.is_a?(Proc)
scope_object = eval("self", scope)
scope = scope_object.instance_eval{binding} if block_given?
else
scope_object = scope
scope = scope.instance_eval{binding}
scope = scope_object.instance_eval{binding}
end
scope_object.send(:instance_variable_set, '@_haml_locals', @options[:locals])
set_locals = @options[:locals].keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
eval(set_locals, scope)
scope_object.extend Haml::Helpers
buffer = @buffer
scope_object.instance_eval do
@ -100,12 +125,8 @@ module Haml
@haml_stack.push(buffer)
end
scope_object.send(:instance_variable_set, '@_haml_locals', @options[:locals])
set_locals = @options[:locals].keys.map { |k| "#{k} = @_haml_locals[#{k.inspect}]" }.join("\n")
eval(set_locals, scope)
begin
eval(@precompiled, scope, '(haml-eval)', &block)
eval(@precompiled, scope, '(haml-eval)')
rescue Exception => e
raise add_exception_info(e, scope_object)
end

View File

@ -11,8 +11,8 @@ require 'haml/engine'
class EngineTest < Test::Unit::TestCase
def render(text, options = {})
Haml::Engine.new(text, options).to_html(options.delete(:scope) || Object.new)
def render(text, options = {}, &block)
Haml::Engine.new(text, options).to_html(options.delete(:scope) || Object.new, &block)
end
def test_empty_render_should_remain_empty
@ -310,4 +310,8 @@ class EngineTest < Test::Unit::TestCase
assert_equal("<p>THIS IS A STRING!</p>\n<p>Instance variable</p>\n<p>Local variable</p>\n",
render("%p= upcase\n%p= @var\n%p= var", :scope => b))
end
def test_yield_should_work_with_binding
assert_equal("12\nFOO\n", render("= yield\n= upcase", :scope => "foo".instance_eval{binding}) { 12 })
end
end