Class: Chef::Node::Attribute
- Includes:
- Immutablize, Enumerable
- Defined in:
- lib/chef/node/attribute.rb
Overview
Attribute
Attribute implements a nested key-value (Hash) and flat collection (Array) data structure supporting multiple levels of precedence, such that a given key may have multiple values internally, but will only return the highest precedence value when reading.
Constant Summary collapse
- COMPONENTS =
List of the component attribute hashes, in order of precedence, low to high.
[ :@default, :@env_default, :@role_default, :@force_default, :@normal, :@override, :@role_override, :@env_override, :@force_override, :@automatic, ].freeze
- DEFAULT_COMPONENTS =
[ :@default, :@env_default, :@role_default, :@force_default, ]
- OVERRIDE_COMPONENTS =
[ :@override, :@role_override, :@env_override, :@force_override, ]
Instance Attribute Summary collapse
-
#automatic ⇒ Object
return the automatic level attribute component.
-
#deep_merge_cache ⇒ Object
Cache of deep merged values by top-level key.
-
#default ⇒ Object
return the cookbook level default attribute component.
-
#env_default ⇒ Object
return the environment level default attribute component.
-
#env_override ⇒ Object
return the enviroment level override attribute component.
-
#force_default ⇒ Object
return the force_default level attribute component.
-
#force_override ⇒ Object
return the force override level attribute component.
-
#normal ⇒ Object
return the “normal” level attribute component.
-
#override ⇒ Object
return the cookbook level override attribute component.
-
#role_default ⇒ Object
return the role level default attribute component.
-
#role_override ⇒ Object
return the role level override attribute component.
-
#top_level_breadcrumb ⇒ Object
This is used to track the top level key as we descend through method chaining into a precedence level (e.g. node.default[‘bar’]= results in ‘foo’ here).
Instance Method Summary collapse
- #[](key) ⇒ Object
- #[]=(key, value) ⇒ Object
- #combined_default(*path) ⇒ Object
- #combined_override(*path) ⇒ Object
-
#debug_value(*args) ⇒ Object
Debug what’s going on with an attribute.
-
#default!(opts = {}) ⇒ Object
sets default attributes without merging.
-
#force_default!(opts = {}) ⇒ Object
clears from all default precedence levels and then sets force_default.
-
#force_override!(opts = {}) ⇒ Object
clears from all override precedence levels and then sets force_override.
- #has_key?(key) ⇒ Boolean (also: #attribute?, #member?, #include?, #key?)
-
#initialize(normal, default, override, automatic) ⇒ Attribute
constructor
A new instance of Attribute.
- #inspect ⇒ Object
-
#merged_attributes(*path) ⇒ Object
Accessing merged attributes.
- #method_missing(symbol, *args) ⇒ Object
-
#normal!(opts = {}) ⇒ Object
sets normal attributes without merging.
-
#override!(opts = {}) ⇒ Object
sets override attributes without merging.
-
#reset_cache(path = nil) ⇒ Object
(also: #reset)
Invalidate a key in the deep_merge_cache.
-
#rm(*args) ⇒ Object
clears attributes from all precedence levels.
-
#rm_default(*args) ⇒ Object
clears attributes from all default precedence levels.
-
#rm_normal(*args) ⇒ Object
clears attributes from normal precedence.
-
#rm_override(*args) ⇒ Object
clears attributes from all override precedence levels.
- #set_unless? ⇒ Boolean
-
#set_unless_value_present=(setting) ⇒ Object
Enables or disables ‘||=`-like attribute setting.
- #to_s ⇒ Object
Methods included from Immutablize
Methods inherited from Mash
#delete, #except, #fetch, from_hash, #initialize_copy, #merge, #regular_update, #regular_writer, #stringify_keys!, #symbolize_keys, #to_hash, #update, #values_at
Constructor Details
#initialize(normal, default, override, automatic) ⇒ Attribute
Returns a new instance of Attribute.
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/chef/node/attribute.rb', line 189 def initialize(normal, default, override, automatic) @set_unless_present = false @default = VividMash.new(self, default) @env_default = VividMash.new(self, {}) @role_default = VividMash.new(self, {}) @force_default = VividMash.new(self, {}) @normal = VividMash.new(self, normal) @override = VividMash.new(self, override) @role_override = VividMash.new(self, {}) @env_override = VividMash.new(self, {}) @force_override = VividMash.new(self, {}) @automatic = VividMash.new(self, automatic) @merged_attributes = nil @combined_override = nil @combined_default = nil @top_level_breadcrumb = nil @deep_merge_cache = {} end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(symbol, *args) ⇒ Object
463 464 465 466 467 468 469 470 471 472 473 474 475 476 |
# File 'lib/chef/node/attribute.rb', line 463 def method_missing(symbol, *args) if args.empty? if key?(symbol) self[symbol] else raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'" end elsif symbol.to_s =~ /=$/ key_to_set = symbol.to_s[/^(.+)=$/, 1] self[key_to_set] = (args.length == 1 ? args[0] : args) else raise NoMethodError, "Undefined node attribute or method `#{symbol}' on `node'" end end |
Instance Attribute Details
#automatic ⇒ Object
return the automatic level attribute component
174 175 176 |
# File 'lib/chef/node/attribute.rb', line 174 def automatic @automatic end |
#deep_merge_cache ⇒ Object
Cache of deep merged values by top-level key. This is a simple hash which has keys that are the top-level keys of the node object, and we save the computed deep-merge for that key here. There is no cache of subtrees.
187 188 189 |
# File 'lib/chef/node/attribute.rb', line 187 def deep_merge_cache @deep_merge_cache end |
#default ⇒ Object
return the cookbook level default attribute component
147 148 149 |
# File 'lib/chef/node/attribute.rb', line 147 def default @default end |
#env_default ⇒ Object
return the environment level default attribute component
153 154 155 |
# File 'lib/chef/node/attribute.rb', line 153 def env_default @env_default end |
#env_override ⇒ Object
return the enviroment level override attribute component
168 169 170 |
# File 'lib/chef/node/attribute.rb', line 168 def env_override @env_override end |
#force_default ⇒ Object
return the force_default level attribute component
156 157 158 |
# File 'lib/chef/node/attribute.rb', line 156 def force_default @force_default end |
#force_override ⇒ Object
return the force override level attribute component
171 172 173 |
# File 'lib/chef/node/attribute.rb', line 171 def force_override @force_override end |
#normal ⇒ Object
return the “normal” level attribute component
159 160 161 |
# File 'lib/chef/node/attribute.rb', line 159 def normal @normal end |
#override ⇒ Object
return the cookbook level override attribute component
162 163 164 |
# File 'lib/chef/node/attribute.rb', line 162 def override @override end |
#role_default ⇒ Object
return the role level default attribute component
150 151 152 |
# File 'lib/chef/node/attribute.rb', line 150 def role_default @role_default end |
#role_override ⇒ Object
return the role level override attribute component
165 166 167 |
# File 'lib/chef/node/attribute.rb', line 165 def role_override @role_override end |
#top_level_breadcrumb ⇒ Object
This is used to track the top level key as we descend through method chaining into a precedence level (e.g. node.default[‘bar’]= results in ‘foo’ here). We need this so that when we hit the end of a method chain which results in a mutator method that we can invalidate the whole top-level deep merge cache for the top-level key. It is the responsibility of the accessor on the Chef::Node object to reset this to nil, and then the first VividMash#[] call can ||= and set this to the first key we encounter.
182 183 184 |
# File 'lib/chef/node/attribute.rb', line 182 def @top_level_breadcrumb end |
Instance Method Details
#[](key) ⇒ Object
436 437 438 439 440 441 442 443 444 |
# File 'lib/chef/node/attribute.rb', line 436 def [](key) if deep_merge_cache.has_key?(key.to_s) # return the cache of the deep merged values by top-level key deep_merge_cache[key.to_s] else # save all the work of computing node[key] deep_merge_cache[key.to_s] = merged_attributes(key) end end |
#[]=(key, value) ⇒ Object
446 447 448 |
# File 'lib/chef/node/attribute.rb', line 446 def []=(key, value) raise Exceptions::ImmutableAttributeModification end |
#combined_default(*path) ⇒ Object
432 433 434 |
# File 'lib/chef/node/attribute.rb', line 432 def combined_default(*path) immutablize(merge_defaults(path)) end |
#combined_override(*path) ⇒ Object
428 429 430 |
# File 'lib/chef/node/attribute.rb', line 428 def combined_override(*path) immutablize(merge_overrides(path)) end |
#debug_value(*args) ⇒ Object
Debug what’s going on with an attribute. args
is a path spec to the attribute you’re interested in. For example, to debug where the value of ‘node[:default_interface]` is coming from, use:
debug_value(:network, :default_interface).
The return value is an Array of Arrays. The first element is ‘[“set_unless_enabled?”, Boolean]`, which describes whether the attribute collection is in “set_unless” mode. The rest of the Arrays are pairs of `[“precedence_level”, value]`, where precedence level is the component, such as role default, normal, etc. and value is the attribute value set at that precedence level. If there is no value at that precedence level, value
will be the symbol :not_present
.
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 |
# File 'lib/chef/node/attribute.rb', line 224 def debug_value(*args) components = COMPONENTS.map do |component| ivar = instance_variable_get(component) value = args.inject(ivar) do |so_far, key| if so_far == :not_present :not_present elsif so_far.has_key?(key) so_far[key] else :not_present end end [component.to_s.sub(/^@/, ""), value] end [["set_unless_enabled?", @set_unless_present]] + components end |
#default!(opts = {}) ⇒ Object
sets default attributes without merging
380 381 382 383 384 |
# File 'lib/chef/node/attribute.rb', line 380 def default!(opts = {}) # FIXME: do not flush whole cache reset MultiMash.new(self, @default, [], opts) end |
#force_default!(opts = {}) ⇒ Object
clears from all default precedence levels and then sets force_default
401 402 403 404 405 |
# File 'lib/chef/node/attribute.rb', line 401 def force_default!(opts = {}) # FIXME: do not flush whole cache reset MultiMash.new(self, @force_default, [@default, @env_default, @role_default], opts) end |
#force_override!(opts = {}) ⇒ Object
clears from all override precedence levels and then sets force_override
408 409 410 411 412 |
# File 'lib/chef/node/attribute.rb', line 408 def force_override!(opts = {}) # FIXME: do not flush whole cache reset MultiMash.new(self, @force_override, [@override, @env_override, @role_override], opts) end |
#has_key?(key) ⇒ Boolean Also known as: attribute?, member?, include?, key?
450 451 452 453 454 |
# File 'lib/chef/node/attribute.rb', line 450 def has_key?(key) COMPONENTS.any? do |component_ivar| instance_variable_get(component_ivar).has_key?(key) end end |
#inspect ⇒ Object
482 483 484 485 486 |
# File 'lib/chef/node/attribute.rb', line 482 def inspect "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map {|iv| "#{iv}=#{instance_variable_get(iv).inspect}" }.join(", ") << ">" end |
#merged_attributes(*path) ⇒ Object
422 423 424 425 426 |
# File 'lib/chef/node/attribute.rb', line 422 def merged_attributes(*path) # immutablize( merge_all(path) # ) end |
#normal!(opts = {}) ⇒ Object
sets normal attributes without merging
387 388 389 390 391 |
# File 'lib/chef/node/attribute.rb', line 387 def normal!(opts = {}) # FIXME: do not flush whole cache reset MultiMash.new(self, @normal, [], opts) end |
#override!(opts = {}) ⇒ Object
sets override attributes without merging
394 395 396 397 398 |
# File 'lib/chef/node/attribute.rb', line 394 def override!(opts = {}) # FIXME: do not flush whole cache reset MultiMash.new(self, @override, [], opts) end |
#reset_cache(path = nil) ⇒ Object Also known as: reset
Invalidate a key in the deep_merge_cache. If called with nil, or no arg, this will invalidate the entire deep_merge cache. In the case of the user doing node.default[‘bar’]= that eventually results in a call to reset_cache(‘foo’) here. A node.default=hash_thing call must invalidate the entire cache and re-deep-merge the entire node object.
250 251 252 253 254 255 256 |
# File 'lib/chef/node/attribute.rb', line 250 def reset_cache(path = nil) if path.nil? @deep_merge_cache = {} else deep_merge_cache.delete(path.to_s) end end |
#rm(*args) ⇒ Object
clears attributes from all precedence levels
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/chef/node/attribute.rb', line 323 def rm(*args) reset(args[0]) # just easier to compute our retval, rather than collect+merge sub-retvals ret = args.inject(merged_attributes) do |attr, arg| if attr.nil? || !attr.respond_to?(:[]) nil else begin attr[arg] rescue TypeError raise TypeError, "Wrong type in index of attribute (did you use a Hash index on an Array?)" end end end rm_default(*args) rm_normal(*args) rm_override(*args) ret end |
#rm_default(*args) ⇒ Object
clears attributes from all default precedence levels
equivalent to: force_default![‘bar’].delete(‘baz’)
354 355 356 357 |
# File 'lib/chef/node/attribute.rb', line 354 def rm_default(*args) reset(args[0]) remove_from_precedence_level(force_default!(autovivify: false), *args) end |
#rm_normal(*args) ⇒ Object
clears attributes from normal precedence
equivalent to: normal![‘bar’].delete(‘baz’)
362 363 364 365 |
# File 'lib/chef/node/attribute.rb', line 362 def rm_normal(*args) reset(args[0]) remove_from_precedence_level(normal!(autovivify: false), *args) end |
#rm_override(*args) ⇒ Object
clears attributes from all override precedence levels
equivalent to: force_override![‘bar’].delete(‘baz’)
370 371 372 373 |
# File 'lib/chef/node/attribute.rb', line 370 def rm_override(*args) reset(args[0]) remove_from_precedence_level(force_override!(autovivify: false), *args) end |
#set_unless? ⇒ Boolean
488 489 490 |
# File 'lib/chef/node/attribute.rb', line 488 def set_unless? @set_unless_present end |
#set_unless_value_present=(setting) ⇒ Object
Enables or disables ‘||=`-like attribute setting. See, e.g., Node#set_unless
242 243 244 |
# File 'lib/chef/node/attribute.rb', line 242 def set_unless_value_present=(setting) @set_unless_present = setting end |
#to_s ⇒ Object
478 479 480 |
# File 'lib/chef/node/attribute.rb', line 478 def to_s merged_attributes.to_s end |