class Hash
Mu extensions to Ruby's {Hash} type for internal Mu use
Public Class Methods
bok_minimize(o)
click to toggle source
Strip extraneous fields out of a {MU::Config} hash to make it suitable for shorthand printing, such as with mu-adopt --diff
# File modules/mu.rb, line 42 def self.bok_minimize(o) if o.is_a?(Hash) newhash = o.reject { |k, v| !v.is_a?(Array) and !v.is_a?(Hash) and !["name", "id", "cloud_id"].include?(k) } # newhash.delete("cloud_id") if newhash["name"] or newhash["id"] newhash.each_pair { |k, v| newhash[k] = bok_minimize(v) } newhash.reject! { |_k, v| v.nil? or v.empty? } newhash = newhash.values.first if newhash.size == 1 return newhash elsif o.is_a?(Array) newarray = [] o.each { |v| newvalue = bok_minimize(v) newarray << newvalue if !newvalue.nil? and !newvalue.empty? } newarray = newarray.first if newarray.size == 1 return newarray end o end
Public Instance Methods
<=>(other)
click to toggle source
A comparison function for sorting arrays of hashes
# File modules/mu.rb, line 68 def <=>(other) return 1 if other.nil? or self.size > other.size return -1 if other.size > self.size # Sort any array children we have self.each_pair { |k, v| self[k] = v.sort if v.is_a?(Array) } other.each_pair { |k, v| other[k] = v.sort if v.is_a?(Array) } return 0 if self == other # that was easy! # compare elements and decide who's "bigger" based on their totals? # fine, try some brute force and just hope everything implements to_s self.flatten.map { |e| e.to_s }.join() <=> other.flatten.map { |e| e.to_s }.join() end
deep_merge!(with, on = self)
click to toggle source
Implement a merge! that just updates each hash leaf as needed, not trashing the branch on the way there.
# File modules/mu.rb, line 185 def deep_merge!(with, on = self) if on and with and with.is_a?(Hash) with.each_pair { |k, v| if !on[k] or !on[k].is_a?(Hash) on[k] = v else deep_merge!(with[k], on[k]) end } elsif with on = with end on end
diff(with, on = self, level: 0, parents: [], report: {}, habitat: nil)
click to toggle source
Recursively compare two Mu Basket of Kittens hashes and report the differences
# File modules/mu.rb, line 86 def diff(with, on = self, level: 0, parents: [], report: {}, habitat: nil) return if with.nil? and on.nil? if with.nil? or on.nil? or with.class != on.class return # XXX ...however we're flagging differences end return if on == with changes = [] report ||= {} if on.is_a?(Hash) on_unique = (on.keys - with.keys) with_unique = (with.keys - on.keys) shared = (with.keys & on.keys) shared.each { |k| report_data = diff(with[k], on[k], level: level+1, parents: parents + [k], report: report[k], habitat: habitat) if report_data and !report_data.empty? report ||= {} report[k] = report_data end } on_unique.each { |k| report[k] = { :action => :removed, :parents => parents, :value => on[k].clone } report[k][:habitat] = habitat if habitat } with_unique.each { |k| report[k] = { :action => :added, :parents => parents, :value => with[k].clone } report[k][:habitat] = habitat if habitat } elsif on.is_a?(Array) return if with == on # special case- Basket of Kittens lists of declared resources of a type; # we use this to decide if we can compare two array elements as if they # should be equivalent # We also implement comparison operators for {Hash} and our various # custom objects which we might find in here so that we can get away with # sorting arrays full of weird, non-primitive types. done = [] on.sort.each { |elt| if elt.is_a?(Hash) and !MU::MommaCat.getChunkName(elt).first.nil? elt_namestr, elt_location, elt_location_list = MU::MommaCat.getChunkName(elt) with.sort.each { |other_elt| other_elt_namestr, other_elt_location, other_elt_location_list = MU::MommaCat.getChunkName(other_elt) # Case 1: The array element exists in both version of this array if elt_namestr and other_elt_namestr and elt_namestr == other_elt_namestr and (elt_location.nil? or other_elt_location.nil? or elt_location == other_elt_location or !(elt_location_list & other_elt_location_list).empty? ) done << elt done << other_elt break if elt == other_elt # if they're identical, we're done report_data = diff(other_elt, elt, level: level+1, parents: parents + [elt_namestr], habitat: (elt_location || habitat)) if report_data and !report_data.empty? report ||= {} report[elt_namestr] = report_data end break end } end } on_unique = (on - with) - done with_unique = (with - on) - done # Case 2: This array entry exists in the old version, but not the new one on_unique.each { |e| namestr, loc = MU::MommaCat.getChunkName(e) report ||= {} report[namestr] = { :action => :removed, :parents => parents, :value => e.clone } report[namestr][:habitat] = loc if loc } # Case 3: This array entry exists in the new version, but not the old one with_unique.each { |e| namestr, loc = MU::MommaCat.getChunkName(e) report ||= {} report[namestr] = { :action => :added, :parents => parents, :value => e.clone } report[namestr][:habitat] = loc if loc } # A plain old leaf node of data else if on != with report = { :action => :changed, :parents => parents, :oldvalue => on, :value => with.clone } report[:habitat] = habitat if habitat end end report.freeze end