Ruby para programadores PHP

03/08/07

A maneira mais fácil de se aprender uma nova linguagem é comparando-a com uma linguagem que você já conhece. Pelo menos é assim que faço! Para os que são como eu, aqui vai uma série de comparações/equivalências entre as linguagens Ruby e PHP.

Leia na íntegra »

Removendo caracteres com o método trim no Ruby

02/08/07

Já precisou remover caracteres de uma string, com funções semelhantes a trim, rtrim e ltrim do PHP? Pois é! No Ruby você não tem isso nativamente. Para adicionar tais funcionalidades, basta estender a classe String com os métodos abaixo.

class String
  def trim!(chars)
    rtrim!(chars)
    ltrim!(chars)
  end
 
  def rtrim!(chars)
    gsub!(/(#{trim_prepare(chars)})+$/, '')
  end
 
  def ltrim!(chars)
    gsub!(/^(#{trim_prepare(chars)})+/, '')
  end
 
  def trim(chars)
    dup.rtrim(chars).ltrim(chars)
  end
 
  def rtrim(chars)
    dup.rtrim!(chars)
  end
 
  def ltrim(chars)
    dup.ltrim!(chars)
  end
 
  private
    def trim_prepare(chars)
      chars = chars.split("").collect { |char| Regexp.escape(char) }
      chars.join('|')
    end
end

Seu funcionamento é muito semelhante às funções do PHP. Veja:

text = '|_ ruby _|'
puts text.trim(' _|')  # both sides
puts text.ltrim(' _|') # left side
puts text.rtrim(' _|') # right side

Lembre-se que você não precisa passar os caracteres que serão removidos na ordem em que eles aparecem.

Usando number_to_currency em modelos no Rails

16/06/07

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