views:

256

answers:

3

As I retrieve data from a database table an array is populated. Some of the fields are defined as decimal & money fields and within the array they are represented as BigDecimal.

I use these array values to populate a CSV file, but the problem is that all BigDecimal values are by default represented in Scientific format (which is the default behaviour of the BigDecimal to_s method). I can show the values by using to_s('F'), but how can I override the default?

A: 

Ruby makes this easy. Behold:

class BigDecimal
  def to_s
    return "Whatever weird format you want"
  end
end

# Now BigDecimal#to_s will do something new, for all BigDecimal objects everywhere.

This technique is called monkey patching. As you might guess from the name, it's something you should use cautiously. This use seems reasonable to me, though.

David Seiler
A: 
class BigDecimal
  alias old_to_s to_s

  def to_s( param = nil )
      self.old_to_s( param || 'F' )
   end
end
Farrel
Skoppensboer
Please don't do this. It unnecessarily pollutes `BigDecimal`'s namespace with a completely useless `old_to_s` method.
Jörg W Mittag
A: 

This is built on @Farrel's answer, but without polluting the method namespace with a useless old_xyz method. Also, why not use default arguments directly?

class BigDecimal
  old_to_s = instance_method :to_s

  define_method :to_s do |param='F'|
    old_to_s.bind(self).(param)
  end
end

In Ruby 1.8, this gets slightly uglier:

class BigDecimal
  old_to_s = instance_method :to_s

  define_method :to_s do |param|
    old_to_s.bind(self).call(param || 'F')
  end
end

Or, if you don't like the warning you get with the above code:

class BigDecimal
  old_to_s = instance_method :to_s

  define_method :to_s do |*param|
    old_to_s.bind(self).call(param.first || 'F')
  end
end
Jörg W Mittag
Tried this code, but got "syntax error, unexpected '=', expecting tCOLON2 or '[' or '.' on the define_method line
Skoppensboer
@Skoppensboer: Optional parameters with default arguments for blocks is a Ruby 1.9 feature. As is the `block.(foo)` syntax. In Ruby 1.8 you have to use a different solution for supplying the default argument and you need to use the `call` method.
Jörg W Mittag
Thx Joerg, thought it may be the case, but guys I'm trying to help out is still on 1.8.7
Skoppensboer