Ruby 2.6 に投げたパッチが取り込まれた話

[ブログ記事](http://secret-garden.hatenablog.com/entry/2018/12/25/235407)からの転載です。

先日 Ruby 2.6 がリリースされましたが、それにわたしが投げたパッチが4つ含まれています。
と、いうことで具体的にどんなパッチを投げてどんな機能が取り込まれたのかを簡単に書いてみようかと


### [Refinements で定義した #to_proc が &hoge 時に呼ばれないのを緩和する提案](https://bugs.ruby-lang.org/issues/14223)

表題そのままなんですが、次のように Refinements で `to_proc` を定義した場合、`&hoge` で `to_proc` が呼ばれなかったのを呼ばれるようにしたパッチです。

```ruby
using Module.new {
	# Refinements で to_proc を定義
	refine String do
		def to_proc
			proc { |it| it.send self }
		end
	end
}

p "upcase".to_proc.call "homu"
# => HOMU

# "upcase".to_proc が呼ばれるようになった
p %w(homu mami mado).map &"upcase"
# => ["HOMU", "MAMI", "MADO"]
```


このパッチを投げたのは Ruby 2.5 のリリース直前で、ドサクサに紛れて取り込まれないかなーという気持ちで投げました。
まあ流石に直前だと無理だったので Ruby 2.5 には入りませんでしたが、パッチ自体は特に問題なく取り込まれて Ruby 2.6 で正式に使えるようになりました。
ここから怒涛の Refinements パッチが始まります。


### [Proposal: Enable refinements to `#public_send`](https://bugs.ruby-lang.org/issues/15326)

先程の `to_proc` のパッチが取り込まれてからだいぶ時間が経って、11月取り込まれたパッチになります。
前回からだいぶ間が空いているんですが、この間にもいくつかパッチを投げており…。
matz に『日本語よりも英語で上げたほうがいいよー』とツッコまれたのでこのあたりからがんばって英語でパッチを投げるようにしました。
パッチも `diff` ファイルを直接添付していたんですが、CI を回したかったので github 経由で pull request を投げるようにしています。
パッチ自体は以下のように『`public_send` でも Refinements を有効にする』と言うような内容です。

```ruby
using Module.new {
	# Refinements でメソッドを定義
	refine String do
		def twice
			self + self
		end
	end
}

# public_send 経由でもメソッドが呼ばれるようになった
p "homu".public_send(:twice)
# => "hogehoge"
```

まあ `#send` も Refinements が有効になっているから `#public_send` も有効になってもいいよねーという気持ちで提案しました。
提案したものの（Refinements 的な意味で）議論されて取り込まれるまでに時間がかかるかなー、と心配していたんですが割とあっさり入ったのでちょっと面食らいました。
感触としては Ruby の方針としてはこのあたりはそこまで厳密に Refinements を制限する、という感じではなさそうな感じなんですかね。


### [Proposal: Enable refinements to `#respond_to?`](https://bugs.ruby-lang.org/issues/15327)

これも先程の `#public_send` と同じで『`#public_send` で Refinements を有効にする』というパッチになります。

```ruby
using Module.new {
	# Refinements でメソッドを定義
	refine String do
		def twice
			self + self
		end
	end
}

p "homu".respond_to?(:twice)
# => true
```

こちらも `#public_send` と同じタイミングで取り込まれました。


### [`Ruby で定義したメソッドに `&:hoge` を渡しても refinements が有効にならない`](https://bugs.ruby-lang.org/issues/15114)

これは今回投げた中では一番大変なパッチでした。
このパッチを投げた経緯は[こちら](http://secret-garden.hatenablog.com/entry/2018/09/17/204612)を参照してもらうと詳しく書いてあります。

パッチ自体は9月ぐらいに書いてすぐに投げたんですが、その後特に進展がなく、先月頭ぐらいにバグ認定されて、今月の頭に取り込まれたんですが、テストで落ちてたみたいで一旦 revert されて…という経緯があります。
Ruby 2.6 に絶対に入れたかったのでテストで落ちていた箇所を直してもう一度パッチを投げたんですが、そしたら別の場所でテストが失敗してしまったらしくて…。
けど、原因を調べてみたら実際はこのパッチとは全然関係ない箇所で、しょうがないのでこっちで原因を調べてみたら実は [Ruby のバグ](https://bugs.ruby-lang.org/issues/15427)を踏んでいてそれを報告して…。

というのがここ1〜2週間のハイライトになります。
まさか trunk で Ruby のバグを踏んでいるとは思わなくて実はかなり悩んでいました。
まあ結果的にこの不具合が修正されたので Ruby 2.6 ではいい感じに Refinements が使えるようになると思います。

```ruby
using Module.new {
	# Refinements でメソッドを定義
	refine String do
		def twice
			self + self
		end
	end
}

def meth &block
	block.call "homu"
end

# Ruby で定義したメソッドのブロック引数でも有効になった
p meth &:twice
```

これが今まで動かなかったんですよねー。
何が嬉しいかって ActiveRecord のリレーションで定義されている `map` のブロック引数とかでも Refinements が有効になったのが大きいかなーと思います。
ってか、それで使えなくて困っていたのでパッチ書いて投げました。


### 所感

と、言う感じで Ruby 2.6 で取り込まれたパッチをいくつか紹介しました。
改めて見ると全部 Refinements のパッチですね、これ。
Refinements はもっと使い勝手よくしたいんですよねえ。

ちなみに今回取り込まれたパッチは4つでしたが、実際にはこの倍近くのパッチを投げています。
本当は [`#method`](https://bugs.ruby-lang.org/issues/15373) と [`#method_missing`](https://bugs.ruby-lang.org/issues/15374) で Refinements が有効になるパッチも投げていたんですが、残念ながら Ruby 2.6 には間に合いませんでした。
このあたりが Ruby 2.7 で取り込まれるとだいぶ Refinements が使いやすくなるかなーと思います。
Ruby 2.7 で入るといいですねえ。
そろそろ Ruby のパッチを書くのにも慣れてきたので、何か思いついたらまたパッチを投げていきたいですねー。
パッチを書くよりも取り込まれるまでが大変ですが…。