Given the following two pieces of code:
def hello(z)
\"hello\".gsub(/(o)/, &z)
end
z = proc {|m| p $1}
hello(z)
# prints: nil
The two versions are different because the $1 variable is thread-local and method-local. In the first example, $1 only exists in the block outside the hello method. In the second example, $1 exists inside the hello method.
There is no way to pass $1 in a block to gsub from outside of the method definition.
Note that gsub passes the match string into the block, so z = proc { |m| pp m } will only work as long as your regular expression only contains the whole match. As soon as your regular expression contains anything other than the reference you want, you're out of luck.
For example, "hello".gsub(/l(o)/) { |m| m } => hello, because the whole match string was passed to the block.
Whereas, "hello".gsub(/l(o)/) { |m| $1 } => helo, because the l that was matched is discarded by the block, all we are interested in is the captured o.
My solution is to match the regular expression, then pass the MatchData object into the block:
require 'pp'
def hello(z)
string = "hello"
regex = /(o)/
m = string.match(regex)
string.gsub(regex, z.call(m))
end
z = proc { |m| pp m[1] }
pp hello(z)