class Extenso
Constants
- BRL
- CENTENAS
As centenas, com exceção de 'cento', também variam em gênero. Aqui também se faz necessário dois conjuntos de strings (masculinas e femininas).
- CENTENAS_ORDINAL
- CENTENA_EXATA
- DE11A19
- DEZENAS
- DEZENAS_ORDINAL
- GENERO_FEM
- GENERO_MASC
- MILHAR
'Mil' é invariável, seja em gênero, seja em número
- MILHAR_ORDINAL
- MILHOES
- NUM_PLURAL
- NUM_SING
- POS_GENERO
- UNIDADES
As unidades 1 e 2 variam em gênero, pelo que precisamos de dois conjuntos de strings (masculinas e femininas) para as unidades
- UNIDADES_ORDINAL
- VALOR_MAXIMO
Public Class Methods
is_float?(str)
click to toggle source
# File lib/extensobr.rb, line 179 def self.is_float?(str) !!Float(str) rescue false end
is_int(s)
click to toggle source
# File lib/extensobr.rb, line 175 def self.is_int(s) Integer(s) != nil rescue false end
moeda( valor, casas_decimais = 2, info_unidade = ['Real', 'Reais', GENERO_MASC], info_fracao = ['Centavo', 'Centavos', GENERO_MASC] )
click to toggle source
# File lib/extensobr.rb, line 290 def self.moeda( valor, casas_decimais = 2, info_unidade = ['Real', 'Reais', GENERO_MASC], info_fracao = ['Centavo', 'Centavos', GENERO_MASC] ) # Gera a representação por extenso de um valor monetário, maior que zero e menor ou igual a Extenso::VALOR_MAXIMO. # # # PARÂMETROS: # valor (Float) O valor monetário cujo extenso se deseja gerar. # casas_decimais (Integer) [Opcional; valor padrão: 2] Número de casas decimais a serem consideradas como parte fracionária (centavos) # # info_unidade (Array) [Opcional; valor padrão: ['real', 'reais', Extenso::GENERO_MASC]] Fornece informações sobre a moeda a ser # utilizada. O primeiro valor da matriz corresponde ao nome da moeda no singular, o segundo ao nome da moeda no plural e o terceiro # ao gênero gramatical do nome da moeda (Extenso::GENERO_MASC ou Extenso::GENERO_FEM) # # info_fracao (Array) [Opcional; valor padrão: ['centavo', 'centavos', Extenso::GENERO_MASC]] Provê informações sobre a parte fracionária # da moeda. O primeiro valor da matriz corresponde ao nome da parte fracionária no singular, o segundo ao nome da parte fracionária no plural # e o terceiro ao gênero gramatical da parte fracionária (Extenso::GENERO_MASC ou Extenso::GENERO_FEM) # # VALOR DE RETORNO: # (String) O valor monetário por extenso # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ---- if ! self.is_float?(valor.to_f.round(casas_decimais).to_s) raise "[Exceção em Extenso.moeda] Parâmetro 'valor' não é numérico (recebido: '#{valor}')" elsif valor <= 0 "Zero" elsif ! self.is_int(casas_decimais) || casas_decimais < 0 raise "[Exceção em Extenso.moeda] Parâmetro 'casas_decimais' não é numérico ou é menor que zero (recebido: '#{casas_decimais}')" elsif info_unidade.class != Array || info_unidade.length < 3 temp = info_unidade.class == Array ? '[' + info_unidade.join(', ') + ']' : "'#{info_unidade}'" raise "[Exceção em Extenso.moeda] Parâmetro 'info_unidade' não é uma matriz com 3 (três) elementos (recebido: #{temp})" elsif info_unidade[POS_GENERO] != GENERO_MASC && info_unidade[POS_GENERO] != GENERO_FEM raise "Exceção em Extenso: valor incorreto para o parâmetro 'info_unidade[POS_GENERO]' (recebido: '#{info_unidade[POS_GENERO]}')" elsif info_fracao.class != Array || info_fracao.length < 3 temp = info_fracao.class == Array ? '[' + info_fracao.join(', ') + ']' : "'#{info_fracao}'" raise "[Exceção em Extenso.moeda] Parâmetro 'info_fracao' não é uma matriz com 3 (três) elementos (recebido: #{temp})" elsif info_fracao[POS_GENERO] != GENERO_MASC && info_fracao[POS_GENERO] != GENERO_FEM raise "[Exceção em Extenso.moeda] valor incorreto para o parâmetro 'info_fracao[POS_GENERO]' (recebido: '#{info_fracao[POS_GENERO]}')." end # ----------------------------------------------- ret = '' valor = sprintf("%#{casas_decimais.to_f / 100}f", valor) # A parte inteira do valor monetário corresponde ao valor passado antes do '.' no tipo float. parte_inteira = valor.split('.')[0].to_i # A parte fracionária ('centavos'), por seu turno, corresponderá ao valor passado depois do '.' fracao = valor.to_s.split('.')[1].to_i # os préstimos do método Extenso::numero(). if parte_inteira > 0 ret = self.numero(parte_inteira, info_unidade[POS_GENERO]) + ((parte_inteira >= 1000000 && (parte_inteira.to_s.chars.reverse[5] == "0" ) ) ? ' de ' : ' ') ret += parte_inteira == 1 ? info_unidade[NUM_SING] : info_unidade[NUM_PLURAL] ret end # De forma semelhante, o extenso da fracao somente será gerado se esta for maior que zero. */ if fracao > 0 # Se a parte_inteira for maior que zero, o extenso para ela já terá sido gerado. Antes de juntar os # centavos, precisamos colocar o conectivo 'e'. if parte_inteira > 0 ret += ' e ' end ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' ' ret += fracao == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL] end if valor.to_f == 0 ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' ' ret += parte_inteira == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL] end ret end
numero(valor, genero = GENERO_MASC)
click to toggle source
# File lib/extensobr.rb, line 185 def self.numero (valor, genero = GENERO_MASC) # Gera a representação por extenso de um número inteiro, maior que zero e menor ou igual a VALOR_MAXIMO. # # PARÂMETROS: # valor (Integer) O valor numérico cujo extenso se deseja gerar # # genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM) # do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'. # # VALOR DE RETORNO: # (String) O número por extenso # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ---- if !is_int(valor) raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')" elsif valor <= 0 'Zero' elsif valor > VALOR_MAXIMO raise "[Exceção em Extenso.numero] Parâmetro '#{valor} deve ser um inteiro entre 1 e #{VALOR_MAXIMO.to_s} (recebido: '#{valor}')" elsif genero != GENERO_MASC && genero != GENERO_FEM raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')" # ------------------------------------------------ elsif valor >= 1 && valor <= 9 UNIDADES[genero][valor] elsif valor == 10 DEZENAS[valor] elsif valor >= 11 && valor <= 19 DE11A19[valor] elsif valor >= 20 && valor <= 99 dezena = valor - (valor % 10) ret = DEZENAS[dezena] # Chamada recursiva à função para processar resto se este for maior que zero. # O conectivo 'e' é utilizado entre dezenas e unidades. resto = valor - dezena if resto > 0 ret += ' e ' + self.numero(resto, genero) end ret elsif valor == 100 CENTENA_EXATA elsif valor >= 101 && valor <= 999 centena = valor - (valor % 100) ret = CENTENAS[genero][centena] # As centenas (exceto 'cento') variam em gênero # Chamada recursiva à função para processar resto se este for maior que zero. # O conectivo 'e' é utilizado entre centenas e dezenas. resto = valor - centena if resto > 0 ret += ' e ' + self.numero(resto, genero) end ret elsif valor >= 1000 && valor <= 999999 # A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000, # assim determinando a quantidade de milhares. O resultado é enviado a uma chamada recursiva # da função. A palavra 'mil' não se flexiona. milhar = (valor / 1000).floor ret = self.numero(milhar, GENERO_MASC) + ' ' + MILHAR # 'Mil' é do gênero masculino resto = valor % 1000 # Chamada recursiva à função para processar resto se este for maior que zero. # O conectivo 'e' é utilizado entre milhares e números entre 1 e 99, bem como antes de centenas exatas. if resto > 0 && ((resto >= 1 && resto <= 99) || resto % 100 == 0) ret += ' e ' + self.numero(resto, genero) # Nos demais casos, após o milhar é utilizada a vírgula. elsif (resto > 0) ret += ', ' + self.numero(resto, genero) end ret elsif valor >= 100000 && valor <= VALOR_MAXIMO # A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000000, # assim determinando a quantidade de milhões. O resultado é enviado a uma chamada recursiva # da função. A palavra 'milhão' flexiona-se no plural. milhoes = (valor / 1000000).floor ret = self.numero(milhoes, GENERO_MASC) + ' ' # Milhão e milhões são do gênero masculino # Se a o número de milhões for maior que 1, deve-se utilizar a forma flexionada no plural ret += milhoes == 1 ? MILHOES[NUM_SING] : MILHOES[NUM_PLURAL] resto = valor % 1000000 # Chamada recursiva à função para processar resto se este for maior que zero. # O conectivo 'e' é utilizado entre milhões e números entre 1 e 99, bem como antes de centenas exatas. if resto && (resto >= 1 && resto <= 99) ret += ' e ' + self.numero(resto, genero) # Nos demais casos, após o milhão é utilizada a vírgula. elsif resto > 0 ret += ', ' + self.numero(resto, genero) end ret end end
ordinal(valor, genero = GENERO_MASC)
click to toggle source
# File lib/extensobr.rb, line 381 def self.ordinal (valor, genero = GENERO_MASC) # Gera a representação ordinal de um número inteiro de 1 à 1000 # PARÂMETROS: # valor (Integer) O valor numérico cujo extenso se deseja gerar # # genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM) # do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'. # # VALOR DE RETORNO: # (String) O número por extenso # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ---- if !is_int(valor) raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')" elsif valor <= 0 'Zero' # raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')" elsif valor > VALOR_MAXIMO raise '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')" elsif genero != GENERO_MASC && genero != GENERO_FEM raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')" # ------------------------------------------------ elsif valor >= 1 && valor <= 9 return UNIDADES_ORDINAL[genero][valor] elsif valor >= 10 && valor <= 99 dezena = valor - (valor % 10) resto = valor - dezena ret = DEZENAS_ORDINAL[genero][dezena]+" " if resto > 0 then ret+= self.ordinal(resto,genero); end return ret elsif valor >= 100 && valor <= 999 centena = valor - (valor % 100) resto = valor - centena ret = CENTENAS_ORDINAL[genero][centena]+" " if resto > 0 then ret += self.ordinal(resto, genero); end return ret elsif valor == 1000 return MILHAR_ORDINAL[genero][valor]+" " end end
real_formatado(valor)
click to toggle source
Gera o valor em formato de Real
Exemplo:
Extenso.real_formatado(10) - R$ 10,00 Extenso.real_formatado(1.55) - R$ 1,55
# File lib/extensobr.rb, line 432 def self.real_formatado(valor) float_valor = sprintf("%#0.02f", valor) if float_valor.chars.count >= 7 float_valor = float_valor.chars.reverse.insert(6, '.').reverse.join end if float_valor.chars.count >= 11 float_valor = float_valor.chars.reverse.insert(10, '.').reverse.join end float_valor = float_valor.chars.reverse float_valor[2] = ',' "R$ #{float_valor.reverse.join}" end