Created
June 28, 2011 19:28
-
-
Save avdi/1051967 to your computer and use it in GitHub Desktop.
Revisions
-
Avdi Grimm revised this gist
Jun 28, 2011 . 1 changed file with 9 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -29,12 +29,19 @@ def [](*keys) end h = { :foo => { :bar => [:x, :y, :z], :baz => Hash.new{ "missing value in :bar" } } } h.extend(DeepFetch) h[:foo] # => {:baz=>{}, :bar=>[:x, :y, :z]} h[:foo, :bar] # => [:x, :y, :z] h[:foo, :bar, 1] # => :y h[:foo, :bar, 5] # => nil h[:foo, :baz] # => {} h[:foo, :baz, :fuz] # => "missing value in :bar" h.deep_fetch(:foo, :bar, 0) # => :x h.deep_fetch(:buz) { :default_value } # => :default_value h.deep_fetch(:foo, :bar, 5) { :default_value } # => :default_value -
Avdi Grimm revised this gist
Jun 28, 2011 . 1 changed file with 23 additions and 16 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,33 +1,40 @@ module DeepFetch def deep_fetch(*keys, &fetch_default) throw_fetch_default = fetch_default && lambda {|key, coll| args = [key, coll] # only provide extra block args if requested args = args.slice(0, fetch_default.arity) if fetch_default.arity >= 0 # If we need the default, we need to stop processing the loop immediately throw :df_value, fetch_default.call(*args) } catch(:df_value){ keys.inject(self){|value,key| block = throw_fetch_default && lambda{|*args| # sneak the current collection in as an extra block arg args << value throw_fetch_default.call(*args) } value.fetch(key, &block) } } end # Overload [] to work with multiple keys def [](*keys) case keys.size when 1 then super else deep_fetch(*keys){|key, coll| coll[key]} end end end h = {:foo => {:bar => [:x, :y, :z]}} h.extend(DeepFetch) h[:foo] # => {:bar=>[:x, :y, :z]} h[:foo, :bar] # => [:x, :y, :z] h[:foo, :bar, 1] # => :y h[:foo, :bar, 5] # => nil h.deep_fetch(:foo, :bar, 0) # => :x h.deep_fetch(:buz) { :default_value } # => :default_value h.deep_fetch(:foo, :bar, 5) { :default_value } # => :default_value -
Avdi Grimm created this gist
Jun 28, 2011 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,33 @@ module DeepFetch def deep_fetch(*keys, &fetch_default) # If we need the default, we need to stop processing the loop immediately throw_fetch_default = fetch_default && lambda {|*args| throw :df_value, fetch_default.call(*args) } catch(:df_value){ keys.inject(self){|value,key| value.fetch(key, &throw_fetch_default) } } end def [](*keys) case keys.size when 1 then super else deep_fetch(*keys){_df_default_} end end # Don't want to step on any naming toes def _df_default_(&default_block) # Hashes have fancy defaulting logic value = if respond_to?(:default_proc) && default_proc default_proc.call elsif respond_to?(:default) default else nil end throw :df_value, value end end