diff options
Diffstat (limited to 'lib/hashie/extensions/deep_fetch.rb')
-rw-r--r-- | lib/hashie/extensions/deep_fetch.rb | 29 |
1 files changed, 29 insertions, 0 deletions
diff --git a/lib/hashie/extensions/deep_fetch.rb b/lib/hashie/extensions/deep_fetch.rb new file mode 100644 index 0000000..d8746cb --- /dev/null +++ b/lib/hashie/extensions/deep_fetch.rb @@ -0,0 +1,29 @@ +module Hashie + module Extensions + # Searches a deeply nested datastructure for a key path, and returns the associated value. + # + # options = { user: { location: { address: '123 Street' } } } + # options.deep_fetch :user, :location, :address #=> '123 Street' + # + # If a block is provided its value will be returned if the key does not exist. + # + # options.deep_fetch(:user, :non_existent_key) { 'a value' } #=> 'a value' + # + # This is particularly useful for fetching values from deeply nested api responses or params hashes. + module DeepFetch + class UndefinedPathError < StandardError; end + + def deep_fetch(*args, &block) + args.reduce(self) do |obj, arg| + begin + arg = Integer(arg) if obj.kind_of? Array + obj.fetch(arg) + rescue ArgumentError, IndexError => e + break block.call(arg) if block + raise UndefinedPathError, "Could not fetch path (#{args.join(' > ')}) at #{arg}", e.backtrace + end + end + end + end + end +end |