The documentation for Enumerable#find
/#detect
says:
find(ifnone = nil) { |obj| block } → obj or nil
find(ifnone = nil) → an_enumerator
Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns
nil
otherwise.
However, when it is called on the Hash, the result has changed the type to Array instead of the original Hash.
Is it some implementation fault or some historical conventions regarding this datatype?
{a: 'a', b:'b'}.find {|k, v| v == 'b'}
# => [:b, 'b']
The Hash#detect
is inherited from Enumerable#detect
method.
Enumerable
module generates multiple methods(such as sort
, min
, max
including detect
etc.) based on the each
method of the class which includes Enumerable
.
It doesn't care about how each
is implemented as long as it
"...yields successive members of the collection. " from ruby-doc
So for the Hash#detect
method, it relies on Hash#each
's behavior, which is:
Calls block once for each key in hsh, passing the key-value pair as parameters. If no block is given, an enumerator is returned instead.
h = { "a" => 100, "b" => 200 }
h.each {|key, value| puts "#{key} is #{value}" }
Because Hash#each
yields the hash as two pair array, all methods inherited from the Enumerable
module works based on that.
That's why Hash#detect
produces a two elements array instead of the an hash object itself.