Class: Puppet::Parser::Scope
- Includes:
- Enumerable, Resource::TypeCollectionHelper, Util::Errors
- Defined in:
- lib/puppet/parser/scope.rb
Defined Under Namespace
Classes: Ephemeral
Constant Summary collapse
Instance Attribute Summary collapse
-
#base ⇒ Object
Returns the value of attribute base.
-
#compiler ⇒ Object
Returns the value of attribute compiler.
-
#keyword ⇒ Object
Returns the value of attribute keyword.
-
#level ⇒ Object
Returns the value of attribute level.
-
#namespaces ⇒ Object
readonly
Returns the value of attribute namespaces.
-
#parent ⇒ Object
Returns the value of attribute parent.
-
#resource ⇒ Object
Returns the value of attribute resource.
-
#source ⇒ Object
Returns the value of attribute source.
-
#top ⇒ Object
Returns the value of attribute top.
-
#translated ⇒ Object
Returns the value of attribute translated.
Class Method Summary collapse
-
.number?(value) ⇒ Boolean
Is the value a number?, return the correct object or nil if not a number.
-
.true?(value) ⇒ Boolean
Is the value true? This allows us to control the definition of truth in one place.
Instance Method Summary collapse
-
#add_namespace(ns) ⇒ Object
Add to our list of namespaces.
-
#catalog ⇒ Object
A demeterific shortcut to the catalog.
-
#class_scope(klass) ⇒ Object
Return the scope associated with a class.
-
#class_set(name, scope) ⇒ Object
Store the fact that we’ve evaluated a class, and store a reference to the scope in which it was evaluated, so that we can look it up later.
-
#environment ⇒ Object
Remove this when rebasing.
-
#ephemeral?(name) ⇒ Boolean
is name an ephemeral variable?.
- #ephemeral_from(match, file = nil, line = nil) ⇒ Object
-
#ephemeral_include?(name) ⇒ Boolean
check if name exists in one of the ephemeral scope.
- #ephemeral_level ⇒ Object
- #find_builtin_resource_type(type) ⇒ Object
- #find_defined_resource_type(type) ⇒ Object
- #find_definition(name) ⇒ Object
- #find_hostclass(name) ⇒ Object
- #find_resource_type(type) ⇒ Object
- #findresource(string, name = nil) ⇒ Object
-
#host ⇒ Object
Proxy accessors.
-
#initialize(hash = {}) ⇒ Scope
constructor
Initialize our new scope.
-
#lookupdefaults(type) ⇒ Object
Collect all of the defaults set at any higher scopes.
-
#lookuptype(name) ⇒ Object
Look up a defined type.
-
#lookupvar(name, usestring = true) ⇒ Object
Look up a variable.
- #new_ephemeral ⇒ Object
-
#newscope(options = {}) ⇒ Object
Create a new scope and set these options.
- #parent_module_name ⇒ Object
- #resolve_type_and_titles(type, titles) ⇒ Object
-
#scope_path ⇒ Object
Return the list of scopes up to the top scope, ordered with our own first.
-
#setdefaults(type, params) ⇒ Object
Set defaults for a type.
-
#setvar(name, value, options = {}) ⇒ Object
Set a variable in the current scope.
-
#strinterp(string, file = nil, line = nil) ⇒ Object
Return an interpolated string.
-
#tags ⇒ Object
Return the tags associated with this scope.
-
#to_hash(recursive = true) ⇒ Object
Return a hash containing our variables and their values, optionally (and by default) including the values defined in our parent.
-
#to_s ⇒ Object
Used mainly for logging.
-
#topscope? ⇒ Boolean
Are we the top scope?.
-
#unset_ephemeral_var(level = :all) ⇒ Object
remove ephemeral scope up to level.
-
#unsetvar(var) ⇒ Object
Undefine a variable; only used for testing.
Methods included from Util::Errors
#adderrorcontext, #devfail, #error_context, #exceptwrap, #fail
Methods included from Resource::TypeCollectionHelper
Constructor Details
#initialize(hash = {}) ⇒ Scope
Initialize our new scope. Defaults to having no parent.
125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 |
# File 'lib/puppet/parser/scope.rb', line 125 def initialize(hash = {}) if hash.include?(:namespace) if n = hash[:namespace] @namespaces = [n] end hash.delete(:namespace) else @namespaces = [""] end hash.each { |name, val| method = name.to_s + "=" if self.respond_to? method self.send(method, val) else raise Puppet::DevError, "Invalid scope argument #{name}" end } extend_with_functions_module @tags = [] # 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 # this is actually implemented as a stack, with each ephemeral scope # shadowing the previous one @ephemeral = [ Ephemeral.new ] # 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. @defaults = Hash.new { |dhash,type| dhash[type] = {} } # The table for storing class singletons. This will only actually # be used by top scopes and node scopes. @class_scopes = {} end |
Instance Attribute Details
#base ⇒ Object
Returns the value of attribute base.
22 23 24 |
# File 'lib/puppet/parser/scope.rb', line 22 def base @base end |
#compiler ⇒ Object
Returns the value of attribute compiler.
23 24 25 |
# File 'lib/puppet/parser/scope.rb', line 23 def compiler @compiler end |
#keyword ⇒ Object
Returns the value of attribute keyword.
22 23 24 |
# File 'lib/puppet/parser/scope.rb', line 22 def keyword @keyword end |
#level ⇒ Object
Returns the value of attribute level.
21 22 23 |
# File 'lib/puppet/parser/scope.rb', line 21 def level @level end |
#namespaces ⇒ Object (readonly)
Returns the value of attribute namespaces.
25 26 27 |
# File 'lib/puppet/parser/scope.rb', line 25 def namespaces @namespaces end |
#parent ⇒ Object
Returns the value of attribute parent.
24 25 26 |
# File 'lib/puppet/parser/scope.rb', line 24 def parent @parent end |
#resource ⇒ Object
Returns the value of attribute resource.
21 22 23 |
# File 'lib/puppet/parser/scope.rb', line 21 def resource @resource end |
#source ⇒ Object
Returns the value of attribute source.
21 22 23 |
# File 'lib/puppet/parser/scope.rb', line 21 def source @source end |
#top ⇒ Object
Returns the value of attribute top.
23 24 25 |
# File 'lib/puppet/parser/scope.rb', line 23 def top @top end |
#translated ⇒ Object
Returns the value of attribute translated.
23 24 25 |
# File 'lib/puppet/parser/scope.rb', line 23 def translated @translated end |
Class Method Details
.number?(value) ⇒ Boolean
Is the value a number?, return the correct object or nil if not a number
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/puppet/parser/scope.rb', line 72 def self.number?(value) return nil unless value.is_a?(Fixnum) or value.is_a?(Bignum) or value.is_a?(Float) or value.is_a?(String) if value.is_a?(String) if value =~ /^-?\d+(:?\.\d+|(:?\.\d+)?e\d+)$/ return value.to_f elsif value =~ /^0x[0-9a-f]+$/i return value.to_i(16) elsif value =~ /^0[0-7]+$/ return value.to_i(8) elsif value =~ /^-?\d+$/ return value.to_i else return nil end end # it is one of Fixnum,Bignum or Float value end |
.true?(value) ⇒ Boolean
Is the value true? This allows us to control the definition of truth in one place.
67 68 69 |
# File 'lib/puppet/parser/scope.rb', line 67 def self.true?(value) (value != false and value != "" and value != :undef) end |
Instance Method Details
#add_namespace(ns) ⇒ Object
Add to our list of namespaces.
93 94 95 96 97 98 99 100 |
# File 'lib/puppet/parser/scope.rb', line 93 def add_namespace(ns) return false if @namespaces.include?(ns) if @namespaces == [""] @namespaces = [ns] else @namespaces << ns end end |
#catalog ⇒ Object
A demeterific shortcut to the catalog.
52 53 54 |
# File 'lib/puppet/parser/scope.rb', line 52 def catalog compiler.catalog end |
#class_scope(klass) ⇒ Object
Return the scope associated with a class. This is just here so that subclasses can set their parent scopes to be the scope of their parent class, and it’s also used when looking up qualified variables.
180 181 182 183 184 |
# File 'lib/puppet/parser/scope.rb', line 180 def class_scope(klass) # They might pass in either the class or class name k = klass.respond_to?(:name) ? klass.name : klass @class_scopes[k] || (parent && parent.class_scope(k)) end |
#class_set(name, scope) ⇒ Object
Store the fact that we’ve evaluated a class, and store a reference to the scope in which it was evaluated, so that we can look it up later.
171 172 173 174 |
# File 'lib/puppet/parser/scope.rb', line 171 def class_set(name, scope) return parent.class_set(name,scope) if parent @class_scopes[name] = scope end |
#environment ⇒ Object
Remove this when rebasing
103 104 105 |
# File 'lib/puppet/parser/scope.rb', line 103 def environment compiler.environment end |
#ephemeral?(name) ⇒ Boolean
is name an ephemeral variable?
454 455 456 |
# File 'lib/puppet/parser/scope.rb', line 454 def ephemeral?(name) name =~ /^\d+$/ end |
#ephemeral_from(match, file = nil, line = nil) ⇒ Object
466 467 468 469 470 471 472 473 474 475 |
# File 'lib/puppet/parser/scope.rb', line 466 def ephemeral_from(match, file = nil, line = nil) raise(ArgumentError,"Invalid regex match data") unless match.is_a?(MatchData) new_ephemeral 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 |
#ephemeral_include?(name) ⇒ Boolean
check if name exists in one of the ephemeral scope.
446 447 448 449 450 451 |
# File 'lib/puppet/parser/scope.rb', line 446 def ephemeral_include?(name) @ephemeral.reverse.each do |eph| return true if eph.include?(name) end false end |
#ephemeral_level ⇒ Object
458 459 460 |
# File 'lib/puppet/parser/scope.rb', line 458 def ephemeral_level @ephemeral.size end |
#find_builtin_resource_type(type) ⇒ Object
483 484 485 |
# File 'lib/puppet/parser/scope.rb', line 483 def find_builtin_resource_type(type) Puppet::Type.type(type.to_s.downcase.to_sym) end |
#find_defined_resource_type(type) ⇒ Object
487 488 489 |
# File 'lib/puppet/parser/scope.rb', line 487 def find_defined_resource_type(type) environment.known_resource_types.find_definition(namespaces, type.to_s.downcase) end |
#find_definition(name) ⇒ Object
116 117 118 |
# File 'lib/puppet/parser/scope.rb', line 116 def find_definition(name) known_resource_types.find_definition(namespaces, name) end |
#find_hostclass(name) ⇒ Object
112 113 114 |
# File 'lib/puppet/parser/scope.rb', line 112 def find_hostclass(name) known_resource_types.find_hostclass(namespaces, name) end |
#find_resource_type(type) ⇒ Object
477 478 479 480 481 |
# File 'lib/puppet/parser/scope.rb', line 477 def find_resource_type(type) # It still works fine without the type == 'class' short-cut, but it is a lot slower. return nil if ["class", "node"].include? type.to_s.downcase find_builtin_resource_type(type) || find_defined_resource_type(type) end |
#findresource(string, name = nil) ⇒ Object
120 121 122 |
# File 'lib/puppet/parser/scope.rb', line 120 def findresource(string, name = nil) compiler.findresource(string, name) end |
#host ⇒ Object
Proxy accessors
61 62 63 |
# File 'lib/puppet/parser/scope.rb', line 61 def host @compiler.node.name end |
#lookupdefaults(type) ⇒ Object
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.
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/puppet/parser/scope.rb', line 190 def lookupdefaults(type) values = {} # first collect the values from the parents unless parent.nil? parent.lookupdefaults(type).each { |var,value| values[var] = value } end # then override them with any current values # this should probably be done differently if @defaults.include?(type) @defaults[type].each { |var,value| values[var] = value } end #Puppet.debug "Got defaults for %s: %s" % # [type,values.inspect] values end |
#lookuptype(name) ⇒ Object
Look up a defined type.
214 215 216 |
# File 'lib/puppet/parser/scope.rb', line 214 def lookuptype(name) find_definition(name) || find_hostclass(name) end |
#lookupvar(name, usestring = true) ⇒ Object
Look up a variable. The simplest value search we do. Default to returning an empty string for missing values, but support returning a constant.
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/puppet/parser/scope.rb', line 238 def lookupvar(name, usestring = true) 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 =~ /::/ return lookup_qualified_var(name, usestring) end # We can't use "if table[name]" here because the value might be false if ephemeral_include?(name) or table.include?(name) if usestring and table[name] == :undef return "" else return table[name] end elsif self.parent return parent.lookupvar(name, usestring) elsif usestring return "" else return :undefined end end |
#new_ephemeral ⇒ Object
462 463 464 |
# File 'lib/puppet/parser/scope.rb', line 462 def new_ephemeral @ephemeral.push(Ephemeral.new(@ephemeral.last)) end |
#newscope(options = {}) ⇒ Object
Create a new scope and set these options.
282 283 284 |
# File 'lib/puppet/parser/scope.rb', line 282 def newscope( = {}) compiler.newscope(self, ) end |
#parent_module_name ⇒ Object
286 287 288 289 290 |
# File 'lib/puppet/parser/scope.rb', line 286 def parent_module_name return nil unless @parent return nil unless @parent.source @parent.source.module_name end |
#resolve_type_and_titles(type, titles) ⇒ Object
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 |
# File 'lib/puppet/parser/scope.rb', line 491 def resolve_type_and_titles(type, titles) raise ArgumentError, "titles must be an array" unless titles.is_a?(Array) case type.downcase when "class" # resolve the titles titles = titles.collect do |a_title| hostclass = find_hostclass(a_title) hostclass ? hostclass.name : a_title end when "node" # no-op else # resolve the type resource_type = find_resource_type(type) type = resource_type.name if resource_type end return [type, titles] end |
#scope_path ⇒ Object
Return the list of scopes up to the top scope, ordered with our own first. This is used for looking up variables and defaults.
294 295 296 297 298 299 300 |
# File 'lib/puppet/parser/scope.rb', line 294 def scope_path if parent [self, parent.scope_path].flatten.compact else [self] end end |
#setdefaults(type, params) ⇒ Object
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.
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 |
# File 'lib/puppet/parser/scope.rb', line 305 def setdefaults(type, params) table = @defaults[type] # if we got a single param, it'll be in its own array params = [params] unless params.is_a?(Array) params.each { |param| #Puppet.debug "Default for %s is %s => %s" % # [type,ary[0].inspect,ary[1].inspect] if table.include?(param.name) raise Puppet::ParseError.new("Default already defined for #{type} { #{param.name} }; cannot redefine", param.line, param.file) end table[param.name] = param } end |
#setvar(name, value, options = {}) ⇒ Object
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.
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
# File 'lib/puppet/parser/scope.rb', line 324 def setvar(name,value, = {}) table = [:ephemeral] ? @ephemeral.last : @symtable #Puppet.debug "Setting %s to '%s' at level %s mode append %s" % # [name.inspect,value,self.level, append] if table.include?(name) unless [:append] error = Puppet::ParseError.new("Cannot reassign variable #{name}") else error = Puppet::ParseError.new("Cannot append, variable #{name} is defined in this scope") end error.file = [:file] if [:file] error.line = [:line] if [:line] raise error end unless [:append] table[name] = value else # append case # lookup the value in the scope if it exists and insert the var table[name] = lookupvar(name) # concatenate if string, append if array, nothing for other types case value when Array table[name] += value when Hash raise ArgumentError, "Trying to append to a hash with something which is not a hash is unsupported" unless value.is_a?(Hash) table[name].merge!(value) else table[name] << value end end end |
#strinterp(string, file = nil, line = nil) ⇒ Object
Return an interpolated string.
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 |
# File 'lib/puppet/parser/scope.rb', line 358 def strinterp(string, file = nil, line = nil) # Most strings won't have variables in them. ss = StringScanner.new(string) out = "" while not ss.eos? if ss.scan(/^\$\{((\w*::)*\w+|[0-9]+)\}|^\$([0-9])|^\$((\w*::)*\w+)/) # If it matches the backslash, then just retun the dollar sign. if ss.matched == '\\$' out << '$' else # look the variable up # make sure $0-$9 are lookupable only if ephemeral var = ss[1] || ss[3] || ss[4] if var and var =~ /^[0-9]+$/ and not ephemeral_include?(var) next end out << lookupvar(var).to_s || "" end elsif ss.scan(/^\\(.)/) # Puppet.debug("Got escape: pos:%d; m:%s" % [ss.pos, ss.matched]) case ss[1] when 'n' out << "\n" when 't' out << "\t" when 's' out << " " when '\\' out << '\\' when '$' out << '$' else str = "Unrecognised escape sequence '#{ss.matched}'" str += " in file #{file}" if file str += " at line #{line}" if line Puppet.warning str out << ss.matched end elsif ss.scan(/^\$/) out << '$' elsif ss.scan(/^\\\n/) # an escaped carriage return next else tmp = ss.scan(/[^\\$]+/) # Puppet.debug("Got other: pos:%d; m:%s" % [ss.pos, tmp]) unless tmp error = Puppet::ParseError.new("Could not parse string #{string.inspect}") {:file= => file, :line= => line}.each do |m,v| error.send(m, v) if v end raise error end out << tmp end end out end |
#tags ⇒ Object
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.
419 420 421 |
# File 'lib/puppet/parser/scope.rb', line 419 def resource. end |
#to_hash(recursive = true) ⇒ Object
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.
263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/puppet/parser/scope.rb', line 263 def to_hash(recursive = true) target = parent.to_hash(recursive) if recursive and parent target ||= Hash.new @symtable.keys.each { |name| value = @symtable[name] if value == :undef target.delete(name) else target[name] = value end } target end |
#to_s ⇒ Object
Used mainly for logging
424 425 426 |
# File 'lib/puppet/parser/scope.rb', line 424 def to_s "Scope(#{@resource})" end |
#topscope? ⇒ Boolean
Are we the top scope?
108 109 110 |
# File 'lib/puppet/parser/scope.rb', line 108 def topscope? @level == 1 end |
#unset_ephemeral_var(level = :all) ⇒ Object
remove ephemeral scope up to level
435 436 437 438 439 440 441 442 443 |
# File 'lib/puppet/parser/scope.rb', line 435 def unset_ephemeral_var(level=:all) if level == :all @ephemeral = [ Ephemeral.new ] else (@ephemeral.size - level).times do @ephemeral.pop end end end |
#unsetvar(var) ⇒ Object
Undefine a variable; only used for testing.
429 430 431 432 |
# File 'lib/puppet/parser/scope.rb', line 429 def unsetvar(var) table = ephemeral?(var) ? @ephemeral.last : @symtable table.delete(var) if table.include?(var) end |