summaryrefslogtreecommitdiff
path: root/lib/hashie/extensions/deep_fetch.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/hashie/extensions/deep_fetch.rb')
-rw-r--r--lib/hashie/extensions/deep_fetch.rb29
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