module EasyFormat

Public Instance Methods

deep_diff(base, comparison) click to toggle source

Deep diff two structures For a hash, returns keys found in both hashes where the values don't match. If a key exists in the base, but NOT the comparison, it is NOT considered a difference so that it can be a one way comparison. For an array, returns an array with values found in the comparison array but not in the base array.

# File lib/easy_format/data_type_helper.rb, line 116
def deep_diff(base, comparison)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  if base.nil? # if base is nil, entire comparison object is different
    return comparison.is_a?(Hash) ? comparison.dup : comparison
  end

  case comparison
  when nil
    {}
  when ::Hash
    differing_values = {}
    base = base.dup
    comparison.each do |src_key, src_value|
      difference = deep_diff(base[src_key], src_value)
      differing_values[src_key] = difference unless difference == :no_diff
    end
    differing_values.reject { |_k, v| v.is_a?(::Hash) && v.empty? }
  when ::Array
    difference = comparison - base
    difference.empty? ? :no_diff : difference
  else
    base == comparison ? :no_diff : comparison
  end
end
deep_diff_by_key(base, comparison, keep_values: false) click to toggle source

Identifies what keys in the comparison hash are missing from base hash. Optionally keep the values from the comparison hash, otherwise assigns the missing keys a value of :missing_key

# File lib/easy_format/data_type_helper.rb, line 99
def deep_diff_by_key(base, comparison, keep_values: false)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  missing_keys = {}
  if comparison.is_a?(::Hash)
    compared_keys = base.is_a?(::Hash) ? comparison.keys - base.keys : comparison.keys # Determine what keys the comparison has that the base doesn't
    compared_keys.each { |k| missing_keys[k] = keep_values ? comparison[k] : :missing_key } # Save the missing keys
    comparison.each do |k, v|
      missing_keys[k] = deep_diff_by_key(base[k], v, keep_values: keep_values) if v.is_a?(::Hash) # Recurse to find more missing keys if the hash goes deeper
    end
  end
  missing_keys.reject { |_k, v| v.is_a?(::Hash) && v.empty? } # Remove any empty hashes as there were no missing keys in them
end
deep_merge(base, override, boolean_or: false, left_outer_join_depth: 0) click to toggle source

Deep merge two structures

boolean_or: use a boolean || operator on the base and override if they are not a Hash or Array
Left outer join: Only merge keys that already exist in the base
# File lib/easy_format/data_type_helper.rb, line 68
def deep_merge(base, override, boolean_or: false, left_outer_join_depth: 0)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  left_outer_join_depth -= 1 # decrement left_outer_join_depth for recursion
  if base.nil?
    return nil if left_outer_join_depth >= 0
    return override.is_a?(Hash) ? override.dup : override
  end

  case override
  when nil
    base = base.dup if base.is_a?(Hash) # duplicate hash to avoid modification by reference issues
    base # if override doesn't exist, simply return the existing value
  when ::Hash
    base = base.dup
    override.each do |src_key, src_value|
      next if base[src_key].nil? && left_outer_join_depth >= 0 # if this is a left outer join and the key does not exist in the base, skip it
      base[src_key] = base[src_key] ? deep_merge(base[src_key], src_value, boolean_or: boolean_or, left_outer_join_depth: left_outer_join_depth) : src_value # Recurse if both are Hash
    end
    base
  when ::Array
    base |= override
    base
  when ::String, ::Integer, ::Time, ::TrueClass, ::FalseClass
    boolean_or ? base || override : override
  else
    throw "Implementation for deep merge of type #{override.class} is missing."
  end
end
deep_reject(hash) { |k, v| ... } click to toggle source

Reject hash keys however deep they are. Provide a block and if it evaluates to true for a given key/value pair, it will be rejected.

# File lib/easy_format/data_type_helper.rb, line 142
def deep_reject(hash, &block)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  hash.each_with_object({}) do |(k, v), h|
    next if yield(k, v) # reject the current key/value pair by skipping it if the block given evaluates to true
    h[k] = v.is_a?(::Hash) ? deep_reject(v, &block) : v # recursively go up the hash tree or keep the value if it's not a hash.
  end
end
deep_reject_by_hash(base, comparison) click to toggle source

Deep diff two Hashes Remove any keys in the first hash also contained in the second hash If a key exists in the base, but NOT the comparison, it is kept.

# File lib/easy_format/data_type_helper.rb, line 153
def deep_reject_by_hash(base, comparison)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  return nil if base.nil?

  case comparison
  when ::Hash
    return base unless base.is_a?(::Hash) # if base is not a hash but the comparison is, return the base
    base = base.dup
    comparison.each do |src_key, src_value|
      base[src_key] = deep_reject_by_hash(base[src_key], src_value) # recurse to the leaf
      base[src_key] = nil if base[src_key].is_a?(::Hash) && base[src_key].empty? # set leaves to nil if they are empty hashes
    end
    base.reject { |_k, v| v.nil? } # reject any leaves that were set to nil
  else # rubocop:disable Style/EmptyElse - for clarity
    nil # drop the value if we have reached a leaf in the comparison hash
  end
end
reject_keys_with_nil_values(base) click to toggle source
# File lib/easy_format/data_type_helper.rb, line 171
def reject_keys_with_nil_values(base)
  EasyFormat::Hash.log_deprecation('EasyFormat', __method__)
  deep_reject(base) { |_k, v| v.nil? }
end
validate_parameters(method, method_binding, optional_parameters = []) click to toggle source

Optional parameters should be an array of symbols or strings rubocop:disable Security/Eval

# File lib/easy_format/validation.rb, line 6
def validate_parameters(method, method_binding, optional_parameters = [])
  method.parameters.each do |parameter|
    parameter_name = parameter.last.to_s
    next if optional_parameters.any? { |o| o.to_s.casecmp(parameter_name) == 0 }
    parameter_value = eval(parameter_name, method_binding)
    raise "#{parameter_name} is a required parameter for #{caller[2][/`.*'/][1..-2]}!" if parameter_value.nil? || (parameter_value.respond_to?(:empty?) && parameter_value.empty?)
  end
end