E64b3f6a4b0bde29f654eca45fcbb20f

I wanted a Hash#fetch that would return all matches for a particular key in a hash with nested hashes and arrays, and this is what I came up with. I'm pretty new to Ruby, so I can't help but think there's a better way to do it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Hash
  def fetch_all(key)
    results = []
    hashfinder = lambda {|h|
      arrayfinder = lambda {|a|
        a.each do |v|
          hashfinder[v] if v.is_a?(Hash)
          arrayfinder[v] if v.is_a?(Array)
        end
      }
      if h.has_key?(key)
        results << h.fetch(key)
      end
      h.values.each do |v|
        hashfinder[v] if v.is_a?(Hash)
        arrayfinder[v] if v.is_a?(Array)
      end
    }
    hashfinder.call(self)
    results
  end
end

Refactorings

No refactoring yet !

0f8ba0cdebc6938f4cd0601aeef21621

jes5199

March 21, 2008, March 21, 2008 00:20, permalink

No rating. Login to rate!

well, since we're already reopening standard classes, I thought it might make sense to move the Array logic into class Array. Now we have simple recursion of methods, instead of having to make private functions.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Hash
  def fetch_all(key)
    return [] if not self.has_key?(key)
    value = self.fetch(key)
    [ value ] + [ value ].fetch_all(key)
  end
end

class Array
  def fetch_all(key)
    self.find_all{|x| x.respond_to? :fetch_all} \
      .map{|x| x.fetch_all(key) } \
      .inject( [] ){|a,b| a + b }
  end
end

Your refactoring





Format Copy from initial code

or Cancel