Module: DR::CoreExt::Hash

Defined in:
lib/dr/ruby_ext/core_modules.rb

Instance Method Summary collapse

Instance Method Details

#deep_merge(other_hash, &block) ⇒ Object

Returns a new hash with +self+ and +other_hash+ merged recursively.

h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
h2 = { x: { y: [7,8,9] }, z: 'xyz' }

h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"}
h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
#=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}

Adapted from active support


33
34
35
# File 'lib/dr/ruby_ext/core_modules.rb', line 33

def deep_merge(other_hash, &block)
	dup.deep_merge!(other_hash, &block)
end

#deep_merge!(other_hash, &block) ⇒ Object

Same as +deep_merge+, but modifies +self+.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/dr/ruby_ext/core_modules.rb', line 38

def deep_merge!(other_hash, &block)
	return unless other_hash
	other_hash.each_pair do |k,v|
		tv = self[k]
		case
		when tv.is_a?(Hash) && v.is_a?(Hash)
			self[k] = tv.deep_merge(v, &block)
		when tv.is_a?(Array) && v.is_a?(Array)
			if v.length > 0 && v.first.nil? then
				#hack: if the array begins with nil, we append the new
				#value rather than overwrite it
				v.shift
				self[k] += v
			else
				self[k] = block && tv ? block.call(k, tv, v) : v
			end
		when tv.nil? && v.is_a?(Array)
			#here we still need to remove nil (see above)
			if v.length > 0 && v.first.nil? then
				v.shift
				self[k]=v
			else
				self[k] = block && tv ? block.call(k, tv, v) : v
			end
		else
			self[k] = block && tv ? block.call(k, tv, v) : v
		end
	end
	self
end

#inverseObject

from a hash [values] produce a hash [keys] there is already Hash#invert using Hash#key which does that, but the difference here is that we flatten Enumerable values h=2, plim: 2, plam: 3 h.invert #=> 3=>:plam h.inverse #=> :plim], 3=>[:plam]



74
75
76
77
78
79
80
81
82
83
84
85
# File 'lib/dr/ruby_ext/core_modules.rb', line 74

def inverse
	r={}
	each_key do |k|
		values=fetch(k)
		values=[values] unless values.respond_to?(:each)
		values.each do |v|
			r[v]||=[]
			r[v]<< k
		end
	end
	return r
end

#keyed_value(key, sep: "/") ⇒ Object

take a key of the form ploum/plam/plim and return self[:ploum][:plam][:plim]



98
99
100
101
102
103
104
105
106
# File 'lib/dr/ruby_ext/core_modules.rb', line 98

def keyed_value(key, sep: "/")
	r=self.dup
	return r if key.empty?
	key.to_s.split(sep).each do |k|
		k=k.to_sym if r.key?(k.to_sym) && !r.key?(k)
		r=r[k]
	end
	return r
end

#leafs(nodes) ⇒ Object

from a hash [:bar, :baz], bar: [:plum, :qux], then leaf [:foo] returns [:plum, :qux, :baz]



125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/dr/ruby_ext/core_modules.rb', line 125

def leafs(nodes)
	expanded=[] #prevent loops
	r=nodes.dup
	begin
		s,r=r,r.map do |n|
			if key?(n) && !expanded.include?(n)
				expanded << n
				fetch(n)
			else
				n
			end
		end.flatten
	end until s==r
	r
end

#set_keyed_value(key, value, sep: "/", symbolize: true) ⇒ Object

take a key of the form ploum/plam/plim and return self[:ploum][:plam][:plim]=value



110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/dr/ruby_ext/core_modules.rb', line 110

def set_keyed_value(key,value, sep: "/", symbolize: true)
	r=self
	*keys,last=key.to_s.split(sep)
	keys.each do |k|
		k=k.to_sym if (symbolize || r.key?(k.to_sym)) and !r.key?(k)
		r[k]={} unless r.key?(k)
		r=r[k]
	end
	last=last.to_sym if symbolize
	r[last]=value
	self
end

#sort_allObject

sort the keys and the values of the hash



88
89
90
91
92
93
94
# File 'lib/dr/ruby_ext/core_modules.rb', line 88

def sort_all
	r=::Hash[self.sort]
	r.each do |k,v|
		r[k]=v.sort
	end
	return r
end