The other day I had
(5…8).map { |x|
# stuff
}.other_stuff
and at some point I wanted x to be in increments of 0.5. What to do?
Well I could be silly and define Float#succ. Short of that, I need to
change the code to either
accum = []
5.step(8, 0.5) { |x|
accum <<
# stuff
}
accum.other_stuff
or
((25)…(28)).map { |x|
x = x.to_f/2
# stuff
}.other_stuff
both of which seem unappealing compared to the original.
There are natural kinds of Ranges which, currently, which would
require a preposterous definition such as Float#succ or Integer#succ.
And we can’t assume it’s possible to create an array to use as the
elements of your Enumeration because such an array can be arbitrarily
large.
I propose giving Range.new an optional block which acts as succ
function:
Range.new(4, 16){|x| x + 4}.map{|x| x}
=> [4, 8, 12, 16]
Range.new(3.1, 6.2){|x| x + 0.3}.map{|x| x}
=> [3.1, 3.4, 3.7, 4.0, 4.3, 4.6, 4.9, 5.2, 5.5, 5.8, 6.1]
Range.new(“a”, “r”){|x| x.succ.succ}.map{|x| x}
=> [“a”, “c”, “e”, “g”, “i”, “k”, “m”, “o”, “q”]
Such a block naturally must assume <=> since it’s possible to miss the
endpoint.
Here is a ruby implementation. (Note #member and #step need to be
defined as well.)
class Range
alias_method :orig_init, :initialize
def initialize(first, last, exclude_end = false, &succ_block)
orig_init(first, last, exclude_end)
@succ_block = nil
@succ_block = succ_block if block_given?
end
alias_method :orig_each, :each
def each(&block)
if @succ_block.nil?
orig_each(&block)
else
cur = self.first
while true
comp = (cur <=> self.last)
if comp > 0 or (comp == 0 and self.exclude_end?)
break
else
block.call(cur)
cur = @succ_block.call(cur)
end
end
self
end
end
end
···
Do you Yahoo!?
Yahoo! Photos: High-quality 4x6 digital prints for 25¢