From: lucasbuchala@... Date: 2018-05-19T15:50:55+00:00 Subject: [ruby-core:87194] [Ruby trunk Feature#14777] Add Range#offset ? Issue #14777 has been updated by lucasbuchala (Lucas Buchala). Hello. I don't have any strong opinion about this feature, but I guess I would welcome such feature if it used standard operators. After seeing this issue, I remembered that I have tried this in the past, so I'm just sharing a snippet to give some ideas. I took this approach as a beginner. Hopefully someone more experienced will have a more idiomatic solution: ~~~ruby class Range def _build(sym, *args) b = self.begin.__send__(sym, *args) e = self.end.__send__(sym, *args) self.class.new(b, e, exclude_end?) end def +(n); _build(:+, n) end def -(n); _build(:-, n) end def *(n); _build(:*, n) end def /(n); _build(:/, n) end end ~~~ ~~~ruby p (0..4) + 5 #=> 5..9 p (5..9) - 5 #=> 0..4 p (1..4) * 2 #=> 2..8 p (2..8) / 2 #=> 1..4 p (0...4) + 5 #=> 5...9 p (5...9) - 5 #=> 0...4 p (1...4) * 2 #=> 2...8 p (2...8) / 2 #=> 1...4 ~~~ As a comparision, Perl 6 ranges implement the same behavior: ~~~ say (0..4) + 5; #=> 5..9 say (5..9) - 5; #=> 0..4 say (1..4) * 2; #=> 2..8 say (2..8) / 2; #=> 1.0..4.0 say (0..^4) + 5; #=> 5..^9 say (5..^9) - 5; #=> ^4 say (1..^4) * 2; #=> 2..^8 say (2..^8) / 2; #=> 1.0..^4.0 ~~~ Also, in a superficial search, I found a similar already proposed feature: https://bugs.ruby-lang.org/issues/7580 ---------------------------------------- Feature #14777: Add Range#offset ? https://bugs.ruby-lang.org/issues/14777#change-72183 * Author: owst (Owen Stephens) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- Hi, As mentioned in https://bugs.ruby-lang.org/issues/14473#note-17 an addition to Range that we find useful is an `Range#offset(n)` method that adds (or subtracts) `n` to the range, for example: ~~~ruby (1..10).offset(2) # => (3..12) (1...10).offset(1) # => (2...11) (1..10).offset(-10) # => (-9..0) ~~~ Similarly to `Range#step` we can support non-Numeric objects if they implement `succ`: ~~~ruby ('a'..'e').offset(2) # => ('c'..'g') ~~~ Alternative names could be `Range#shift` (i.e. shift the elements of the Range up or down) or perhaps `>>`/`<<`: ~~~ruby (1..10).shift(2) # => (3..12) (1..10) >> 2 # => (3..12) (1...10) << 1 # => (0...9) ~~~ However, I don't think the operators are clear enough, so I prefer `offset` or `shift`. An example pure Ruby implementation is: ~~~ruby class Range def offset(n) add_n = ->(x) do if x.is_a?(Numeric) x + n elsif x.respond_to?(:succ) n.times { x = x.succ } x else raise ArgumentError, "Can't offset #{x.class}" end end if exclude_end? (add_n.call(first)...add_n.call(last)) else (add_n.call(first)..add_n.call(last)) end end end ~~~ Please let me know your thoughts, I can then look to implement this properly in C. Regards, Owen. -- https://bugs.ruby-lang.org/ Unsubscribe: