How does the "#map(&proc)" idiom work when introspecting module classes?

Viewed 428

Presenting the Idiom

I found an interesting but unexplained alternative to an accepted answer. The code clearly works in the REPL. For example:

module Foo
  class Bar
    def baz
    end
  end
end
Foo.constants.map(&Foo.method(:const_get)).grep(Class)
=> [Foo::Bar]

However, I don't fully understand the idiom in use here. In particular, I don't understand the use of &Foo, which seems to be some sort of closure, or how this specific invocation of #grep operates on the result.

Parsing the Idiom

So far, I've been able to parse bits and pieces of this, but I'm not really seeing how it all fits together. Here's what I think I understand about the sample code.

  1. Foo.constants returns an array of module constants as symbols.

  2. method(:const_get) uses Object#method to perform a method lookup and return a closure.

  3. Foo.method(:const_get).call :Bar is a closure that returns a qualified path to a constant within the class.

  4. &Foo seems to be some sort of special lambda. The docs say:

    The & argument preserves the tricks if a Proc object is given by & argument.

    I'm not sure I fully understand what that means in this specific context, either. Why a Proc? What "tricks," and why are they necessary here?

  5. grep(Class) is operating on the value of the #map method, but its features are not obvious.

    • Why is this #map construct returning a greppable Array instead of an Enumerator?

      Foo.constants.map(&Foo.method(:const_get)).class
      => Array
      
    • How does grepping for a class named Class actually work, and why is that particular construction necessary here?

      [Foo::Bar].grep Class
      => [Foo::Bar]
      

The Question, Restated

I'd really like to understand this idiom in its entirety. Can anyone fill in the gaps here, and explain how the pieces all fit together?

4 Answers
Related