views:

134

answers:

3

Hello,

My objective is to convert form input, like "100 megabytes" or "1 gigabyte", and converts it to a filesize in kilobytes I can store in the database. Currently, I have this:

def quota_convert
  @regex = /([0-9]+) (.*)s/
  @sizes = %w{kilobyte megabyte gigabyte}
  m = self.quota.match(@regex)
  if @sizes.include? m[2]
    eval("self.quota = #{m[1]}.#{m[2]}")
  end
end

This works, but only if the input is a multiple ("gigabytes", but not "gigabyte") and seems insanely unsafe due to the use of eval. So, functional, but I won't sleep well tonight.

Any guidance?

EDIT: ------

All right. For some reason, the regex with (.*?) isn't working correctly on my setup, but I've worked around it with Rails stuff. Also, I've realized that bytes would work better for me.

def quota_convert
  @regex = /^([0-9]+\.?[0-9]*?) (.*)/
  @sizes = { 'kilobyte' => 1024, 'megabyte' => 1048576, 'gigabyte' => 1073741824}
  m = self.quota.match(@regex)
  if @sizes.include? m[2].singularize
    self.quota = m[1].to_f*@sizes[m[2].singularize]
  end
end

This catches "1 megabyte", "1.5 megabytes", and most other things (I hope). It then makes it the singular version regardless. Then it does the multiplication and spits out magic answers.

Is this legit?

EDIT AGAIN: See answer below. Much cleaner than my nonsense.

+1  A: 

why don't you simply create a hash that contains various spellings of the multiplier as the key and the numerical value as the value? No eval necessary and no regexs either!

ennuikiller
The problem with that is I want to account for all cases ("550 megabytes", "1.5 gigabytes", etc) and a hash would just be ridiculous if I did that. I'd rather hand the conversion part over to Rails. I just need to parse it all out...somehow...
Evan Walsh
the point is you can read in the numeric values as numbers and just have the hash contain the multiplicative factor (kb, gb, mb etc.)
ennuikiller
A: 

First of all, changing your regex to @regex = /([0-9]+) (.*?)s?/ will fix the plural issue. The ? says match either 0 or 1 characters for the 's' and it causes .* to match in a non-greedy manner (as few characters as possible).

As for the size, you could have a hash like this:

@hash = { 'kilobyte' => 1, 'megabyte' => 1024, 'gigabyte' => 1024*1024}

and then your calculation is just self.quota = m[1].to_i*@hash[m2]

EDIT: Changed values to base 2

hundredwatt
Also, to account for values such as '1.5 kilobytes', your regex would be `@regex = /([0-9]+\.?[0-9]*?) (.*?)s?/`. In that case, you would need to change the calculation to `m[1].to_f` to convert the string to a floating point value
hundredwatt
A: 
def quota_convert
  @regex = /([0-9]+) (.*)s?/
  @sizes = "kilobytes megabytes gigabytes"
  m = self.quota.match(@regex)
  if @sizes.include? m[2]
    m[1].to_f.send(m[2])
  end
end
  • Added ? for optional plural in the regex.
  • Changed @sizes to a string of plurals.
  • Convert m[1] (the number to a float).
  • Send the message m[2] directly
Bryan Ash
Wow. This is really perfect. Thank you so much. _It's so clean._
Evan Walsh
If clean is what you seek, how about moving that functionality into String#bytes and calling `self.quota.bytes`
Bryan Ash