[Feature #18368] Range#step の挙動を調整する提案

2024/07/14に公開

[Feature #18368] Range#step semantics for non-Numeric ranges

  • Range#step の挙動を調整するチケット
  • 現状の実装だと「 #succ で begin を N 回進めて、結果を返す」という挙動になっている
  • それを「begin + step で繰り返して結果を返す」という挙動に変えたいというのがチケットの内容
  • 要は Range#step の挙動を調整し、以下のようなコードを動かせるようにするのがチケットの目的
# 1日ずつ加算して配列に変換したい
# いまはこれができない
(Time.parse('2021-12-01')..Time.parse('2021-12-24')).step(1.day).to_a
  • 最終的には互換性を保ちつつ + でも繰り返すようにされる予定
# 以下のようなコードが動くようになる
p ('a'..).step('a').take(3)
# => ["a", "aa", "aaa"]

p (Time.now..).step(24*60*60).take(3)
# => [2023-03-04 12:16:52.546531817 +0200,
#     2023-03-05 12:16:52.546531817 +0200,
#     2023-03-06 12:16:52.546531817 +0200]
  • また、いくつか挙動が調整されており、以下のように #step に負の値 + ブロックを渡したときにエラーにならなくなりました
# これは Ruby 3.3 でも PR でも変わらない
p (1..-10).step(-3).to_a
# => [1, -2, -5, -8]

# これは元々エラーになっていたが動くようになる
(1..-10).step(-3) { p _1 }
# Ruby 3.3 => step can't be negative (ArgumentError) -- inconsistent with ArithmeticSequence behavior
# PR       => 1, -2, -5, -8
  • また、以下のように float が絡む場合の挙動も変わる
require 'active_support/all'

p (1.0..).step(2.minutes).take(3)
# Ruby 3.3 => [1.0, 121.0, 241.0] -- これは内部で #to_f が呼ばれて、その値が加算される
# PR       => [1.0, 2 minutes and 1.0 second, 4 minutes and 1.0 second] -- これは #coerce で適切に変換されるようになった
GitHubで編集を提案

Discussion