module Hashie::Extensions::DeepLocate

def self._construct_key_comparator(search_key, object)

def self._construct_key_comparator(search_key, object)
  if object.respond_to?(:indifferent_access?) && object.indifferent_access? ||
     activesupport_indifferent?(object)
    search_key = search_key.to_s
  end
  lambda do |non_callable_object|
    ->(key, _, _) { key == non_callable_object }
  end.call(search_key)
end

def self._deep_locate(comparator, object, result = [])

def self._deep_locate(comparator, object, result = [])
  if object.is_a?(::Enumerable)
    if object.any? { |value| _match_comparator?(value, comparator, object) }
      result.push object
    end
    (object.respond_to?(:values) ? object.values : object.entries).each do |value|
      _deep_locate(comparator, value, result)
    end
  end
  result
end

def self._match_comparator?(value, comparator, object)

def self._match_comparator?(value, comparator, object)
  if object.is_a?(::Hash)
    key, value = value
  else
    key = nil
  end
  comparator.call(key, value, object)
end

def self.activesupport_indifferent?(object)

def self.activesupport_indifferent?(object)
  defined?(::ActiveSupport::HashWithIndifferentAccess) &&
    object.is_a?(::ActiveSupport::HashWithIndifferentAccess)
end

def self.deep_locate(comparator, object)

# => [{:title=>"Ruby for beginners", :pages=>120}, ...]
DeepLocate.deep_locate -> (key, value, object) { key == :title }, books

]
...
},
pages: 120
title: "Ruby for beginners",
{
books = [
@example

see #deep_locate.
to include/extend the base datastructure. For further examples please
The module level implementation of #deep_locate, incase you do not want
def self.deep_locate(comparator, object)
  unless comparator.respond_to?(:call)
    comparator = _construct_key_comparator(comparator, object)
  end
  _deep_locate(comparator, object)
end

def deep_locate(comparator)

# {:title=>"CSS for intermediates", :pages=>80}]
# => [{:title=>"Ruby for beginners", :pages=>120},
books.deep_locate -> (key, value, object) { key == :pages && value <= 120 }

# {:title=>"Ruby for the rest of us", :pages=>576}]
# => [{:title=>"Ruby for beginners", :pages=>120},
books.deep_locate -> (key, value, object) { key == :title && value.include?("Ruby") }

# http://ruby-journal.com/becareful-with-space-in-lambda-hash-rocket-syntax-between-ruby-1-dot-9-and-2-dot-0/
# for ruby 1.9 leave *no* space between the lambda rocket and the braces

books.extend(Hashie::Extensions::DeepLocate)

]
}
]
}
pages: 576
title: "Ruby for the rest of us",
{
books: [
title: "Collection of ruby books",
{
},
pages: 80
title: "CSS for intermediates",
{
},
pages: 120
title: "Ruby for beginners",
{
books = [
@example

callable returns true for at least one the its elements.
given comparator callable and returns each Enumerable, for which the
Performs a depth-first search on deeply nested data structures for a
def deep_locate(comparator)
  Hashie::Extensions::DeepLocate.deep_locate(comparator, self)
end