Those variables have been created to be short lived and used mainly
to define temporary special variables.
They do not persist after a call to unset_ephemeral_var.
Also Scope#set_ephemeral_from can be used to promote a regexp
MatchData to ephemeral values.

Signed-off-by: Brice Figureau <[email protected]>
---
 lib/puppet/parser/ast/vardef.rb |    2 +-
 lib/puppet/parser/scope.rb      |   61 ++++++++++++++++++++++++----------
 spec/unit/parser/ast/vardef.rb  |    4 +-
 spec/unit/parser/scope.rb       |   68 +++++++++++++++++++++++++++++++++++----
 4 files changed, 107 insertions(+), 28 deletions(-)

diff --git a/lib/puppet/parser/ast/vardef.rb b/lib/puppet/parser/ast/vardef.rb
index 2d5f623..ae24b32 100644
--- a/lib/puppet/parser/ast/vardef.rb
+++ b/lib/puppet/parser/ast/vardef.rb
@@ -17,7 +17,7 @@ class Puppet::Parser::AST
             value = @value.safeevaluate(scope)
 
             parsewrap do
-                scope.setvar(name,value, @file, @line, @append)
+                scope.setvar(name,value, :file => @file, :line => @line, 
:append => @append)
             end
         end
 
diff --git a/lib/puppet/parser/scope.rb b/lib/puppet/parser/scope.rb
index be4dc12..5b3c6d0 100644
--- a/lib/puppet/parser/scope.rb
+++ b/lib/puppet/parser/scope.rb
@@ -128,6 +128,11 @@ class Puppet::Parser::Scope
         # The symbol table for this scope.  This is where we store variables.
         @symtable = {}
 
+        # the ephemeral symbol tables
+        # those should not persist long, and are used for the moment only
+        # for $0..$xy capture variables of regexes
+        @ephemeral = {}
+
         # All of the defaults set for types.  It's a hash of hashes,
         # with the first key being the type, then the second key being
         # the parameter.
@@ -189,16 +194,17 @@ class Puppet::Parser::Scope
     # Look up a variable.  The simplest value search we do.  Default to 
returning
     # an empty string for missing values, but support returning a constant.
     def lookupvar(name, usestring = true)
+        table = ephemeral?(name) ? @ephemeral : @symtable
         # If the variable is qualified, then find the specified scope and look 
the variable up there instead.
         if name =~ /::/
             return lookup_qualified_var(name, usestring)
         end
-        # We can't use "if @symtable[name]" here because the value might be 
false
-        if @symtable.include?(name)
-            if usestring and @symtable[name] == :undef
+        # We can't use "if table[name]" here because the value might be false
+        if table.include?(name)
+            if usestring and table[name] == :undef
                 return ""
             else
-                return @symtable[name]
+                return table[name]
             end
         elsif self.parent
             return parent.lookupvar(name, usestring)
@@ -286,34 +292,35 @@ 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.
-    def setvar(name,value, file = nil, line = nil, append = false)
+    def setvar(name,value, options = {})
+        table = options[:ephemeral] ? @ephemeral : @symtable
         #Puppet.debug "Setting %s to '%s' at level %s mode append %s" %
         #    [name.inspect,value,self.level, append]
-        if @symtable.include?(name)
-            unless append
+        if table.include?(name)
+            unless options[:append]
                 error = Puppet::ParseError.new("Cannot reassign variable %s" % 
name)
             else
                 error = Puppet::ParseError.new("Cannot append, variable %s is 
defined in this scope" % name)
             end
-            if file
-                error.file = file
+            if options[:file]
+                error.file = options[:file]
             end
-            if line
-                error.line = line
+            if options[:line]
+                error.line = options[:line]
             end
             raise error
         end
 
-        unless append
-            @symtable[name] = value
+        unless options[:append]
+            table[name] = value
         else # append case
             # lookup the value in the scope if it exists and insert the var
-            @symtable[name] = lookupvar(name)
+            table[name] = lookupvar(name)
             # concatenate if string, append if array, nothing for other types
             if value.is_a?(Array)
-                @symtable[name] += value
+                table[name] += value
             else
-                @symtable[name] << value
+                table[name] << value
             end
         end
     end
@@ -391,8 +398,26 @@ class Puppet::Parser::Scope
 
     # Undefine a variable; only used for testing.
     def unsetvar(var)
-        if @symtable.include?(var)
-            @symtable.delete(var)
+        table = ephemeral?(var) ? @ephemeral : @table
+        if table.include?(var)
+            table.delete(var)
+        end
+    end
+
+    def unset_ephemeral_var
+        @ephemeral = {}
+    end
+
+    def ephemeral?(name)
+        @ephemeral.include?(name)
+    end
+
+    def ephemeral_from(match, file = nil, line = nil)
+        raise(ArgumentError,"Invalid regex match data") unless 
match.is_a?(MatchData)
+
+        setvar("0", match[0], :file => file, :line => line, :ephemeral => true)
+        match.captures.each_with_index do |m,i|
+            setvar("#{i+1}", m, :file => file, :line => line, :ephemeral => 
true)
         end
     end
 end
diff --git a/spec/unit/parser/ast/vardef.rb b/spec/unit/parser/ast/vardef.rb
index 14de689..9730cee 100755
--- a/spec/unit/parser/ast/vardef.rb
+++ b/spec/unit/parser/ast/vardef.rb
@@ -25,7 +25,7 @@ describe Puppet::Parser::AST::VarDef do
             name = stub 'name', :safeevaluate => "var"
             value = stub 'value', :safeevaluate => "1"
 
-            @scope.expects(:setvar).with { |name,value,file,line,append| 
append == nil }
+            @scope.expects(:setvar).with { |name,value,options| 
options[:append] == nil }
 
             vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => 
value, :file => nil,
                                                      :line => nil
@@ -36,7 +36,7 @@ describe Puppet::Parser::AST::VarDef do
             name = stub 'name', :safeevaluate => "var"
             value = stub 'value', :safeevaluate => "1"
 
-            @scope.expects(:setvar).with { |name,value,file,line,append| 
append == true }
+            @scope.expects(:setvar).with { |name,value,options| 
options[:append] == true }
 
             vardef = Puppet::Parser::AST::VarDef.new :name => name, :value => 
value, :file => nil,
                                                      :line => nil, :append => 
true
diff --git a/spec/unit/parser/scope.rb b/spec/unit/parser/scope.rb
index a9784e0..641a3f9 100755
--- a/spec/unit/parser/scope.rb
+++ b/spec/unit/parser/scope.rb
@@ -111,24 +111,24 @@ describe Puppet::Parser::Scope do
 
     describe "when setvar is called with append=true" do
         it "should raise error if the variable is already defined in this 
scope" do
-            @scope.setvar("var","1",nil,nil,false)
-            lambda { @scope.setvar("var","1",nil,nil,true) }.should 
raise_error(Puppet::ParseError)
+            @scope.setvar("var","1", :append => false)
+            lambda { @scope.setvar("var","1", :append => true) }.should 
raise_error(Puppet::ParseError)
         end
 
         it "it should lookup current variable value" do
             @scope.expects(:lookupvar).with("var").returns("2")
-            @scope.setvar("var","1",nil,nil,true)
+            @scope.setvar("var","1", :append => true)
         end
 
         it "it should store the concatenated string '42'" do
-            @topscope.setvar("var","4",nil,nil,false)
-            @scope.setvar("var","2",nil,nil,true)
+            @topscope.setvar("var","4", :append => false)
+            @scope.setvar("var","2", :append => true)
             @scope.lookupvar("var").should == "42"
         end
 
         it "it should store the concatenated array [4,2]" do
-            @topscope.setvar("var",[4],nil,nil,false)
-            @scope.setvar("var",[2],nil,nil,true)
+            @topscope.setvar("var",[4], :append => false)
+            @scope.setvar("var",[2], :append => true)
             @scope.lookupvar("var").should == [4,2]
         end
 
@@ -195,4 +195,58 @@ describe Puppet::Parser::Scope do
             Puppet::Parser::Scope.number?("0x89g").should be_nil
         end
     end
+
+    describe "when using ephemeral variables" do
+        it "should store the variable value" do
+            @scope.setvar("1", :value, :ephemeral => true)
+
+            @scope.lookupvar("1").should == :value
+        end
+
+        it "should remove the variable value when unset_ephemeral_var is 
called" do
+            @scope.setvar("1", :value, :ephemeral => true)
+            @scope.stubs(:parent).returns(nil)
+
+            @scope.unset_ephemeral_var
+
+            @scope.lookupvar("1", false).should == :undefined
+        end
+
+        it "should not remove classic variables when unset_ephemeral_var is 
called" do
+            @scope.setvar("myvar", :value1)
+            @scope.setvar("1", :value2, :ephemeral => true)
+            @scope.stubs(:parent).returns(nil)
+
+            @scope.unset_ephemeral_var
+
+            @scope.lookupvar("myvar", false).should == :value1
+        end
+    end
+
+    describe "when setting ephemeral vars from matches" do
+        before :each do
+            @match = stub 'match', :is_a? => true
+            @match.stubs(:[]).with(0).returns("this is a string")
+            @match.stubs(:captures).returns([])
+            @scope.stubs(:setvar)
+        end
+
+        it "should accept only MatchData" do
+            lambda { @scope.ephemeral_from("match") }.should raise_error
+        end
+
+        it "should set $0 with the full match" do
+            @scope.expects(:setvar).with { |*arg| arg[0] == "0" and arg[1] == 
"this is a string" and arg[2][:ephemeral] }
+
+            @scope.ephemeral_from(@match)
+        end
+
+        it "should set every capture as ephemeral var" do
+            @match.stubs(:captures).returns([:capture1,:capture2])
+            @scope.expects(:setvar).with { |*arg| arg[0] == "1" and arg[1] == 
:capture1 and arg[2][:ephemeral] }
+            @scope.expects(:setvar).with { |*arg| arg[0] == "2" and arg[1] == 
:capture2 and arg[2][:ephemeral] }
+
+            @scope.ephemeral_from(@match)
+        end
+    end
 end
-- 
1.6.0.2


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to