extensobr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5e99b58efe83a3f99bb83bb9be0848571a809e4d
4
+ data.tar.gz: fe0ccbb85bbf842a10c77120e9e6e41a5e661113
5
+ SHA512:
6
+ metadata.gz: f0b80a3ea762824614f683473463b6943794e10701d5a2c2e0eec51a6f5b75083dfcded2e0d659e38d31b1061f3743d2d36b819d936fe3ee64b41aabdc31c2dc
7
+ data.tar.gz: 45907740fd1c97467723502ba54705e5b0937bcaa560517cfbb8deaefca136d72a9d71be1d0add7ec9e905c63f7ea37fcf29b0a68d9f6dadf88b8a304b428ad8
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at rickmaxg3@hotmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in extensobr.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 MacBook Pro
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ # Extensobr
2
+
3
+ Esta gem foi desenvolvida para auxiliar no desenvolvimento de aplicações onde é necessário escrever ou imprimir números ou moedas por extenso como por exemplo em recibos, contratos entre outros.
4
+
5
+
6
+ ## Instalação
7
+
8
+ Adicionando em sua Gemfile:
9
+
10
+ ```ruby
11
+ gem 'extensobr'
12
+ ```
13
+
14
+ Ou instale você mesmo:
15
+
16
+ $ gem install extensobr
17
+
18
+ ## Exemplos de uso
19
+
20
+ Para obter o extenso de um número, utilize GExtenso.numero.
21
+
22
+ irb
23
+
24
+ require 'Extensobr.rb'
25
+
26
+ puts Extenso.numero(832); # oitocentos e trinta e dois
27
+ puts Extenso.numero(832, Extenso::GENERO_FEM) # oitocentas e trinta e duas
28
+
29
+ Para obter o extenso de um valor monetário, utilize GExtenso.moeda.
30
+
31
+ require 'Extenso.rb'
32
+
33
+ ## IMPORTANTE: este método recebe um valor inteiro(int), para a contagem das casas decimais!
34
+
35
+ puts Extenso.moeda(15402) # cento e cinquenta e quatro reais e dois centavos
36
+ puts Extenso.moeda(47) # quarenta e sete centavos
37
+ puts Extenso.moeda(357082, 2, ['peseta', 'pesetas', Extenso::GENERO_FEM], ['cêntimo', 'cêntimos', Extenso::GENERO_MASC])
38
+
39
+ ## três mil, quinhentas e setenta pesetas e oitenta e dois cêntimos
40
+
41
+ # Developers
42
+
43
+ [Henrique Max](https://github.com/rickmax),
44
+ [Fausto G. Cintra](https://github.com/goncin)
45
+
46
+ ## Como contribuir?
47
+
48
+ 1. Fazer um fork do projeto
49
+ 1. Fazer os devidos ajustes com os respectivos testes
50
+ 1. Fazer pull request
51
+
52
+
53
+ ## Licença
54
+
55
+ Está Gem esta disponível sob ostermos de licença [MIT License](http://opensource.org/licenses/MIT).
56
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "extensobr"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
data/extensobr.gemspec ADDED
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'extensobr/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "extensobr"
8
+ spec.version = Extensobr::VERSION
9
+ spec.authors = ["Henrique Max"]
10
+ spec.email = ["rickmaxg3@hotmail.com"]
11
+
12
+ spec.summary = %q{ExtendoBr escreve números e moeda por extenso.}
13
+ spec.description = %q{ExtensoBr é uma gem que foi desenvolvida para auxiliar na impressão de números e moedas por extenso em portugês do Brasil.}
14
+ spec.homepage = "https://github.com/rickmax/extensobr"
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+
20
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
21
+ f.match(%r{^(test|spec|features)/})
22
+ end
23
+ spec.bindir = "exe"
24
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25
+ spec.require_paths = ["lib"]
26
+
27
+ spec.add_development_dependency "bundler", "~> 1.13"
28
+ spec.add_development_dependency "rake", "~> 10.0"
29
+ end
@@ -0,0 +1,3 @@
1
+ module Extensobr
2
+ VERSION = "0.1.0"
3
+ end
data/lib/extensobr.rb ADDED
@@ -0,0 +1,451 @@
1
+ require "extensobr/version"
2
+ class Extenso
3
+ # Extenso class file
4
+
5
+ # Extenso é uma classe que gera a representação por extenso de um número ou valor monetário.
6
+ #
7
+ # ATENÇÃO: A PÁGINA DE CÓDIGO DESTE ARQUIVO É UTF-8 (Unicode)!
8
+ #
9
+ # Sua implementação foi feita como prova de conceito, utilizando:
10
+ # * Métodos estáticos, implementando o padrão de projeto ("design pattern") SINGLETON;
11
+ # * Chamadas recursivas a métodos, minimizando repetições e mantendo o código enxuto; e
12
+ # * Tratamento de erros por intermédio de exceções.
13
+ #
14
+ # = EXEMPLOS DE USO =
15
+ #
16
+ # Para obter o extenso de um número, utilize Extenso.numero.
17
+ #
18
+ # puts Extenso.numero(832); # oitocentos e trinta e dois
19
+ # puts Extenso.numero(832, Extenso::GENERO_FEM) # oitocentas e trinta e duas
20
+ #
21
+ #
22
+ # Para obter o extenso de um valor monetário, utilize Extenso.moeda.
23
+ #
24
+ # # IMPORTANTE: veja nota sobre o parâmetro 'valor' na documentação do método!
25
+ #
26
+ # puts Extenso.moeda(15402) # cento e cinquenta e quatro reais e dois centavos
27
+ #
28
+ # puts Extenso.moeda(47) # quarenta e sete centavos
29
+ #
30
+ # puts Extenso.moeda(357082, 2,
31
+ # ['peseta', 'pesetas', Extenso::GENERO_FEM],
32
+ # ['cêntimo', 'cêntimos', Extenso::GENERO_MASC])
33
+ # # três mil, quinhentas e setenta pesetas e oitenta e dois cêntimos
34
+ #
35
+
36
+ NUM_SING = 0
37
+ NUM_PLURAL = 1
38
+ POS_GENERO = 2
39
+ GENERO_MASC = 0
40
+ GENERO_FEM = 1
41
+
42
+ VALOR_MAXIMO = 999999999
43
+
44
+ # As unidades 1 e 2 variam em gênero, pelo que precisamos de dois conjuntos de strings (masculinas e femininas) para as unidades
45
+ UNIDADES = {
46
+ GENERO_MASC => {
47
+ 1 => 'Um',
48
+ 2 => 'Dois',
49
+ 3 => 'Três',
50
+ 4 => 'Quatro',
51
+ 5 => 'Cinco',
52
+ 6 => 'Seis',
53
+ 7 => 'Sete',
54
+ 8 => 'Oito',
55
+ 9 => 'Nove'
56
+ },
57
+ GENERO_FEM => {
58
+ 1 => 'Uma',
59
+ 2 => 'Duas',
60
+ 3 => 'Três',
61
+ 4 => 'Quatro',
62
+ 5 => 'Cinco',
63
+ 6 => 'Seis',
64
+ 7 => 'Sete',
65
+ 8 => 'Oito',
66
+ 9 => 'Nove'
67
+ }
68
+ }
69
+
70
+ DE11A19 = {
71
+ 11 => 'Onze',
72
+ 12 => 'Doze',
73
+ 13 => 'Treze',
74
+ 14 => 'Quatorze',
75
+ 15 => 'Quinze',
76
+ 16 => 'Dezesseis',
77
+ 17 => 'Dezessete',
78
+ 18 => 'Dezoito',
79
+ 19 => 'Dezenove'
80
+ }
81
+
82
+ DEZENAS = {
83
+ 10 => 'Dez',
84
+ 20 => 'Vinte',
85
+ 30 => 'Trinta',
86
+ 40 => 'Quarenta',
87
+ 50 => 'Cinquenta',
88
+ 60 => 'Sessenta',
89
+ 70 => 'Setenta',
90
+ 80 => 'Oitenta',
91
+ 90 => 'Noventa'
92
+ }
93
+
94
+ CENTENA_EXATA = 'Cem'
95
+
96
+ # As centenas, com exceção de 'cento', também variam em gênero. Aqui também se faz
97
+ # necessário dois conjuntos de strings (masculinas e femininas).
98
+
99
+ CENTENAS = {
100
+ GENERO_MASC => {
101
+ 100 => 'Cento',
102
+ 200 => 'Duzentos',
103
+ 300 => 'Trezentos',
104
+ 400 => 'Quatrocentos',
105
+ 500 => 'Quinhentos',
106
+ 600 => 'Seiscentos',
107
+ 700 => 'Setecentos',
108
+ 800 => 'Oitocentos',
109
+ 900 => 'Novecentos'
110
+ },
111
+ GENERO_FEM => {
112
+ 100 => 'Cento',
113
+ 200 => 'Duzentas',
114
+ 300 => 'Trezentas',
115
+ 400 => 'Quatrocentas',
116
+ 500 => 'Quinhentas',
117
+ 600 => 'Seiscentas',
118
+ 700 => 'Setecentas',
119
+ 800 => 'Oitocentas',
120
+ 900 => 'Novecentas'
121
+ }
122
+ }
123
+
124
+ #'Mil' é invariável, seja em gênero, seja em número
125
+ MILHAR = 'mil'
126
+
127
+ MILHOES = {
128
+ NUM_SING => 'Milhão',
129
+ NUM_PLURAL => 'Milhões'
130
+ }
131
+
132
+ UNIDADES_ORDINAL = {
133
+ GENERO_MASC => {
134
+ 1 => 'Primeiro',
135
+ 2 => 'Segundo',
136
+ 3 => 'Terceiro',
137
+ 4 => 'Quarto',
138
+ 5 => 'Quinto',
139
+ 6 => 'Sexto',
140
+ 7 => 'Sétimo',
141
+ 8 => 'Oitavo',
142
+ 9 => 'Nono'},
143
+ GENERO_FEM => {
144
+ 1 => 'Primeira',
145
+ 2 => 'Segunda',
146
+ 3 => 'Terceira',
147
+ 4 => 'Quarta',
148
+ 5 => 'Quinta',
149
+ 6 => 'Sexta',
150
+ 7 => 'Sétima',
151
+ 8 => 'Oitava',
152
+ 9 => 'Nona'}}
153
+
154
+ DEZENAS_ORDINAL = {
155
+ GENERO_MASC => {
156
+ 10 => 'Décimo',
157
+ 20 => 'Vigésimo',
158
+ 30 => 'Trigésimo',
159
+ 40 => 'Quadragésimo',
160
+ 50 => 'Quinquagésimo',
161
+ 60 => 'Sexagésimo',
162
+ 70 => 'Septuagésimo',
163
+ 80 => 'Octogésimo',
164
+ 90 => 'Nonagésimo'},
165
+ GENERO_FEM => {
166
+ 10 => 'Décima',
167
+ 20 => 'Vigésima',
168
+ 30 => 'Trigésima',
169
+ 40 => 'Quadragésima',
170
+ 50 => 'Quinquagésima',
171
+ 60 => 'Sexagésima',
172
+ 70 => 'Septuagésima',
173
+ 80 => 'Octogésima',
174
+ 90 => 'Nonagésima'}}
175
+
176
+ CENTENAS_ORDINAL = {
177
+ GENERO_MASC => {
178
+ 100 => 'Centésimo',
179
+ 200 => 'Ducentésimo',
180
+ 300 => 'Trecentésimo',
181
+ 400 => 'Quadringentésimo',
182
+ 500 => 'Quingentésimo',
183
+ 600 => 'Seiscentésimo',
184
+ 700 => 'Septingentésimo',
185
+ 800 => 'Octingentésimo',
186
+ 900 => 'Noningentésimo'},
187
+ GENERO_FEM => {
188
+ 100 => 'Centésima',
189
+ 200 => 'Ducentésima',
190
+ 300 => 'Trecentésima',
191
+ 400 => 'Quadringentésima',
192
+ 500 => 'Quingentésima',
193
+ 600 => 'Seiscentésima',
194
+ 700 => 'Septingentésima',
195
+ 800 => 'Octingentésima',
196
+ 900 => 'Noningentésima'}}
197
+
198
+
199
+ MILHAR_ORDINAL = {
200
+ GENERO_MASC => {
201
+ 1000 => 'Milésimo'},
202
+ GENERO_FEM =>{
203
+ 1000 => 'Milésima'}}
204
+
205
+ def self.is_int(s)
206
+ Integer(s) != nil rescue false
207
+ end
208
+
209
+ #######################################################################################################################################
210
+
211
+ def self.numero (valor, genero = GENERO_MASC)
212
+
213
+ # Gera a representação por extenso de um número inteiro, maior que zero e menor ou igual a VALOR_MAXIMO.
214
+ #
215
+ # PARÂMETROS:
216
+ # valor (Integer) O valor numérico cujo extenso se deseja gerar
217
+ #
218
+ # genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
219
+ # do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'.
220
+ #
221
+ # VALOR DE RETORNO:
222
+ # (String) O número por extenso
223
+
224
+ # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
225
+
226
+ if !is_int(valor)
227
+ raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
228
+ elsif valor <= 0
229
+ raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')"
230
+ elsif valor > VALOR_MAXIMO
231
+ raise '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')"
232
+ elsif genero != GENERO_MASC && genero != GENERO_FEM
233
+ raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
234
+
235
+ # ------------------------------------------------
236
+
237
+ elsif valor >= 1 && valor <= 9
238
+ UNIDADES[genero][valor]
239
+
240
+ elsif valor == 10
241
+ DEZENAS[valor]
242
+
243
+ elsif valor >= 11 && valor <= 19
244
+ DE11A19[valor]
245
+
246
+ elsif valor >= 20 && valor <= 99
247
+ dezena = valor - (valor % 10)
248
+ ret = DEZENAS[dezena]
249
+ # Chamada recursiva à função para processar resto se este for maior que zero.
250
+ # O conectivo 'e' é utilizado entre dezenas e unidades.
251
+ resto = valor - dezena
252
+ if resto > 0
253
+ ret += ' e ' + self.numero(resto, genero)
254
+ end
255
+ ret
256
+
257
+ elsif valor == 100
258
+ CENTENA_EXATA
259
+
260
+ elsif valor >= 101 && valor <= 999
261
+ centena = valor - (valor % 100)
262
+ ret = CENTENAS[genero][centena] # As centenas (exceto 'cento') variam em gênero
263
+ # Chamada recursiva à função para processar resto se este for maior que zero.
264
+ # O conectivo 'e' é utilizado entre centenas e dezenas.
265
+ resto = valor - centena
266
+ if resto > 0
267
+ ret += ' e ' + self.numero(resto, genero)
268
+ end
269
+ ret
270
+
271
+ elsif valor >= 1000 && valor <= 999999
272
+ # A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000,
273
+ # assim determinando a quantidade de milhares. O resultado é enviado a uma chamada recursiva
274
+ # da função. A palavra 'mil' não se flexiona.
275
+ milhar = (valor / 1000).floor
276
+ ret = self.numero(milhar, GENERO_MASC) + ' ' + MILHAR # 'Mil' é do gênero masculino
277
+ resto = valor % 1000
278
+ # Chamada recursiva à função para processar resto se este for maior que zero.
279
+ # O conectivo 'e' é utilizado entre milhares e números entre 1 e 99, bem como antes de centenas exatas.
280
+ if resto > 0 && ((resto >= 1 && resto <= 99) || resto % 100 == 0)
281
+ ret += ' e ' + self.numero(resto, genero)
282
+ # Nos demais casos, após o milhar é utilizada a vírgula.
283
+ elsif (resto > 0)
284
+ ret += ', ' + self.numero(resto, genero)
285
+ end
286
+ ret
287
+
288
+ elsif valor >= 100000 && valor <= VALOR_MAXIMO
289
+ # A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000000,
290
+ # assim determinando a quantidade de milhões. O resultado é enviado a uma chamada recursiva
291
+ # da função. A palavra 'milhão' flexiona-se no plural.
292
+ milhoes = (valor / 1000000).floor
293
+ ret = self.numero(milhoes, GENERO_MASC) + ' ' # Milhão e milhões são do gênero masculino
294
+
295
+ # Se a o número de milhões for maior que 1, deve-se utilizar a forma flexionada no plural
296
+ ret += milhoes == 1 ? MILHOES[NUM_SING] : MILHOES[NUM_PLURAL]
297
+
298
+ resto = valor % 1000000
299
+
300
+ # Chamada recursiva à função para processar resto se este for maior que zero.
301
+ # O conectivo 'e' é utilizado entre milhões e números entre 1 e 99, bem como antes de centenas exatas.
302
+ if resto && ((resto >= 1 && resto <= 99) || resto % 100 == 0)
303
+ ret += ' e ' + ret.numero(resto, genero)
304
+ # Nos demais casos, após o milhão é utilizada a vírgula.
305
+ elsif resto > 0
306
+ ret += ', ' + self.numero(resto, genero)
307
+ end
308
+ ret
309
+
310
+ end
311
+
312
+ end
313
+
314
+ #######################################################################################################################################
315
+
316
+ def self.moeda(
317
+ valor,
318
+ casas_decimais = 2,
319
+ info_unidade = ['Real', 'Reais', GENERO_MASC],
320
+ info_fracao = ['Centavo', 'Centavos', GENERO_MASC]
321
+ )
322
+
323
+ # Gera a representação por extenso de um valor monetário, maior que zero e menor ou igual a Extenso::VALOR_MAXIMO.
324
+ #
325
+ #
326
+ # PARÂMETROS:
327
+ # valor (Integer) O valor monetário cujo extenso se deseja gerar.
328
+ # ATENÇÃO: PARA EVITAR OS CONHECIDOS PROBLEMAS DE ARREDONDAMENTO COM NÚMEROS DE PONTO FLUTUANTE, O VALOR DEVE SER PASSADO
329
+ # JÁ DEVIDAMENTE MULTIPLICADO POR 10 ELEVADO A $casasDecimais (o que equivale, normalmente, a passar o valor com centavos
330
+ # multiplicado por 100)
331
+ #
332
+ # casas_decimais (Integer) [Opcional; valor padrão: 2] Número de casas decimais a serem consideradas como parte fracionária (centavos)
333
+ #
334
+ # info_unidade (Array) [Opcional; valor padrão: ['real', 'reais', Extenso::GENERO_MASC]] Fornece informações sobre a moeda a ser
335
+ # utilizada. O primeiro valor da matriz corresponde ao nome da moeda no singular, o segundo ao nome da moeda no plural e o terceiro
336
+ # ao gênero gramatical do nome da moeda (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
337
+ #
338
+ # info_fracao (Array) [Opcional; valor padrão: ['centavo', 'centavos', Extenso::GENERO_MASC]] Provê informações sobre a parte fracionária
339
+ # 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
340
+ # e o terceiro ao gênero gramatical da parte fracionária (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
341
+ #
342
+ # VALOR DE RETORNO:
343
+ # (String) O valor monetário por extenso
344
+
345
+ # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
346
+
347
+ if ! self.is_int(valor)
348
+ raise "[Exceção em Extenso.moeda] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
349
+
350
+ elsif valor <= 0
351
+ raise "[Exceção em Extenso.moeda] Parâmetro valor igual a ou menor que zero (recebido: '#{valor}')"
352
+
353
+ elsif ! self.is_int(casas_decimais) || casas_decimais < 0
354
+ raise "[Exceção em Extenso.moeda] Parâmetro 'casas_decimais' não é numérico ou é menor que zero (recebido: '#{casas_decimais}')"
355
+
356
+ elsif info_unidade.class != Array || info_unidade.length < 3
357
+ temp = info_unidade.class == Array ? '[' + info_unidade.join(', ') + ']' : "'#{info_unidade}'"
358
+ raise "[Exceção em Extenso.moeda] Parâmetro 'info_unidade' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
359
+
360
+ elsif info_unidade[POS_GENERO] != GENERO_MASC && info_unidade[POS_GENERO] != GENERO_FEM
361
+ raise "Exceção em Extenso: valor incorreto para o parâmetro 'info_unidade[POS_GENERO]' (recebido: '#{info_unidade[POS_GENERO]}')"
362
+
363
+ elsif info_fracao.class != Array || info_fracao.length < 3
364
+ temp = info_fracao.class == Array ? '[' + info_fracao.join(', ') + ']' : "'#{info_fracao}'"
365
+ raise "[Exceção em Extenso.moeda] Parâmetro 'info_fracao' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
366
+
367
+ elsif info_fracao[POS_GENERO] != GENERO_MASC && info_fracao[POS_GENERO] != GENERO_FEM
368
+ raise "[Exceção em Extenso.moeda] valor incorreto para o parâmetro 'info_fracao[POS_GENERO]' (recebido: '#{info_fracao[POS_GENERO]}')."
369
+
370
+ end
371
+
372
+ # -----------------------------------------------
373
+
374
+ ret = ''
375
+
376
+ # A parte inteira do valor monetário corresponde ao valor passado dividido por 10 elevado a casas_decimais, desprezado o resto.
377
+ # Assim, com o padrão de 2 casas_decimais, o valor será dividido por 100 (10^2), e o resto é descartado utilizando-se floor().
378
+ parte_inteira = valor.floor / (10**casas_decimais)
379
+
380
+ # A parte fracionária ('centavos'), por seu turno, corresponderá ao resto da divisão do valor por 10 elevado a casas_decimais.
381
+ # No cenário comum em que trabalhamos com 2 casas_decimais, será o resto da divisão do valor por 100 (10^2).
382
+ fracao = valor % (10**casas_decimais)
383
+
384
+ # O extenso para a parte_inteira somente será gerado se esta for maior que zero. Para tanto, utilizamos
385
+ # os préstimos do método Extenso::numero().
386
+ if parte_inteira > 0
387
+ ret = self.numero(parte_inteira, info_unidade[POS_GENERO]) + ' '
388
+ ret += parte_inteira == 1 ? info_unidade[NUM_SING] : info_unidade[NUM_PLURAL]
389
+ end
390
+
391
+ # De forma semelhante, o extenso da fracao somente será gerado se esta for maior que zero. */
392
+ if fracao > 0
393
+ # Se a parte_inteira for maior que zero, o extenso para ela já terá sido gerado. Antes de juntar os
394
+ # centavos, precisamos colocar o conectivo 'e'.
395
+ if parte_inteira > 0
396
+ ret += ' e '
397
+ end
398
+ ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' '
399
+ ret += parte_inteira == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL]
400
+ end
401
+
402
+ ret
403
+
404
+ end
405
+
406
+ ######################################################################################################################################################
407
+ def self.ordinal (valor, genero = GENERO_MASC)
408
+
409
+ # Gera a representação ordinal de um número inteiro de 1 à 1000
410
+
411
+ # PARÂMETROS:
412
+ # valor (Integer) O valor numérico cujo extenso se deseja gerar
413
+ #
414
+ # genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
415
+ # do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'.
416
+ #
417
+ # VALOR DE RETORNO:
418
+ # (String) O número por extenso
419
+
420
+ # ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
421
+
422
+ if !is_int(valor)
423
+ raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
424
+ elsif valor <= 0
425
+ raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')"
426
+ elsif valor > VALOR_MAXIMO
427
+ raise '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')"
428
+ elsif genero != GENERO_MASC && genero != GENERO_FEM
429
+ raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
430
+ # ------------------------------------------------
431
+ elsif valor >= 1 && valor <= 9
432
+ return UNIDADES_ORDINAL[genero][valor]
433
+ elsif valor >= 10 && valor <= 99
434
+ dezena = valor - (valor % 10)
435
+ resto = valor - dezena
436
+ ret = DEZENAS_ORDINAL[genero][dezena]+" "
437
+ if resto > 0 then ret+= self.ordinal(resto,genero); end
438
+ return ret
439
+ elsif valor >= 100 && valor <= 999
440
+ centena = valor - (valor % 100)
441
+ resto = valor - centena
442
+ ret = CENTENAS_ORDINAL[genero][centena]+" "
443
+ if resto > 0 then ret += self.ordinal(resto, genero); end
444
+ return ret
445
+ elsif valor == 1000
446
+ return MILHAR_ORDINAL[genero][valor]+" "
447
+ end
448
+ end
449
+
450
+
451
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: extensobr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Henrique Max
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: ExtensoBr é uma gem que foi desenvolvida para auxiliar na impressão de
42
+ números e moedas por extenso em portugês do Brasil.
43
+ email:
44
+ - rickmaxg3@hotmail.com
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - ".gitignore"
50
+ - CODE_OF_CONDUCT.md
51
+ - Gemfile
52
+ - LICENSE.txt
53
+ - README.md
54
+ - Rakefile
55
+ - bin/console
56
+ - bin/setup
57
+ - extensobr.gemspec
58
+ - lib/extensobr.rb
59
+ - lib/extensobr/version.rb
60
+ homepage: https://github.com/rickmax/extensobr
61
+ licenses:
62
+ - MIT
63
+ metadata: {}
64
+ post_install_message:
65
+ rdoc_options: []
66
+ require_paths:
67
+ - lib
68
+ required_ruby_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: '0'
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ requirements: []
79
+ rubyforge_project:
80
+ rubygems_version: 2.5.1
81
+ signing_key:
82
+ specification_version: 4
83
+ summary: ExtendoBr escreve números e moeda por extenso.
84
+ test_files: []