diff options
author | danielsdeleo <dan@opscode.com> | 2013-05-27 11:15:01 -0700 |
---|---|---|
committer | danielsdeleo <dan@opscode.com> | 2013-05-29 11:32:22 -0700 |
commit | ca4cd1f830fae2fac3e2c18bbd2693b0caddcb33 (patch) | |
tree | 705a53ee2a2fd379096a8a15ebd6c070a7667639 | |
parent | 00de51bb552ea2e613afec4825277b855775b71e (diff) | |
download | chef-ca4cd1f830fae2fac3e2c18bbd2693b0caddcb33.tar.gz |
Pass template extensions through to partials
- move the new TemplateContext code into mixin/template and consolidate
with ChefContext
- Copy extension modules from parent template to partial template.
- Functional tests for helpers with partials.
-rw-r--r-- | lib/chef/mixin/template.rb | 83 | ||||
-rw-r--r-- | lib/chef/provider/template/content.rb | 30 | ||||
-rw-r--r-- | spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb | 1 | ||||
-rw-r--r-- | spec/functional/resource/template_spec.rb | 15 | ||||
-rw-r--r-- | spec/unit/cookbook/syntax_check_spec.rb | 8 | ||||
-rw-r--r-- | spec/unit/mixin/template_spec.rb | 9 |
6 files changed, 101 insertions, 45 deletions
diff --git a/lib/chef/mixin/template.rb b/lib/chef/mixin/template.rb index 4906734900..0e7bbeb73a 100644 --- a/lib/chef/mixin/template.rb +++ b/lib/chef/mixin/template.rb @@ -23,7 +23,32 @@ class Chef module Mixin module Template + # == ChefContext + # ChefContext was previously used to mix behavior into Erubis::Context so + # that it would be available to templates. This behavior has now moved to + # TemplateContext, but this module is still mixed in to the + # TemplateContext class so that any user code that modified ChefContext + # will continue to work correctly. module ChefContext + end + + # TODO: extract to file + # TODO: docs + class TemplateContext < Erubis::Context + + include ChefContext + + attr_reader :_extension_modules + + def initialize(variables) + super + @_extension_modules = [] + end + + ### + # USER FACING API + ### + def node return @node if @node raise "Could not find a value for node. If you are explicitly setting variables in a template, " + @@ -56,22 +81,60 @@ class Chef def render(partial_name, options = {}) raise "You cannot render partials in this context" unless @template_finder - if variables = options.delete(:variables) - context = {} - context.merge!(variables) - context[:node] = @node - context[:template_finder] = @template_finder - else - context = self.dup - end + partial_variables = options.delete(:variables) || _public_instance_variables + partial_context = self.class.new(partial_variables) + partial_context._extend_modules(@_extension_modules) template_location = @template_finder.find(partial_name, options) eruby = Erubis::Eruby.new(IO.read(template_location)) - eruby.evaluate(context) + eruby.evaluate(partial_context) + end + + ### + # INTERNAL PUBLIC API + ### + + def _define_helpers(helper_methods) + # TODO (ruby 1.8 hack) + # This is most elegantly done with Object#define_singleton_method, + # however ruby 1.8.7 does not support that, so we create a module and + # include it. This should be revised when 1.8 support is not needed. + helper_mod = Module.new do + helper_methods.each do |method_name, method_body| + define_method(method_name, &method_body) + end + end + @_extension_modules << helper_mod + extend(helper_mod) + end + + def _define_helpers_from_blocks(blocks) + blocks.each do |module_body| + helper_mod = Module.new(&module_body) + extend(helper_mod) + @_extension_modules << helper_mod + end + end + + def _extend_modules(module_names) + module_names.each do |mod| + extend(mod) + @_extension_modules << mod + end + end + + def _public_instance_variables + all_ivars = instance_variables + all_ivars.delete(:@_extension_modules) + all_ivars.inject({}) do |ivar_map, ivar_symbol_name| + value = instance_variable_get(ivar_symbol_name) + name_without_at = ivar_symbol_name.to_s[1..-1].to_sym + ivar_map[name_without_at] = value + ivar_map + end end end - ::Erubis::Context.send(:include, ChefContext) # Render a template with Erubis. Takes a template as a string, and a # context hash. diff --git a/lib/chef/provider/template/content.rb b/lib/chef/provider/template/content.rb index 5629ee9a19..f26b7a5b92 100644 --- a/lib/chef/provider/template/content.rb +++ b/lib/chef/provider/template/content.rb @@ -23,36 +23,6 @@ class Chef class Provider class Template - # TODO: extract to file - # TODO: integrate into mixin/template (make it work with partials) - # TODO: docs - class TemplateContext < Erubis::Context - - def _define_helpers(helper_methods) - # TODO (ruby 1.8 hack) - # This is most elegantly done with Object#define_singleton_method, - # however ruby 1.8.7 does not support that, so we create a module and - # include it. This should be revised when 1.8 support is not needed. - helper_mod = Module.new do - helper_methods.each do |method_name, method_body| - define_method(method_name, &method_body) - end - end - extend(helper_mod) - end - - def _define_helpers_from_blocks(blocks) - blocks.each do |module_body| - helper_mod = Module.new(&module_body) - extend(helper_mod) - end - end - - def _extend_modules(module_names) - module_names.each { |mod| extend(mod) } - end - end - class Content < Chef::FileContentManagement::ContentBase include Chef::Mixin::Template diff --git a/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb b/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb new file mode 100644 index 0000000000..f94b6b5979 --- /dev/null +++ b/spec/data/cookbooks/openldap/templates/default/helpers_via_partial_test.erb @@ -0,0 +1 @@ +<%= render("helper_test.erb").strip %> diff --git a/spec/functional/resource/template_spec.rb b/spec/functional/resource/template_spec.rb index 4d8c6c8738..d966aefb6a 100644 --- a/spec/functional/resource/template_spec.rb +++ b/spec/functional/resource/template_spec.rb @@ -42,6 +42,11 @@ describe Chef::Resource::Template do resource = Chef::Resource::Template.new(path, run_context) resource.source('openldap_stuff.conf.erb') resource.cookbook('openldap') + + # TODO: partials rely on `cookbook_name` getting set by chef internals and + # ignore the user-set `cookbook` attribute. + resource.cookbook_name = "openldap" + resource end @@ -167,5 +172,15 @@ describe Chef::Resource::Template do it_behaves_like "a template with helpers" end + + context "using helpers with partial templates" do + before do + resource.source("helpers_via_partial_test.erb") + resource.helper(:helper_method) { "value from helper method" } + end + + it_behaves_like "a template with helpers" + + end end end diff --git a/spec/unit/cookbook/syntax_check_spec.rb b/spec/unit/cookbook/syntax_check_spec.rb index cea5c89e87..7007d06920 100644 --- a/spec/unit/cookbook/syntax_check_spec.rb +++ b/spec/unit/cookbook/syntax_check_spec.rb @@ -33,8 +33,12 @@ describe Chef::Cookbook::SyntaxCheck do @defn_files = %w{client.rb server.rb}.map { |f| File.join(cookbook_path, 'definitions', f)} @recipes = %w{default.rb gigantor.rb one.rb}.map { |f| File.join(cookbook_path, 'recipes', f) } @ruby_files = @attr_files + @defn_files + @recipes - - @template_files = %w{helper_test.erb openldap_stuff.conf.erb openldap_variable_stuff.conf.erb test.erb}.map { |f| File.join(cookbook_path, 'templates', 'default', f)} + basenames = %w{ helpers_via_partial_test.erb + helper_test.erb + openldap_stuff.conf.erb + openldap_variable_stuff.conf.erb + test.erb } + @template_files = basenames.map { |f| File.join(cookbook_path, 'templates', 'default', f)} end it "creates a syntax checker given the cookbook name when Chef::Config.cookbook_path is set" do diff --git a/spec/unit/mixin/template_spec.rb b/spec/unit/mixin/template_spec.rb index bded4a697c..1fc2265ee0 100644 --- a/spec/unit/mixin/template_spec.rb +++ b/spec/unit/mixin/template_spec.rb @@ -24,16 +24,19 @@ describe Chef::Mixin::Template, "render_template" do before :each do @template = TinyTemplateClass.new + @context = Chef::Mixin::Template::TemplateContext.new({}) end it "should render the template evaluated in the given context" do - @template.render_template("<%= @foo %>", { :foo => "bar" }) do |tmp| + @context[:foo] = "bar" + @template.render_template("<%= @foo %>", @context) do |tmp| tmp.open.read.should == "bar" end end it "should provide a node method to access @node" do - @template.render_template("<%= node %>",{:node => "tehShizzle"}) do |tmp| + @context[:node] = "tehShizzle" + @template.render_template("<%= node %>", @context) do |tmp| tmp.open.read.should == "tehShizzle" end end @@ -64,7 +67,7 @@ describe Chef::Mixin::Template, "render_template" do @content_provider = Chef::Provider::Template::Content.new(@resource, @current_resource, @run_context) - @template_context = {} + @template_context = Chef::Mixin::Template::TemplateContext.new({}) @template_context[:node] = @node @template_context[:template_finder] = Chef::Provider::TemplateFinder.new(@run_context, @resource.cookbook_name, @node) end |