zsh grep and mvim: search for a string in a directory in file type, and open that point

open_all {pattern} {extension}

#!/bin/zsh
grep -n $1 **/*$2 | sed 's/^([a-zA-Z_/.]*):([0-9]*).*$/2 1/' | while read line file
do
  mvim --remote-tab-silent +$line $file
done

Usage:

# find all occurrences of "def" as a whole word and open the files in separate tabs:
open_all '<def>' .rb

Fun with the Ruby & (unary ampersand) and String#to_proc

In trying to grasp the unary & operator in ruby, I ran across [Stupid Ruby Tricks: String#to_proc].

Therefore, I decided I had to further twist the language features to my own will.

Like many things in Ruby with duck-typing, the following syntax:

('a'..'z').map &:upcase

...makes use of the fact that Symbol has a #to_proc method, which means that the following call is an explicit version of the above call.

('a'..'z').map &:upcase.to_proc

If you wanted to allow for a shorthand notation for map, then you could add #to_proc to String, as follows:

class String
  def to_proc
    eval "Proc.new { |*args| args.first#{self} }"
  end
end

This allows for the following call:

[1,2,3].map &'*2'                     # [2, 4, 6]

...which is equivalent to:

[1,2,3].map { |*args| args.first*2 } # note: no space

...But what if I wanted to specify a library function to have the Array members passed to? (Certainly, this is venturing deeper into solving a problem that doesn't exist.) Also, what if I want to pass an Array for the arguments?

class String
  def to_proc
    # assume an initial word character is a library function, otherwise evaluate as before
    if /^w/ =~ self
      eval "Proc.new { |*args| #{self}(*args.first) }"
    else
      eval "Proc.new { |*args| args.first#{self} }"
    end
  end

The above code will expand an embedded Array into an argument list:

[[2,2],[9,3],[64,4]].map &'Math.log'  # [1.0, 2.0, 3.0]
[1.0, 2.0, 4.0].map &'Math.sqrt'      # [1.0, 1.4142135623730951, 1.7320508075688772]
[1,2,3].map &'*2'                     # [2, 4, 6]
[[2,2],[9,3],[64,4], 4].map &'Math.log' # [1.0, 2.0, 3.0, 1.3862943611198906]