From fd849357dff87787dd61035cf234c55c949f7e60 Mon Sep 17 00:00:00 2001
From: Andrea Campi <andrea.campi@zephirworks.com>
Date: Wed, 14 Nov 2012 01:23:26 +0100
Subject: [PATCH] Quick and dirty implementation of "render partial" in
 templates.

---
 lib/chef/mixin/template.rb                         |   13 +++++++
 lib/chef/provider/template.rb                      |    4 ++
 .../cookbooks/openldap/templates/default/_test.erb |    1 +
 spec/unit/mixin/template_spec.rb                   |   39 ++++++++++++++++++++
 4 files changed, 57 insertions(+)
 create mode 100644 spec/data/cookbooks/openldap/templates/default/_test.erb

diff --git a/lib/chef/mixin/template.rb b/lib/chef/mixin/template.rb
index 78148d2..449d1d7 100644
--- a/lib/chef/mixin/template.rb
+++ b/lib/chef/mixin/template.rb
@@ -29,6 +29,19 @@ class Chef
           raise "Could not find a value for node. If you are explicitly setting variables in a template, " +
                 "include a node variable if you plan to use it."
         end
+
+        def render(name_or_options)
+          partial_name = name_or_options.is_a?(Hash) ? name_or_options.delete(:partial) : name_or_options
+          partial_name = "_#{partial_name}"
+
+          if @partial_resolver
+            template_location = @partial_resolver.call(partial_name)
+            eruby = Erubis::Eruby.new(IO.read(template_location))
+            output = eruby.evaluate(self)
+          else
+            "foo"
+          end
+        end
       end
       
       ::Erubis::Context.send(:include, ChefContext)
diff --git a/lib/chef/provider/template.rb b/lib/chef/provider/template.rb
index c937b9d..cce3418 100644
--- a/lib/chef/provider/template.rb
+++ b/lib/chef/provider/template.rb
@@ -109,6 +109,10 @@ class Chef
         context = {}
         context.merge!(@new_resource.variables)
         context[:node] = node
+        context[:partial_resolver] = lambda do
+          cookbook = _run_context.cookbook_collection[resource_cookbook]
+          partial_location = cookbook.preferred_filename_on_disk_location(node, :templates, partial_name)
+        end
         render_template(IO.read(template_location), context, &block)
       end
 
diff --git a/spec/data/cookbooks/openldap/templates/default/_test.erb b/spec/data/cookbooks/openldap/templates/default/_test.erb
new file mode 100644
index 0000000..354f410
--- /dev/null
+++ b/spec/data/cookbooks/openldap/templates/default/_test.erb
@@ -0,0 +1 @@
+Awesome partial!
diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb
index 3d8a723..a9f0824 100644
--- a/spec/unit/mixin/template_spec.rb
+++ b/spec/unit/mixin/template_spec.rb
@@ -44,6 +44,45 @@ describe Chef::Mixin::Template, "render_template" do
     end
   end
 
+  describe "with a template resource" do
+    before :each do
+      @cookbook_repo = File.expand_path(File.join(CHEF_SPEC_DATA, "cookbooks"))
+      Chef::Cookbook::FileVendor.on_create { |manifest| Chef::Cookbook::FileSystemFileVendor.new(manifest, @cookbook_repo) }
+
+      @node = Chef::Node.new
+      cl = Chef::CookbookLoader.new(@cookbook_repo)
+      cl.load_cookbooks
+      @cookbook_collection = Chef::CookbookCollection.new(cl)
+      @events = Chef::EventDispatch::Dispatcher.new
+      @run_context = Chef::RunContext.new(@node, @cookbook_collection, @events)
+
+      @rendered_file_location = Dir.tmpdir + '/openldap_stuff.conf'
+
+      @resource = Chef::Resource::Template.new(@rendered_file_location)
+      @resource.cookbook_name = 'openldap'
+
+      @provider = Chef::Provider::Template.new(@resource, @run_context)
+      @current_resource = @resource.dup
+      @provider.current_resource = @current_resource
+    end
+
+    it "should provide a render method" do
+      _run_context = @run_context
+      context = {}
+      context[:node] = @node
+      context[:partial_resolver] = lambda do |partial_name|
+        @provider.instance_eval do
+          cookbook = run_context.cookbook_collection[resource_cookbook]
+          partial_location = cookbook.preferred_filename_on_disk_location(node, :templates, partial_name)
+        end
+      end
+
+      @provider.render_template("before {<%= render 'test.erb' %>} after", context) do |tmp|
+        tmp.open.read.should == "before {Awesome partial!\n} after"
+      end
+    end
+  end
+
   describe "when an exception is raised in the template" do
     def do_raise
       @context = {:chef => "cool"}
-- 
1.7.10.2

