From 0d2e0672eb516a1b1f2ced6b8c74bd2064dd205e Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 07:03:54 -0700 Subject: Adding []/[]= support to Scope The interface to scope is much clearer this way anyway, but this is needed to integrate Puppet with Hiera[1]. It just provides hash-like behavior to Scope, which Hiera and others can now easily rely on. I also went through all of the code that used Scope#lookupvar and Scope#setvar and changed it if possible, and at the same time cleaned up a lot of tests that were unnecessarily stubbing (and thus making it difficult to tell if I had actually broken anything). 1 - https://github.com/ripienaar/hiera Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/ast/leaf.rb | 4 +- lib/puppet/parser/compiler.rb | 4 +- lib/puppet/parser/functions/extlookup.rb | 12 ++-- lib/puppet/parser/functions/fqdn_rand.rb | 2 +- lib/puppet/parser/resource.rb | 2 +- lib/puppet/parser/scope.rb | 57 ++++++++++------- lib/puppet/parser/templatewrapper.rb | 4 +- lib/puppet/resource/type.rb | 16 ++--- spec/unit/parser/ast/casestatement_spec.rb | 2 +- spec/unit/parser/ast/leaf_spec.rb | 53 ++++++++-------- spec/unit/parser/ast/resource_reference_spec.rb | 2 +- spec/unit/parser/compiler_spec.rb | 4 +- spec/unit/parser/functions/extlookup_spec.rb | 10 +-- spec/unit/parser/functions/fqdn_rand_spec.rb | 12 +--- spec/unit/parser/resource_spec.rb | 6 +- spec/unit/parser/scope_spec.rb | 83 +++++++++++++------------ spec/unit/parser/templatewrapper_spec.rb | 6 +- spec/unit/resource/type_spec.rb | 20 +++--- test/language/ast/variable.rb | 29 --------- test/language/functions.rb | 24 +++---- test/language/scope.rb | 30 ++++----- 21 files changed, 178 insertions(+), 204 deletions(-) delete mode 100755 test/language/ast/variable.rb diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index c8ebc9483..64a197492 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -124,7 +124,7 @@ class Puppet::Parser::AST # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do - if (var = scope.lookupvar(@value, :file => file, :line => line)) == :undefined + if (var = scope[@value, {:file => file, :line => line}]) == :undefined var = :undef end var @@ -141,7 +141,7 @@ class Puppet::Parser::AST def evaluate_container(scope) container = variable.respond_to?(:evaluate) ? variable.safeevaluate(scope) : variable - (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope.lookupvar(container, :file => file, :line => line) + (container.is_a?(Hash) or container.is_a?(Array)) ? container : scope[container, {:file => file, :line => line}] end def evaluate_key(scope) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index c1daade4c..f43a31285 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -450,7 +450,7 @@ class Puppet::Parser::Compiler # Set the node's parameters into the top-scope as variables. def set_node_parameters node.parameters.each do |param, value| - @topscope.setvar(param, value) + @topscope[param] = value end # These might be nil. @@ -473,7 +473,7 @@ class Puppet::Parser::Compiler Puppet.settings.each do |name, setting| next if name.to_s == "name" - scope.setvar name.to_s, environment[name] + scope[name.to_s] = environment[name] end end diff --git a/lib/puppet/parser/functions/extlookup.rb b/lib/puppet/parser/functions/extlookup.rb index 5fbf26cec..9ffca59a7 100644 --- a/lib/puppet/parser/functions/extlookup.rb +++ b/lib/puppet/parser/functions/extlookup.rb @@ -91,9 +91,9 @@ This is for back compatibility to interpolate variables with %. % interpolation raise Puppet::ParseError, ("extlookup(): wrong number of arguments (#{args.length}; must be <= 3)") if args.length > 3 - extlookup_datadir = undef_as('',lookupvar('::extlookup_datadir')) + extlookup_datadir = undef_as('',self['::extlookup_datadir']) - extlookup_precedence = undef_as([],lookupvar('::extlookup_precedence')).collect { |var| var.gsub(/%\{(.+?)\}/) { lookupvar("::#{$1}") } } + extlookup_precedence = undef_as([],self['::extlookup_precedence']).collect { |var| var.gsub(/%\{(.+?)\}/) { self["::#{$1}"] } } datafiles = Array.new @@ -121,9 +121,9 @@ This is for back compatibility to interpolate variables with %. % interpolation if result[0].length == 2 val = result[0][1].to_s - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while val =~ /%\{(.+?)\}/ - val.gsub!(/%\{#{$1}\}/, lookupvar($1)) + val.gsub!(/%\{#{$1}\}/, self[$1]) end desired = val @@ -134,9 +134,9 @@ This is for back compatibility to interpolate variables with %. % interpolation # Individual cells in a CSV result are a weird data type and throws # puppets yaml parsing, so just map it all to plain old strings desired = cells.map do |c| - # parse %{}'s in the CSV into local variables using lookupvar() + # parse %{}'s in the CSV into local variables using the current scope while c =~ /%\{(.+?)\}/ - c.gsub!(/%\{#{$1}\}/, lookupvar($1)) + c.gsub!(/%\{#{$1}\}/, self[$1]) end c.to_s diff --git a/lib/puppet/parser/functions/fqdn_rand.rb b/lib/puppet/parser/functions/fqdn_rand.rb index 93ab98bcd..668802e73 100644 --- a/lib/puppet/parser/functions/fqdn_rand.rb +++ b/lib/puppet/parser/functions/fqdn_rand.rb @@ -7,6 +7,6 @@ Puppet::Parser::Functions::newfunction(:fqdn_rand, :type => :rvalue, :doc => $random_number_seed = fqdn_rand(30,30)") do |args| require 'digest/md5' max = args.shift - srand(Digest::MD5.hexdigest([lookupvar('::fqdn'),args].join(':')).hex) + srand(Digest::MD5.hexdigest([self['::fqdn'],args].join(':')).hex) rand(max).to_s end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 3bb5f8601..305ba81e8 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -258,7 +258,7 @@ class Puppet::Parser::Resource < Puppet::Resource def add_backward_compatible_relationship_param(name) # Skip metaparams for which we get no value. - return unless val = scope.lookupvar(name.to_s) and val != :undefined + return unless val = scope[name.to_s] and val != :undefined # The default case: just set the value set_parameter(name, val) and return unless @parameters[name] diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index ed67cd141..67dcb1cb0 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -48,6 +48,35 @@ class Puppet::Parser::Scope end end + def [](name, options = {}) + table = ephemeral?(name) ? @ephemeral.last : @symtable + # If the variable is qualified, then find the specified scope and look the variable up there instead. + if name =~ /^(.*)::(.+)$/ + begin + qualified_scope($1)[$2,options] + rescue RuntimeError => e + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" + :undefined + end + elsif ephemeral_include?(name) or table.include?(name) + # We can't use "if table[name]" here because the value might be false + if options[:dynamic] and self != compiler.topscope + location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' + Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." + end + table[name] + elsif parent + parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))] + else + :undefined + end + end + + def []=(var, value) + setvar(var, value) + end + # A demeterific shortcut to the catalog. def catalog compiler.catalog @@ -223,29 +252,9 @@ class Puppet::Parser::Scope private :qualified_scope # Look up a variable. The simplest value search we do. + # This method is effectively deprecated - use self[] instead. def lookupvar(name, options = {}) - table = ephemeral?(name) ? @ephemeral.last : @symtable - # If the variable is qualified, then find the specified scope and look the variable up there instead. - if name =~ /^(.*)::(.+)$/ - begin - qualified_scope($1).lookupvar($2,options) - rescue RuntimeError => e - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" - :undefined - end - elsif ephemeral_include?(name) or table.include?(name) - # We can't use "if table[name]" here because the value might be false - if options[:dynamic] and self != compiler.topscope - location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' - Puppet.deprecation_warning "Dynamic lookup of $#{name}#{location} is deprecated. Support will be removed in Puppet 2.8. Use a fully-qualified variable name (e.g., $classname::variable) or parameterized classes." - end - table[name] - elsif parent - parent.lookupvar(name,options.merge(:dynamic => (dynamic || options[:dynamic]))) - else - :undefined - end + self[name, options] end # Return a hash containing our variables and their values, optionally (and @@ -312,6 +321,8 @@ class Puppet::Parser::Scope # Set a variable in the current scope. This will override settings # in scopes above, but will not allow variables in the current scope # to be reassigned. + # It's preferred that you use self[]= instead of this; only use this + # when you need to set options. def setvar(name,value, options = {}) table = options[:ephemeral] ? @ephemeral.last : @symtable if table.include?(name) @@ -329,7 +340,7 @@ class Puppet::Parser::Scope table[name] = value else # append case # lookup the value in the scope if it exists and insert the var - table[name] = undef_as('',lookupvar(name)) + table[name] = undef_as('',self[name]) # concatenate if string, append if array, nothing for other types case value when Array diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 27d75bf92..83d18cc3f 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -25,7 +25,7 @@ class Puppet::Parser::TemplateWrapper # Should return true if a variable is defined, false if it is not def has_variable?(name) - scope.lookupvar(name.to_s, :file => file, :line => script_line) != :undefined + scope[name.to_s, {:file => file, :line => script_line}] != :undefined end # Allow templates to access the defined classes @@ -56,7 +56,7 @@ class Puppet::Parser::TemplateWrapper # the missing_method definition here until we declare the syntax finally # dead. def method_missing(name, *args) - value = scope.lookupvar(name.to_s,:file => file,:line => script_line) + value = scope[name.to_s, {:file => file,:line => script_line}] if value != :undefined return value else diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index f8d820b77..7b251e8c7 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -225,22 +225,22 @@ class Puppet::Resource::Type param = param.to_sym fail Puppet::ParseError, "#{resource.ref} does not accept attribute #{param}" unless valid_parameter?(param) - exceptwrap { scope.setvar(param.to_s, value) } + exceptwrap { scope[param.to_s] = value } set[param] = true end if @type == :hostclass - scope.setvar("title", resource.title.to_s.downcase) unless set.include? :title - scope.setvar("name", resource.name.to_s.downcase ) unless set.include? :name + scope["title"] = resource.title.to_s.downcase unless set.include? :title + scope["name"] = resource.name.to_s.downcase unless set.include? :name else - scope.setvar("title", resource.title ) unless set.include? :title - scope.setvar("name", resource.name ) unless set.include? :name + scope["title"] = resource.title unless set.include? :title + scope["name"] = resource.name unless set.include? :name end - scope.setvar("module_name", module_name) if module_name and ! set.include? :module_name + scope["module_name"] = module_name if module_name and ! set.include? :module_name if caller_name = scope.parent_module_name and ! set.include?(:caller_module_name) - scope.setvar("caller_module_name", caller_name) + scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? # Verify that all required arguments are either present or @@ -253,7 +253,7 @@ class Puppet::Resource::Type fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default value = default.safeevaluate(scope) - scope.setvar(param.to_s, value) + scope[param.to_s] = value # Set it in the resource, too, so the value makes it to the client. resource[param] = value diff --git a/spec/unit/parser/ast/casestatement_spec.rb b/spec/unit/parser/ast/casestatement_spec.rb index e21190706..a76a9ae1f 100755 --- a/spec/unit/parser/ast/casestatement_spec.rb +++ b/spec/unit/parser/ast/casestatement_spec.rb @@ -154,7 +154,7 @@ describe Puppet::Parser::AST::CaseStatement do tests.each do |should, values| values.each do |value| @scope = Puppet::Parser::Scope.new - @scope.setvar("testparam", value) + @scope['testparam'] = value result = ast.evaluate(@scope) result.should == should diff --git a/spec/unit/parser/ast/leaf_spec.rb b/spec/unit/parser/ast/leaf_spec.rb index ff3fed5e9..36c790a41 100755 --- a/spec/unit/parser/ast/leaf_spec.rb +++ b/spec/unit/parser/ast/leaf_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' describe Puppet::Parser::AST::Leaf do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @value = stub 'value' @leaf = Puppet::Parser::AST::Leaf.new(:value => @value) end @@ -56,7 +56,7 @@ end describe Puppet::Parser::AST::Concat do describe "when evaluating" do before :each do - @scope = stub_everything 'scope' + @scope = Puppet::Parser::Scope.new end it "should interpolate variables and concatenate their values" do one = Puppet::Parser::AST::String.new(:value => "one") @@ -86,7 +86,7 @@ end describe Puppet::Parser::AST::Undef do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @undef = Puppet::Parser::AST::Undef.new(:value => :undef) end @@ -101,12 +101,12 @@ end describe Puppet::Parser::AST::HashOrArrayAccess do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new end describe "when evaluating" do it "should evaluate the variable part if necessary" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) + @scope["a"] = ["b"] variable = stub 'variable', :evaluate => "a" access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => variable, :key => 0 ) @@ -117,7 +117,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should evaluate the access key part if necessary" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["b"]) + @scope["a"] = ["b"] index = stub 'index', :evaluate => 0 access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => index ) @@ -128,7 +128,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an array member" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(["val1", "val2", "val3"]) + @scope["a"] = %w{val1 val2 val3} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => 1 ) @@ -136,7 +136,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an array member when index is a stringified number" do - @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns(["val1", "val2", "val3"]) + @scope["a"] = %w{val1 val2 val3} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "1" ) @@ -144,7 +144,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error when accessing an array with a key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns(["val1", "val2", "val3"]) + @scope["a"] = ["val1", "val2", "val3"] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) @@ -152,7 +152,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an hash value" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key1" => "val1", "key2" => "val2", "key3" => "val3" }) + @scope["a"] = { "key1" => "val1", "key2" => "val2", "key3" => "val3" } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) @@ -160,7 +160,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should be able to return an hash value with a numerical key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns({ "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" }) + @scope["a"] = { "key1" => "val1", "key2" => "val2", "45" => "45", "key3" => "val3" } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "45" ) @@ -168,7 +168,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error if the variable lookup didn't return an hash or an array" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns("I'm a string") + @scope["a"] = "I'm a string" access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) @@ -176,8 +176,6 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should raise an error if the variable wasn't in the scope" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns(nil) - access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key2" ) lambda { access.evaluate(@scope) }.should raise_error @@ -189,7 +187,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should work with recursive hash access" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => { "subkey" => "b" }}) + @scope["a"] = { "key" => { "subkey" => "b" }} access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => "subkey") @@ -198,7 +196,7 @@ describe Puppet::Parser::AST::HashOrArrayAccess do end it "should work with interleaved array and hash access" do - @scope.stubs(:lookupvar).with { |name,options| name == 'a'}.returns({ "key" => [ "a" , "b" ]}) + @scope['a'] = { "key" => [ "a" , "b" ]} access1 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") access2 = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => access1, :key => 1) @@ -210,16 +208,16 @@ describe Puppet::Parser::AST::HashOrArrayAccess do describe "when assigning" do it "should add a new key and value" do scope = Puppet::Parser::Scope.new - scope.setvar("a", { 'a' => 'b' }) + scope['a'] = { 'a' => 'b' } access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "b") access.assign(scope, "c" ) - scope.lookupvar("a").should be_include("b") + scope['a'].should be_include("b") end it "should raise an error when assigning an array element with a key" do - @scope.stubs(:lookupvar).with { |name,options| name == "a"}.returns([]) + @scope['a'] = [] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "get_me_the_second_element_please" ) @@ -228,16 +226,16 @@ describe Puppet::Parser::AST::HashOrArrayAccess do it "should be able to return an array member when index is a stringified number" do scope = Puppet::Parser::Scope.new - scope.setvar("a", []) + scope['a'] = [] access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "0" ) access.assign(scope, "val2") - scope.lookupvar("a").should == ["val2"] + scope['a'].should == ["val2"] end it "should raise an error when trying to overwrite an hash value" do - @scope.stubs(:lookupvar).with { |name,options| name == "a" }.returns({ "key" => [ "a" , "b" ]}) + @scope['a'] = { "key" => [ "a" , "b" ]} access = Puppet::Parser::AST::HashOrArrayAccess.new(:variable => "a", :key => "key") lambda { access.assign(@scope, "test") }.should raise_error @@ -247,7 +245,7 @@ end describe Puppet::Parser::AST::Regex do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new end describe "when initializing" do @@ -330,22 +328,21 @@ end describe Puppet::Parser::AST::Variable do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @var = Puppet::Parser::AST::Variable.new(:value => "myvar", :file => 'my.pp', :line => 222) end it "should lookup the variable in scope" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:myvalue) + @scope["myvar"] = :myvalue @var.safeevaluate(@scope).should == :myvalue end it "should pass the source location to lookupvar" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" and options[:file] == 'my.pp' and options[:line] == 222 }.returns(:myvalue) + @scope.setvar("myvar", :myvalue, :file => 'my.pp', :line => 222 ) @var.safeevaluate(@scope).should == :myvalue end it "should return undef if the variable wasn't set" do - @scope.expects(:lookupvar).with { |name,options| name == "myvar" }.returns(:undefined) @var.safeevaluate(@scope).should == :undef end @@ -359,7 +356,7 @@ end describe Puppet::Parser::AST::HostName do before :each do - @scope = stub 'scope' + @scope = Puppet::Parser::Scope.new @value = stub 'value', :=~ => false @value.stubs(:to_s).returns(@value) @value.stubs(:downcase).returns(@value) diff --git a/spec/unit/parser/ast/resource_reference_spec.rb b/spec/unit/parser/ast/resource_reference_spec.rb index 4d1c191cf..4e069cca0 100755 --- a/spec/unit/parser/ast/resource_reference_spec.rb +++ b/spec/unit/parser/ast/resource_reference_spec.rb @@ -36,7 +36,7 @@ describe Puppet::Parser::AST::ResourceReference do end it "should return an array of resources if given a variable containing an array of titles" do - @scope.setvar("my_files", ["foo", "bar"]) + @scope["my_files"] = ["foo", "bar"] titles = Puppet::Parser::AST::Variable.new(:value => "my_files") ref = newref('File', titles) ref.evaluate(@scope).should == [ diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index fcce9f6f4..9648e292c 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -177,8 +177,8 @@ describe Puppet::Parser::Compiler do @node.stubs(:parameters).returns(params) compile_stub(:set_node_parameters) @compiler.compile - @compiler.topscope.lookupvar("a").should == "b" - @compiler.topscope.lookupvar("c").should == "d" + @compiler.topscope['a'].should == "b" + @compiler.topscope['c'].should == "d" end it "should set the client and server versions on the catalog" do diff --git a/spec/unit/parser/functions/extlookup_spec.rb b/spec/unit/parser/functions/extlookup_spec.rb index f68daaf3f..30962e137 100755 --- a/spec/unit/parser/functions/extlookup_spec.rb +++ b/spec/unit/parser/functions/extlookup_spec.rb @@ -64,7 +64,7 @@ describe "the extlookup function" do describe "should look in $extlookup_datadir for data files listed by $extlookup_precedence" do before do - @scope.stubs(:lookupvar).with('::extlookup_datadir').returns("/tmp") + @scope.stubs(:[]).with('::extlookup_datadir').returns("/tmp") File.open("/tmp/one.csv","w"){|one| one.puts "key,value1" } File.open("/tmp/two.csv","w") do |two| two.puts "key,value2" @@ -73,21 +73,21 @@ describe "the extlookup function" do end it "when the key is in the first file" do - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) + @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key" ]) result.should == "value1" end it "when the key is in the second file" do - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns(["one","two"]) + @scope.stubs(:[]).with('::extlookup_precedence').returns(["one","two"]) result = @scope.function_extlookup([ "key2" ]) result.should == "value_two" end it "should not modify extlookup_precedence data" do variable = '%{fqdn}' - @scope.stubs(:lookupvar).with('::extlookup_precedence').returns([variable,"one"]) - @scope.stubs(:lookupvar).with('::fqdn').returns('myfqdn') + @scope.stubs(:[]).with('::extlookup_precedence').returns([variable,"one"]) + @scope.stubs(:[]).with('::fqdn').returns('myfqdn') result = @scope.function_extlookup([ "key" ]) variable.should == '%{fqdn}' end diff --git a/spec/unit/parser/functions/fqdn_rand_spec.rb b/spec/unit/parser/functions/fqdn_rand_spec.rb index 90fc0ef41..53c498453 100755 --- a/spec/unit/parser/functions/fqdn_rand_spec.rb +++ b/spec/unit/parser/functions/fqdn_rand_spec.rb @@ -8,6 +8,7 @@ describe "the fqdn_rand function" do before :each do @scope = Puppet::Parser::Scope.new + @scope[:fqdn] = "127.0.0.1" end it "should exist" do @@ -15,49 +16,40 @@ describe "the fqdn_rand function" do end it "should handle 0 arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([]) }.should_not raise_error(Puppet::ParseError) end it "should handle 1 argument'}" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3]) }.should_not raise_error(Puppet::ParseError) end (1..10).each { |n| it "should handle #{n} additional arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,1,2,3,4,5,6,7,8,9,10][0..n]) }.should_not raise_error(Puppet::ParseError) end it "should handle #{n} additional string arguments" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") lambda { @scope.function_fqdn_rand([3,%w{ 1 2 3 4 5 6 7 8 9 10}].flatten[0..n]) }.should_not raise_error(Puppet::ParseError) end } it "should return a value less than max" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") @scope.function_fqdn_rand([3]).should satisfy {|n| n.to_i < 3 } end it "should return the same values on subsequent invocations for the same host" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1").twice @scope.function_fqdn_rand([3,4]).should eql(@scope.function_fqdn_rand([3, 4])) end it "should return different sequences of value for different hosts" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.2") + @scope.expects(:[]).with("::fqdn").returns("127.0.0.2") val2 = @scope.function_fqdn_rand([10000000,4]) val1.should_not eql(val2) end it "should return different values for the same hosts with different seeds" do - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val1 = @scope.function_fqdn_rand([10000000,4]) - @scope.expects(:lookupvar).with("::fqdn").returns("127.0.0.1") val2 = @scope.function_fqdn_rand([10000000,42]) val1.should_not eql(val2) end diff --git a/spec/unit/parser/resource_spec.rb b/spec/unit/parser/resource_spec.rb index 1190716d7..8513b8997 100755 --- a/spec/unit/parser/resource_spec.rb +++ b/spec/unit/parser/resource_spec.rb @@ -271,7 +271,7 @@ describe Puppet::Parser::Resource do end it "should not copy relationship metaparams when not in metaparam compatibility mode" do - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns false @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -280,7 +280,7 @@ describe Puppet::Parser::Resource do end it "should copy relationship metaparams when in metaparam compatibility mode" do - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } @@ -290,7 +290,7 @@ describe Puppet::Parser::Resource do it "should stack relationship metaparams when in metaparam compatibility mode" do @resource.set_parameter("require", "foo") - @scope.setvar("require", "bar") + @scope['require'] = "bar" @resource.stubs(:metaparam_compatibility_mode?).returns true @resource.class.publicize_methods(:add_metaparams) { @resource.add_metaparams } diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 5308856ed..cd34df065 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -83,29 +83,34 @@ describe Puppet::Parser::Scope do end describe "when looking up a variable" do + it "should support :lookupvar and :setvar for backward compatibility" do + @scope.setvar("var", "yep") + @scope.lookupvar("var").should == "yep" + end + it "should return ':undefined' for unset variables" do - @scope.lookupvar("var").should == :undefined + @scope["var"].should == :undefined end it "should be able to look up values" do - @scope.setvar("var", "yep") - @scope.lookupvar("var").should == "yep" + @scope["var"] = "yep" + @scope["var"].should == "yep" end it "should be able to look up hashes" do - @scope.setvar("var", {"a" => "b"}) - @scope.lookupvar("var").should == {"a" => "b"} + @scope["var"] = {"a" => "b"} + @scope["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" + @topscope["var"] = "parentval" + @scope["var"].should == "parentval" end it "should prefer its own values to parent values" do - @topscope.setvar("var", "parentval") - @scope.setvar("var", "childval") - @scope.lookupvar("var").should == "childval" + @topscope["var"] = "parentval" + @scope["var"] = "childval" + @scope["var"].should == "childval" end describe "and the variable is qualified" do @@ -133,84 +138,84 @@ describe Puppet::Parser::Scope do it "should be able to look up explicitly fully qualified variables from main" do other_scope = create_class_scope("") - other_scope.setvar("othervar", "otherval") + other_scope["othervar"] = "otherval" - @scope.lookupvar("::othervar").should == "otherval" + @scope["::othervar"].should == "otherval" end it "should be able to look up explicitly fully qualified variables from other scopes" do other_scope = create_class_scope("other") - other_scope.setvar("var", "otherval") + other_scope["var"] = "otherval" - @scope.lookupvar("::other::var").should == "otherval" + @scope["::other::var"].should == "otherval" end it "should be able to look up deeply qualified variables" do other_scope = create_class_scope("other::deep::klass") - other_scope.setvar("var", "otherval") + other_scope["var"] = "otherval" - @scope.lookupvar("other::deep::klass::var").should == "otherval" + @scope["other::deep::klass::var"].should == "otherval" end it "should return ':undefined' for qualified variables that cannot be found in other classes" do other_scope = create_class_scope("other::deep::klass") - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should == :undefined end it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do klass = newclass("other::deep::klass") @scope.expects(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should == :undefined end it "should warn and return ':undefined' for qualified variables whose classes do not exist" do @scope.expects(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should == :undefined end it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do @scope.stubs(:warning) - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should == :undefined end it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do @scope.stubs(:warning) klass = newclass("other::deep::klass") - @scope.lookupvar("other::deep::klass::var").should == :undefined + @scope["other::deep::klass::var"].should == :undefined end end end - describe "when setvar is called with append=true" do - it "should raise error if the variable is already defined in this scope" do + describe "when variables are set with append=true" do + it "should raise an error if the variable is already defined in this scope" do @scope.setvar("var","1", :append => false) lambda { @scope.setvar("var","1", :append => true) }.should raise_error(Puppet::ParseError) end it "should lookup current variable value" do - @scope.expects(:lookupvar).with("var").returns("2") + @scope.expects(:[]).with("var").returns("2") @scope.setvar("var","1", :append => true) end it "should store the concatenated string '42'" do @topscope.setvar("var","4", :append => false) @scope.setvar("var","2", :append => true) - @scope.lookupvar("var").should == "42" + @scope["var"].should == "42" end it "should store the concatenated array [4,2]" do @topscope.setvar("var",[4], :append => false) @scope.setvar("var",[2], :append => true) - @scope.lookupvar("var").should == [4,2] + @scope["var"].should == [4,2] end 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"} + @scope["var"].should == {"a" => "b", "c" => "d"} end it "should raise an error when appending a hash with something other than another hash" do @@ -285,7 +290,7 @@ describe Puppet::Parser::Scope do it "should store the variable value" do @scope.setvar("1", :value, :ephemeral => true) - @scope.lookupvar("1").should == :value + @scope["1"].should == :value end it "should remove the variable value when unset_ephemeral_var is called" do @@ -294,17 +299,17 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope.lookupvar("1").should == :undefined + @scope["1"].should == :undefined end it "should not remove classic variables when unset_ephemeral_var is called" do - @scope.setvar("myvar", :value1) + @scope['myvar'] = :value1 @scope.setvar("1", :value2, :ephemeral => true) @scope.stubs(:parent).returns(nil) @scope.unset_ephemeral_var - @scope.lookupvar("myvar").should == :value1 + @scope["myvar"].should == :value1 end it "should raise an error when setting it again" do @@ -325,7 +330,7 @@ describe Puppet::Parser::Scope do @scope.setvar("0", :earliest, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :latest, :ephemeral => true) - @scope.lookupvar("0").should == :latest + @scope["0"].should == :latest end it "should be able to report the current level" do @@ -356,7 +361,7 @@ describe Puppet::Parser::Scope do @scope.setvar("1", :value1, :ephemeral => true) @scope.new_ephemeral @scope.setvar("0", :value2, :ephemeral => true) - @scope.lookupvar("1").should == :value1 + @scope["1"].should == :value1 end describe "when calling unset_ephemeral_var without a level" do @@ -367,7 +372,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope.lookupvar("1").should == :undefined + @scope["1"].should == :undefined end end @@ -381,7 +386,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var(2) - @scope.lookupvar("1").should == :value2 + @scope["1"].should == :value2 end end end @@ -421,22 +426,22 @@ describe Puppet::Parser::Scope do describe "when unsetting variables" do it "should be able to unset normal variables" do - @scope.setvar("foo", "bar") + @scope["foo"] = "bar" @scope.unsetvar("foo") - @scope.lookupvar("foo").should == :undefined + @scope["foo"].should == :undefined end it "should be able to unset ephemeral variables" do @scope.setvar("0", "bar", :ephemeral => true) @scope.unsetvar("0") - @scope.lookupvar("0").should == :undefined + @scope["0"].should == :undefined end it "should not unset ephemeral variables in previous ephemeral scope" do @scope.setvar("0", "bar", :ephemeral => true) @scope.new_ephemeral @scope.unsetvar("0") - @scope.lookupvar("0").should == "bar" + @scope["0"].should == "bar" end end diff --git a/spec/unit/parser/templatewrapper_spec.rb b/spec/unit/parser/templatewrapper_spec.rb index 600293bbf..6080346fb 100755 --- a/spec/unit/parser/templatewrapper_spec.rb +++ b/spec/unit/parser/templatewrapper_spec.rb @@ -72,25 +72,23 @@ describe Puppet::Parser::TemplateWrapper do end it "should return the contents of a variable if called via method_missing" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") + @scope["chicken"] = "is good" tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.chicken.should eql("is good") end it "should throw an exception if a variable is called via method_missing and it does not exist" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) lambda { tw.chicken }.should raise_error(Puppet::ParseError) end it "should allow you to check whether a variable is defined with has_variable?" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns("is good") + @scope["chicken"] = "is good" tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(true) end it "should allow you to check whether a variable is not defined with has_variable?" do - @scope.expects(:lookupvar).with { |name,options| name == "chicken"}.returns(:undefined) tw = Puppet::Parser::TemplateWrapper.new(@scope) tw.has_variable?("chicken").should eql(false) end diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index 352f767e4..f29c93931 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -249,7 +249,7 @@ describe Puppet::Resource::Type do var = Puppet::Parser::AST::Variable.new({'value' => variable}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar('foo').should == 'bar' + @scope['foo'].should == 'bar' end end @@ -262,7 +262,7 @@ describe Puppet::Resource::Type do var = Puppet::Parser::AST::Variable.new({'value' => 'name'}) @type.set_arguments :foo => var @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar('foo').should == 'foobar' + @scope['foo'].should == 'foobar' end it "should set each of the resource's parameters as variables in the scope" do @@ -272,8 +272,8 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "bar" - @scope.lookupvar("boo").should == "baz" + @scope['foo'].should == "bar" + @scope['boo'].should == "baz" end it "should set the variables as strings" do @@ -282,7 +282,7 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "bar" + @scope['foo'].should == "bar" end it "should fail if any of the resource's parameters are not valid attributes" do @@ -295,7 +295,7 @@ describe Puppet::Resource::Type do it "should evaluate and set its default values as variables for parameters not provided by the resource" do @type.set_arguments :foo => stub("value", :safeevaluate => "something") @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("foo").should == "something" + @scope['foo'].should == "something" end it "should set all default values as parameters in the resource" do @@ -316,13 +316,13 @@ describe Puppet::Resource::Type do it "should set the resource's title as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("title").should == "bar" + @scope['title'].should == "bar" end it "should set the resource's name as a variable if not otherwise provided" do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("name").should == "bar" + @scope['name'].should == "bar" end it "should set its module name in the scope if available" do @@ -330,7 +330,7 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("module_name").should == "mymod" + @scope["module_name"].should == "mymod" end it "should set its caller module name in the scope if available" do @@ -338,7 +338,7 @@ describe Puppet::Resource::Type do @type.set_resource_parameters(@resource, @scope) - @scope.lookupvar("caller_module_name").should == "mycaller" + @scope["caller_module_name"].should == "mycaller" end end diff --git a/test/language/ast/variable.rb b/test/language/ast/variable.rb deleted file mode 100755 index 968d1b7c3..000000000 --- a/test/language/ast/variable.rb +++ /dev/null @@ -1,29 +0,0 @@ -#!/usr/bin/env ruby -# -# Created by Luke A. Kanies on 2007-0419. -# Copyright (c) 2006. All rights reserved. - -require File.expand_path(File.dirname(__FILE__) + '/../../lib/puppettest') - -require 'puppettest' -require 'puppettest/parsertesting' - -class TestVariable < Test::Unit::TestCase - include PuppetTest - include PuppetTest::ParserTesting - AST = Puppet::Parser::AST - - def setup - super - @scope = mkscope - @name = "myvar" - @var = AST::Variable.new(:value => @name) - end - - def test_evaluate - assert_equal(:undef, @var.evaluate(@scope), "did not return :undef on unset var") - @scope.setvar(@name, "something") - assert_equal("something", @var.evaluate(@scope), "incorrect variable value") - end -end - diff --git a/test/language/functions.rb b/test/language/functions.rb index 84b1b3861..44d86f0f9 100755 --- a/test/language/functions.rb +++ b/test/language/functions.rb @@ -148,17 +148,17 @@ class TestLangFunctions < Test::Unit::TestCase # Test that our use of an undefined instance variable does not throw # an exception, but only safely continues. - scope.setvar("one", "One") + scope['one'] = "One" assert_nothing_raised do ast.evaluate(scope) end # Ensure that we got the output we expected from that evaluation. - assert_equal("template One\ntemplate \n", scope.lookupvar("output"), "Undefined template variables do not raise exceptions") + assert_equal("template One\ntemplate \n", scope['output'], "Undefined template variables do not raise exceptions") # Now, fill in the last variable and make sure the whole thing # evaluates correctly. - scope.setvar("two", "Two") + scope['two'] = "Two" scope.unsetvar("output") assert_nothing_raised do ast.evaluate(scope) @@ -166,7 +166,7 @@ class TestLangFunctions < Test::Unit::TestCase assert_equal( - "template One\ntemplate Two\n", scope.lookupvar("output"), + "template One\ntemplate Two\n", scope['output'], "Templates were not handled correctly") end @@ -199,7 +199,7 @@ class TestLangFunctions < Test::Unit::TestCase ast.evaluate(scope) end - scope.setvar("yay", "this is yay") + scope['yay'] = "this is yay" assert_nothing_raised do ast.evaluate(scope) @@ -207,7 +207,7 @@ class TestLangFunctions < Test::Unit::TestCase assert_equal( - "template this is yay\n", scope.lookupvar("output"), + "template this is yay\n", scope['output'], "Templates were not handled correctly") @@ -243,14 +243,14 @@ class TestLangFunctions < Test::Unit::TestCase end # Verify that we evaluate and return their value correctly. - scope.setvar("deprecated", "deprecated value") + scope["deprecated"] = "deprecated value" assert_nothing_raised do ast.evaluate(scope) end assert_equal( - "template deprecated value\n", scope.lookupvar("output"), + "template deprecated value\n", scope['output'], "Deprecated template variables were not handled correctly") end @@ -305,7 +305,7 @@ class TestLangFunctions < Test::Unit::TestCase ast = varobj("output", func) scope = mkscope - scope.setvar("myvar", "this is yayness") + scope['myvar'] = "this is yayness" assert_raise(Puppet::ParseError) do ast.evaluate(scope) end @@ -381,15 +381,15 @@ class TestLangFunctions < Test::Unit::TestCase false => "false", }.each do |string, value| scope = mkscope - scope.setvar("yayness", string) - assert_equal(string, scope.lookupvar("yayness")) + scope['yayness'] = string + assert_equal(scope['yayness'], string, "did not correctly evaluate '#{string}'") assert_nothing_raised("An empty string was not a valid variable value") do ast.evaluate(scope) end assert_equal( - "template #{value}\n", scope.lookupvar("output"), + "template #{value}\n", scope['output'], "#{string.inspect} did not get evaluated correctly") end end diff --git a/test/language/scope.rb b/test/language/scope.rb index ccc359651..57824d887 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -40,24 +40,24 @@ class TestScope < Test::Unit::TestCase scopes = {:top => topscope, :mid => midscope, :bot => botscope} # Set a variable in the top and make sure all three can get it - topscope.setvar("first", "topval") + topscope['first'] = 'topval' scopes.each do |name, scope| - assert_equal("topval", scope.lookupvar("first"), "Could not find var in #{name}") + assert_equal("topval", scope['first'], "Could not find var in #{name}") end # Now set a var in the midscope and make sure the mid and bottom can see it but not the top - midscope.setvar("second", "midval") - assert_equal(:undefined, scopes[:top].lookupvar("second"), "Found child var in top scope") + midscope['second'] = "midval" + assert_equal(:undefined, scopes[:top]['second'], "Found child var in top scope") [:mid, :bot].each do |name| - assert_equal("midval", scopes[name].lookupvar("second"), "Could not find var in #{name}") + assert_equal("midval", scopes[name]['second'], "Could not find var in #{name}") end # And set something in the bottom, and make sure we only find it there. - botscope.setvar("third", "botval") + botscope['third'] = "botval" [:top, :mid].each do |name| - assert_equal(:undefined, scopes[name].lookupvar("third"), "Found child var in top scope") + assert_equal(:undefined, scopes[name]['third'], "Found child var in top scope") end - assert_equal("botval", scopes[:bot].lookupvar("third"), "Could not find var in bottom scope") + assert_equal("botval", scopes[:bot]['third'], "Could not find var in bottom scope") # Test that the scopes convert to hash structures correctly. @@ -84,7 +84,7 @@ class TestScope < Test::Unit::TestCase # Finally, check the ability to shadow symbols by adding a shadow to # bottomscope, then checking that we see the right stuff. - botscope.setvar("first", "shadowval") + botscope['first'] = "shadowval" assert_equal( {"third" => "botval", "first" => "shadowval"}, @@ -105,16 +105,16 @@ class TestScope < Test::Unit::TestCase sub = mkscope(:parent => top) assert_nothing_raised { - top.setvar("test","value") + top['test'] = "value" } assert_raise(Puppet::ParseError) { - top.setvar("test","other") + top['test'] = 'other' } assert_nothing_raised { - sub.setvar("test","later") + top['other'] = 'later' } assert_raise(Puppet::ParseError) { - top.setvar("test","yeehaw") + top['other'] = 'yeehaw' } end @@ -259,8 +259,8 @@ Host <<||>>" def test_lookupvar_with_undef scope = mkscope - scope.setvar("testing", :undef) - assert_equal(:undef, scope.lookupvar("testing"), "undef was not returned as :undef") + scope['testing'] = :undef + assert_equal(:undef, scope['testing'], "undef was not returned as :undef") end end -- cgit From 06e86e40bbb173fa24a7d1c2ecf4e54e1748de67 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 18:55:10 -0700 Subject: Adding default environment to Scope We were previously not defaulting to an environment, which is silly given that there's always a default. It just made setup code harder. We now default to the default environment. This makes further testing involving scopes much easier. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 8 ++------ spec/unit/parser/scope_spec.rb | 24 ++++++++++++------------ 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 67dcb1cb0..711655e44 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -82,10 +82,6 @@ class Puppet::Parser::Scope compiler.catalog end - def environment - compiler.environment - end - # Proxy accessors def host @compiler.node.name @@ -130,7 +126,7 @@ class Puppet::Parser::Scope # Remove this when rebasing def environment - compiler ? compiler.environment : nil + compiler ? compiler.environment : Puppet::Node::Environment.new end def find_hostclass(name) @@ -454,6 +450,6 @@ class Puppet::Parser::Scope def extend_with_functions_module extend Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.root) - extend Puppet::Parser::Functions.environment_module(environment) + extend Puppet::Parser::Functions.environment_module(environment) if environment != Puppet::Node::Environment.root end end diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index cd34df065..e08180020 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -47,6 +47,10 @@ describe Puppet::Parser::Scope do scope = Puppet::Parser::Scope.new :compiler => compiler scope.environment.should equal(env) end + + it "should use the default environment if none is available" do + Puppet::Parser::Scope.new.environment.should equal(Puppet::Node::Environment.new) + end it "should use the resource type collection helper to find its known resource types" do Puppet::Parser::Scope.ancestors.should include(Puppet::Resource::TypeCollectionHelper) @@ -55,22 +59,18 @@ describe Puppet::Parser::Scope do describe "when initializing" do it "should extend itself with its environment's Functions module as well as the default" do env = Puppet::Node::Environment.new("myenv") + root = Puppet::Node::Environment.root compiler = stub 'compiler', :environment => env - mod = Module.new - root_mod = Module.new - Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns root_mod - Puppet::Parser::Functions.expects(:environment_module).with(env).returns mod - Puppet::Parser::Scope.new(:compiler => compiler).singleton_class.ancestors.should be_include(mod) + scope = Puppet::Parser::Scope.new(:compiler => compiler) + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(env)) + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root)) end - it "should extend itself with the default Functions module if it has no environment" do - mod = Module.new - Puppet::Parser::Functions.expects(:environment_module).with(Puppet::Node::Environment.root).returns(mod) - - Puppet::Parser::Functions.expects(:environment_module).with(nil).returns mod - - Puppet::Parser::Scope.new.singleton_class.ancestors.should be_include(mod) + it "should extend itself with the default Functions module if its environment is the default" do + root = Puppet::Node::Environment.root + scope = Puppet::Parser::Scope.new + scope.singleton_class.ancestors.should be_include(Puppet::Parser::Functions.environment_module(root)) end it "should remember if it is dynamic" do -- cgit From 9d608ea176224f38c6af349883065d9363dd1bb1 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Wed, 8 Jun 2011 22:36:25 -0700 Subject: Resource type defaults cleanup This is again done to make support for hiera easier. The way we were handling lookup of resource defaults was over-complicated. This does a decent bit of cleanup overall, but primarily focused on resource type defaults and how they get set during compilation. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/compiler.rb | 10 ++++--- lib/puppet/resource.rb | 33 +++++++++++++++++++++ lib/puppet/resource/type.rb | 34 ++++++++++------------ spec/unit/parser/compiler_spec.rb | 6 ++-- spec/unit/resource/type_spec.rb | 38 ++++++++++++------------ spec/unit/resource_spec.rb | 61 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 136 insertions(+), 46 deletions(-) diff --git a/lib/puppet/parser/compiler.rb b/lib/puppet/parser/compiler.rb index f43a31285..06cd80a1e 100644 --- a/lib/puppet/parser/compiler.rb +++ b/lib/puppet/parser/compiler.rb @@ -139,19 +139,21 @@ class Puppet::Parser::Compiler # evaluated later in the process. def evaluate_classes(classes, scope, lazy_evaluate = true) raise Puppet::DevError, "No source for scope passed to evaluate_classes" unless scope.source - param_classes = nil + class_parameters = nil # if we are a param class, save the classes hash # and transform classes to be the keys if classes.class == Hash - param_classes = classes + class_parameters = classes classes = classes.keys end classes.each do |name| # If we can find the class, then make a resource that will evaluate it. if klass = scope.find_hostclass(name) - if param_classes - resource = klass.ensure_in_catalog(scope, param_classes[name] || {}) + # If parameters are passed, then attempt to create a duplicate resource + # so the appropriate error is thrown. + if class_parameters + resource = klass.ensure_in_catalog(scope, class_parameters[name] || {}) else next if scope.class_scope(klass) resource = klass.ensure_in_catalog(scope) diff --git a/lib/puppet/resource.rb b/lib/puppet/resource.rb index 59e387d00..217eb11c8 100644 --- a/lib/puppet/resource.rb +++ b/lib/puppet/resource.rb @@ -343,6 +343,26 @@ class Puppet::Resource [ type, title ].join('/') end + def set_default_parameters(scope) + return [] unless resource_type and resource_type.respond_to?(:arguments) + + result = [] + + resource_type.arguments.each do |param, default| + param = param.to_sym + next if parameters.include?(param) + unless is_a?(Puppet::Parser::Resource) + fail Puppet::DevError, "Cannot evaluate default parameters for #{self} - not a parser resource" + end + + next if default.nil? + + self[param] = default.safeevaluate(scope) + result << param + end + result + end + def to_resource self end @@ -351,6 +371,19 @@ class Puppet::Resource resource_type.valid_parameter?(name) end + # Verify that all required arguments are either present or + # have been provided with defaults. + # Must be called after 'set_default_parameters'. We can't join the methods + # because Type#set_parameters needs specifically ordered behavior. + def validate_complete + return unless resource_type and resource_type.respond_to?(:arguments) + + resource_type.arguments.each do |param, default| + param = param.to_sym + fail Puppet::ParseError, "Must pass #{param} to #{self}" unless parameters.include?(param) + end + end + def validate_parameter(name) raise ArgumentError, "Invalid parameter #{name}" unless valid_parameter?(name) end diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index 7b251e8c7..ca6e8b53b 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -158,11 +158,7 @@ class Puppet::Resource::Type return resource end resource = Puppet::Parser::Resource.new(resource_type, name, :scope => scope, :source => self) - if parameters - parameters.each do |k,v| - resource.set_parameter(k,v) - end - end + assign_parameter_values(parameters, resource) instantiate_resource(scope, resource) scope.compiler.add_resource(scope, resource) resource @@ -188,6 +184,14 @@ class Puppet::Resource::Type @name.is_a?(Regexp) end + def assign_parameter_values(parameters, resource) + return unless parameters + scope = resource.scope || {} + arguments.merge(parameters).each do |name, default| + resource.set_parameter name, default + end + end + # MQR TODO: # # The change(s) introduced by the fix for #4270 are mostly silly & should be @@ -243,22 +247,14 @@ class Puppet::Resource::Type scope["caller_module_name"] = caller_name end scope.class_set(self.name,scope) if hostclass? or node? - # Verify that all required arguments are either present or - # have been provided with defaults. - arguments.each do |param, default| - param = param.to_sym - next if set.include?(param) - - # Even if 'default' is a false value, it's an AST value, so this works fine - fail Puppet::ParseError, "Must pass #{param} to #{resource.ref}" unless default - value = default.safeevaluate(scope) - scope[param.to_s] = value - - # Set it in the resource, too, so the value makes it to the client. - resource[param] = value - end + # Evaluate the default parameters, now that all other variables are set + default_params = resource.set_default_parameters(scope) + default_params.each { |param| scope[param.to_s] = resource[param] } + # This has to come after the above parameters so that default values + # can use their values + resource.validate_complete end # Check whether a given argument is valid. diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index 9648e292c..06f8044e3 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -614,15 +614,15 @@ describe Puppet::Parser::Compiler do @node.classes = klass klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) @compiler.topscope.known_resource_types.add klass - lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Must pass 2 to Class[Foo]" + lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Must pass 2 to Class[Foo]") end it "should fail if invalid parameters are passed" do klass = {'foo'=>{'3'=>'one'}} @node.classes = klass - klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {'1' => nil, '2' => nil}) + klass = Puppet::Resource::Type.new(:hostclass, 'foo', :arguments => {}) @compiler.topscope.known_resource_types.add klass - lambda { @compiler.compile }.should raise_error Puppet::ParseError, "Invalid parameter 3" + lambda { @compiler.compile }.should raise_error(Puppet::ParseError, "Invalid parameter 3") end it "should ensure class is in catalog without params" do diff --git a/spec/unit/resource/type_spec.rb b/spec/unit/resource/type_spec.rb index f29c93931..416fbac42 100755 --- a/spec/unit/resource/type_spec.rb +++ b/spec/unit/resource/type_spec.rb @@ -238,9 +238,10 @@ describe Puppet::Resource::Type do describe "when setting its parameters in the scope" do before do - @scope = Puppet::Parser::Scope.new(:compiler => stub("compiler", :environment => Puppet::Node::Environment.new), :source => stub("source")) + @scope = Puppet::Parser::Scope.new @resource = Puppet::Parser::Resource.new(:foo, "bar", :scope => @scope) - @type = Puppet::Resource::Type.new(:hostclass, "foo") + @type = Puppet::Resource::Type.new(:definition, "foo") + @resource.environment.known_resource_types.add @type end ['module_name', 'name', 'title'].each do |variable| @@ -256,7 +257,7 @@ describe Puppet::Resource::Type do # this test is to clarify a crazy edge case # if you specify these special names as params, the resource # will override the special variables - it "resource should override defaults" do + it "should allow the resource to override defaults" do @type.set_arguments :name => nil @resource[:name] = 'foobar' var = Puppet::Parser::AST::Variable.new({'value' => 'name'}) @@ -293,13 +294,13 @@ describe Puppet::Resource::Type do end it "should evaluate and set its default values as variables for parameters not provided by the resource" do - @type.set_arguments :foo => stub("value", :safeevaluate => "something") + @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something") @type.set_resource_parameters(@resource, @scope) @scope['foo'].should == "something" end it "should set all default values as parameters in the resource" do - @type.set_arguments :foo => stub("value", :safeevaluate => "something") + @type.set_arguments :foo => Puppet::Parser::AST::String.new(:value => "something") @type.set_resource_parameters(@resource, @scope) @@ -308,7 +309,6 @@ describe Puppet::Resource::Type do it "should fail if the resource does not provide a value for a required argument" do @type.set_arguments :foo => nil - @resource.expects(:to_hash).returns({}) lambda { @type.set_resource_parameters(@resource, @scope) }.should raise_error(Puppet::ParseError) end @@ -344,15 +344,14 @@ describe Puppet::Resource::Type do describe "when describing and managing parent classes" do before do - @code = Puppet::Resource::TypeCollection.new("env") + @krt = Puppet::Node::Environment.new.known_resource_types @parent = Puppet::Resource::Type.new(:hostclass, "bar") - @code.add @parent + @krt.add @parent @child = Puppet::Resource::Type.new(:hostclass, "foo", :parent => "bar") - @code.add @child + @krt.add @child - @env = stub "environment", :known_resource_types => @code - @scope = stub "scope", :environment => @env, :namespaces => [""] + @scope = Puppet::Parser::Scope.new end it "should be able to define a parent" do @@ -365,16 +364,16 @@ describe Puppet::Resource::Type do it "should be able to find parent nodes" do parent = Puppet::Resource::Type.new(:node, "bar") - @code.add parent + @krt.add parent child = Puppet::Resource::Type.new(:node, "foo", :parent => "bar") - @code.add child + @krt.add child child.parent_type(@scope).should equal(parent) end it "should cache a reference to the parent type" do - @code.stubs(:hostclass).with("foo::bar").returns nil - @code.expects(:hostclass).with("bar").once.returns @parent + @krt.stubs(:hostclass).with("foo::bar").returns nil + @krt.expects(:hostclass).with("bar").once.returns @parent @child.parent_type(@scope) @child.parent_type end @@ -386,7 +385,7 @@ describe Puppet::Resource::Type do it "should be considered the child of a parent's parent" do @grandchild = Puppet::Resource::Type.new(:hostclass, "baz", :parent => "foo") - @code.add @grandchild + @krt.add @grandchild @child.parent_type(@scope) @grandchild.parent_type(@scope) @@ -396,7 +395,7 @@ describe Puppet::Resource::Type do it "should correctly state when it is not another type's child" do @notchild = Puppet::Resource::Type.new(:hostclass, "baz") - @code.add @notchild + @krt.add @notchild @notchild.should_not be_child_of(@parent) end @@ -406,14 +405,13 @@ describe Puppet::Resource::Type do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("mynode")) @scope = Puppet::Parser::Scope.new :compiler => @compiler - @resource = Puppet::Parser::Resource.new(:foo, "yay", :scope => @scope) + @resource = Puppet::Parser::Resource.new(:class, "foo", :scope => @scope) # This is so the internal resource lookup works, yo. @compiler.catalog.add_resource @resource - @known_resource_types = stub 'known_resource_types' - @resource.stubs(:known_resource_types).returns @known_resource_types @type = Puppet::Resource::Type.new(:hostclass, "foo") + @resource.environment.known_resource_types.add @type end it "should add hostclass names to the classes list" do diff --git a/spec/unit/resource_spec.rb b/spec/unit/resource_spec.rb index 5c8e8dcf9..0485bc7aa 100755 --- a/spec/unit/resource_spec.rb +++ b/spec/unit/resource_spec.rb @@ -272,6 +272,67 @@ describe Puppet::Resource do Puppet::Resource.new("file", "/foo").should_not == Puppet::Resource.new("file", "/f") end + describe "when setting default parameters" do + before do + @scope = Puppet::Parser::Scope.new + end + + it "should fail when asked to set default values and it is not a parser resource" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "default")}) + ) + resource = Puppet::Resource.new("default_param", "name") + lambda { resource.set_default_parameters(@scope) }.should raise_error(Puppet::DevError) + end + + it "should evaluate and set any default values when no value is provided" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) + resource.set_default_parameters(@scope) + resource["a"].should == "a_default_value" + end + + it "should skip attributes with no default value" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "no_default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("no_default_param", "name", :scope => Puppet::Parser::Scope.new) + lambda { resource.set_default_parameters(@scope) }.should_not raise_error + end + + it "should return the list of default parameters set" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "default_param", :arguments => {"a" => Puppet::Parser::AST::String.new(:value => "a_default_value")}) + ) + resource = Puppet::Parser::Resource.new("default_param", "name", :scope => Puppet::Parser::Scope.new) + resource.set_default_parameters(@scope).should == [:a] + end + end + + describe "when validating all required parameters are present" do + it "should be able to validate that all required parameters are present" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "required_param", :arguments => {"a" => nil}) + ) + lambda { Puppet::Resource.new("required_param", "name").validate_complete }.should raise_error(Puppet::ParseError) + end + + it "should not fail when all required parameters are present" do + Puppet::Node::Environment.new.known_resource_types.add( + Puppet::Resource::Type.new(:definition, "no_required_param") + ) + resource = Puppet::Resource.new("no_required_param", "name") + resource["a"] = "meh" + lambda { resource.validate_complete }.should_not raise_error + end + + it "should not validate against builtin types" do + lambda { Puppet::Resource.new("file", "/bar").validate_complete }.should_not raise_error + end + end + describe "when referring to a resource with name canonicalization" do it "should canonicalize its own name" do res = Puppet::Resource.new("file", "/path/") -- cgit From b3c155430965280ab59b1dd70c020c6da3396fc9 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 16 Jun 2011 18:37:04 -0700 Subject: Adding Scope#include? method This is primarily for Hiera/DataLibrary support, but is a decent idea regardless. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 4 ++++ spec/unit/parser/scope_spec.rb | 9 +++++++++ 2 files changed, 13 insertions(+) diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 711655e44..7b75ca86b 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -87,6 +87,10 @@ class Puppet::Parser::Scope @compiler.node.name end + def include?(name) + self[name] != :undefined + end + # Is the value true? This allows us to control the definition of truth # in one place. def self.true?(value) diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index e08180020..887890ead 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -113,6 +113,15 @@ describe Puppet::Parser::Scope do @scope["var"].should == "childval" end + it "should be able to detect when variables are set" do + @scope["var"] = "childval" + @scope.should be_include("var") + end + + it "should be able to detect when variables are not set" do + @scope.should_not be_include("var") + end + describe "and the variable is qualified" do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode")) -- cgit From 3b2a24602d11d4ca2f7e761fb831f126ecf2de62 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Thu, 16 Jun 2011 18:41:19 -0700 Subject: Adding Scope#each method The capability was already there via to_hash, and Enumerable was already included, but this method was missing. Given the kind of hacking RI is doing, this seemed appropriate. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/scope.rb | 4 ++++ spec/unit/parser/scope_spec.rb | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 7b75ca86b..3a87f964b 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -82,6 +82,10 @@ class Puppet::Parser::Scope compiler.catalog end + def each + to_hash.each { |name, value| yield(name, value) } + end + # Proxy accessors def host @compiler.node.name diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 887890ead..78feaf08b 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -122,6 +122,18 @@ describe Puppet::Parser::Scope do @scope.should_not be_include("var") end + it "should support iteration over its variables" do + @scope["one"] = "two" + @scope["three"] = "four" + hash = {} + @scope.each { |name, value| hash[name] = value } + hash.should == {"one" => "two", "three" => "four" } + end + + it "should include Enumerable" do + @scope.singleton_class.ancestors.should be_include(Enumerable) + end + describe "and the variable is qualified" do before do @compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("foonode")) -- cgit From 784d54c20bbc6272d408de1aee831a883298c5cd Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 11:57:53 -0700 Subject: Improving an error message Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/resource.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 305ba81e8..6b072bd90 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -173,7 +173,7 @@ class Puppet::Parser::Resource < Puppet::Resource :name => param, :value => value, :source => self.source ) elsif ! param.is_a?(Puppet::Parser::Resource::Param) - raise ArgumentError, "Must pass a parameter or all necessary values" + raise ArgumentError, "Received incomplete information - no value provided for parameter #{param}" end tag(*param.value) if param.name == :tag -- cgit From ef7e25b468c70537d172129b70f096364ac3e6d5 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 11:58:26 -0700 Subject: Cleanup up a small amount of whitespace Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- spec/unit/parser/scope_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 78feaf08b..00212a2d5 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -47,7 +47,7 @@ describe Puppet::Parser::Scope do scope = Puppet::Parser::Scope.new :compiler => compiler scope.environment.should equal(env) end - + it "should use the default environment if none is available" do Puppet::Parser::Scope.new.environment.should equal(Puppet::Node::Environment.new) end -- cgit From 79c8023d45d8c86f0f21cf6c4c27e0e5389c7528 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 11:58:34 -0700 Subject: Fixing default parameter value assignment The method for adding class resources to the catalog was only working in cases where the default values weren't AST objects. This commit fixes this, along with the tests that were failing and drew out the problem. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/resource/type.rb | 8 +++-- spec/unit/parser/compiler_spec.rb | 76 ++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/lib/puppet/resource/type.rb b/lib/puppet/resource/type.rb index ca6e8b53b..8b154ce95 100644 --- a/lib/puppet/resource/type.rb +++ b/lib/puppet/resource/type.rb @@ -187,8 +187,12 @@ class Puppet::Resource::Type def assign_parameter_values(parameters, resource) return unless parameters scope = resource.scope || {} - arguments.merge(parameters).each do |name, default| - resource.set_parameter name, default + + # It'd be nice to assign default parameter values here, + # but we can't because they often rely on local variables + # created during set_resource_parameters. + parameters.each do |name, value| + resource.set_parameter name, value end end diff --git a/spec/unit/parser/compiler_spec.rb b/spec/unit/parser/compiler_spec.rb index 06f8044e3..e6f481114 100755 --- a/spec/unit/parser/compiler_spec.rb +++ b/spec/unit/parser/compiler_spec.rb @@ -571,42 +571,62 @@ describe Puppet::Parser::Compiler do @compiler.evaluate_classes(%w{myclass}, @scope) end - it "should ensure each node class hash is in catalog and have appropriate parameters", :'fails_on_ruby_1.9.2' => true do - klasses = {'foo'=>{'1'=>'one'}, 'bar::foo'=>{'2'=>'two'}, 'bar'=>{'1'=> [1,2,3], '2'=>{'foo'=>'bar'}}} - @node.classes = klasses - ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') - klasses.each do |name, params| - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + describe "and the classes are specified as a hash with parameters" do + before do + @node.classes = {} + @ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') + end + + # Define the given class with default parameters + def define_class(name, parameters) + @node.classes[name] = parameters + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => @ast_obj, '2' => @ast_obj}) @compiler.topscope.known_resource_types.add klass end - catalog = @compiler.compile - catalog.classes.should =~ ['foo', 'bar::foo', 'settings', 'bar'] - r1 = catalog.resources.detect {|r| r.title == 'Foo' } - r1.to_hash.should == {:'1' => 'one', :'2' => 'foo'} - r1.tags. should =~ ['class', 'foo'] + def compile + @catalog = @compiler.compile + end - r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } - r2.to_hash.should == {:'1' => 'foo', :'2' => 'two'} - r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + it "should record which classes are evaluated" do + classes = {'foo'=>{}, 'bar::foo'=>{}, 'bar'=>{}} + classes.each { |c, params| define_class(c, params) } + compile() + classes.each { |name, p| @catalog.classes.should include(name) } + end - r2 = catalog.resources.detect {|r| r.title == 'Bar' } - r2.to_hash.should == {:'1' => [1,2,3], :'2' => {'foo'=>'bar'}} - r2.tags.should =~ ['class', 'bar'] - end + it "should provide default values for parameters that have no values specified" do + define_class('foo', {}) + compile() + @catalog.resource(:class, 'foo')['1'].should == "foo" + end - it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do - klasses = ['bar::foo'] - @node.classes = klasses - ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') - klasses.each do |name| - klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) - @compiler.topscope.known_resource_types.add klass + it "should use any provided values" do + define_class('foo', {'1' => 'real_value'}) + compile() + @catalog.resource(:class, 'foo')['1'].should == "real_value" end - catalog = @compiler.compile - r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } - r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + it "should support providing some but not all values" do + define_class('foo', {'1' => 'real_value'}) + compile() + @catalog.resource(:class, 'Foo')['1'].should == "real_value" + @catalog.resource(:class, 'Foo')['2'].should == "foo" + end + + it "should ensure each node class is in catalog and has appropriate tags", :'fails_on_ruby_1.9.2' => true do + klasses = ['bar::foo'] + @node.classes = klasses + ast_obj = Puppet::Parser::AST::String.new(:value => 'foo') + klasses.each do |name| + klass = Puppet::Resource::Type.new(:hostclass, name, :arguments => {'1' => ast_obj, '2' => ast_obj}) + @compiler.topscope.known_resource_types.add klass + end + catalog = @compiler.compile + + r2 = catalog.resources.detect {|r| r.title == 'Bar::Foo' } + r2.tags.should =~ ['bar::foo', 'class', 'bar', 'foo'] + end end it "should fail if required parameters are missing" do -- cgit From 2431bb3fc8fba238cb2cf1bb71f316c62ba384b7 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:03:40 -0700 Subject: Cleaning up indentation in versoncmp function Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/functions/versioncmp.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/puppet/parser/functions/versioncmp.rb b/lib/puppet/parser/functions/versioncmp.rb index 6091e0923..e4edb151e 100644 --- a/lib/puppet/parser/functions/versioncmp.rb +++ b/lib/puppet/parser/functions/versioncmp.rb @@ -1,10 +1,8 @@ require 'puppet/util/package' - Puppet::Parser::Functions::newfunction( - :versioncmp, :type => :rvalue, - - :doc => "Compares two versions +Puppet::Parser::Functions::newfunction( :versioncmp, :type => :rvalue, +:doc => "Compares two versions Prototype: -- cgit From baf32de1dcda02f7da8b2926abee7f46d0d47fe1 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:25:54 -0700 Subject: Making the Functions module more resilient We were previously storing the module name with the environment instances as the key, which meant if the environment instances were removed, we could never get those modules again. Given that the functions weren't reloaded, this meant the functions were gone if we ever reloaded the environment. This makes the Functions environment module resilient across environment reloads, and it also makes the method work correctly when handed either an environment or a string. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/functions.rb | 5 ++++- spec/unit/parser/scope_spec.rb | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/puppet/parser/functions.rb b/lib/puppet/parser/functions.rb index e19ac127f..22eee70d7 100644 --- a/lib/puppet/parser/functions.rb +++ b/lib/puppet/parser/functions.rb @@ -29,8 +29,11 @@ module Puppet::Parser::Functions Environment = Puppet::Node::Environment def self.environment_module(env = nil) + if env and ! env.is_a?(Puppet::Node::Environment) + env = Puppet::Node::Environment.new(env) + end @modules.synchronize { - @modules[ env || Environment.current || Environment.root ] ||= Module.new + @modules[ (env || Environment.current || Environment.root).name ] ||= Module.new } end diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index 00212a2d5..d3ea8dfa8 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -42,7 +42,7 @@ describe Puppet::Parser::Scope do end it "should get its environment from its compiler" do - env = stub 'environment' + env = Puppet::Node::Environment.new compiler = stub 'compiler', :environment => env scope = Puppet::Parser::Scope.new :compiler => compiler scope.environment.should equal(env) -- cgit From 540377b526424e7ef9b2c06460d43af2b780a4af Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:28:44 -0700 Subject: Removing an unnecessary stub in the Scope tests Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- spec/unit/parser/functions_spec.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/unit/parser/functions_spec.rb b/spec/unit/parser/functions_spec.rb index 8240a184c..7eb6f299b 100755 --- a/spec/unit/parser/functions_spec.rb +++ b/spec/unit/parser/functions_spec.rb @@ -20,13 +20,17 @@ describe Puppet::Parser::Functions do end it "should have a method for returning an environment-specific module" do - Puppet::Parser::Functions.environment_module("myenv").should be_instance_of(Module) + Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should be_instance_of(Module) end it "should use the current default environment if no environment is provided" do Puppet::Parser::Functions.environment_module.should be_instance_of(Module) end + it "should be able to retrieve environment modules asked for by name rather than instance" do + Puppet::Parser::Functions.environment_module(Puppet::Node::Environment.new("myenv")).should equal(Puppet::Parser::Functions.environment_module("myenv")) + end + describe "when calling newfunction" do before do @module = Module.new -- cgit From 9662045bfe551821823b38fe6511e621998aef0b Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 12:34:49 -0700 Subject: Fixing a failing test because of mismatched error string Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- spec/unit/parser/functions/create_resources_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/unit/parser/functions/create_resources_spec.rb b/spec/unit/parser/functions/create_resources_spec.rb index da76e75d0..94b1e7c68 100755 --- a/spec/unit/parser/functions/create_resources_spec.rb +++ b/spec/unit/parser/functions/create_resources_spec.rb @@ -78,7 +78,7 @@ notify{test:} end it 'should fail if defines are missing params' do @scope.function_create_resources(['foo', {'blah'=>{}}]) - lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, 'Must pass one to Foo[blah] at line 1') + lambda { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /Must pass one to Foo\[blah\]/) end it 'should be able to add multiple defines' do hash = {} -- cgit From bdc0f8716ae8ccb2b2657dfab591afe9589d8902 Mon Sep 17 00:00:00 2001 From: Luke Kanies Date: Tue, 5 Jul 2011 16:32:03 -0700 Subject: Scope[] now returns nil for undefined variables Given that we have the 'include?' method, this feature is unnecessary, and it makes sense to convert to more ruby-like behavior. Any code that previously checked whether lookupvar (or the new []) returned :undefined should now check whether 'scope.include?(var)'. Thus, you can have the same behavior, but it takes a bit different code to get it. Signed-off-by: Luke Kanies Reviewed-by: Nick Lewis --- lib/puppet/parser/ast/leaf.rb | 7 ++++--- lib/puppet/parser/resource.rb | 3 ++- lib/puppet/parser/scope.rb | 12 ++++++++---- lib/puppet/parser/templatewrapper.rb | 7 +++---- spec/unit/parser/scope_spec.rb | 32 ++++++++++++++++---------------- test/language/scope.rb | 4 ++-- 6 files changed, 35 insertions(+), 30 deletions(-) diff --git a/lib/puppet/parser/ast/leaf.rb b/lib/puppet/parser/ast/leaf.rb index 64a197492..3efb52f63 100644 --- a/lib/puppet/parser/ast/leaf.rb +++ b/lib/puppet/parser/ast/leaf.rb @@ -124,10 +124,11 @@ class Puppet::Parser::AST # not include syntactical constructs, like '$' and '{}'). def evaluate(scope) parsewrap do - if (var = scope[@value, {:file => file, :line => line}]) == :undefined - var = :undef + if ! scope.include?(@value) + :undef + else + scope[@value, {:file => file, :line => line}] end - var end end diff --git a/lib/puppet/parser/resource.rb b/lib/puppet/parser/resource.rb index 6b072bd90..56887c357 100644 --- a/lib/puppet/parser/resource.rb +++ b/lib/puppet/parser/resource.rb @@ -258,7 +258,8 @@ class Puppet::Parser::Resource < Puppet::Resource def add_backward_compatible_relationship_param(name) # Skip metaparams for which we get no value. - return unless val = scope[name.to_s] and val != :undefined + return unless scope.include?(name.to_s) + val = scope[name.to_s] # The default case: just set the value set_parameter(name, val) and return unless @parameters[name] diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb index 3a87f964b..9d84c7e65 100644 --- a/lib/puppet/parser/scope.rb +++ b/lib/puppet/parser/scope.rb @@ -57,7 +57,7 @@ class Puppet::Parser::Scope rescue RuntimeError => e location = (options[:file] && options[:line]) ? " at #{options[:file]}:#{options[:line]}" : '' warning "Could not look up qualified variable '#{name}'; #{e.message}#{location}" - :undefined + nil end elsif ephemeral_include?(name) or table.include?(name) # We can't use "if table[name]" here because the value might be false @@ -69,7 +69,7 @@ class Puppet::Parser::Scope elsif parent parent[name,options.merge(:dynamic => (dynamic || options[:dynamic]))] else - :undefined + nil end end @@ -92,7 +92,7 @@ class Puppet::Parser::Scope end def include?(name) - self[name] != :undefined + ! self[name].nil? end # Is the value true? This allows us to control the definition of truth @@ -244,7 +244,11 @@ class Puppet::Parser::Scope end def undef_as(x,v) - (v == :undefined) ? x : (v == :undef) ? x : v + if v.nil? or v == :undef + x + else + v + end end def qualified_scope(classname) diff --git a/lib/puppet/parser/templatewrapper.rb b/lib/puppet/parser/templatewrapper.rb index 83d18cc3f..9336e704d 100644 --- a/lib/puppet/parser/templatewrapper.rb +++ b/lib/puppet/parser/templatewrapper.rb @@ -25,7 +25,7 @@ class Puppet::Parser::TemplateWrapper # Should return true if a variable is defined, false if it is not def has_variable?(name) - scope[name.to_s, {:file => file, :line => script_line}] != :undefined + scope.include?(name.to_s) end # Allow templates to access the defined classes @@ -56,9 +56,8 @@ class Puppet::Parser::TemplateWrapper # the missing_method definition here until we declare the syntax finally # dead. def method_missing(name, *args) - value = scope[name.to_s, {:file => file,:line => script_line}] - if value != :undefined - return value + if scope.include?(name.to_s) + return scope[name.to_s, {:file => file,:line => script_line}] else # Just throw an error immediately, instead of searching for # other missingmethod things or whatever. diff --git a/spec/unit/parser/scope_spec.rb b/spec/unit/parser/scope_spec.rb index d3ea8dfa8..3c0d15cd7 100755 --- a/spec/unit/parser/scope_spec.rb +++ b/spec/unit/parser/scope_spec.rb @@ -88,8 +88,8 @@ describe Puppet::Parser::Scope do @scope.lookupvar("var").should == "yep" end - it "should return ':undefined' for unset variables" do - @scope["var"].should == :undefined + it "should return nil for unset variables" do + @scope["var"].should be_nil end it "should be able to look up values" do @@ -180,32 +180,32 @@ describe Puppet::Parser::Scope do @scope["other::deep::klass::var"].should == "otherval" end - it "should return ':undefined' for qualified variables that cannot be found in other classes" do + it "should return nil for qualified variables that cannot be found in other classes" do other_scope = create_class_scope("other::deep::klass") - @scope["other::deep::klass::var"].should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should warn and return ':undefined' for qualified variables whose classes have not been evaluated" do + it "should warn and return nil for qualified variables whose classes have not been evaluated" do klass = newclass("other::deep::klass") @scope.expects(:warning) - @scope["other::deep::klass::var"].should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should warn and return ':undefined' for qualified variables whose classes do not exist" do + it "should warn and return nil for qualified variables whose classes do not exist" do @scope.expects(:warning) - @scope["other::deep::klass::var"].should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should return ':undefined' when asked for a non-string qualified variable from a class that does not exist" do + it "should return nil when asked for a non-string qualified variable from a class that does not exist" do @scope.stubs(:warning) - @scope["other::deep::klass::var"].should == :undefined + @scope["other::deep::klass::var"].should be_nil end - it "should return ':undefined' when asked for a non-string qualified variable from a class that has not been evaluated" do + it "should return nil when asked for a non-string qualified variable from a class that has not been evaluated" do @scope.stubs(:warning) klass = newclass("other::deep::klass") - @scope["other::deep::klass::var"].should == :undefined + @scope["other::deep::klass::var"].should be_nil end end end @@ -320,7 +320,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope["1"].should == :undefined + @scope["1"].should be_nil end it "should not remove classic variables when unset_ephemeral_var is called" do @@ -393,7 +393,7 @@ describe Puppet::Parser::Scope do @scope.unset_ephemeral_var - @scope["1"].should == :undefined + @scope["1"].should be_nil end end @@ -449,13 +449,13 @@ describe Puppet::Parser::Scope do it "should be able to unset normal variables" do @scope["foo"] = "bar" @scope.unsetvar("foo") - @scope["foo"].should == :undefined + @scope["foo"].should be_nil end it "should be able to unset ephemeral variables" do @scope.setvar("0", "bar", :ephemeral => true) @scope.unsetvar("0") - @scope["0"].should == :undefined + @scope["0"].should be_nil end it "should not unset ephemeral variables in previous ephemeral scope" do diff --git a/test/language/scope.rb b/test/language/scope.rb index 57824d887..c80178e7b 100755 --- a/test/language/scope.rb +++ b/test/language/scope.rb @@ -47,7 +47,7 @@ class TestScope < Test::Unit::TestCase # Now set a var in the midscope and make sure the mid and bottom can see it but not the top midscope['second'] = "midval" - assert_equal(:undefined, scopes[:top]['second'], "Found child var in top scope") + assert_nil(scopes[:top]['second'], "Found child var in top scope") [:mid, :bot].each do |name| assert_equal("midval", scopes[name]['second'], "Could not find var in #{name}") end @@ -55,7 +55,7 @@ class TestScope < Test::Unit::TestCase # And set something in the bottom, and make sure we only find it there. botscope['third'] = "botval" [:top, :mid].each do |name| - assert_equal(:undefined, scopes[name]['third'], "Found child var in top scope") + assert_nil(scopes[name]['third'], "Found child var in top scope") end assert_equal("botval", scopes[:bot]['third'], "Could not find var in bottom scope") -- cgit