Usando number_to_currency em modelos no Rails
Leia em 1 minuto
No PHP, uma função muito usada é number_format, mas no Ruby não temos nada assim nativamente. O Rails implementa sua própria versão com o helper number_to_currency
, que satisfaz totalmente minhas necessidades. O problema é que ele só está disponível na view e, sendo assim, você não consegue utilizá-lo nem no modelo, nem no controller.
Para resolver isto, estendi algumas classes de modo que isso esteja disponível para qualquer instância de números (Fixnum
, Bignum
ou Float
). Adicionalmente, um método to_number
foi adicionado aos objetos da classe String
, convertendo valores como 150.00
ou 150,00
para números do tipo Float
.
module Currency
BRL = {:delimiter => ".", :separator => ",", :unit => "R$", :precision => 2, :position => "before"}
USD = {:delimiter => ',', :separator => ".", :unit => "US$", :precision => 2, :position => "before"}
DEFAULT = USD.merge(:unit => "$")
module String
def to_number(options={})
return self.gsub(/,/, '.').to_f if self.numeric?
nil
end
def numeric?
self =~ /^(|-)?[0-9]+((\.|,)[0-9]+)?$/ ? true : false
end
end
module Number
def to_currency(options = {})
number = self
default = Currency::DEFAULT.stringify_keys
options = default.merge(options.stringify_keys)
precision = options["precision"] || default["precision"]
unit = options["unit"] || default["unit"]
position = options["position"] || default["position"]
separator = precision > 0 ? options["separator"] || default["separator"] : ""
delimiter = options["delimiter"] || default["delimiter"]
begin
parts = number.with_precision(precision).split('.')
number = parts[0].to_i.with_delimiter(delimiter) + separator + parts[1].to_s
position == "before" ? unit + number : number + unit
rescue
number
end
end
def with_delimiter(delimiter=",", separator=".")
number = self
begin
parts = number.to_s.split(separator)
parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\1#{delimiter}")
parts.join separator
rescue
self
end
end
def with_precision(precision=3)
number = self
"%01.#{precision}f" % number
end
end
end
class Fixnum; include Currency::Number; end
class Bignum; include Currency::Number; end
class Float; include Currency::Number; end
class String; include Currency::String; end
Para ter estes novos métodos funcionando basta adicionar o código acima ao arquivo "environment.rb". Veja alguns exemplos de uso:
number = 9999.99
# using default settings
puts number.to_currency # $9,999.99
# using Brazilian Real
puts number.to_currency(Currency::BRL) # R$9.999,99
# using US Dollar
puts number.to_currency(Currency::USD) # US$9,999.99
# setting default to Brazilian Real
silence_warnings do
Currency::DEFAULT = Currency::BRL
end
# using default settings, now
# Brazilian Real
number.to_currency # R$9.999,99
puts '199.99'.to_number # 199.99
puts '199,99'.to_number # 199.99
puts '+199,99'.to_number # 199.99
puts '-199,99'.to_number # -199.99