Number formatter

Hi,

Does anyone know if the reverse of the rails 20.kilobytes (megabytes/ gigabytes etc.) exists? I have lots of values in my model that are stored as bytes and I'd like to easily convert them to a MB or GB approximation (say 1 decimal place) with *B as a suffix after the number.

I also need to do the same for decimal numbers in terms of thousands and millions.

I could write something to do it but I wondered if there was an easier way?

Also if I did write a class to deal with it where in the rails directory structure should it go? helpers?

Thanks, Toby

http://api.rubyonrails.org/classes/ActiveSupport/CoreExtensions/Numeric/Bytes.html

I am aware of the ruby extensions that will go in one direction but those don't work in the other direction. All my values are bytes already and I want to convert those to kilo/mega/giga bytes etc.

Also if I did write a class to deal with it where in the rails directory structure should it go? helpers?

You could put it there if you think you're unlikely to use it anywhere other than just this app, else I tend to put things like this into their own file in lib.

that was a fun little exercise... here's how i interpreted your need:

class Numeric   def to(unit, places=1)     units = { :b => 1,               :kb => 1024**1,               :mb => 1024**2,               :gb => 1024**3,               :tb => 1024**4,               :pb => 1024**5,               :eb => 1024**6}     unitval = units[unit.to_s.downcase.to_sym]     "#{sprintf("%.#{places}f", self / unitval)} #{unit.to_s.upcase}"   end # to end

puts 1024.to(:kb) # 1.0 KB puts 20000.0.to(:kb) # 19.5 KB puts 123456789.to(:mb) # 117.0 MB puts 123456789.to('MB') # 117.0 MB puts 123456789.to(:MB) # 117.0 MB puts 123456789.to(:mb, 0) # 117 MB puts 345678912345.4.to(:gb, 3) # 321.939 GB

Thanks that's great - I did something similar in the end except mine didn't have the ability to choose, it just went to the smallest that wasn't less than zero. I think I'll combine the two!

You can use number_to_human_size(size, precision=1) from ActionView::Helpers::NumberHelper (http://api.rubyonrails.org/classes/ActionView/Helpers/NumberHelper.html#M000524)

Adam

tobyclemson@gmail.com wrote:

Does anyone know if the reverse of the rails 20.kilobytes (megabytes/ gigabytes etc.) exists? I have lots of values in my model that are stored as bytes and I'd like to easily convert them to a MB or GB approximation (say 1 decimal place) with *B as a suffix after the number.

This reply is over a year old, but I thought I'd archive the information in this thread.

While ActionView in rails does have a helper for this, it requires you to supply the number of decimal places. What follows is my own code (as a Ramaze helper) that (by default) automatically determines the number of decimal places based on the size of the answer.

For example: [ 1500 12_000 130_000 1_400_000 ].each do |bytes|   puts nice_bytes( b ) end #=> 1.46kB #=> 11.7kB #=> 127kB #=> 1.34MB

module Ramaze::Helper::NiceBytes   K = 2.0**10   M = 2.0**20   G = 2.0**30   T = 2.0**40   def nice_bytes( bytes, max_digits=3 )     value, suffix, precision = case bytes       when 0...K         [ bytes, 'b', 0 ]       else         value, suffix = case bytes           when K...M : [ bytes / K, 'kB' ]           when M...G : [ bytes / M, 'MB' ]           when G...T : [ bytes / G, 'GB' ]           else [ bytes / T, 'TB' ]         end         used_digits = case value           when 0...10 : 1           when 10...100 : 2           when 100...1000 : 3         end         leftover_digits = max_digits - used_digits         [ value, suffix, leftover_digits > 0 ? leftover_digits : 0 ]     end     "%.#{precision}f#{suffix}" % value   end end

Gavin Kistner wrote:

While ActionView in rails does have a helper for this, it requires you to supply the number of decimal places. What follows is my own code (as a Ramaze helper) that (by default) automatically determines the number of decimal places based on the size of the answer.

I just found this thread an Rails' number_to_human_size does exactly what you want as far as I can see, so there is no need to write your own function it seems?

Michael Hasenstein wrote:

Gavin Kistner wrote:

While ActionView in rails does have a helper for this, it requires you to supply the number of decimal places. What follows is my own code (as a Ramaze helper) that (by default) automatically determines the number of decimal places based on the size of the answer.

I just found this thread an Rails' number_to_human_size does exactly what you want as far as I can see, so there is no need to write your own function it seems?

ActionView::Helpers::NumberHelper

If you read the part of what I wrote that you quoted again, I think you'll find that Rails' method does not do the same thing when no precision parameter is supplied.

If you read the part of what I wrote that you quoted again, I think you'll find that Rails' method does not do the same thing when no precision parameter is supplied.

So what is so difficult or bad about giving it that one parameter :precision => 2 that you feel you have to roll your own lengthy function?

I still don't understand, but I would like to.

Michael Hasenstein wrote:

I still don't understand, but I would like to.

Okay, now I do. But I still think a new function is not necessary. The only difference in behavior without the precision parameter is that the Rails function defaults to 1. Output of your example using the Rails function:

1.5 KB (your function: 1.46) 11.7 KB 127 KB 1.3 MB (your function: 1.34)

That looks very acceptable to me and a lot of people. Of course, do what you want, the only reason I post is because when *I* found this thread looking for such a functionality I copied your code, and only then realized there's a function already. I respond to let others know right away who find this through Google.

Michael Hasenstein wrote:

That looks very acceptable to me and a lot of people. Of course, do what you want, the only reason I post is because when *I* found this thread looking for such a functionality I copied your code, and only then realized there's a function already. I respond to let others know right away who find this through Google.

I think it's excellent that you recorded for the record the simplest case for others to follow. To be clear, here's the output I want (and have):

[ 1, 12, 123, 1234, 12345, 123456, 1234567, 12345678, 123456789, 1234567890 ].each{ |bytes|   puts nice_bytes( bytes ) }

#=> 1b #=> 12b #=> 123b #=> 1.21kB #=> 12.1kB #=> 121kB #=> 1.18MB #=> 11.8MB #=> 118MB #=> 1.15GB

With the exception of bytes, I get two decimal places when there are less than 10 of the amount, one decimal place with less than a hundred, and no decimal places for hundreds. Windows does this, and I actually like it. Although unrelated to real significant figures, it's similar: there are ~always 3 digits displayed. As the number grows in magnitude, I am less interested in the details of the exact decimals.

When working with a large number of files all in the same rough range, this lets me automatically visually display them in a way that allows them to be compared and distinguished, without too much detail.

*shrug*

Not a big deal. As you say, most people will find the rails method suits their needs.

BTW, here's updated 1.9 compatible code for the function: K = 2.0**10 M = 2.0**20 G = 2.0**30 T = 2.0**40 def nice_bytes( bytes, max_digits=3 )   value, suffix, precision = case bytes     when 0...K       [ bytes, 'b', 0 ]     else       value, suffix = case bytes         when K...M then [ bytes / K, 'kB' ]         when M...G then [ bytes / M, 'MB' ]         when G...T then [ bytes / G, 'GB' ]         else [ bytes / T, 'TB' ]       end       used_digits = case value         when 0...10 then 1         when 10...100 then 2         when 100...1000 then 3       end       leftover_digits = max_digits - used_digits       [ value, suffix, leftover_digits > 0 ? leftover_digits : 0 ]   end   "%.#{precision}f#{suffix}" % value end

Gavin Kistner wrote:

Bah. One, final, 1.9-compatible post that also handles the edge case of values in the range 1000...1024 of a value correctly.

Thanks for the effort!

Why don't you submit it to Rails so that they replace their version with yours?