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!(*args) ⇒ Object
sets default attributes without merging.
- #default_unless(*args) ⇒ Object
- #exist?(*path) ⇒ Boolean
-
#force_default!(*args) ⇒ Object
clears from all default precedence levels and then sets force_default.
-
#force_override!(*args) ⇒ 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!(*args) ⇒ Object
sets normal attributes without merging.
- #normal_unless(*args) ⇒ Object
-
#override!(*args) ⇒ Object
sets override attributes without merging.
- #override_unless(*args) ⇒ Object
-
#read(*path) ⇒ Object
method-style access to attributes.
- #read!(*path) ⇒ Object
-
#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(*args) ⇒ Object
- #to_s ⇒ Object
- #unlink(level, *path) ⇒ Object
- #unlink!(level, *path) ⇒ Object
- #write(level, *args, &block) ⇒ Object
- #write!(level, *args, &block) ⇒ 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.
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 191 def initialize(normal, default, override, automatic) @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
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/chef/node/attribute.rb', line 516 def method_missing(symbol, *args) if symbol == :to_ary merged_attributes.send(symbol, *args) elsif args.empty? Chef.log_deprecation %q{method access to node attributes (node.foo.bar) is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]["bar"])} if key?(symbol) self[symbol] else raise NoMethodError, "Undefined method or attribute `#{symbol}' on `node'" end elsif symbol.to_s =~ /=$/ Chef.log_deprecation %q{method setting of node attributes (node.foo="bar") is deprecated and will be removed in Chef 13, please use bracket syntax (node["foo"]="bar")} 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
176 177 178 |
# File 'lib/chef/node/attribute.rb', line 176 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.
189 190 191 |
# File 'lib/chef/node/attribute.rb', line 189 def deep_merge_cache @deep_merge_cache end |
#default ⇒ Object
return the cookbook level default attribute component
149 150 151 |
# File 'lib/chef/node/attribute.rb', line 149 def default @default end |
#env_default ⇒ Object
return the environment level default attribute component
155 156 157 |
# File 'lib/chef/node/attribute.rb', line 155 def env_default @env_default end |
#env_override ⇒ Object
return the enviroment level override attribute component
170 171 172 |
# File 'lib/chef/node/attribute.rb', line 170 def env_override @env_override end |
#force_default ⇒ Object
return the force_default level attribute component
158 159 160 |
# File 'lib/chef/node/attribute.rb', line 158 def force_default @force_default end |
#force_override ⇒ Object
return the force override level attribute component
173 174 175 |
# File 'lib/chef/node/attribute.rb', line 173 def force_override @force_override end |
#normal ⇒ Object
return the “normal” level attribute component
161 162 163 |
# File 'lib/chef/node/attribute.rb', line 161 def normal @normal end |
#override ⇒ Object
return the cookbook level override attribute component
164 165 166 |
# File 'lib/chef/node/attribute.rb', line 164 def override @override end |
#role_default ⇒ Object
return the role level default attribute component
152 153 154 |
# File 'lib/chef/node/attribute.rb', line 152 def role_default @role_default end |
#role_override ⇒ Object
return the role level override attribute component
167 168 169 |
# File 'lib/chef/node/attribute.rb', line 167 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.
184 185 186 |
# File 'lib/chef/node/attribute.rb', line 184 def @top_level_breadcrumb end |
Instance Method Details
#[](key) ⇒ Object
489 490 491 492 493 494 495 496 497 |
# File 'lib/chef/node/attribute.rb', line 489 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
499 500 501 |
# File 'lib/chef/node/attribute.rb', line 499 def []=(key, value) raise Exceptions::ImmutableAttributeModification end |
#combined_default(*path) ⇒ Object
464 465 466 |
# File 'lib/chef/node/attribute.rb', line 464 def combined_default(*path) immutablize(merge_defaults(path)) end |
#combined_override(*path) ⇒ Object
460 461 462 |
# File 'lib/chef/node/attribute.rb', line 460 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 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
.
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 |
# File 'lib/chef/node/attribute.rb', line 222 def debug_value(*args) 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 end |
#default!(*args) ⇒ Object
sets default attributes without merging
-
this API autovivifies (and cannot trainwreck)
377 378 379 380 |
# File 'lib/chef/node/attribute.rb', line 377 def default!(*args) return Decorator::Unchain.new(self, :default!) unless args.length > 0 write(:default, *args) end |
#default_unless(*args) ⇒ Object
473 474 475 476 |
# File 'lib/chef/node/attribute.rb', line 473 def default_unless(*args) return Decorator::Unchain.new(self, :default_unless) unless args.length > 0 write(:default, *args) if read(*args[0...-1]).nil? end |
#exist?(*path) ⇒ Boolean
426 427 428 |
# File 'lib/chef/node/attribute.rb', line 426 def exist?(*path) merged_attributes.exist?(*path) end |
#force_default!(*args) ⇒ Object
clears from all default precedence levels and then sets force_default
-
this API autovivifies (and cannot trainwreck)
401 402 403 404 405 406 |
# File 'lib/chef/node/attribute.rb', line 401 def force_default!(*args) return Decorator::Unchain.new(self, :force_default!) unless args.length > 0 value = args.pop rm_default(*args) write(:force_default, *args, value) end |
#force_override!(*args) ⇒ Object
clears from all override precedence levels and then sets force_override
409 410 411 412 413 414 |
# File 'lib/chef/node/attribute.rb', line 409 def force_override!(*args) return Decorator::Unchain.new(self, :force_override!) unless args.length > 0 value = args.pop rm_override(*args) write(:force_override, *args, value) end |
#has_key?(key) ⇒ Boolean Also known as: attribute?, member?, include?, key?
503 504 505 506 507 |
# File 'lib/chef/node/attribute.rb', line 503 def has_key?(key) COMPONENTS.any? do |component_ivar| instance_variable_get(component_ivar).has_key?(key) end end |
#inspect ⇒ Object
539 540 541 542 543 |
# File 'lib/chef/node/attribute.rb', line 539 def inspect "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map {|iv| "#{iv}=#{instance_variable_get(iv).inspect}" }.join(", ") << ">" end |
#merged_attributes(*path) ⇒ Object
454 455 456 457 458 |
# File 'lib/chef/node/attribute.rb', line 454 def merged_attributes(*path) # immutablize( merge_all(path) # ) end |
#normal!(*args) ⇒ Object
sets normal attributes without merging
-
this API autovivifies (and cannot trainwreck)
385 386 387 388 |
# File 'lib/chef/node/attribute.rb', line 385 def normal!(*args) return Decorator::Unchain.new(self, :normal!) unless args.length > 0 write(:normal, *args) end |
#normal_unless(*args) ⇒ Object
468 469 470 471 |
# File 'lib/chef/node/attribute.rb', line 468 def normal_unless(*args) return Decorator::Unchain.new(self, :normal_unless) unless args.length > 0 write(:normal, *args) if read(*args[0...-1]).nil? end |
#override!(*args) ⇒ Object
sets override attributes without merging
-
this API autovivifies (and cannot trainwreck)
393 394 395 396 |
# File 'lib/chef/node/attribute.rb', line 393 def override!(*args) return Decorator::Unchain.new(self, :override!) unless args.length > 0 write(:override, *args) end |
#override_unless(*args) ⇒ Object
478 479 480 481 |
# File 'lib/chef/node/attribute.rb', line 478 def override_unless(*args) return Decorator::Unchain.new(self, :override_unless) unless args.length > 0 write(:override, *args) if read(*args[0...-1]).nil? end |
#read(*path) ⇒ Object
method-style access to attributes
418 419 420 |
# File 'lib/chef/node/attribute.rb', line 418 def read(*path) merged_attributes.read(*path) end |
#read!(*path) ⇒ Object
422 423 424 |
# File 'lib/chef/node/attribute.rb', line 422 def read!(*path) merged_attributes.read!(*path) 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.
242 243 244 245 246 247 248 |
# File 'lib/chef/node/attribute.rb', line 242 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
315 316 317 318 319 320 321 |
# File 'lib/chef/node/attribute.rb', line 315 def rm(*args) with_deep_merged_return_value(self, *args) do rm_default(*args) rm_normal(*args) rm_override(*args) end end |
#rm_default(*args) ⇒ Object
clears attributes from all default precedence levels
similar to: force_default![‘bar’].delete(‘baz’)
-
does not autovivify
-
does not trainwreck if interior keys do not exist
328 329 330 331 332 333 334 335 |
# File 'lib/chef/node/attribute.rb', line 328 def rm_default(*args) with_deep_merged_return_value(combined_default, *args) do default.unlink(*args) role_default.unlink(*args) env_default.unlink(*args) force_default.unlink(*args) end end |
#rm_normal(*args) ⇒ Object
clears attributes from normal precedence
equivalent to: normal![‘bar’].delete(‘baz’)
-
does not autovivify
-
does not trainwreck if interior keys do not exist
342 343 344 |
# File 'lib/chef/node/attribute.rb', line 342 def rm_normal(*args) normal.unlink(*args) end |
#rm_override(*args) ⇒ Object
clears attributes from all override precedence levels
equivalent to: force_override![‘bar’].delete(‘baz’)
-
does not autovivify
-
does not trainwreck if interior keys do not exist
351 352 353 354 355 356 357 358 |
# File 'lib/chef/node/attribute.rb', line 351 def rm_override(*args) with_deep_merged_return_value(combined_override, *args) do override.unlink(*args) role_override.unlink(*args) env_override.unlink(*args) force_override.unlink(*args) end end |
#set_unless(*args) ⇒ Object
483 484 485 486 487 |
# File 'lib/chef/node/attribute.rb', line 483 def set_unless(*args) Chef.log_deprecation("node.set_unless is deprecated and will be removed in Chef 14, please use node.default_unless/node.override_unless (or node.normal_unless if you really need persistence)") return Decorator::Unchain.new(self, :default_unless) unless args.length > 0 write(:normal, *args) if read(*args[0...-1]).nil? end |
#to_s ⇒ Object
535 536 537 |
# File 'lib/chef/node/attribute.rb', line 535 def to_s merged_attributes.to_s end |
#unlink(level, *path) ⇒ Object
438 439 440 |
# File 'lib/chef/node/attribute.rb', line 438 def unlink(level, *path) self.send(level).unlink(*path) end |
#unlink!(level, *path) ⇒ Object
442 443 444 |
# File 'lib/chef/node/attribute.rb', line 442 def unlink!(level, *path) self.send(level).unlink!(*path) end |
#write(level, *args, &block) ⇒ Object
430 431 432 |
# File 'lib/chef/node/attribute.rb', line 430 def write(level, *args, &block) self.send(level).write(*args, &block) end |
#write!(level, *args, &block) ⇒ Object
434 435 436 |
# File 'lib/chef/node/attribute.rb', line 434 def write!(level, *args, &block) self.send(level).write!(*args, &block) end |