From: "Eregon (Benoit Daloze) via ruby-core" Date: 2026-07-07T20:44:32+00:00 Subject: [ruby-core:125962] [Ruby Feature#22175] Add `Range#clamp` Issue #22175 has been updated by Eregon (Benoit Daloze). Regarding the 3x3 neighborhood of a cell, my favorite solution is this: ```ruby board = {} # x+y.i => v fill(board) [-1i-1, -1i, -1i+1, -1, +1, 1i-1, 1i, 1i+1].each do { |dir| board[pos + dir] } ``` It avoids the nested loop and the need to check for bounds since `Hash#[]` is just `nil` if out of bounds. ---------------------------------------- Feature #22175: Add `Range#clamp` https://bugs.ruby-lang.org/issues/22175#change-117938 * Author: nobu (Nobuyoshi Nakada) * Status: Open ---------------------------------------- I would like to propose `Range#clamp`, which returns a new `Range` whose begin and end values are clamped to the given bounds. Proposed call-seq: ```ruby range.clamp(min, max) -> range range.clamp(bounds) -> range ``` This is a range counterpart of `Comparable#clamp`. While `Comparable#clamp` clamps a single value, `Range#clamp` clamps both endpoints of a range. Examples: ```ruby (1..10).clamp(3, 7) #=> 3..7 (1...10).clamp(3, 7) #=> 3..7 (1...10).clamp(3, 10) #=> 3...10 (0...).clamp(0, 10) #=> 0..10 (1..10).clamp(3..7) #=> 3..7 (1..10).clamp(3...7) #=> 3...7 (1..5).clamp(3...7) #=> 3..5 ``` `clamp(min, max)` behaves like clamping by an inclusive range `min..max`. If an exclusive upper bound is needed, a range argument can be used: ```ruby (1..10).clamp(3...7) #=> 3...7 ``` Beginless and endless ranges are also supported: ```ruby (..10).clamp(3, 7) #=> 3..7 (0...).clamp(0, 10) #=> 0..10 (1..10).clamp(..7) #=> 1..7 (1..10).clamp(...7) #=> 1...7 (1..10).clamp(3..) #=> 3..10 ``` If the receiver is entirely outside the clamping bounds, the returned range is empty: ```ruby (1..10).clamp(20..30) #=> 20...20 (1..10).clamp(-10..0) #=> 0...0 (1..).clamp(..0) #=> 0...0 ``` The returned range excludes its end when the returned end value is an excluded end value of either the receiver or the argument range: ```ruby (1...10).clamp(3, 10) #=> 3...10 (1..10).clamp(3...10) #=> 3...10 ``` Otherwise, the returned range includes its end. #### Relation to [Feature #16757] [Feature #16757] proposes `Range#intersection` / `Range#&` as a general operation for intersecting two ranges. `Range#clamp` is closely related, but intentionally narrower. It treats the argument as clamping bounds for the receiver, similar to how `Comparable#clamp` treats its arguments as bounds for one value. For overlapping ranges, `range.clamp(bounds)` often produces the same result as a range intersection. For example: ```ruby (1..10).clamp(3..7) #=> 3..7 ``` However, `clamp` has a bounds-oriented API and naturally supports the two-argument form: ```ruby (1..10).clamp(3, 7) #=> 3..7 ``` Also, when the receiver is outside the bounds, `clamp` returns an empty `Range` at the nearest bound, rather than needing to decide whether a general intersection operation should return `nil`, `[]`, an empty range, or raise: ```ruby (1..10).clamp(20..30) #=> 20...20 ``` So this proposal can be considered either independently, as a range counterpart of `Comparable#clamp`, or as a smaller operation that could coexist with a future `Range#intersection`. #### Motivation It is common to restrict ranges to known boundaries, for example when limiting source locations, pagination windows, numeric domains, date/time windows, or user-provided ranges. Currently this has to be written manually by clamping both endpoints and reconstructing the range while preserving the correct excluded-end behavior. That logic is easy to get subtly wrong, especially with exclusive ranges, beginless/endless ranges, and ranges that become empty after clamping. `Range#clamp` would provide a small, direct API for this operation. #### Notes The method returns a new `Range` instance. The single-argument form accepts a range-like object accepted by Ruby���s range conversion logic. Source checked: [[Feature #16757]: Add intersection to Range](https://bugs.ruby-lang.org/issues/16757). #### Implementation [GH-17652](https://github.com/ruby/ruby/pull/17652) -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/lists/ruby-core.ml.ruby-lang.org/