Question

Possible Duplicate:
In Ruby is there a way to overload the initialize constructor?

BigDecimal does not take a float as in initial value, so I am writing a constructor to handle it. It seems to be ignoring the initialize method and calling the default constructor.

It throws TypeError can't convert Float into String (TypeError)

The method format does work.

file BigDecimal.rb:

require 'bigdecimal'

class BigDecimal

    def initialize
        if self.class == Float
            super self.to_s
        end
    end

    def format
        sprintf("%.2f", self)
    end

end

Then, in file test.rb:

require 'BigDecimal' # => true
bd = BigDecimal.new('54.4477') # works
puts bd.format # 54.44
bd2 = BigDecimal.new(34.343) # TypeError: can't convert Float into String (TypeError)

Ruby 1.9.2

Was it helpful?

Solution

Problems with your code:

  1. You use a monkey patch instead of inheriting, so in your initialize method, super will call the initialize method of Object, which is the super class of BigDecimal. To call the default constructor, you have to use some other method as showing below.

  2. You did not put arguments for the initialize method.

  3. BigDecimal DOES take float as constructor argument

Therefore,

  1. You can use directly the default constructor and pass a float as:

    BigDecimal.new(34.343, 5) # 5 is the precision
    
  2. You can override the constructor in this way:

NOTE: we usually alias initialize method. However in this case this does not seem to work (for some unknown reason that initialize does not get called)... So we have to alias new method which is more fundamental.

    require 'bigdecimal'

    class BigDecimal

        class << self
          alias_method :__new__, :new  #alias the original constructor so we can call later
          def new(*args)
              if args.length == 1 && args[0].is_a?(Float)
                  __new__(args[0].to_s)
              else
                  __new__(*args)
              end
          end
        end

        def format
            sprintf("%.2f", self)
        end

    end

    BigDecimal.new(12.334)
    #<BigDecimal:10a9a48,'0.12334E2',18(18)>

OTHER TIPS

BigDecimal does not take a float as in initial value

Are you sure?

BigDecimal.new(2.4)
#=>ArgumentError: can't omit precision for a Rational.

So you have to give a precision as second argument:

BigDecimal.new(2.4, 2)
#=> #<BigDecimal:7ff689b0f2e8,'0.24E1',18(36)>

The docs don't indicate a change between 1.9.2 and 1.9.3.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top