views:

194

answers:

2

sprintf("%g", [float]) allows me to format a floating point number without specifying precision, such that 10.00 is rendered as 10 and 10.01 is rendered as 10.01, and so on. This is neat.

In my application I'm rendering numbers using the Rails NumberHelper methods so that I can take advantage of the localization features, but I can't figure out how to achieve the above functionality through these helpers since they expect an explicit :precision option.

Is there a simple way around this?

+1  A: 

Why not just use Ruby's Kernel::sprintf with NumberHelper? Recommended usage with this syntax: str % arg where str is the format string (%g in your case):


>> "%g" % 10.01
=> "10.01"
>> "%g" % 10
=> "10"

Then you can use the NumberHelper to print just the currency symbol:


>>  foo = ActionView::Base.new
>>  foo.number_to_currency(0, :format => "%u") + "%g"%10.0 
=> "$10"

and define your own convenience method:


 def pretty_currency(val) 
    number_to_currency(0, :format => "%u") + "%g"%val
 end

pretty_currency(10.0)  # "$10"
pretty_currency(10.01) # "$10.01"

klochner
Thanks, but this doesn't achieve what I need. Specifically, I require the number formatted with different separators and delimiters based on the current locale of the user. So basically I need to use "%g" inside the NumberHelper method itself, which isn't possible to override. I will post my workaround as an answer.
Olly
+1  A: 

I have solved this by adding another method to the NumberHelper module as follows:

module ActionView
  module Helpers #:nodoc:
    module NumberHelper
      # Formats a +number+ such that the the level of precision is determined using the logic of sprintf("%g%"), that
      # is: "Convert a floating point number using exponential form if the exponent is less than -4 or greater than or
      #      equal to the precision, or in d.dddd form otherwise."
      # You can customize the format in the +options+ hash.
      #
      # ==== Options
      # * <tt>:separator</tt>  - Sets the separator between the units (defaults to ".").
      # * <tt>:delimiter</tt>  - Sets the thousands delimiter (defaults to "").
      #
      # ==== Examples
      #  number_with_auto_precision(111.2345)                    # => "111.2345"
      #  number_with_auto_precision(111)                         # => "111"
      #  number_with_auto_precision(1111.2345, :separator => ',', :delimiter => '.')  # "1,111.2345"
      #  number_with_auto_precision(1111, :separator => ',', :delimiter => '.')       # "1,111"
      def number_with_auto_precision(number, *args)
        options = args.extract_options!
        options.symbolize_keys!

        defaults           = I18n.translate(:'number.format', :locale => options[:locale], :raise => true) rescue {}
        separator ||= (options[:separator] || defaults[:separator])
        delimiter ||= (options[:delimiter] || defaults[:delimiter])

        begin
          number_with_delimiter("%g" % number,
            :separator => separator,
            :delimiter => delimiter)
        rescue
          number
        end
      end
    end
  end
end

It is the specific call to number_with_delimiter with the %g option which renders the number as described in the code comments above.

This works great for me, but I'd welcome thoughts on this solution.

Olly
looks good to me
klochner