# Instance\_eval, regexp with block : losing $1

**URL:** <https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441>\
**Category:** Ruby\
**Created:** [June 3, 2008, 11:10pm UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441 "2008-06-03T23:10:21Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![cngump](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@cngump](https://www.ruby-forum.com/u/cngump)\
**Post date:** [June 3, 2008, 11:10pm UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441/1 "2008-06-03T23:10:21Z")

</div>

To build a wiki-like engine (or DSL) with dynamically generated  
methods, I do the following :

class Base  
def self.match(name, regexp, &block)  
define\_method(name) do |text|  
text.gsub!(regexp) do  
puts “$1 in match method : #{$1}”  
#block.call  
instance\_eval(&block)  
end  
end  
end  
end

class Foo \< Base  
match :g, /(.)g$/i do  
puts “$1 in passed block : #{$1}” #Unfortunately $1 is lost !  
‘ggg’ #so only hardcoded values ☹  
end  
end

f = Foo.new  
f.g(‘bla’) #bla  
f.g(‘doing’) #doiggg ; problem is I cannot use $1 in block

After some research I found these 2 links  
[http://eigenclass.org/hiki/binding.of\_caller+substitute](http://eigenclass.org/hiki/binding.of_caller+substitute)  
[http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/202600](http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/202600)  
(BTW I am trying to avoid any third-party libraries)

But I don’t manage to get these to work…  
I need to get $1, $2, etc. special values  
in the block I pass in Base subclasses.  
How can I do that ?

Thanks,

Vincent

---

<div class="post-metadata">

**Author:** ![cngump](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@cngump](https://www.ruby-forum.com/u/cngump)\
**Post date:** [June 4, 2008, 2:43am UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441/2 "2008-06-04T02:43:45Z")

</div>

> f.g(‘doing’) #doiggg ; problem is I cannot use $1 in block

# maybe pass it as a parameter or save it away to some global variable

or ‘per thread’ variable.  
-R

---

<div class="post-metadata">

**Author:** ![cngump](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@cngump](https://www.ruby-forum.com/u/cngump)\
**Post date:** [June 4, 2008, 12:09pm UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441/3 "2008-06-04T12:09:05Z")

</div>

I finally managed to get it to work :

class Base  
def self.match(name, regexp, &block)  
define\_method(name) do |text|  
puts “#{text}”  
text.gsub!(regexp) do  
#hack to restore magical $~ (and so $1, $2, etc.) in block  
eval(‘lambda{|x| $~ = x}’, block).call($~)  
block.call #or instance\_eval(&block)  
end  
puts “=\> #{text}”  
end  
end  
end

class Foo \< Base  
match :g, /(.)g$/i do  
$1.upcase + ‘\_ggg’  
end  
end

f = Foo.new  
f.g(‘bla’)  
f.g(‘doing’)

---

<div class="post-metadata">

**Author:** ![cngump](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@cngump](https://www.ruby-forum.com/u/cngump)\
**Post date:** [June 4, 2008, 12:57pm UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441/4 "2008-06-04T12:57:59Z")

</div>

Vincent L. wrote:

> I finally managed to get it to work :
> 
> class Base  
> def self.match(name, regexp, &block)  
> define\_method(name) do |text|  
> puts “#{text}”  
> text.gsub!(regexp) do  
> #hack to restore magical $~ (and so $1, $2, etc.) in block  
> eval(‘lambda{|x| $~ = x}’, block).call($~)  
> block.call #or instance\_eval(&block)

instance\_eval(&block) works definitely better here.

---

<div class="post-metadata">

**Author:** ![cngump](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/e19adc/32.png) [@cngump](https://www.ruby-forum.com/u/cngump)\
**Post date:** [June 4, 2008, 4:14pm UTC](https://www.ruby-forum.com/t/instance-eval-regexp-with-block-losing-1/139441/5 "2008-06-04T16:14:52Z")

</div>

Vincent L. wrote:

> class Foo \< Base  
> match :g, /(.)g$/i do  
> puts “$1 in passed block : #{$1}” #Unfortunately $1 is lost !  
> ‘ggg’ #so only hardcoded values ☹  
> end  
> end  
> …  
> But I don’t manage to get these to work…  
> I need to get $1, $2, etc. special values  
> in the block I pass in Base subclasses.  
> How can I do that ?

The backref and numbered group globals are tied to the containing  
method/class body. So here, where you have a match call with a block  
inside a class body, the capture would be the one that lives in that  
body. That’s part of the problem with relying on these special variables  
and the side effect of e.g. gsub: you can’t implement the same behavior  
in Ruby because certain core methods like gsub have “special” side  
effects impossible to emulate.

- Charlie
