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.
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 212 213 |
# File 'lib/chef/node/attribute.rb', line 191 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
465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
# File 'lib/chef/node/attribute.rb', line 465 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
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
438 439 440 441 442 443 444 445 446 |
# File 'lib/chef/node/attribute.rb', line 438 def [](key) if deep_merge_cache.has_key?(key) # return the cache of the deep merged values by top-level key deep_merge_cache[key] else # save all the work of computing node[key] deep_merge_cache[key] = merged_attributes(key) end end |
#[]=(key, value) ⇒ Object
448 449 450 |
# File 'lib/chef/node/attribute.rb', line 448 def []=(key, value) raise Exceptions::ImmutableAttributeModification end |
#combined_default(*path) ⇒ Object
434 435 436 |
# File 'lib/chef/node/attribute.rb', line 434 def combined_default(*path) immutablize(merge_defaults(path)) end |
#combined_override(*path) ⇒ Object
430 431 432 |
# File 'lib/chef/node/attribute.rb', line 430 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
.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/chef/node/attribute.rb', line 226 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
382 383 384 385 386 |
# File 'lib/chef/node/attribute.rb', line 382 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
403 404 405 406 407 |
# File 'lib/chef/node/attribute.rb', line 403 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
410 411 412 413 414 |
# File 'lib/chef/node/attribute.rb', line 410 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?
452 453 454 455 456 |
# File 'lib/chef/node/attribute.rb', line 452 def has_key?(key) COMPONENTS.any? do |component_ivar| instance_variable_get(component_ivar).has_key?(key) end end |
#inspect ⇒ Object
480 481 482 483 484 |
# File 'lib/chef/node/attribute.rb', line 480 def inspect "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map{|iv| "#{iv}=#{instance_variable_get(iv).inspect}" }.join(', ') << ">" end |
#merged_attributes(*path) ⇒ Object
424 425 426 427 428 |
# File 'lib/chef/node/attribute.rb', line 424 def merged_attributes(*path) # immutablize( merge_all(path) # ) end |
#normal!(opts = {}) ⇒ Object
sets normal attributes without merging
389 390 391 392 393 |
# File 'lib/chef/node/attribute.rb', line 389 def normal!(opts={}) # FIXME: do not flush whole cache reset MultiMash.new(self, @normal, [], opts) end |
#override!(opts = {}) ⇒ Object
sets override attributes without merging
396 397 398 399 400 |
# File 'lib/chef/node/attribute.rb', line 396 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.
252 253 254 255 256 257 258 |
# File 'lib/chef/node/attribute.rb', line 252 def reset_cache(path = nil) if path.nil? @deep_merge_cache = {} else deep_merge_cache.delete(path) end end |
#rm(*args) ⇒ Object
clears attributes from all precedence levels
325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/chef/node/attribute.rb', line 325 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’)
356 357 358 359 |
# File 'lib/chef/node/attribute.rb', line 356 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’)
364 365 366 367 |
# File 'lib/chef/node/attribute.rb', line 364 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’)
372 373 374 375 |
# File 'lib/chef/node/attribute.rb', line 372 def rm_override(*args) reset(args[0]) remove_from_precedence_level(force_override!(autovivify: false), *args) end |
#set_unless? ⇒ Boolean
486 487 488 |
# File 'lib/chef/node/attribute.rb', line 486 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
244 245 246 |
# File 'lib/chef/node/attribute.rb', line 244 def set_unless_value_present=(setting) @set_unless_present = setting end |