<p>I have some Ruby code which takes dates on the command line in the format:</p>

<pre><code>-d 20080101,20080201..20080229,20080301
</code></pre>

<p>I want to run for all dates between <code>20080201</code> and <code>20080229</code> inclusive and the other dates present in the list.</p>

<p>I can get the string <code>20080201..20080229</code>, so is the best way to convert this to a Range instance? Currently, I am using <code>eval</code>, but it feels like there should be a better way.</p>

<hr>

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

[{'answer_id': 53504, 'author': 'Purfideas', 'author_id': 4615, 'author_profile': 'https://Stackoverflow.com/users/4615', 'pm_score': 2, 'selected': False, 'text': "<p>assuming you want the range to iterate properly through months etc, try</p>\n\n<pre><code>require 'date'\n\nends = '20080201..20080229'.split('..').map{|d| Date.parse(d)}\n(ends[0]..ends[1]).each do |d|\n  p d.day\nend\n</code></pre>\n"}, {'answer_id': 53588, 'author': 'Purfideas', 'author_id': 4615, 'author_profile': 'https://Stackoverflow.com/users/4615', 'pm_score': 5, 'selected': True, 'text': "<p>But then just do </p>\n\n<pre><code>ends = '20080201..20080229'.split('..').map{|d| Integer(d)}\nends[0]..ends[1]\n</code></pre>\n\n<p>anyway I don't recommend eval, for security reasons</p>\n"}, {'answer_id': 54647, 'author': 'theschmitzer', 'author_id': 2167252, 'author_profile': 'https://Stackoverflow.com/users/2167252', 'pm_score': 3, 'selected': False, 'text': "<p>Inject with no args works well for two element arrays:</p>\n\n<pre><code>rng='20080201..20080229'.split('..').inject { |s,e| s.to_i..e.to_i }\n</code></pre>\n\n<p>Of course, this can be made generic</p>\n\n<pre><code>class Range\n  def self.from_ary(a)\n    a.inject{|s,e| s..e }\n  end\nend\n\nrng = Range.from_ary('20080201..20080229'.split('..').map{|s| s.to_i})\nrng.class  # =&gt; Range\n</code></pre>\n"}, {'answer_id': 3243732, 'author': 'ujifgc', 'author_id': 391229, 'author_profile': 'https://Stackoverflow.com/users/391229', 'pm_score': 5, 'selected': False, 'text': '<pre><code>Range.new(*self.split("..").map(&amp;:to_i))\n</code></pre>\n'}, {'answer_id': 21399899, 'author': 'MetalArend', 'author_id': 1945685, 'author_profile': 'https://Stackoverflow.com/users/1945685', 'pm_score': 0, 'selected': False, 'text': "<p>Combining @Purfideas answer with another answer somewhere on StackOverflow, I solved this by also surrounding the code with an input check, so the only thing used is a valid enumerable </p>\n\n<pre><code>if !value[/^[0-9]+\\.\\.[0-9]+$/].nil?\n    ends = value.split('..').map{|d| Integer(d)}\n    value = ends[0]..ends[1]\nend\n</code></pre>\n\n<p>It essentially rewrites your string value to a enumerable value. This comes in handy if you add a enumerable field in a yaml config file.</p>\n\n<p>If you need it for your application, you could extend the regex with an optional third literal dot, that could be optional.</p>\n"}, {'answer_id': 26996959, 'author': 'nurettin', 'author_id': 227755, 'author_profile': 'https://Stackoverflow.com/users/227755', 'pm_score': 0, 'selected': False, 'text': '<p>If we do it like</p>\n\n<pre><code>v= "20140101..20150101"\nraise "Error: invalid format: #{v}" if /\\d{8}\\.\\.\\d{8}/ !~ v\nr= eval(v)\n</code></pre>\n\n<p>and the attacker has a way of bypassing the raise check (simply by means of manipulating the runtime to disable exceptions) then we can get a dangerous eval which will potentially destroy the universe.</p>\n\n<p>So for the sake of reducing attack vectors, we check the format, and then do the parsing manually, then check the results</p>\n\n<pre><code>v= "20140101..20150101"\nraise "Error: invalid format: #{v}" if /\\d{8}\\.\\.\\d{8}/ !~ v\nr= Range.new(*v.split(/\\.\\./).map(&amp;:to_i))\nraise "Error: invalid range: #{v}" if r.first&gt; r.last\n</code></pre>\n'}, {'answer_id': 29943562, 'author': 'Epigene', 'author_id': 3319298, 'author_profile': 'https://Stackoverflow.com/users/3319298', 'pm_score': 1, 'selected': False, 'text': '<p><a href="https://github.com/Epigene/ranger" rel="nofollow noreferrer">Ranger</a> uses regex to validate strings with no SQL injection fear, and then <code>eval</code>.</p>\n'}, {'answer_id': 48169090, 'author': 'shubham mishra', 'author_id': 7516788, 'author_profile': 'https://Stackoverflow.com/users/7516788', 'pm_score': 0, 'selected': False, 'text': "<p>Here suppose you want to store the hash as a system constant value and fetch it in any model. The hash key will be a range value.</p>\n\n<pre><code>hash_1 = {1..5 =&gt; 'a', 6..12 =&gt; 'b', 13..67 =&gt; 'c', 68..9999999 =&gt; 'd'}\n</code></pre>\n\n<p>Then create the system constant with value as hash_1.to_json.\n.to_json will convert your hash object to JSON object.\nNow inside the code create a new hash hash_2,</p>\n\n<pre><code>JSON.parse(SystemConstant.get('Constant_name')).each{|key,val| temp_k=key.split('..').map{|d| Integer(d)}; hash_2[temp_k[0]..temp_k[1]] = val}\n</code></pre>\n\n<p>The new hash_2 will be the required hash_1</p>\n"}, {'answer_id': 65895545, 'author': 'Matthew', 'author_id': 145725, 'author_profile': 'https://Stackoverflow.com/users/145725', 'pm_score': 0, 'selected': False, 'text': '<p>I had a similar requirement although in my case the strings were in two possible formats, occasionally they were single number strings such as &quot;7&quot;, other times they were ranges such as &quot;10-14&quot;. Either way I wanted to turn the string into an Enumerable collection of numbers.</p>\n<p>My approach (inspired by the <a href="https://stackoverflow.com/a/3243732/145725">highest voted answer</a>) was:</p>\n\n<pre class="lang-ruby prettyprint-override"><code>def numbers(from_string:)\n  if from_string.include?(\'-\')\n    return Range.new(*from_string.split(\'-\').map(&amp;:to_i))\n  else\n    return [from_string.to_i] # put number in an array so we can enumerate over it\n  end\nend\n</code></pre>\n<p>It can also be done as a (long) one-liner if you think that\'s more readable:</p>\n<pre class="lang-ruby prettyprint-override"><code>from_string.include?(\'-\') ? Range.new(*from_string.split(\'-\').map(&amp;:to_i)) : [from_string.to_i]\n</code></pre>\n<p>I was processing a long list of known strings, not dealing with arbitrary user input so this doesn\'t guard against malicious input.</p>\n'}]
['https://Stackoverflow.com/questions/53472', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/4121/']