diff options
author | Brice Figureau <brice-puppet@daysofwonder.com> | 2009-11-10 16:43:37 +0100 |
---|---|---|
committer | test branch <puppet-dev@googlegroups.com> | 2010-02-17 06:50:53 -0800 |
commit | 75c32f910ea124a938a7035b3352c11a11b57d0c (patch) | |
tree | 744d30ad3c4234f57a92c417484a3b33685af99b /spec/unit | |
parent | 9122ac51284086a050d61df8fe060616aaf83d3c (diff) | |
download | puppet-75c32f910ea124a938a7035b3352c11a11b57d0c.tar.gz puppet-75c32f910ea124a938a7035b3352c11a11b57d0c.tar.xz puppet-75c32f910ea124a938a7035b3352c11a11b57d0c.zip |
Fix #2389 - Enhance Puppet DSL with Hashes
This bring a new container syntax to the Puppet DSL: hashes.
Hashes are defined like Ruby Hash:
{ key1 => val1, ... }
Hash keys are strings, but hash values can be any possible right
values admitted in Puppet DSL (ie function call, variables access...)
Currently it is possible:
1) to assign hashes to variable
$myhash = { key1 => "myval", key2 => $b }
2) to access hash members (recursively) from a variable containing
a hash (works for array too):
$myhash = { key => { subkey => "b" }}
notice($myhash[key][subjey]]
3) to use hash member access as resource title
4) to use hash in default definition parameter or resource parameter if
the type supports it (known for the moment).
It is not possible to string interpolate an hash access. If it proves
to be an issue it can be added or work-arounded with a string concatenation
operator easily.
It is not possible to use an hash as a resource title. This might be
possible once we support compound resource title.
Unlike the proposed syntax in the ticket it is not possible to assign
individual hash member (mostly to respect write once nature of variable
in puppet).
Signed-off-by: Brice Figureau <brice-puppet@daysofwonder.com>
Diffstat (limited to 'spec/unit')
-rw-r--r-- | spec/unit/parser/ast/asthash.rb | 64 | ||||
-rwxr-xr-x | spec/unit/parser/ast/leaf.rb | 83 | ||||
-rwxr-xr-x | spec/unit/parser/scope.rb | 10 |
3 files changed, 157 insertions, 0 deletions
diff --git a/spec/unit/parser/ast/asthash.rb b/spec/unit/parser/ast/asthash.rb new file mode 100644 index 000000000..4c700fe4b --- /dev/null +++ b/spec/unit/parser/ast/asthash.rb @@ -0,0 +1,64 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../../../spec_helper' + +describe Puppet::Parser::AST::ASTHash do + before :each do + @scope = Puppet::Parser::Scope.new() + end + + it "should have a [] accessor" do + hash = Puppet::Parser::AST::ASTHash.new(:value => {}) + hash.should respond_to(:[]) + end + + it "should have a merge functionality" do + hash = Puppet::Parser::AST::ASTHash.new(:value => {}) + hash.should respond_to(:merge) + end + + it "should be able to merge 2 AST hashes" do + hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) + + hash.merge(Puppet::Parser::AST::ASTHash.new(:value => {"c" => "d"})) + + hash.value.should == { "a" => "b", "c" => "d" } + end + + it "should be able to merge with a ruby Hash" do + hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b" }) + + hash.merge({"c" => "d"}) + + hash.value.should == { "a" => "b", "c" => "d" } + end + + it "should evaluate each hash value" do + key1 = stub "key1" + value1 = stub "value1" + key2 = stub "key2" + value2 = stub "value2" + + value1.expects(:safeevaluate).with(@scope).returns("b") + value2.expects(:safeevaluate).with(@scope).returns("d") + + operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) + operator.evaluate(@scope) + end + + it "should return an evaluated hash" do + key1 = stub "key1" + value1 = stub "value1", :safeevaluate => "b" + key2 = stub "key2" + value2 = stub "value2", :safeevaluate => "d" + + operator = Puppet::Parser::AST::ASTHash.new(:value => { key1 => value1, key2 => value2}) + operator.evaluate(@scope).should == { key1 => "b", key2 => "d" } + end + + it "should return a valid string with to_s" do + hash = Puppet::Parser::AST::ASTHash.new(:value => { "a" => "b", "c" => "d" }) + + hash.to_s.should == '{a => b, c => d}' + end +end diff --git a/spec/unit/parser/ast/leaf.rb b/spec/unit/parser/ast/leaf.rb index 640c25237..12ec2711e 100755 --- a/spec/unit/parser/ast/leaf.rb +++ b/spec/unit/parser/ast/leaf.rb @@ -94,6 +94,89 @@ describe Puppet::Parser::AST::Undef do end end +describe Puppet::Parser::AST::HashOrArrayAccess do + before :each do + @scope = stub 'scope' + end + + it "should evaluate the variable part if necessary" do + @scope.stubs(:lookupvar).with("a").returns(["b"]) + + variable = stub 'variable', :evaluate => "a" + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 ) + + variable.expects(:safeevaluate).with(@scope).returns("a") + + access.evaluate(@scope).should == "b" + end + + it "should evaluate the access key part if necessary" do + @scope.stubs(:lookupvar).with("a").returns(["b"]) + + index = stub 'index', :evaluate => 0 + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index ) + + index.expects(:safeevaluate).with(@scope).returns(0) + + access.evaluate(@scope).should == "b" + end + + it "should be able to return an array member" do + @scope.stubs(:lookupvar).with("a").returns(["val1", "val2", "val3"]) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) + + access.evaluate(@scope).should == "val2" + end + + it "should be able to return an hash value" do + @scope.stubs(:lookupvar).with("a").returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" }) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) + + access.evaluate(@scope).should == "val2" + end + + it "should raise an error if the variable lookup didn't return an hash or an array" do + @scope.stubs(:lookupvar).with("a").returns("I'm a string") + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) + + lambda { access.evaluate(@scope) }.should raise_error + end + + it "should raise an error if the variable wasn't in the scope" do + @scope.stubs(:lookupvar).with("a").returns(nil) + + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) + + lambda { access.evaluate(@scope) }.should raise_error + end + + it "should return a correct string representation" do + access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) + access.to_s.should == '$a[key2]' + end + + it "should work with recursive hash access" do + @scope.stubs(:lookupvar).with("a").returns({ "key" => { "subkey" => "b" }}) + + access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") + access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") + + access2.evaluate(@scope).should == 'b' + end + + it "should work with interleaved array and hash access" do + @scope.stubs(:lookupvar).with("a").returns({ "key" => [ "a" , "b" ]}) + + access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") + access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1) + + access2.evaluate(@scope).should == 'b' + end +end + describe Puppet::Parser::AST::Regex do before :each do @scope = stub 'scope' diff --git a/spec/unit/parser/scope.rb b/spec/unit/parser/scope.rb index 04ae3047c..2f553e460 100755 --- a/spec/unit/parser/scope.rb +++ b/spec/unit/parser/scope.rb @@ -64,6 +64,11 @@ describe Puppet::Parser::Scope do @scope.lookupvar("var").should == "yep" end + it "should be able to look up hashes" do + @scope.setvar("var", {"a" => "b"}) + @scope.lookupvar("var").should == {"a" => "b"} + end + it "should be able to look up variables in parent scopes" do @topscope.setvar("var", "parentval") @scope.lookupvar("var").should == "parentval" @@ -167,6 +172,11 @@ describe Puppet::Parser::Scope do @scope.lookupvar("var").should == [4,2] end + it "it should store the merged hash {a => b, c => d}" do + @topscope.setvar("var",{"a" => "b"}, :append => false) + @scope.setvar("var",{"c" => "d"}, :append => true) + @scope.lookupvar("var").should == {"a" => "b", "c" => "d"} + end end describe "when calling number?" do |