class Nucleon::Config

Base configuration object

The Nucleon::Config class defines a tree data container that can easily be merged and persisted to different mediums.

The configuration is at the core of the Nucleon framework. The configuration allows us to store, lookup, and perform other operations (such as merge) on our class data by treating a subset of class properties as a tree based data structure.

Four main goals with this object:

  1. Centralized property trees for objects

  2. Easy access and management of nested properties

  3. Mergeable objects (deep or shallow merges of tree based data)

  4. Provide basic data translation utilities to sub classes

Global interface

The Nucleon::Config class uses two static mixins that provide a central registry for option groups and property collections.

Option groups are contextualized collections of properties

Property collections are flexible groups of properties that can be logged to file system.

Instance generators

The core configuration object provides a few instance generators that allow for easier initialization of configurations.

Public Class Methods

array(data, default = [], split_string = false) click to toggle source

Ensure a data object is an array.

See:

    # File lib/core/config.rb
904 def self.array(data, default = [], split_string = false)
905   return Util::Data.array(data, default, split_string)
906 end
ensure(config, defaults = {}, force = true, basic_merge = true) click to toggle source

Ensure the return of a Nucleon::Config object based on different inputs.

This method can also initialize defaults for the configuration object if the configurations do not exist yet.

For example: (you will see variants of this pattern everywhere)

def some_method(options = {})
  # Options might be a Config object or Hash?
  config = Config.ensure(options, { :my_property => 'default value' })
  prop   = config[:my_property]
end
  • Parameters

    • nil, Hash, Nucleon::Config

      config Configurations to evaluate and possibly convert

    • Hash

      defaults Configuration defaults that may be overridden by config data

    • Boolean

      force Whether or not to force override of values where types don’t match during merge

    • Boolean

      basic_merge Whether or not to perform a basic merge or deep (recursive) merge

  • Returns

  • Errors

See:

    # File lib/core/config.rb
 93 def self.ensure(config, defaults = {}, force = true, basic_merge = true)
 94   case config
 95   when Nucleon::Config
 96     return config.defaults(defaults, { :force => force, :basic => basic_merge })
 97   when Hash
 98     return new(config, defaults, force, basic_merge)
 99   end
100   return new({}, defaults, force, basic_merge)
101 end
filter(data, method = false) click to toggle source

Run a defined filter on a data object.

This method ensures that a given data object meets some criteria or else an empty value for that type is returned that matches the criteria.

Currently implemented filters:

  1. ::array Ensure result is an array (non arrays are converted)

  2. ::hash Ensure result is a hash (non hashes are converted)

  3. ::string Ensure result is a string (non strings are converted)

  4. ::symbol Ensure result is a symbol (non symbols are converted)

  5. ::test Ensure result is not empty (runs a boolean ::empty? check)

See:

    # File lib/core/config.rb
884 def self.filter(data, method = false)
885   return Util::Data.filter(data, method)
886 end
hash(data, default = {}) click to toggle source

Ensure a data object is a hash.

See:

    # File lib/core/config.rb
922 def self.hash(data, default = {})
923   data = data.export if data.is_a?(Nucleon::Config)
924   return Util::Data.hash(data, default)
925 end
init(options, contexts = [], hierarchy = [], defaults = {}, force = true, basic_merge = true) click to toggle source

Initialize a new configuration object with contextualized defaults from the global configuration option collection.

This method is not really used much within Nucleon itself, but is used to help create the corl gem Puppet interface that forms the provisioner configurations for resource creation based on options defined in Puppet.

This method supports hierarchical lookup of context properties.

Example:

Nucleon::Config::set_options([ :context1, :prefix_context2 ], { :my_property => 'value' })

config = Nucleon::Config.init({ :other_property => 'something' }, :context2, :prefix)
config.export
# {
#   :my_property => 'value',
#   :other_property => 'something'
# }
  • Parameters

    • nil, Hash, Nucleon::Config

      config Configurations to evaluate and possibly convert

    • Array<String, Symbol>, String, Symbol

      contexts Context names to include in list

    • Array<String, Symbol>, String, Symbol

      hierarchy Hierarchy of prefixes to apply to given contexts

    • Hash

      defaults Configuration defaults that may be overridden by config data

    • Boolean

      force Whether or not to force override of values where types don’t match during merge

    • Boolean

      basic_merge Whether or not to perform a basic merge or deep (recursive) merge

  • Returns

  • Errors

See also:

    # File lib/core/config.rb
144 def self.init(options, contexts = [], hierarchy = [], defaults = {}, force = true, basic_merge = true)
145   contexts = contexts(contexts, hierarchy)
146   config   = new(get_options(contexts), defaults, force, basic_merge)
147   config.import(options) unless Util::Data.empty?(options)
148   return config
149 end
init_flat(options, contexts = [], defaults = {}, force = true, basic_merge = true) click to toggle source

Initialize a new configuration object with contextualized defaults from the global configuration option collection (no hierarchical support).

This method is not really used much within Nucleon itself, but is used to help create the corl gem Puppet interface that forms the provisioner configurations for resource creation based on options defined in Puppet.

Example:

Nucleon::Config::set_options([ :context1, :context2 ], { :my_property => 'value' })

config = Nucleon::Config.init_flat({ :other_property => 'something' }, :context2)
config.export
# {
#   :my_property => 'value',
#   :other_property => 'something'
# }
  • Parameters

    • nil, Hash, Nucleon::Config

      config Configurations to evaluate and possibly convert

    • Array<String, Symbol>, String, Symbol

      contexts Context names to include in list

    • Hash

      defaults Configuration defaults that may be overridden by config data

    • Boolean

      force Whether or not to force override of values where types don’t match during merge

    • Boolean

      basic_merge Whether or not to perform a basic merge or deep (recursive) merge

  • Returns

  • Errors

See:

    # File lib/core/config.rb
184 def self.init_flat(options, contexts = [], defaults = {}, force = true, basic_merge = true)
185   return init(options, contexts, [], defaults, force, basic_merge)
186 end
new(data = {}, defaults = {}, force = true, basic_merge = true) click to toggle source

Initialize a new configuration object with given options and defaults.

The defaults are split out from the original options because we have found it handy to have them initialized from two different data objects. Defaults are only set if the original data lacks the default property name.

The configuration object is ultimately designed to provide a starting point for creating distributed objects, which are easily loaded, dumped, and merged to form composite objects.

The configuration serves as the framework base class to all Nucleon plugins, core objects, and a few utilities. This class is the most important object in the entire Nucleon framework, as it is used the most.

Example:

config = Nucleon::Config.new({ :other_property => 'something' }, {
  :my_property => 'default',
  :other_property => 'default'
})
config.export
# {
#   :my_property => 'default',
#   :other_property => 'something'
# }
  • Parameters

    • nil, Hash, Nucleon::Config

      data Configurations to evaluate and possibly convert

    • Hash

      defaults Configuration defaults that may be overridden by config data

    • Boolean

      force Whether or not to force override of values where types don’t match during merge

    • Boolean

      basic_merge Whether or not to perform a basic merge or deep (recursive) merge

  • Returns

  • Errors

See also:

    # File lib/core/config.rb
236 def initialize(data = {}, defaults = {}, force = true, basic_merge = true)
237   @force       = force
238   @basic_merge = basic_merge
239   @properties  = {}
240 
241   if defaults.is_a?(Hash) && ! defaults.empty?
242     defaults = symbol_map(Util::Data.clone(defaults))
243   end
244 
245   case data
246   when Nucleon::Config
247     @properties = Util::Data.merge([ defaults, data.export ], force, basic_merge)
248   when Hash
249     @properties = {}
250     if data.is_a?(Hash)
251       @properties = Util::Data.merge([ defaults, symbol_map(Util::Data.clone(data)) ], force, basic_merge)
252     end
253   else
254     @properties = defaults if defaults.is_a?(Hash)
255   end
256 end
string(data, default = '') click to toggle source

Ensure a data object is a string.

See:

    # File lib/core/config.rb
941 def self.string(data, default = '')
942   return Util::Data.string(data, default)
943 end
string_map(data) click to toggle source

Return hash as a string map.

This method converts all hash keys to strings. Nested hashes are recursively translated as well.

This comes in really handy when performing operations across hashes in Ruby because of the distinction between symbols and strings.

See:

    # File lib/core/config.rb
854 def self.string_map(data)
855   return Util::Data.string_map(data)
856 end
symbol(data, default = :undefined) click to toggle source

Ensure a data object is a symbol.

See:

    # File lib/core/config.rb
959 def self.symbol(data, default = :undefined)
960   return Util::Data.symbol(data, default)
961 end
symbol_map(data) click to toggle source

Return hash as a symbol map.

This method converts all hash keys to symbols. Nested hashes are recursively translated as well.

This comes in really handy when performing operations across hashes in Ruby because of the distinction between symbols and strings.

See:

    # File lib/core/config.rb
812 def self.symbol_map(data)
813   return Util::Data.symbol_map(data)
814 end
test(data) click to toggle source

Test a data object for emptiness and return boolean result.

See:

    # File lib/core/config.rb
977 def self.test(data)
978   return Util::Data.test(data)
979 end

Public Instance Methods

[](name, default = nil, format = false) click to toggle source

Fetch value for key path in the configuration object.

This method is really just to provide an easier interface compatible with Hash access for simpler configuration groups.

  • Parameters

    • String, Symbol

      name Key to fetch

    • ANY

      default Default value is no value is found for key

    • false, Symbol, String

      format Format to filter final returned value or false for none

  • Returns

    • ANY

      Filtered value for key path from configuration object

  • Errors

See:

    # File lib/core/config.rb
459 def [](name, default = nil, format = false)
460   get(name, default, format)
461 end
[]=(name, value) click to toggle source

Set value for key in the configuration object.

This method is really just to provide an easier interface compatible with Hash access for simpler configuration groups.

  • Parameters

    • String, Symbol

      name Key to fetch

    • ANY

      value Value to set for key

  • Returns

    • Void

      Return value thrown away

  • Errors

See:

    # File lib/core/config.rb
631 def []=(name, value)
632   set(name, value)
633 end
append(keys, value) click to toggle source

Append a value for an array key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to modify

    • ANY

      value Value to set for key path

  • Returns

  • Errors

See:

See also:

    # File lib/core/config.rb
572 def append(keys, value)
573   modify(@properties, symbol_array(array(keys).flatten), value, false) do |key, processed_value, existing|
574     if existing.is_a?(Array)
575       [ existing, processed_value ].flatten
576     else
577       [ processed_value ]
578     end
579   end
580   return self
581 end
array(data, default = [], split_string = false) click to toggle source

Ensure a data object is an array.

See:

    # File lib/core/config.rb
913 def array(data, default = [], split_string = false)
914   return self.class.array(data, default, split_string)
915 end
clear() click to toggle source

Clear all properties from the configuration object.

  • Parameters

  • Returns

  • Errors

    # File lib/core/config.rb
667 def clear
668   @properties = {}
669   return self
670 end
defaults(defaults, options = {}) click to toggle source

Set default property values in the configuration object if they don’t exist.

If defaults are given as a string or symbol and the configuration object has a lookup method implemented (corl gem) then the defaults will be dynamically looked up and set.

  • Parameters

    • String, Symbol, Array, Hash

      defaults Data to set as defaults

    • Hash

      options Import options

  • Returns

  • Errors

See:

See also:

    # File lib/core/config.rb
780 def defaults(defaults, options = {})
781   config = Config.new(options).set(:import_type, :default)
782   return import_base(defaults, config)
783 end
delete(keys, default = nil) click to toggle source

Delete key path from the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to remove

    • ANY

      default Default value to return if no existing value found

  • Returns

    • ANY

      Returns default or last value removed from configuration object

  • Errors

See:

See also:

    # File lib/core/config.rb
652 def delete(keys, default = nil)
653   existing = modify(@properties, symbol_array(array(keys).flatten), nil, true)
654   return existing[:value] unless existing[:value].nil?
655   return default
656 end
empty?() click to toggle source

Check whether or not this configuration object is empty.

  • Parameters

  • Returns

    • Boolean

      Whether or not configuration object is empty

  • Errors

    # File lib/core/config.rb
270 def empty?
271   @properties.empty?
272 end
export() click to toggle source

Export properties into a regular hash object (cloned)

  • Parameters

  • Returns

    • Hash

      Returns a hash of all the configuration properties

  • Errors

    # File lib/core/config.rb
794 def export
795   return Util::Data.clone(@properties)
796 end
filter(data, method = false) click to toggle source

Run a defined filter on a data object.

See:

    # File lib/core/config.rb
893 def filter(data, method = false)
894   return self.class.filter(data, method)
895 end
get(keys, default = nil, format = false) click to toggle source

Fetch value for key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to fetch

    • ANY

      default Default value is no value is found for key path

    • false, Symbol, String

      format Format to filter final returned value or false for none

  • Returns

    • ANY

      Filtered value for key path from configuration object

  • Errors

See:

See also:

    # File lib/core/config.rb
437 def get(keys, default = nil, format = false)
438   return fetch(@properties, symbol_array(array(keys).flatten), default, format)
439 end
get_array(keys, default = []) click to toggle source

Fetch filtered array value for key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to fetch

    • Array

      default Default value is no value is found for key path

  • Returns

    • Array

      Filtered array value for key path from configuration object

  • Errors

See:

See also:

    # File lib/core/config.rb
481 def get_array(keys, default = [])
482   return get(keys, default, :array)
483 end
get_hash(keys, default = {}) click to toggle source

Fetch filtered hash value for key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to fetch

    • Hash

      default Default hash value is no value is found for key path

  • Returns

    • Hash

      Filtered hash value for key path from configuration object

  • Errors

See:

See also:

    # File lib/core/config.rb
503 def get_hash(keys, default = {})
504   return get(keys, default, :hash)
505 end
has_key?(keys) click to toggle source

Check whether or not this configuration object has a specific key.

The purpose of this method is to provide a complimentary has_key? method to the Hash class so we can check either interchangeably.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to check

  • Returns

    • Boolean

      Whether or not configuration object has a specific key

  • Errors

See:

    # File lib/core/config.rb
290 def has_key?(keys)
291   get(keys).nil? ? false : true
292 end
hash(data, default = {}) click to toggle source

Ensure a data object is a hash

See:

    # File lib/core/config.rb
932 def hash(data, default = {})
933   return self.class.hash(data, default)
934 end
import(properties, options = {}) click to toggle source

Import new property values into the configuration object. (override)

If properties are given as a string or symbol and the configuration object has a lookup method implemented (corl gem) then the properties will be dynamically looked up and imported.

  • Parameters

    • String, Symbol, Array, Hash

      properties Data to import

    • Hash

      options Import options

  • Returns

  • Errors

See:

    # File lib/core/config.rb
754 def import(properties, options = {})
755   return import_base(properties, options)
756 end
init(keys, default = nil) click to toggle source

Initialize value for key path in the configuration object if one does not exist yet.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to modify

    • ANY

      default Default value to set for key path if it does not exist yet

  • Returns

  • Errors

See:

    # File lib/core/config.rb
523 def init(keys, default = nil)
524   return set(keys, get(keys, default))
525 end
keys() click to toggle source

Return all of the keys for the configuration properties hash.

The purpose of this method is to provide a complimentary keys method to the Hash class so we can return either interchangeably.

  • Parameters

  • Returns

    • Array<Symbol>

      Array of existing configuration properties

  • Errors

    # File lib/core/config.rb
309 def keys
310   @properties.keys
311 end
prepend(keys, value, reverse = false) click to toggle source

Prepend a value to an array key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to modify

    • ANY

      value Value to set for key path

    • Boolean

      reverse Whether or not to reverse any input value arrays given before prepending

  • Returns

  • Errors

See:

See also:

    # File lib/core/config.rb
601 def prepend(keys, value, reverse = false)
602   modify(@properties, symbol_array(array(keys).flatten), value, false) do |key, processed_value, existing|
603     processed_value = processed_value.reverse if reverse && processed_value.is_a?(Array)
604 
605     if existing.is_a?(Array)
606       [ processed_value, existing ].flatten
607     else
608       [ processed_value ]
609     end
610   end
611   return self
612 end
set(keys, value, delete_nil = false) { |key, value, existing| ... } click to toggle source

Set value for key path in the configuration object.

  • Parameters

    • Array<String, Symbol>, String, Symbol

      keys Key path to modify

    • ANY

      value Value to set for key path

    • Boolean

      delete_nil Delete nil value (serves as an internal way to delete properties)

  • Returns

  • Errors

  • Yields

    • Symbol

      key Configuration key to modify

    • ANY

      value New value of configuration key

    • ANY

      existing Existing value being replaced for the configuration key

See:

See also:

    # File lib/core/config.rb
550 def set(keys, value, delete_nil = false, &code) # :yields: key, value, existing
551   modify(@properties, symbol_array(array(keys).flatten), value, delete_nil, &code)
552   return self
553 end
string(data, default = '') click to toggle source

Ensure a data object is a string.

See:

    # File lib/core/config.rb
950 def string(data, default = '')
951   return self.class.string(data, default)
952 end
string_map(data) click to toggle source

Return hash as a string map.

See:

    # File lib/core/config.rb
863 def string_map(data)
864   return self.class.string_map(data)
865 end
symbol(data, default = :undefined) click to toggle source

Ensure a data object is a symbol.

See:

    # File lib/core/config.rb
968 def symbol(data, default = :undefined)
969   return self.class.symbol(data, default)
970 end
symbol_array(array) click to toggle source

Return a symbolized array

  • Parameters

    • Array<String, Symbol>

      array Array of strings or symbols

  • Returns

    • Array<Symbol>

      Returns array of symbols

  • Errors

    # File lib/core/config.rb
835 def symbol_array(array)
836   result = []
837   array.each do |item|
838     result << item.to_sym unless item.nil?
839   end
840   result
841 end
symbol_map(data) click to toggle source

Return hash as a symbol map.

See:

    # File lib/core/config.rb
821 def symbol_map(data)
822   return self.class.symbol_map(data)
823 end
test(data) click to toggle source

Test a data object for emptiness and return boolean result.

See:

    # File lib/core/config.rb
986 def test(data)
987   return self.class.test(data)
988 end

Protected Instance Methods

fetch(data, keys, default = nil, format = false) click to toggle source

Recursively fetch value for key path in the configuration object.

This method serves as a base accessor to the properties that are defined in the central property collection. It is used and built upon by other accessors defined in the class.

Hash data is assumed to already be symbolized.

  • Parameters

    • Hash

      data Configuration property data

    • Array<String, Symbol>, String, Symbol

      keys Key path to fetch

    • ANY

      default Default value is no value is found for key path

    • false, Symbol, String

      format Format to filter final returned value or false for none

  • Returns

    • ANY

      Filtered value for key path from configuration object

  • Errors

See:

    # File lib/core/config.rb
336 def fetch(data, keys, default = nil, format = false)
337   if keys.is_a?(String) || keys.is_a?(Symbol)
338     keys = [ keys ]
339   end
340 
341   keys = keys.flatten.compact
342   key  = keys.shift
343 
344   if data.has_key?(key)
345     value = data[key]
346 
347     if keys.empty?
348       return filter(value, format)
349     else
350       return fetch(data[key], keys, default, format) if data[key].is_a?(Hash)
351     end
352   end
353   return filter(default, format)
354 end
import_base(properties, options = {}) click to toggle source

Base import method for the configuration object.

This method is used to perform merge overrides of new property values and to set defaults if no properties currently exist.

If properties are given as a string or symbol and the configuration object has a lookup method implemented (corl gem) then the properties will be dynamically looked up and imported.

  • Parameters

  • Returns

  • Errors

See also:

    # File lib/core/config.rb
703 def import_base(properties, options = {})
704   config      = Config.new(options, { :force => @force, :basic => @basic_merge }).set(:context, :hash)
705   import_type = config.get(:import_type, :override)
706 
707   properties  = properties.export if properties.is_a?(Nucleon::Config)
708 
709   case properties
710   when Hash
711     data = [ @properties, symbol_map(Util::Data.clone(properties)) ]
712     data = data.reverse if import_type != :override
713 
714     @properties = Util::Data.merge(data, config)
715 
716   when String, Symbol
717     if respond_to?(:lookup)
718       properties = self.class.lookup(properties.to_s, {}, config)
719 
720       data = [ @properties, symbol_map(properties) ]
721       data = data.reverse if import_type != :override
722 
723       @properties = Util::Data.merge(data, config)
724     end
725 
726   when Array
727     Util::Data.clone(properties).each do |item|
728       import_base(item, config)
729     end
730   end
731 
732   return self
733 end
modify(data, keys, value = nil, delete_nil = false) { |key, value, existing| ... } click to toggle source

Modify value for key path in the configuration object.

This method serves as a base modifier to the properties that are defined in the central property collection. It is used and built upon by other modifiers defined in the class.

Hash data is assumed to already be symbolized.

  • Parameters

    • Hash

      data Configuration property data

    • Array<String, Symbol>, String, Symbol

      keys Key path to modify

    • ANY

      value Value to set for key path

    • Boolean

      delete_nil Delete nil value (serves as an internal way to delete properties)

  • Returns

    • ANY

      Existing value for key path from configuration object (before update)

  • Errors

  • Yields

    • Symbol

      key Configuration key to modify

    • ANY

      value New value of configuration key

    • ANY

      existing Existing value being replaced for the configuration key

See:

    # File lib/core/config.rb
385 def modify(data, keys, value = nil, delete_nil = false, &block) # :yields: key, value, existing
386   if keys.is_a?(String) || keys.is_a?(Symbol)
387     keys = [ keys ]
388   end
389 
390   keys     = keys.flatten.compact
391   key      = keys.shift
392   has_key  = data.has_key?(key)
393   existing = {
394     :key   => key,
395     :value => ( has_key ? data[key] : nil )
396   }
397 
398   if keys.empty?
399     if value.nil? && delete_nil
400       data.delete(key) if has_key
401     else
402       value     = symbol_map(value) if value.is_a?(Hash)
403       data[key] = block ? block.call(key, value, existing[:value]) : value
404     end
405   else
406     data[key] = {} unless has_key
407 
408     if data[key].is_a?(Hash)
409       existing = modify(data[key], keys, value, delete_nil, &block)
410     else
411       existing[:value] = nil
412     end
413   end
414 
415   return existing
416 end