Class: Chef::Node::MultiMash
- Defined in:
- lib/chef/node/attribute_collections.rb
Overview
MultiMash
This is a Hash-like object that contains multiple VividMashes in it. Its purpose is so that the user can descend into the mash and delete a subtree from all of the Mash objects (used to delete all values in a subtree from default, force_default, role_default and env_default at the same time). The assignment operator strictly does assignment (does no merging) and works by deleting the subtree and then assigning to the last mash which passed in the initializer.
A lot of the complexity of this class comes from the fact that at any key value some or all of the mashes may walk off their ends and become nil or true or something. The schema may change so that one precidence leve may be ‘true’ object and another may be a VividMash. It is also possible that one or many of them may transition from VividMashes to Hashes or Arrays.
It also supports the case where you may be deleting a key using node.rm in which case if intermediate keys all walk off into nil then you don’t want to be autovivifying keys as you go. On the other hand you may be using node.force_default! in which case you’ll wind up with a []= operator at the end and you want autovivification, so we conditionally have to support either operation.
@todo: can we have an autovivify class that decorates a class that doesn’t autovivify or something so that the code is less awful?
Instance Attribute Summary collapse
-
#mashes ⇒ Object
readonly
Returns the value of attribute mashes.
-
#opts ⇒ Object
readonly
Returns the value of attribute opts.
-
#primary_mash ⇒ Object
readonly
Returns the value of attribute primary_mash.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
Instance Method Summary collapse
- #[](key) ⇒ Object
- #[]=(key, value) ⇒ Object
- #delete(key) ⇒ Object
-
#element(key = nil, *subkeys) ⇒ Object
mash.element(‘foo’, ‘bar’) is the same as mash[‘bar’].
-
#initialize(root, primary_mash, mashes, opts = {}) ⇒ MultiMash
constructor
Initialize with an array of mashes.
Constructor Details
#initialize(root, primary_mash, mashes, opts = {}) ⇒ MultiMash
Initialize with an array of mashes. For the delete return value to work properly the mashes must come from the same attribute level (i.e. all override or all default, but not a mix of both).
248 249 250 251 252 253 254 |
# File 'lib/chef/node/attribute_collections.rb', line 248 def initialize(root, primary_mash, mashes, opts={}) @root = root @primary_mash = primary_mash @mashes = mashes @opts = opts @opts[:autovivify] = true if @opts[:autovivify].nil? end |
Instance Attribute Details
#mashes ⇒ Object (readonly)
Returns the value of attribute mashes.
241 242 243 |
# File 'lib/chef/node/attribute_collections.rb', line 241 def mashes @mashes end |
#opts ⇒ Object (readonly)
Returns the value of attribute opts.
242 243 244 |
# File 'lib/chef/node/attribute_collections.rb', line 242 def opts @opts end |
#primary_mash ⇒ Object (readonly)
Returns the value of attribute primary_mash.
243 244 245 |
# File 'lib/chef/node/attribute_collections.rb', line 243 def primary_mash @primary_mash end |
Instance Method Details
#[](key) ⇒ Object
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/chef/node/attribute_collections.rb', line 256 def [](key) # handle the secondary mashes new_mashes = [] mashes.each do |mash| new_mash = safe_evalute_key(mash, key) # secondary mashes never autovivify so once they fall into nil, we just stop tracking them new_mashes.push(new_mash) unless new_mash.nil? end new_primary_mash = safe_evalute_key(primary_mash, key) if new_primary_mash.nil? && @opts[:autovivify] primary_mash[key] = VividMash.new(root) new_primary_mash = primary_mash[key] end MultiMash.new(root, new_primary_mash, new_mashes, opts) end |
#[]=(key, value) ⇒ Object
275 276 277 278 279 280 281 282 283 284 |
# File 'lib/chef/node/attribute_collections.rb', line 275 def []=(key, value) if primary_mash.nil? # This theoretically should never happen since node#force_default! setter methods will autovivify and # node#rm methods do not end in #[]= operators. raise TypeError, "No autovivification was specified initially on a method chain ending in assignment" end ret = delete(key) primary_mash[key] = value ret end |
#delete(key) ⇒ Object
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 |
# File 'lib/chef/node/attribute_collections.rb', line 293 def delete(key) # the return value is a deep merge which is correct semantics when # merging between attributes on the same level (this would be incorrect # if passed both override and default attributes which would need hash_only # merging). ret = mashes.inject(Mash.new) do |merged, mash| Chef::Mixin::DeepMerge.merge(merged, mash) end ret = Chef::Mixin::DeepMerge.merge(ret, primary_mash) mashes.each do |mash| mash.delete(key) if mash.respond_to?(:delete) end primary_mash.delete(key) if primary_mash.respond_to?(:delete) ret[key] end |
#element(key = nil, *subkeys) ⇒ Object
mash.element(‘foo’, ‘bar’) is the same as mash[‘bar’]
287 288 289 290 291 |
# File 'lib/chef/node/attribute_collections.rb', line 287 def element(key = nil, *subkeys) return self if key.nil? submash = self[key] subkeys.empty? ? submash : submash.element(*subkeys) end |