Class: Chef::Node::Attribute

Inherits:
Mash show all
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

Instance Method Summary collapse

Methods included from Immutablize

#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.



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
# File 'lib/chef/node/attribute.rb', line 190

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
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(symbol, *args) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/chef/node/attribute.rb', line 353

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

#automaticObject

return the automatic level attribute component



188
189
190
# File 'lib/chef/node/attribute.rb', line 188

def automatic
  @automatic
end

#defaultObject

return the cookbook level default attribute component



151
152
153
# File 'lib/chef/node/attribute.rb', line 151

def default
  @default
end

#env_defaultObject

return the environment level default attribute component



157
158
159
# File 'lib/chef/node/attribute.rb', line 157

def env_default
  @env_default
end

#env_overrideObject

return the enviroment level override attribute component



177
178
179
# File 'lib/chef/node/attribute.rb', line 177

def env_override
  @env_override
end

#force_defaultObject Also known as: default!

return the force_default level attribute component



160
161
162
# File 'lib/chef/node/attribute.rb', line 160

def force_default
  @force_default
end

#force_overrideObject Also known as: override!

return the force override level attribute component



180
181
182
# File 'lib/chef/node/attribute.rb', line 180

def force_override
  @force_override
end

#normalObject

return the “normal” level attribute component



168
169
170
# File 'lib/chef/node/attribute.rb', line 168

def normal
  @normal
end

#overrideObject

return the cookbook level override attribute component



171
172
173
# File 'lib/chef/node/attribute.rb', line 171

def override
  @override
end

#role_defaultObject

return the role level default attribute component



154
155
156
# File 'lib/chef/node/attribute.rb', line 154

def role_default
  @role_default
end

#role_overrideObject

return the role level override attribute component



174
175
176
# File 'lib/chef/node/attribute.rb', line 174

def role_override
  @role_override
end

Instance Method Details

#[](key) ⇒ Object



332
333
334
# File 'lib/chef/node/attribute.rb', line 332

def [](key)
  merged_attributes[key]
end

#[]=(key, value) ⇒ Object



336
337
338
# File 'lib/chef/node/attribute.rb', line 336

def []=(key, value)
  merged_attributes[key] = value
end

#combined_defaultObject



328
329
330
# File 'lib/chef/node/attribute.rb', line 328

def combined_default
  @combined_default ||= immutablize(merge_defaults)
end

#combined_overrideObject



324
325
326
# File 'lib/chef/node/attribute.rb', line 324

def combined_override
  @combined_override ||= immutablize(merge_overrides)
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.



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/chef/node/attribute.rb', line 223

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

#has_key?(key) ⇒ Boolean Also known as: attribute?, member?, include?, key?

Returns:

  • (Boolean)


340
341
342
343
344
# File 'lib/chef/node/attribute.rb', line 340

def has_key?(key)
  COMPONENTS.any? do |component_ivar|
    instance_variable_get(component_ivar).has_key?(key)
  end
end

#inspectObject



368
369
370
371
372
# File 'lib/chef/node/attribute.rb', line 368

def inspect
  "#<#{self.class} " << (COMPONENTS + [:@merged_attributes, :@properties]).map{|iv|
    "#{iv}=#{instance_variable_get(iv).inspect}"
  }.join(', ') << ">"
end

#merged_attributesObject



314
315
316
317
318
319
320
321
322
# File 'lib/chef/node/attribute.rb', line 314

def merged_attributes
  @merged_attributes ||= begin
                           components = [merge_defaults, @normal, merge_overrides, @automatic]
                           resolved_attrs = components.inject(Mash.new) do |merged, component|
                             Chef::Mixin::DeepMerge.hash_only_merge(merged, component)
                           end
                           immutablize(resolved_attrs)
                         end
end

#reset_cacheObject Also known as: reset

Clears merged_attributes, which will cause it to be recomputed on the next access.



247
248
249
250
251
252
# File 'lib/chef/node/attribute.rb', line 247

def reset_cache
  @merged_attributes = nil
  @combined_default  = nil
  @combined_override = nil
  @set_unless_present = false
end

#set_unless?Boolean

Returns:

  • (Boolean)


374
375
376
# File 'lib/chef/node/attribute.rb', line 374

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



241
242
243
# File 'lib/chef/node/attribute.rb', line 241

def set_unless_value_present=(setting)
  @set_unless_present = setting
end