ruby-on-railsrubyhash

Deeply compact nested hash in ruby?


Given the following hash structure...

{
  a: nil,
  b: [],
  c: {c1: {c2: nil}},
  d: [{d1: "Value!"}],
  e: "Value!",
  f: {f1: {f2: nil, f3: "Value!"}}
}

I'd like to be able to return...

{
  d: [{d1: "Value!"}],
  e: "Value!",
  f: {f1: {f3: "Value!"}}
}

So the rules would be
1) Remove any key that points to a nil, {}, or [] value
2) Remove any key that leads to value which points to an empty value (example c: from the original hash)
3) Preserve the outer key if one or more inner keys point to a non empty value, but remove inner keys that point to an empty value. (see f: and notice that f2: is removed)

Any help would be appreciated!


Solution

  • You could have some fun with monkey-patching the core classes involved:

    class Object
      def crush
        self
      end
    end
    
    class Array
      def crush
        r = map(&:crush).compact
    
        r.empty? ? nil : r
      end
    end
    
    class Hash
      def crush
        r = each_with_object({ }) do |(k, v), h|
          if (_v = v.crush)
            h[k] = _v
          end
        end
    
        r.empty? ? nil : r
      end
    end
    

    It's an unusual thing to want to do, but if you do need it done writing a method like crush might help.