| Class | Puppet::Parser::Scope |
| In: |
lib/puppet/parser/scope.rb
|
| Parent: | Object |
| AST | = | Puppet::Parser::AST |
| base | [RW] | |
| compiler | [RW] | |
| keyword | [RW] | |
| level | [RW] | |
| nodescope | [RW] | |
| parent | [RW] | |
| parser | [RW] | |
| resource | [RW] | |
| source | [RW] | |
| top | [RW] | |
| translated | [RW] |
Initialize our new scope. Defaults to having no parent.
# File lib/puppet/parser/scope.rb, line 107
107: def initialize(hash = {})
108: if hash.include?(:namespace)
109: if n = hash[:namespace]
110: @namespaces = [n]
111: end
112: hash.delete(:namespace)
113: else
114: @namespaces = [""]
115: end
116: hash.each { |name, val|
117: method = name.to_s + "="
118: if self.respond_to? method
119: self.send(method, val)
120: else
121: raise Puppet::DevError, "Invalid scope argument %s" % name
122: end
123: }
124:
125: @tags = []
126:
127: # The symbol table for this scope. This is where we store variables.
128: @symtable = {}
129:
130: # All of the defaults set for types. It's a hash of hashes,
131: # with the first key being the type, then the second key being
132: # the parameter.
133: @defaults = Hash.new { |dhash,type|
134: dhash[type] = {}
135: }
136: end
Is the value a number?, return the correct object or nil if not a number
# File lib/puppet/parser/scope.rb, line 47
47: def self.number?(value)
48: unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String)
49: return nil
50: end
51:
52: if value.is_a?(String)
53: if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/
54: return value.to_f
55: elsif value =~ /^0x\d+/i
56: return value.to_i(16)
57: elsif value =~ /^0\d+/i
58: return value.to_i(8)
59: elsif value =~ /^-?\d+/
60: return value.to_i
61: else
62: return nil
63: end
64: end
65: # it is one of Fixnum,Bignum or Float
66: return value
67: end
Add to our list of namespaces.
# File lib/puppet/parser/scope.rb, line 70
70: def add_namespace(ns)
71: return false if @namespaces.include?(ns)
72: if @namespaces == [""]
73: @namespaces = [ns]
74: else
75: @namespaces << ns
76: end
77: end
# File lib/puppet/parser/scope.rb, line 84
84: def findclass(name)
85: @namespaces.each do |namespace|
86: if r = parser.findclass(namespace, name)
87: return r
88: end
89: end
90: return nil
91: end
# File lib/puppet/parser/scope.rb, line 93
93: def finddefine(name)
94: @namespaces.each do |namespace|
95: if r = parser.finddefine(namespace, name)
96: return r
97: end
98: end
99: return nil
100: end
# File lib/puppet/parser/scope.rb, line 102
102: def findresource(string, name = nil)
103: compiler.findresource(string, name)
104: end
Proxy accessors
# File lib/puppet/parser/scope.rb, line 28
28: def host
29: @compiler.node.name
30: 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.
# File lib/puppet/parser/scope.rb, line 142
142: def lookupdefaults(type)
143: values = {}
144:
145: # first collect the values from the parents
146: unless parent.nil?
147: parent.lookupdefaults(type).each { |var,value|
148: values[var] = value
149: }
150: end
151:
152: # then override them with any current values
153: # this should probably be done differently
154: if @defaults.include?(type)
155: @defaults[type].each { |var,value|
156: values[var] = value
157: }
158: end
159:
160: #Puppet.debug "Got defaults for %s: %s" %
161: # [type,values.inspect]
162: return values
163: end
Look up a defined type.
# File lib/puppet/parser/scope.rb, line 166
166: def lookuptype(name)
167: finddefine(name) || findclass(name)
168: 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.
# File lib/puppet/parser/scope.rb, line 188
188: def lookupvar(name, usestring = true)
189: # If the variable is qualified, then find the specified scope and look the variable up there instead.
190: if name =~ /::/
191: return lookup_qualified_var(name, usestring)
192: end
193: # We can't use "if @symtable[name]" here because the value might be false
194: if @symtable.include?(name)
195: if usestring and @symtable[name] == :undef
196: return ""
197: else
198: return @symtable[name]
199: end
200: elsif self.parent
201: return parent.lookupvar(name, usestring)
202: elsif usestring
203: return ""
204: else
205: return :undefined
206: end
207: 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.
# File lib/puppet/parser/scope.rb, line 241
241: def nodescope?
242: self.nodescope
243: end
We probably shouldn‘t cache this value… But it‘s a lot faster than doing lots of queries.
# File lib/puppet/parser/scope.rb, line 247
247: def parent
248: unless defined?(@parent)
249: @parent = compiler.parent(self)
250: end
251: @parent
252: 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.
# File lib/puppet/parser/scope.rb, line 256
256: def scope_path
257: if parent
258: [self, parent.scope_path].flatten.compact
259: else
260: [self]
261: end
262: 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.
# File lib/puppet/parser/scope.rb, line 267
267: def setdefaults(type, params)
268: table = @defaults[type]
269:
270: # if we got a single param, it'll be in its own array
271: params = [params] unless params.is_a?(Array)
272:
273: params.each { |param|
274: #Puppet.debug "Default for %s is %s => %s" %
275: # [type,ary[0].inspect,ary[1].inspect]
276: if table.include?(param.name)
277: raise Puppet::ParseError.new("Default already defined for %s { %s }; cannot redefine" % [type, param.name], param.line, param.file)
278: end
279: table[param.name] = param
280: }
281: 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.
# File lib/puppet/parser/scope.rb, line 286
286: def setvar(name,value, file = nil, line = nil, append = false)
287: #Puppet.debug "Setting %s to '%s' at level %s mode append %s" %
288: # [name.inspect,value,self.level, append]
289: if @symtable.include?(name)
290: unless append
291: error = Puppet::ParseError.new("Cannot reassign variable %s" % name)
292: else
293: error = Puppet::ParseError.new("Cannot append, variable %s is defined in this scope" % name)
294: end
295: if file
296: error.file = file
297: end
298: if line
299: error.line = line
300: end
301: raise error
302: end
303:
304: unless append
305: @symtable[name] = value
306: else # append case
307: # lookup the value in the scope if it exists and insert the var
308: @symtable[name] = lookupvar(name)
309: # concatenate if string, append if array, nothing for other types
310: if value.is_a?(Array)
311: @symtable[name] += value
312: else
313: @symtable[name] << value
314: end
315: end
316: end
Return an interpolated string.
# File lib/puppet/parser/scope.rb, line 319
319: def strinterp(string, file = nil, line = nil)
320: # Most strings won't have variables in them.
321: ss = StringScanner.new(string)
322: out = ""
323: while not ss.eos?
324: if ss.scan(/^\$\{((\w*::)*\w+)\}|^\$((\w*::)*\w+)/)
325: # If it matches the backslash, then just retun the dollar sign.
326: if ss.matched == '\\$'
327: out << '$'
328: else # look the variable up
329: out << lookupvar(ss[1] || ss[3]).to_s || ""
330: end
331: elsif ss.scan(/^\\(.)/)
332: # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched])
333: case ss[1]
334: when 'n'
335: out << "\n"
336: when 't'
337: out << "\t"
338: when 's'
339: out << " "
340: when '\\'
341: out << '\\'
342: when '$'
343: out << '$'
344: else
345: str = "Unrecognised escape sequence '#{ss.matched}'"
346: if file
347: str += " in file %s" % file
348: end
349: if line
350: str += " at line %s" % line
351: end
352: Puppet.warning str
353: out << ss.matched
354: end
355: elsif ss.scan(/^\$/)
356: out << '$'
357: elsif ss.scan(/^\\\n/) # an escaped carriage return
358: next
359: else
360: tmp = ss.scan(/[^\\$]+/)
361: # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp])
362: unless tmp
363: error = Puppet::ParseError.new("Could not parse string %s" %
364: string.inspect)
365: {:file= => file, :line= => line}.each do |m,v|
366: error.send(m, v) if v
367: end
368: raise error
369: end
370: out << tmp
371: end
372: end
373:
374: return out
375: 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.
# File lib/puppet/parser/scope.rb, line 212
212: def to_hash(recursive = true)
213: if recursive and parent then
214: target = parent.to_hash(recursive)
215: end
216: target ||= Hash.new
217: @symtable.keys.each { |name|
218: value = @symtable[name]
219: if value == :undef then
220: target.delete(name)
221: else
222: target[name] = value
223: end
224: }
225: return target
226: end
Used mainly for logging
# File lib/puppet/parser/scope.rb, line 385
385: def to_s
386: "Scope(%s)" % @resource.to_s
387: end
Are we the top scope?
# File lib/puppet/parser/scope.rb, line 80
80: def topscope?
81: @level == 1
82: end