2022/09/02 今回の気になった bugs.ruby のチケット
今週は Numbered Parameters の _1
を it
に置き換えるチケットがありました。
[Raises Exception for Range#last(n) with Float::INFINITY]
Range
の終端がFloat::INFINITY
の場合に無限ループする
(6..Float::INFINITY).last(1) # => infinite loop!! (6..).last(1) # cannot get the last element of endless range (RangeError) (-Float::INFINITY..4).last(1) # can't iterate from Float (TypeError) (..4).last(1) # can't iterate from Float (TypeError)
- これを
RangeError
で例外にしようというチケット - そういえば昔
Range#first
で似たようなチケット立てた記憶- https://bugs.ruby-lang.org/issues/15813
- これは
(..10).first # => nil
になっていたのを例外にするようにした奴
- このあたり、微妙に挙動が違っていて無限に難しい
- 引数がない場合は以下のような挙動にもなる
p (1..10).last # => 10 p (1..Float::INFINITY).last # => Infinity p (1..).last # Error: in `last': cannot get the last element of endless range (rangeerror)
[Feature #18159] Integrate functionality of syntax_suggest gem into Ruby
dead_end
あらためsyntax_suggest
が標準ライブラリに追加されました- 去年の RubyKaigi で発表されていた gem ですね
- 現状は標準ライブラリに入っただけでまだ
ruby
コマンドからスクリプトを実行したときには特にエラー出力とかはされないぽいですね- エラー制御周りでまだ実装する必要がありそう?
- https://bugs.ruby-lang.org/issues/18159#note-35
- Ruby 3.2 のリリースまでにはエラー出力までされるようになるんですかねー
[Feature #18980] Re-reconsider numbered parameters: it
as a default block parameter
_1
の変わりにit
を Numbered parameters で利用したいというチケット_1
は『未使用のローカル変数』に見えてしまうらしい- わたしは結構カジュアルに
_1
を使っているんですが今の所名前に関して困ったとか混乱しとかはないですねえ(そういう話も聞いたことはない - 慣れの問題なんですかね?
- どっちかって言うとナンパラ自体が特別な構文なので
it
のような一般的に使用されるような名前よりも_1
のように『特別な名前に見える方』が好みではありますね - チケット内でかなり議論が進んでいるので気になる人は読んでみてみるとよいかも
it
じゃなくて@
を使おう、みたいな話もでてますねit
よりも@
の方が特別な意味があるように見えるのでit
よりはマシだと思うんですが@
にするぐらいなら_1
のままの方がいいかなあ…
[Feature #18951] Object#with to set and restore attributes around a block
- 以下のように一時的に設定を変えたりインスタンス変数を変えたいときがある
def test_something_when_enabled # 一時的に SomeLibrary.enabled を有効にしたい enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true # test things ensure SomeLibrary.enabled = enabled_was end
def with_something_enabled # ブロック引数内では enabled_was を有効な状態で実行したい enabled_was = @enabled @enabled = true yield ensure @enabled = enabled_was end
- この時に以下のような場合だと意図しない挙動になるケースがある
def test_something_when_enabled # some_call_that_may_raise で例外が発生した場合 SomeLibrary.enabled = nil になってしまう # これはまだ enabled_was に対して値が割り当てられていないため some_call_that_may_raise enabled_was, SomeLibrary.enabled = SomeLibrary.enabled, true # test things ensure SomeLibrary.enabled = enabled_was end
- これを解決するために以下のような
Object#with
を導入したいというチケット
class Object def with(**attributes) old_values = {} attributes.each_key do |key| old_values[key] = public_send(key) end begin attributes.each do |key, value| public_send("#{key}=", value) end yield ensure old_values.each do |key, old_value| public_send("#{key}=", old_value) end end end end def test_something_when_enabled SomeLibrary.with(enabled: true) do # test things end end GC.with(measure_total_time: true, auto_compact: false) do # do something end
- こういう制御は結構するので便利そう