[ruby-list:50709] Re: [Q]last_matchをブロックに渡す方法
From:
"Masa Sakano" <imagine@...>
Date:
2018-10-10 22:03:27 UTC
List:
ruby-list #50709
坂野正明です。
On 10 Oct 2018, at 15:55, Kazuhiro NISHIYAMA wrote:
> On Tue, 09 Oct 2018 19:21:33 +0900,
> Masa Sakano wrote:
>> Rubyのメソッドから、ブロックに $1, $2 (を含めた
>> Regexp.last_match) を
>> 渡す方法がないものか、と質問します。
>
> local_variable_set(:$~, $~) ができないようなので、
> 一旦適当なローカル変数
> (名前が衝突する可能性がある) に
> 入れて eval
> で代入する方法しか思いつきませんでしたが、
> できないことはないようです。
binding で、local_variable_set で、それを eval ですか。
恐れ入りました。ありがとうございます!
確かに力技ながら、思っていたことがこれで実現できます。Rubyの潜在力の一旦に触れた思いです。
ブロックの後にもローカルスコープの $&
がそのまま残ることも String#sub と同じですね。
ご指摘の変数の名前の衝突は、ローカル変数「`_`」(アンダースコア)を使用すれば、現実的には回避できることになりませんか。ローカル変数「`_`」はダミーの代入以外には使用しないのが、Ruby
の慣習だったと理解しています(当メソッド内で、一瞬、その慣習に反することになりますが…)。
西山さんのご提示の例を書き換えると、以下のようになります。
ブロック実行後にローカル変数「`_`」をあえて読み出すと、内容が変更されていますが、そもそも読み出すものでないならば事実上の問題はない、と。
def f(&block)
/a/ =~ "a"
block.binding.tap do |b|
b.local_variable_set(:_, $~)
b.eval("$~=_")
end
yield
[1, 2]
end
/x/ =~ 'x'
p $& #=> "x"
y, _, _ = $&, f{p $&} #=> "a"
p y #=> "x"
p $& #=> "a"
p _ #=> "a"
西山さん、お知恵を貸してくださり感謝します!
(本MLへの投稿は10年ぶりくらいになりますが、助かりました。)
坂野正明
>
> def f(&block)
> /a/ =~ "a"
> block.binding.tap do |b|
> b.local_variable_set(:_md, $~)
> b.eval("$~=_md")
> end
> yield
> end
> f{p $&} #=> "a"
>
> --
> |ZnZ(ゼット エヌ ゼット)
> |西山和広(Kazuhiro NISHIYAMA)