def modify(data, keys, value = nil, delete_nil = false, &block) # :yields: key, value, existing
    if keys.is_a?(String) || keys.is_a?(Symbol)
      keys = [ keys ]
    end

    keys     = keys.flatten.compact
    key      = keys.shift
    has_key  = data.has_key?(key)
    existing = {
      :key   => key,
      :value => ( has_key ? data[key] : nil )
    }

    if keys.empty?
      if value.nil? && delete_nil
        data.delete(key) if has_key
      else
        value     = symbol_map(value) if value.is_a?(Hash)
        data[key] = block ? block.call(key, value, existing[:value]) : value
      end
    else
      data[key] = {} unless has_key

      if data[key].is_a?(Hash)
        existing = modify(data[key], keys, value, delete_nil, &block)
      else
        existing[:value] = nil
      end
    end

    return existing
  end
def modify(data, keys, value = nil, delete_nil = false, &block) # :yields: key, value, existing
    if keys.is_a?(String) || keys.is_a?(Symbol)
      keys = [ keys ]
    end

    keys     = keys.flatten.compact
    key      = keys.shift
    has_key  = data.has_key?(key)
    existing = {
      :key   => key,
      :value => ( has_key ? data[key] : nil )
    }

    if keys.empty?
      if value.nil? && delete_nil
        data.delete(key) if has_key
      else
        value     = symbol_map(value) if value.is_a?(Hash)
        data[key] = block ? block.call(key, value, existing[:value]) : value
      end
    else
      data[key] = {} unless has_key

      if data[key].is_a?(Hash)
        existing = modify(data[key], keys, value, delete_nil, &block)
      else
        existing[:value] = nil
      end
    end

    return existing
  end
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:
 - #symbol_map
 - Nucleon::Util::Data::symbol_map