Ruby Range issues

Since I haven't posted to this group in the past 5 years or so, let me start by saying how much I enjoy using Ruby! My comments below reflect my desire to see a couple of small issues improved in this extraordinary language!

The first is a requested feature (which works in 1.8.7 but not in 1.9.2p136), while the second appears to me to be a bug that exists in both 1.8.7 and 1.9.2:

1. Range.step says (per PickAxe 3) that it works with range elements that support .succ, or with numbers. It would be nice to have it work with elements that support .succ, /or with elements that support adding a number to them/. This would allow stepping through time ranges, for example.

2. Range.step where the end is specified to be excluded ( '...') on floats seems to exclude the last value that should be included. For example:
     ( 1.0 ... 5.01).step( 2) {|x| puts x}
     outputs 1.0 and 3.0 but not 5.0.
     Interestingly, ( 1.0 ... 5.01).cover?( 5.0) returns true, as it should!

*Ray Bovet*

···

**

Since I haven't posted to this group in the past 5 years or so, let me start
by saying how much I enjoy using Ruby! My comments below reflect my desire
to see a couple of small issues improved in this extraordinary language!

The first is a requested feature (which works in 1.8.7 but not in
1.9.2p136), while the second appears to me to be a bug that exists in both
1.8.7 and 1.9.2:

1. Range.step says (per PickAxe 3) that it works with range elements that
support .succ, or with numbers. It would be nice to have it work with
elements that support .succ, /or with elements that support adding a number
to them/. This would allow stepping through time ranges, for example.

Not sure this is a good idea. After all, if +1 would be the "default"
increment for a class #succ would have been implemented that way. In
absence of a #succ implementation a Range cannot do any assumption as
to how get the next value - that's the exact reason why there is a
method #succ. You could as well wrap a Time instance in something
that implements #succ accordingly.

irb(main):001:0> require 'delegate'
=> true
irb(main):002:0> class TD < SimpleDelegator
irb(main):003:1> def succ;self.class.new(__getobj__ + 1); end
irb(main):004:1> end
=> nil
irb(main):005:0> t = TD.new(Time.now)
=> 2011-02-01 16:23:24 +0100
irb(main):006:0> t.succ
=> 2011-02-01 16:23:25 +0100
irb(main):007:0> t.succ.succ
=> 2011-02-01 16:23:26 +0100

2. Range.step where the end is specified to be excluded ( '...') on floats
seems to exclude the last value that should be included. For example:
( 1.0 ... 5.01).step( 2) {|x| puts x}
outputs 1.0 and 3.0 but not 5.0.
Interestingly, ( 1.0 ... 5.01).cover?( 5.0) returns true, as it should!

Sounds like a bug which is not present in 1.9.2:

irb(main):008:0> (1.0..5.1).step(2).to_a
=> [1.0, 3.0, 5.0]
irb(main):009:0> (1.0..5.01).step(2).to_a
=> [1.0, 3.0, 5.0]

Cheers

robert

···

On Tue, Feb 1, 2011 at 3:33 PM, Ray Bovet <Ray@bovet.org> wrote:

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Thanks for the comments, Robert.

I agree that .succ for a Time is not obvious (there actually *is* a .succ
method for Time in 1.9.2 although it reports that it is deprecated), but I'd
still like to be able to use a specific step value. It may be that your
wrapping suggestion is the best way forward, but I would think a lot of
people might want to be able to step through time intervals.

On the second issue, you only show the results with two dots. What I was
concerned about was when you use three dots in order to exclude the endpoint
of the range. In both 1.8.7 and 1.9.2p136 you only get 1.0 and 3.0. It
appears that it first converts the end points to Integer before doing the
end comparison. Here's an example in 1.9.2 showing both the 2 dot and the 3
dot versions:

irb
ruby-1.9.2-p136 :001 > ( 1.0 .. 5.01).step(2).to_a
=> [1.0, 3.0, 5.0]
ruby-1.9.2-p136 :002 > ( 1.0 ... 5.01).step(2).to_a
=> [1.0, 3.0]

···

On Tue, Feb 1, 2011 at 7:33 AM, Ray Bovet <Ray@bovet.org> wrote:

Since I haven't posted to this group in the past 5 years or so, let me
start by saying how much I enjoy using Ruby! My comments below reflect my
desire to see a couple of small issues improved in this extraordinary
language!

The first is a requested feature (which works in 1.8.7 but not in
1.9.2p136), while the second appears to me to be a bug that exists in both
1.8.7 and 1.9.2:

1. Range.step says (per PickAxe 3) that it works with range elements that
support .succ, or with numbers. It would be nice to have it work with
elements that support .succ, /or with elements that support adding a number
to them/. This would allow stepping through time ranges, for example.

2. Range.step where the end is specified to be excluded ( '...') on floats
seems to exclude the last value that should be included. For example:
   ( 1.0 ... 5.01).step( 2) {|x| puts x}
   outputs 1.0 and 3.0 but not 5.0.
   Interestingly, ( 1.0 ... 5.01).cover?( 5.0) returns true, as it should!

*Ray Bovet*
**

The logic is in ruby_float_step in float.c.

It doesn't do the obvious (add step to base until exceed maximum),
probably to avoid accumulating errors. But I think the logic is wrong
for the ... case.

            if (!excl) n++;
            for (i=0; i<n; i++) {
                rb_yield(DBL2NUM(i*unit+beg));
            }

···

--
Posted via http://www.ruby-forum.com/.