tags:

views:

971

answers:

4

I have some Ruby code which takes dates on the command line in the format:

-d 20080101,20080201..20080229,20080301

Which means I want to run for all dates between 20080201 and 20080229 (inclusive) and the other dates present in the list.

Given I can get the string 20080201..20080229 what is the best way to convert this to an instance of Range. Currently I am using eval, but it feels like there should be a better way.

@Purfideas I was kind of looking for a more general answer for converting any string of type int..int to a Range I guess.

+2  A: 

assuming you want the range to iterate properly through months etc, try

require 'date'

ends = '20080201..20080229'.split('..').map{|d| Date.parse(d)}
(ends[0]..ends[1]).each do |d|
  p d.day
end
Purfideas
+3  A: 

But then just do

ends = '20080201..20080229'.split('..').map{|d| Integer(d)}
ends[0]..ends[1]

anyway I don't recommend eval, for security reasons

Purfideas
What's the security reason involved with using eval?
Chris Bunch
cmd line input is "user input," so can you be this always gets executed by trusted people? this is the original SQL injection... ask that q in security ... it'll be your highest score ever. :)
Purfideas
+2  A: 

Inject with no args works well for two element arrays:

rng='20080201..20080229'.split('..').inject { |s,e| s.to_i..e.to_i }

Of course, this can be made generic

class Range
  def self.from_ary(a)
    a.inject{|s,e| [s..e]}
  end
end

rng = Range.from_ary('20080201..20080229'.split('..').map{|s| s.to_i})
theschmitzer
Shouldn't that be inject{|s,e| (s.to_i .. e.to_i) } ? As written, it returns an Array with a range as a single element instead of a Range.
cpm
Commenting well after the fact, as I did rush to accept the answer, which when I looked at it, then intention made sense, but I admit when I tried it I found the same problem.
Chris Mayer
A: 
Range.new(*self.split("..").map{|s|s.to_i})
ujifgc