diff --git a/lib/puppet/parser/functions/epp.rb b/lib/puppet/parser/functions/epp.rb index da6d5f3ff..616d61422 100644 --- a/lib/puppet/parser/functions/epp.rb +++ b/lib/puppet/parser/functions/epp.rb @@ -1,41 +1,41 @@ Puppet::Parser::Functions::newfunction(:epp, :type => :rvalue, :arity => -2, :doc => "Evaluates an Embedded Puppet Template (EPP) file and returns the rendered text result as a String. EPP support the following tags: * `<%= puppet expression %>` - This tag renders the value of the expression it contains. * `<% puppet expression(s) %>` - This tag will execute the expression(s) it contains, but renders nothing. * `<%# comment %>` - The tag and its content renders nothing. * `<%%` or `%%>` - Renders a literal `<%` or `%>` respectively. * `<%-` - Same as `<%` but suppresses any leading whitespace. * `-%>` - Same as `%>` but suppresses any trailing whitespace on the same line (including line break). * `<%-( parameters )-%>` - When placed as the first tag declares the template's parameters. File based EPP supports the following visibilities of variables in scope: * Global scope (i.e. top + node scopes) - global scope is always visible * Global + all given arguments - if the EPP template does not declare parameters, and arguments are given * Global + declared parameters - if the EPP declares parameters, given argument names must match EPP supports parameters by placing an optional parameter list as the very first element in the EPP. As an example, `<%- ($x, $y, $z='unicorn') -%>` when placed first in the EPP text declares that the parameters `x` and `y` must be given as template arguments when calling `inline_epp`, and that `z` if not given as a template argument defaults to `'unicorn'`. Template parameters are available as variables, e.g.arguments `$x`, `$y` and `$z` in the example. Note that `<%-` must be used or any leading whitespace will be interpreted as text Arguments are passed to the template by calling `epp` with a Hash as the last argument, where parameters are bound to values, e.g. `epp('...', {'x'=>10, 'y'=>20})`. Excess arguments may be given (i.e. undeclared parameters) only if the EPP templates does not declare any parameters at all. Template parameters shadow variables in outer scopes. File based epp does never have access to variables in the scope where the `epp` function is called from. - See function inline_epp for examples of EPP - Since 3.5 - Requires Future Parser") do |arguments| # Requires future parser unless Puppet[:parser] == "future" raise ArgumentError, "epp(): function is only available when --parser future is in effect" end - Puppet::Pops::Evaluator::EppEvaluator.epp(self, arguments[0], self.compiler.environment.to_s, arguments[1]) + Puppet::Pops::Evaluator::EppEvaluator.epp(self, arguments[0], self.compiler.environment, arguments[1]) end diff --git a/spec/unit/parser/functions/epp_spec.rb b/spec/unit/parser/functions/epp_spec.rb index 536478ee3..b88d3da8f 100644 --- a/spec/unit/parser/functions/epp_spec.rb +++ b/spec/unit/parser/functions/epp_spec.rb @@ -1,88 +1,103 @@ require 'spec_helper' describe "the epp function" do include PuppetSpec::Files before :all do Puppet::Parser::Functions.autoloader.loadall end before :each do Puppet[:parser] = 'future' end let :node do Puppet::Node.new('localhost') end let :compiler do Puppet::Parser::Compiler.new(node) end let :scope do Puppet::Parser::Scope.new(compiler) end context "when accessing scope variables as $ variables" do it "looks up the value from the scope" do scope["what"] = "are belong" eval_template("all your base <%= $what %> to us").should == "all your base are belong to us" end it "get nil accessing a variable that does not exist" do eval_template("<%= $kryptonite == undef %>").should == "true" end it "get nil accessing a variable that is undef" do scope['undef_var'] = :undef eval_template("<%= $undef_var == undef %>").should == "true" end it "gets shadowed variable if args are given" do scope['phantom'] = 'of the opera' eval_template_with_args("<%= $phantom == dragos %>", 'phantom' => 'dragos').should == "true" end it "gets shadowed variable if args are given and parameters are specified" do scope['x'] = 'wrong one' eval_template_with_args("<%-( $x )-%><%= $x == correct %>", 'x' => 'correct').should == "true" end it "raises an error if required variable is not given" do scope['x'] = 'wrong one' expect { eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'y' => 'correct') }.to raise_error(/no value given for required parameters x/) end it "raises an error if too many arguments are given" do scope['x'] = 'wrong one' expect { eval_template_with_args("<%-| $x |-%><%= $x == correct %>", 'x' => 'correct', 'y' => 'surplus') }.to raise_error(/Too many arguments: 2 for 1/) end end # although never a problem with epp it "is not interfered with by having a variable named 'string' (#14093)" do scope['string'] = "this output should not be seen" eval_template("some text that is static").should == "some text that is static" end it "has access to a variable named 'string' (#14093)" do scope['string'] = "the string value" eval_template("string was: <%= $string %>").should == "string was: the string value" end + describe 'when loading from modules' do + include PuppetSpec::Files + it 'an epp template is found' do + modules_dir = dir_containing('modules', { + 'testmodule' => { + 'templates' => { + 'the_x.epp' => 'The x is <%= $x %>' + } + }}) + Puppet.override({:current_environment => (env = Puppet::Node::Environment.create(:testload, [ modules_dir ]))}, "test") do + node.environment = env + expect(scope.function_epp([ 'testmodule/the_x.epp', { 'x' => '3'} ])).to eql("The x is 3") + end + end + end def eval_template_with_args(content, args_hash) file_path = tmpdir('epp_spec_content') filename = File.join(file_path, "template.epp") File.open(filename, "w+") { |f| f.write(content) } Puppet::Parser::Files.stubs(:find_template).returns(filename) scope.function_epp(['template', args_hash]) end def eval_template(content) file_path = tmpdir('epp_spec_content') filename = File.join(file_path, "template.epp") File.open(filename, "w+") { |f| f.write(content) } Puppet::Parser::Files.stubs(:find_template).returns(filename) scope.function_epp(['template']) end end