Class: Hash

Inherits:
Object
  • Object
show all
Defined in:
lib/bblib/core/hash_path/hash_path.rb,
lib/bblib/core/util/hash.rb,
lib/bblib/core/classes/hash_struct.rb

Overview

Monkey patches

Direct Known Subclasses

BBLib::HashStruct

Instance Method Summary collapse

Instance Method Details

#deep_merge(with, merge_arrays: true, overwrite: true, uniq: false) ⇒ Object

Merges with another hash but also merges all nested hashes and arrays/values.



4
5
6
7
8
9
10
11
12
13
14
15
# File 'lib/bblib/core/util/hash.rb', line 4

def deep_merge(with, merge_arrays: true, overwrite: true, uniq: false)
  merger = proc do |_k, v1, v2|
    if BBLib.are_all?(Hash, v1, v2)
      v1.merge(v2, &merger)
    elsif merge_arrays && BBLib.are_all?(Array, v1, v2)
      uniq ? (v1 + v2).uniq : v1 + v2
    else
      overwrite || v1 == v2 ? v2 : (uniq ? [v1, v2].flatten.uniq : [v1, v2].flatten)
    end
  end
  merge(with, &merger)
end

#deep_merge!(*args) ⇒ Object

In place version of deep_merge



18
19
20
# File 'lib/bblib/core/util/hash.rb', line 18

def deep_merge!(*args)
  replace deep_merge(*args)
end

#diff(hash) ⇒ Object

Displays all of the differences between this hash and another. Checks both key and value pairs.



65
66
67
# File 'lib/bblib/core/util/hash.rb', line 65

def diff(hash)
  to_a.diff(hash.to_a).to_h
end

#dive(*keys) ⇒ Object

Returns all matching values with a specific key (or keys) recursively within a Hash (including nested Arrays)



70
71
72
73
74
75
76
77
# File 'lib/bblib/core/util/hash.rb', line 70

def dive(*keys)
  matches = []
  each do |k, v|
    matches << v if keys.any? { |key| (key.is_a?(Regexp) ? key =~ k : key == k) }
    matches += v.dive(*keys) if v.respond_to?(:dive)
  end
  matches
end

#except(*args) ⇒ Object

Returns a version of the hash with the specified keys removed.



135
136
137
# File 'lib/bblib/core/util/hash.rb', line 135

def except(*args)
  reject { |k, _v| args.include?(k) }
end

#expandObject

Expands keys in a hash using a delimiter. Opposite of squish.



121
122
123
124
125
126
127
# File 'lib/bblib/core/util/hash.rb', line 121

def expand
  {}.to_tree_hash.tap do |hash|
    each do |k, v|
      hash.bridge(k => v)
    end
  end.value
end

#hash_path(*path) ⇒ Object Also known as: hpath



109
110
111
# File 'lib/bblib/core/hash_path/hash_path.rb', line 109

def hash_path(*path)
  BBLib.hash_path self, *path
end

#hash_path_copy(*paths) ⇒ Object Also known as: hpath_copy



117
118
119
# File 'lib/bblib/core/hash_path/hash_path.rb', line 117

def hash_path_copy(*paths)
  BBLib.hash_path_copy self, *paths
end

#hash_path_copy_to(to, *paths) ⇒ Object Also known as: hpath_copy_to



121
122
123
# File 'lib/bblib/core/hash_path/hash_path.rb', line 121

def hash_path_copy_to(to, *paths)
  BBLib.hash_path_copy_to self, to, *paths
end

#hash_path_delete(*paths) ⇒ Object Also known as: hpath_delete



125
126
127
# File 'lib/bblib/core/hash_path/hash_path.rb', line 125

def hash_path_delete(*paths)
  BBLib.hash_path_delete self, *paths
end

#hash_path_for(value) ⇒ Object Also known as: hpath_for



141
142
143
# File 'lib/bblib/core/hash_path/hash_path.rb', line 141

def hash_path_for(value)
  BBLib.hash_path_key_for self, value
end

#hash_path_move(*paths) ⇒ Object Also known as: hpath_move



129
130
131
# File 'lib/bblib/core/hash_path/hash_path.rb', line 129

def hash_path_move(*paths)
  BBLib.hash_path_move self, *paths
end

#hash_path_move_to(to, *paths) ⇒ Object Also known as: hpath_move_to



133
134
135
# File 'lib/bblib/core/hash_path/hash_path.rb', line 133

def hash_path_move_to(to, *paths)
  BBLib.hash_path_move_to self, to, *paths
end

#hash_path_set(*paths) ⇒ Object Also known as: hpath_set



113
114
115
# File 'lib/bblib/core/hash_path/hash_path.rb', line 113

def hash_path_set(*paths)
  BBLib.hash_path_set self, *paths
end

#hash_pathsObject Also known as: hpaths



137
138
139
# File 'lib/bblib/core/hash_path/hash_path.rb', line 137

def hash_paths
  BBLib.hash_path_keys self
end

#hmapObject

Map for hash that automatically converts the yield block to a hash. Each yield must produce an array with exactly two elements.



158
159
160
161
# File 'lib/bblib/core/util/hash.rb', line 158

def hmap
  return map unless block_given?
  map { |k, v| yield(k, v) }.compact.to_h
end

#keys_to_s(recursive: true) ⇒ Object

Converts the keys of the hash as well as any nested hashes to strings.



36
37
38
39
40
# File 'lib/bblib/core/util/hash.rb', line 36

def keys_to_s(recursive: true)
  each_with_object({}) do |(k, v), memo|
    memo[k.to_s] = recursive && v.respond_to?(:keys_to_sym) ? v.keys_to_s : v
  end
end

#keys_to_s!(recursive: true) ⇒ Object

In place version of keys_to_s



43
44
45
# File 'lib/bblib/core/util/hash.rb', line 43

def keys_to_s!(recursive: true)
  replace(keys_to_s(recursive: recursive))
end

#keys_to_sym(clean: false, recursive: true) ⇒ Object

Converts the keys of the hash as well as any nested hashes to symbols.



23
24
25
26
27
28
# File 'lib/bblib/core/util/hash.rb', line 23

def keys_to_sym(clean: false, recursive: true)
  each_with_object({}) do |(k, v), memo|
    key = clean ? k.to_s.to_clean_sym : k.to_s.to_sym
    memo[key] = recursive && v.respond_to?(:keys_to_sym) ? v.keys_to_sym(clean: clean) : v
  end
end

#keys_to_sym!(clean: false, recursive: true) ⇒ Object

In place version of keys_to_sym



31
32
33
# File 'lib/bblib/core/util/hash.rb', line 31

def keys_to_sym!(clean: false, recursive: true)
  replace(keys_to_sym(clean: clean, recursive: recursive))
end

#kmapObject

Run a map iterator over the keys in the hash without changing the values.



151
152
153
154
# File 'lib/bblib/core/util/hash.rb', line 151

def kmap
  return map unless block_given?
  map { |k, v| [yield(k), v] }.to_h
end

#only(*args) ⇒ Object

Returns a version of the hash not including the specified keys



130
131
132
# File 'lib/bblib/core/util/hash.rb', line 130

def only(*args)
  select { |k, _v| args.include?(k) }
end

#path_nav(obj, path = '', delimiter = '.', &block) ⇒ Object

Navigate a hash using a dot delimited path.



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/bblib/core/util/hash.rb', line 80

def path_nav(obj, path = '', delimiter = '.', &block)
  case obj
  when Hash
    if obj.empty?
      yield path, obj
    else
      obj.each do |k, v|
        path_nav(
          v,
          (path ? [path, k.to_s.gsub(delimiter, "\\#{delimiter}")].join(delimiter) : k.to_s.gsub(delimiter, "\\#{delimiter}")).to_s,
          delimiter,
          &block
        )
      end
    end
  when Array
    if obj.empty?
      yield path, obj
    else
      obj.each_with_index do |ob, index|
        path_nav(
          ob,
          (path ? [path, "[#{index}]"].join(delimiter) : "[#{index}]").to_s,
          delimiter,
          &block
        )
      end
    end
  else
    yield path, obj
  end
end

#reverseObject

Reverses the order of keys in the Hash



48
49
50
# File 'lib/bblib/core/util/hash.rb', line 48

def reverse
  to_a.reverse.to_h
end

#reverse!Object

In place version of reverse



53
54
55
# File 'lib/bblib/core/util/hash.rb', line 53

def reverse!
  replace(reverse)
end

#squish(delimiter: '.') ⇒ Object

Turns nested values’ keys into delimiter separated paths



114
115
116
117
118
# File 'lib/bblib/core/util/hash.rb', line 114

def squish(delimiter: '.')
  sh = {}
  path_nav(dup, nil, delimiter) { |k, v| sh[k] = v }
  sh
end

#to_hash_struct(recursive = true) ⇒ Object



38
39
40
41
# File 'lib/bblib/core/classes/hash_struct.rb', line 38

def to_hash_struct(recursive = true)
  hash = recursive ? self.hmap { |k, v| [k, v.respond_to?(:to_hash_struct) ? v.to_hash_struct(recursive) : v] } : self
  BBLib::HashStruct.new.merge(hash)
end

#to_tree_hashObject

Convert this hash into a TreeHash object.



140
141
142
# File 'lib/bblib/core/util/hash.rb', line 140

def to_tree_hash
  TreeHash.new(self)
end

#unshift(hash, value = nil) ⇒ Object

Like unshift for Arrays. Adds a key to the beginning of a Hash rather than the end.



58
59
60
61
# File 'lib/bblib/core/util/hash.rb', line 58

def unshift(hash, value = nil)
  hash = { hash => value } unless hash.is_a?(Hash)
  replace(hash.merge(self).merge(hash))
end

#vmapObject

Run a map iterator over the values in the hash without changing the keys.



145
146
147
148
# File 'lib/bblib/core/util/hash.rb', line 145

def vmap
  return map unless block_given?
  map { |k, v| [k, yield(v)] }.to_h
end