Module: Collapsium::RecursiveMerge

Extended by:
ViralCapabilities
Included in:
UberHash
Defined in:
lib/collapsium/recursive_merge.rb

Overview

Provides recursive merge functions for hashes.

Constant Summary

Constants included from ViralCapabilities

ViralCapabilities::DEFAULT_ANCESTORS, ViralCapabilities::ENHANCED_MARKER, ViralCapabilities::READ_METHODS, ViralCapabilities::WRITE_METHODS

Constants included from Support::Methods

Support::Methods::BUILTINS, Support::Methods::WRAPPER_HASH

Class Method Summary collapse

Instance Method Summary collapse

Methods included from ViralCapabilities

call_virality, copy_mods, enhance, enhance_array_value, enhance_hash_value, enhance_value, extended, extended, included, included, prepended, prepended, set_ancestors

Methods included from Support::Methods

builtins, loop_detected?, repeated, #resolve_helpers, #wrap_method, wrappers

Class Method Details

.merged_keys(the_self, v1, v2) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/collapsium/recursive_merge.rb', line 52

def merged_keys(the_self, v1, v2)
  keys = (v1.keys + v2.keys).uniq
  if the_self.singleton_class.ancestors.include?(IndifferentAccess)
    # We want to preserve each Hash's key types as much as possible, but
    # IndifferentAccess doesn't care about types. We can use it to figure out
    # which unique keys only exist in v2.
    only_v2 = IndifferentAccess.unique_keys(keys) \
              - IndifferentAccess.unique_keys(v1.keys)

    # At this point, IndifferentAccess may have modified the key types
    # in only_v2. To get back the original types, we can iterate the
    # Hash and remember all keys that are indifferently contained in
    # only_v2.
    original_types = []
    v2.each do |key, _|
      unique = IndifferentAccess.unique_keys([key])
      if only_v2.include?(unique[0])
        original_types << key
      end
    end
    keys = v1.keys + original_types
  end
  return keys
end

.merger(the_self, v1, v2, overwrite) ⇒ Object



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/collapsium/recursive_merge.rb', line 77

def merger(the_self, v1, v2, overwrite)
  if v1.is_a? Hash and v2.is_a? Hash
    v1 = ViralCapabilities.enhance_value(the_self, v1)
    v2 = ViralCapabilities.enhance_value(the_self, v2)

    # IndifferentAccess has its own idea of which keys are unique, so if
    # we use it, we must consult it.
    keys = merged_keys(the_self, v1, v2)
    new_val = ViralCapabilities.enhance_value(the_self, {})
    keys.each do |key|
      v1_inner = v1[key]
      v2_inner = v2[key]
      if not v1_inner.nil? and not v2_inner.nil?
        new_val[key] = RecursiveMerge.merger(the_self, v1_inner, v2_inner,
                                             overwrite)
      elsif not v1_inner.nil?
        # Nothing to do, we have v1[key]
        new_val[key] = v1_inner
      else
        # v2.key?(key) is true
        new_val[key] = v2_inner
      end
    end

    v1.replace(new_val)
    return v1
  elsif v1.is_a? Array and v2.is_a? Array
    return v1 + v2
  end

  if overwrite
    return v2
  end
  return v1
end

Instance Method Details

#recursive_merge(other, overwrite = true) ⇒ Object

Same as ‘dup.recursive_merge!`

Parameters:

  • other (Hash)

    the hash to merge into ‘:self`

  • overwrite (Boolean) (defaults to: true)

    see method description.



47
48
49
# File 'lib/collapsium/recursive_merge.rb', line 47

def recursive_merge(other, overwrite = true)
  return dup.recursive_merge!(other, overwrite)
end

#recursive_merge!(other, overwrite = true) ⇒ Object

Recursively merge ‘:other` into this Hash.

This starts by merging the leaf-most Hash entries. Arrays are merged by addition.

For everything that’s neither Hash or Array, if the ‘:overwrite` parameter is true, the entry from `:other` is used. Otherwise the entry from `:self` is used.

Parameters:

  • other (Hash)

    the hash to merge into ‘:self`

  • overwrite (Boolean) (defaults to: true)

    see method description.



32
33
34
35
36
37
38
39
40
41
42
# File 'lib/collapsium/recursive_merge.rb', line 32

def recursive_merge!(other, overwrite = true)
  if other.nil?
    return self
  end

  # We can't call merge! because that will only be invoked for keys that
  # are missing, and default_proc doesn't seem to be used there. So we need
  # to call a custom merge function.
  new_self = RecursiveMerge.merger(self, self, other, overwrite)
  replace(new_self)
end