Class Puppet::Parser::Scope
In: lib/puppet/parser/scope.rb
Parent: Object

Methods

Included Modules

Enumerable Puppet::Util::Errors

Constants

AST = Puppet::Parser::AST

Attributes

base  [RW] 
compiler  [RW] 
keyword  [RW] 
level  [RW] 
nodescope  [RW] 
parent  [RW] 
parser  [RW] 
resource  [RW] 
source  [RW] 
top  [RW] 
translated  [RW] 

Public Class methods

Initialize our new scope. Defaults to having no parent.

[Source]

     # File lib/puppet/parser/scope.rb, line 84
 84:     def initialize(hash = {})
 85:         if hash.include?(:namespace)
 86:             if n = hash[:namespace]
 87:                 @namespaces = [n]
 88:             end
 89:             hash.delete(:namespace)
 90:         else
 91:             @namespaces = [""]
 92:         end
 93:         hash.each { |name, val|
 94:             method = name.to_s + "="
 95:             if self.respond_to? method
 96:                 self.send(method, val)
 97:             else
 98:                 raise Puppet::DevError, "Invalid scope argument %s" % name
 99:             end
100:         }
101: 
102:         @tags = []
103: 
104:         # The symbol table for this scope.  This is where we store variables.
105:         @symtable = {}
106: 
107:         # All of the defaults set for types.  It's a hash of hashes,
108:         # with the first key being the type, then the second key being
109:         # the parameter.
110:         @defaults = Hash.new { |dhash,type|
111:             dhash[type] = {}
112:         }
113:     end

Is the value true? This allows us to control the definition of truth in one place.

[Source]

    # File lib/puppet/parser/scope.rb, line 38
38:     def self.true?(value)
39:         if value == false or value == "" or value == :undef
40:             return false
41:         else
42:             return true
43:         end
44:     end

Public Instance methods

Add to our list of namespaces.

[Source]

    # File lib/puppet/parser/scope.rb, line 47
47:     def add_namespace(ns)
48:         return false if @namespaces.include?(ns)
49:         if @namespaces == [""]
50:             @namespaces = [ns]
51:         else
52:             @namespaces << ns
53:         end
54:     end

A demeterific shortcut to the catalog.

[Source]

    # File lib/puppet/parser/scope.rb, line 23
23:     def catalog
24:         compiler.catalog
25:     end

[Source]

    # File lib/puppet/parser/scope.rb, line 61
61:     def findclass(name)
62:         @namespaces.each do |namespace|
63:             if r = parser.findclass(namespace, name)
64:                 return r
65:             end
66:         end
67:         return nil
68:     end

[Source]

    # File lib/puppet/parser/scope.rb, line 70
70:     def finddefine(name)
71:         @namespaces.each do |namespace|
72:             if r = parser.finddefine(namespace, name)
73:                 return r
74:             end
75:         end
76:         return nil
77:     end

[Source]

    # File lib/puppet/parser/scope.rb, line 79
79:     def findresource(string, name = nil)
80:         compiler.findresource(string, name)
81:     end

Proxy accessors

[Source]

    # File lib/puppet/parser/scope.rb, line 28
28:     def host
29:         @compiler.node.name
30:     end

[Source]

    # File lib/puppet/parser/scope.rb, line 32
32:     def interpreter
33:         @compiler.interpreter
34:     end

Collect all of the defaults set at any higher scopes. This is a different type of lookup because it‘s additive — it collects all of the defaults, with defaults in closer scopes overriding those in later scopes.

[Source]

     # File lib/puppet/parser/scope.rb, line 119
119:     def lookupdefaults(type)
120:         values = {}
121: 
122:         # first collect the values from the parents
123:         unless parent.nil?
124:             parent.lookupdefaults(type).each { |var,value|
125:                 values[var] = value
126:             }
127:         end
128: 
129:         # then override them with any current values
130:         # this should probably be done differently
131:         if @defaults.include?(type)
132:             @defaults[type].each { |var,value|
133:                 values[var] = value
134:             }
135:         end
136: 
137:         #Puppet.debug "Got defaults for %s: %s" %
138:         #    [type,values.inspect]
139:         return values
140:     end

Look up a defined type.

[Source]

     # File lib/puppet/parser/scope.rb, line 143
143:     def lookuptype(name)
144:         finddefine(name) || findclass(name)
145:     end

Look up a variable. The simplest value search we do. Default to returning an empty string for missing values, but support returning a constant.

[Source]

     # File lib/puppet/parser/scope.rb, line 165
165:     def lookupvar(name, usestring = true)
166:         # If the variable is qualified, then find the specified scope and look the variable up there instead.
167:         if name =~ /::/
168:             return lookup_qualified_var(name, usestring)
169:         end
170:         # We can't use "if @symtable[name]" here because the value might be false
171:         if @symtable.include?(name)
172:             if usestring and @symtable[name] == :undef
173:                 return ""
174:             else
175:                 return @symtable[name]
176:             end
177:         elsif self.parent 
178:             return parent.lookupvar(name, usestring)
179:         elsif usestring
180:             return ""
181:         else
182:             return :undefined
183:         end
184:     end

[Source]

     # File lib/puppet/parser/scope.rb, line 205
205:     def namespaces
206:         @namespaces.dup
207:     end

Create a new scope and set these options.

[Source]

     # File lib/puppet/parser/scope.rb, line 210
210:     def newscope(options = {})
211:         compiler.newscope(self, options)
212:     end

Is this class for a node? This is used to make sure that nodes and classes with the same name conflict (620), which is required because of how often the names are used throughout the system, including on the client.

[Source]

     # File lib/puppet/parser/scope.rb, line 218
218:     def nodescope?
219:         self.nodescope
220:     end

We probably shouldn‘t cache this value… But it‘s a lot faster than doing lots of queries.

[Source]

     # File lib/puppet/parser/scope.rb, line 224
224:     def parent
225:         unless defined?(@parent)
226:             @parent = compiler.parent(self)
227:         end
228:         @parent
229:     end

Return the list of scopes up to the top scope, ordered with our own first. This is used for looking up variables and defaults.

[Source]

     # File lib/puppet/parser/scope.rb, line 233
233:     def scope_path
234:         if parent
235:             [self, parent.scope_path].flatten.compact
236:         else
237:             [self]
238:         end
239:     end

Set defaults for a type. The typename should already be downcased, so that the syntax is isolated. We don‘t do any kind of type-checking here; instead we let the resource do it when the defaults are used.

[Source]

     # File lib/puppet/parser/scope.rb, line 244
244:     def setdefaults(type, params)
245:         table = @defaults[type]
246: 
247:         # if we got a single param, it'll be in its own array
248:         params = [params] unless params.is_a?(Array)
249: 
250:         params.each { |param|
251:             #Puppet.debug "Default for %s is %s => %s" %
252:             #    [type,ary[0].inspect,ary[1].inspect]
253:             if table.include?(param.name)
254:                 raise Puppet::ParseError.new("Default already defined for %s { %s }; cannot redefine" % [type, param.name], param.line, param.file)
255:             end
256:             table[param.name] = param
257:         }
258:     end

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.

[Source]

     # File lib/puppet/parser/scope.rb, line 263
263:     def setvar(name,value, file = nil, line = nil, append = false)
264:         #Puppet.debug "Setting %s to '%s' at level %s mode append %s" %
265:         #    [name.inspect,value,self.level, append]
266:         if @symtable.include?(name)
267:             unless append
268:                 error = Puppet::ParseError.new("Cannot reassign variable %s" % name)
269:             else
270:                 error = Puppet::ParseError.new("Cannot append, variable %s is defined in this scope" % name)
271:             end
272:             if file
273:                 error.file = file
274:             end
275:             if line
276:                 error.line = line
277:             end
278:             raise error
279:         end
280:         
281:         unless append
282:             @symtable[name] = value
283:         else # append case
284:             # lookup the value in the scope if it exists and insert the var
285:             @symtable[name] = lookupvar(name)
286:             # concatenate if string, append if array, nothing for other types
287:             if value.is_a?(Array)
288:                 @symtable[name] += value
289:             else
290:                 @symtable[name] << value
291:             end
292:         end
293:     end

Return an interpolated string.

[Source]

     # File lib/puppet/parser/scope.rb, line 296
296:     def strinterp(string, file = nil, line = nil)
297:         # Most strings won't have variables in them.
298:         ss = StringScanner.new(string)
299:         out = ""
300:         while not ss.eos?
301:             if ss.scan(/^\$\{((\w*::)*\w+)\}|^\$((\w*::)*\w+)/) 
302:                 # If it matches the backslash, then just retun the dollar sign.
303:                 if ss.matched == '\\$'
304:                     out << '$'
305:                 else # look the variable up
306:                     out << lookupvar(ss[1] || ss[3]).to_s || ""
307:                 end
308:             elsif ss.scan(/^\\(.)/)
309:                 # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched])
310:                 case ss[1]
311:                 when 'n'
312:                     out << "\n"
313:                 when 't'
314:                     out << "\t"
315:                 when 's'
316:                     out << " "
317:                 when '\\'
318:                     out << '\\'
319:                 when '$'
320:                     out << '$'
321:                 else
322:                     str = "Unrecognised escape sequence '#{ss.matched}'"
323:                     if file
324:                         str += " in file %s" % file
325:                     end
326:                     if line
327:                         str += " at line %s" % line
328:                     end
329:                     Puppet.warning str
330:                     out << ss.matched
331:                 end
332:             elsif ss.scan(/^\$/)
333:                 out << '$'
334:             elsif ss.scan(/^\\\n/) # an escaped carriage return
335:                 next
336:             else 
337:                 tmp = ss.scan(/[^\\$]+/)
338:                 # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp])
339:                 unless tmp
340:                     error = Puppet::ParseError.new("Could not parse string %s" %
341:                         string.inspect)
342:                     {:file= => file, :line= => line}.each do |m,v|
343:                         error.send(m, v) if v
344:                     end
345:                     raise error
346:                 end
347:                 out << tmp
348:             end
349:         end
350: 
351:         return out
352:     end

Return the tags associated with this scope. It‘s basically just our parents’ tags, plus our type. We don‘t cache this value because our parent tags might change between calls.

[Source]

     # File lib/puppet/parser/scope.rb, line 357
357:     def tags
358:         resource.tags
359:     end

Return a hash containing our variables and their values, optionally (and by default) including the values defined in our parent. Local values shadow parent values.

[Source]

     # File lib/puppet/parser/scope.rb, line 189
189:     def to_hash(recursive = true)
190:         if recursive and parent then
191:             target = parent.to_hash(recursive)
192:         end
193:         target ||= Hash.new
194:         @symtable.keys.each { |name| 
195:             value = @symtable[name]
196:             if value == :undef then
197:                 target.delete(name)
198:             else
199:                 target[name] = value 
200:             end
201:         }
202:         return target
203:     end

Used mainly for logging

[Source]

     # File lib/puppet/parser/scope.rb, line 362
362:     def to_s
363:         "Scope(%s)" % @resource.to_s
364:     end

Are we the top scope?

[Source]

    # File lib/puppet/parser/scope.rb, line 57
57:     def topscope?
58:         @level == 1
59:     end

Undefine a variable; only used for testing.

[Source]

     # File lib/puppet/parser/scope.rb, line 367
367:     def unsetvar(var)
368:         if @symtable.include?(var)
369:             @symtable.delete(var)
370:         end
371:     end

[Validate]