extensobr 0.1.2 → 1.0.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 +5 -5
- data/.gitignore +10 -10
- data/.rspec +2 -0
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +63 -63
- data/Rakefile +2 -2
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/extensobr.gemspec +29 -29
- data/lib/extensobr.rb +446 -460
- data/lib/extensobr/version.rb +3 -3
- metadata +23 -9
data/lib/extensobr.rb
CHANGED
@@ -1,461 +1,447 @@
|
|
1
|
-
require "extensobr/version"
|
2
|
-
class Extenso
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
#
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
}
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
resto = valor
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
#
|
264
|
-
# O
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
#
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
#
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
valor
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
#
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
#
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
#
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
return MILHAR_ORDINAL[genero][valor]+" "
|
448
|
-
end
|
449
|
-
end
|
450
|
-
|
451
|
-
# Gera o valor em formato de Real
|
452
|
-
#
|
453
|
-
# Exemplo:
|
454
|
-
# Extenso.real_formatado(10) - R$ 10,00
|
455
|
-
# Extenso.real_formatado(1.55) - R$ 1,55
|
456
|
-
#
|
457
|
-
# @params[Object]
|
458
|
-
def self.real_formatado(valor)
|
459
|
-
"R$ #{format("%.2f", valor).to_s.gsub('.', ',')}"
|
460
|
-
end
|
1
|
+
require "extensobr/version"
|
2
|
+
class Extenso
|
3
|
+
|
4
|
+
BRL = {:delimiter => ".", :separator => ",", :unit => "R$", :precision => 2, :position => "before"}
|
5
|
+
|
6
|
+
NUM_SING = 0
|
7
|
+
NUM_PLURAL = 1
|
8
|
+
POS_GENERO = 2
|
9
|
+
GENERO_MASC = 0
|
10
|
+
GENERO_FEM = 1
|
11
|
+
|
12
|
+
VALOR_MAXIMO = 999999999
|
13
|
+
|
14
|
+
# As unidades 1 e 2 variam em gênero, pelo que precisamos de dois conjuntos de strings (masculinas e femininas) para as unidades
|
15
|
+
UNIDADES = {
|
16
|
+
GENERO_MASC => {
|
17
|
+
1 => 'Um',
|
18
|
+
2 => 'Dois',
|
19
|
+
3 => 'Três',
|
20
|
+
4 => 'Quatro',
|
21
|
+
5 => 'Cinco',
|
22
|
+
6 => 'Seis',
|
23
|
+
7 => 'Sete',
|
24
|
+
8 => 'Oito',
|
25
|
+
9 => 'Nove'
|
26
|
+
},
|
27
|
+
GENERO_FEM => {
|
28
|
+
1 => 'Uma',
|
29
|
+
2 => 'Duas',
|
30
|
+
3 => 'Três',
|
31
|
+
4 => 'Quatro',
|
32
|
+
5 => 'Cinco',
|
33
|
+
6 => 'Seis',
|
34
|
+
7 => 'Sete',
|
35
|
+
8 => 'Oito',
|
36
|
+
9 => 'Nove'
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
DE11A19 = {
|
41
|
+
11 => 'Onze',
|
42
|
+
12 => 'Doze',
|
43
|
+
13 => 'Treze',
|
44
|
+
14 => 'Quatorze',
|
45
|
+
15 => 'Quinze',
|
46
|
+
16 => 'Dezesseis',
|
47
|
+
17 => 'Dezessete',
|
48
|
+
18 => 'Dezoito',
|
49
|
+
19 => 'Dezenove'
|
50
|
+
}
|
51
|
+
|
52
|
+
DEZENAS = {
|
53
|
+
10 => 'Dez',
|
54
|
+
20 => 'Vinte',
|
55
|
+
30 => 'Trinta',
|
56
|
+
40 => 'Quarenta',
|
57
|
+
50 => 'Cinquenta',
|
58
|
+
60 => 'Sessenta',
|
59
|
+
70 => 'Setenta',
|
60
|
+
80 => 'Oitenta',
|
61
|
+
90 => 'Noventa'
|
62
|
+
}
|
63
|
+
|
64
|
+
CENTENA_EXATA = 'Cem'
|
65
|
+
|
66
|
+
# As centenas, com exceção de 'cento', também variam em gênero. Aqui também se faz
|
67
|
+
# necessário dois conjuntos de strings (masculinas e femininas).
|
68
|
+
|
69
|
+
CENTENAS = {
|
70
|
+
GENERO_MASC => {
|
71
|
+
100 => 'Cento',
|
72
|
+
200 => 'Duzentos',
|
73
|
+
300 => 'Trezentos',
|
74
|
+
400 => 'Quatrocentos',
|
75
|
+
500 => 'Quinhentos',
|
76
|
+
600 => 'Seiscentos',
|
77
|
+
700 => 'Setecentos',
|
78
|
+
800 => 'Oitocentos',
|
79
|
+
900 => 'Novecentos'
|
80
|
+
},
|
81
|
+
GENERO_FEM => {
|
82
|
+
100 => 'Cento',
|
83
|
+
200 => 'Duzentas',
|
84
|
+
300 => 'Trezentas',
|
85
|
+
400 => 'Quatrocentas',
|
86
|
+
500 => 'Quinhentas',
|
87
|
+
600 => 'Seiscentas',
|
88
|
+
700 => 'Setecentas',
|
89
|
+
800 => 'Oitocentas',
|
90
|
+
900 => 'Novecentas'
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
#'Mil' é invariável, seja em gênero, seja em número
|
95
|
+
MILHAR = 'mil'
|
96
|
+
|
97
|
+
MILHOES = {
|
98
|
+
NUM_SING => 'milhão',
|
99
|
+
NUM_PLURAL => 'milhões'
|
100
|
+
}
|
101
|
+
|
102
|
+
UNIDADES_ORDINAL = {
|
103
|
+
GENERO_MASC => {
|
104
|
+
1 => 'Primeiro',
|
105
|
+
2 => 'Segundo',
|
106
|
+
3 => 'Terceiro',
|
107
|
+
4 => 'Quarto',
|
108
|
+
5 => 'Quinto',
|
109
|
+
6 => 'Sexto',
|
110
|
+
7 => 'Sétimo',
|
111
|
+
8 => 'Oitavo',
|
112
|
+
9 => 'Nono'},
|
113
|
+
GENERO_FEM => {
|
114
|
+
1 => 'Primeira',
|
115
|
+
2 => 'Segunda',
|
116
|
+
3 => 'Terceira',
|
117
|
+
4 => 'Quarta',
|
118
|
+
5 => 'Quinta',
|
119
|
+
6 => 'Sexta',
|
120
|
+
7 => 'Sétima',
|
121
|
+
8 => 'Oitava',
|
122
|
+
9 => 'Nona'}}
|
123
|
+
|
124
|
+
DEZENAS_ORDINAL = {
|
125
|
+
GENERO_MASC => {
|
126
|
+
10 => 'Décimo',
|
127
|
+
20 => 'Vigésimo',
|
128
|
+
30 => 'Trigésimo',
|
129
|
+
40 => 'Quadragésimo',
|
130
|
+
50 => 'Quinquagésimo',
|
131
|
+
60 => 'Sexagésimo',
|
132
|
+
70 => 'Septuagésimo',
|
133
|
+
80 => 'Octogésimo',
|
134
|
+
90 => 'Nonagésimo'},
|
135
|
+
GENERO_FEM => {
|
136
|
+
10 => 'Décima',
|
137
|
+
20 => 'Vigésima',
|
138
|
+
30 => 'Trigésima',
|
139
|
+
40 => 'Quadragésima',
|
140
|
+
50 => 'Quinquagésima',
|
141
|
+
60 => 'Sexagésima',
|
142
|
+
70 => 'Septuagésima',
|
143
|
+
80 => 'Octogésima',
|
144
|
+
90 => 'Nonagésima'}}
|
145
|
+
|
146
|
+
CENTENAS_ORDINAL = {
|
147
|
+
GENERO_MASC => {
|
148
|
+
100 => 'Centésimo',
|
149
|
+
200 => 'Ducentésimo',
|
150
|
+
300 => 'Trecentésimo',
|
151
|
+
400 => 'Quadringentésimo',
|
152
|
+
500 => 'Quingentésimo',
|
153
|
+
600 => 'Seiscentésimo',
|
154
|
+
700 => 'Septingentésimo',
|
155
|
+
800 => 'Octingentésimo',
|
156
|
+
900 => 'Noningentésimo'},
|
157
|
+
GENERO_FEM => {
|
158
|
+
100 => 'Centésima',
|
159
|
+
200 => 'Ducentésima',
|
160
|
+
300 => 'Trecentésima',
|
161
|
+
400 => 'Quadringentésima',
|
162
|
+
500 => 'Quingentésima',
|
163
|
+
600 => 'Seiscentésima',
|
164
|
+
700 => 'Septingentésima',
|
165
|
+
800 => 'Octingentésima',
|
166
|
+
900 => 'Noningentésima'}}
|
167
|
+
|
168
|
+
|
169
|
+
MILHAR_ORDINAL = {
|
170
|
+
GENERO_MASC => {
|
171
|
+
1000 => 'Milésimo'},
|
172
|
+
GENERO_FEM =>{
|
173
|
+
1000 => 'Milésima'}}
|
174
|
+
|
175
|
+
def self.is_int(s)
|
176
|
+
Integer(s) != nil rescue false
|
177
|
+
end
|
178
|
+
|
179
|
+
def self.is_float?(str)
|
180
|
+
!!Float(str) rescue false
|
181
|
+
end
|
182
|
+
|
183
|
+
#######################################################################################################################################
|
184
|
+
|
185
|
+
def self.numero (valor, genero = GENERO_MASC)
|
186
|
+
|
187
|
+
# Gera a representação por extenso de um número inteiro, maior que zero e menor ou igual a VALOR_MAXIMO.
|
188
|
+
#
|
189
|
+
# PARÂMETROS:
|
190
|
+
# valor (Integer) O valor numérico cujo extenso se deseja gerar
|
191
|
+
#
|
192
|
+
# genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
193
|
+
# do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'.
|
194
|
+
#
|
195
|
+
# VALOR DE RETORNO:
|
196
|
+
# (String) O número por extenso
|
197
|
+
|
198
|
+
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
199
|
+
|
200
|
+
if !is_int(valor)
|
201
|
+
raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
|
202
|
+
elsif valor <= 0
|
203
|
+
'Zero'
|
204
|
+
elsif valor > VALOR_MAXIMO
|
205
|
+
raise "[Exceção em Extenso.numero] Parâmetro '#{valor} deve ser um inteiro entre 1 e #{VALOR_MAXIMO.to_s} (recebido: '#{valor}')"
|
206
|
+
elsif genero != GENERO_MASC && genero != GENERO_FEM
|
207
|
+
raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
|
208
|
+
|
209
|
+
# ------------------------------------------------
|
210
|
+
|
211
|
+
elsif valor >= 1 && valor <= 9
|
212
|
+
UNIDADES[genero][valor]
|
213
|
+
|
214
|
+
elsif valor == 10
|
215
|
+
DEZENAS[valor]
|
216
|
+
|
217
|
+
elsif valor >= 11 && valor <= 19
|
218
|
+
DE11A19[valor]
|
219
|
+
|
220
|
+
elsif valor >= 20 && valor <= 99
|
221
|
+
dezena = valor - (valor % 10)
|
222
|
+
ret = DEZENAS[dezena]
|
223
|
+
# Chamada recursiva à função para processar resto se este for maior que zero.
|
224
|
+
# O conectivo 'e' é utilizado entre dezenas e unidades.
|
225
|
+
resto = valor - dezena
|
226
|
+
if resto > 0
|
227
|
+
ret += ' e ' + self.numero(resto, genero)
|
228
|
+
end
|
229
|
+
ret
|
230
|
+
|
231
|
+
elsif valor == 100
|
232
|
+
CENTENA_EXATA
|
233
|
+
|
234
|
+
elsif valor >= 101 && valor <= 999
|
235
|
+
centena = valor - (valor % 100)
|
236
|
+
ret = CENTENAS[genero][centena] # As centenas (exceto 'cento') variam em gênero
|
237
|
+
# Chamada recursiva à função para processar resto se este for maior que zero.
|
238
|
+
# O conectivo 'e' é utilizado entre centenas e dezenas.
|
239
|
+
resto = valor - centena
|
240
|
+
if resto > 0
|
241
|
+
ret += ' e ' + self.numero(resto, genero)
|
242
|
+
end
|
243
|
+
ret
|
244
|
+
|
245
|
+
elsif valor >= 1000 && valor <= 999999
|
246
|
+
# A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000,
|
247
|
+
# assim determinando a quantidade de milhares. O resultado é enviado a uma chamada recursiva
|
248
|
+
# da função. A palavra 'mil' não se flexiona.
|
249
|
+
milhar = (valor / 1000).floor
|
250
|
+
ret = self.numero(milhar, GENERO_MASC) + ' ' + MILHAR # 'Mil' é do gênero masculino
|
251
|
+
resto = valor % 1000
|
252
|
+
# Chamada recursiva à função para processar resto se este for maior que zero.
|
253
|
+
# O conectivo 'e' é utilizado entre milhares e números entre 1 e 99, bem como antes de centenas exatas.
|
254
|
+
if resto > 0 && ((resto >= 1 && resto <= 99) || resto % 100 == 0)
|
255
|
+
ret += ' e ' + self.numero(resto, genero)
|
256
|
+
# Nos demais casos, após o milhar é utilizada a vírgula.
|
257
|
+
elsif (resto > 0)
|
258
|
+
ret += ', ' + self.numero(resto, genero)
|
259
|
+
end
|
260
|
+
ret
|
261
|
+
|
262
|
+
elsif valor >= 100000 && valor <= VALOR_MAXIMO
|
263
|
+
# A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000000,
|
264
|
+
# assim determinando a quantidade de milhões. O resultado é enviado a uma chamada recursiva
|
265
|
+
# da função. A palavra 'milhão' flexiona-se no plural.
|
266
|
+
milhoes = (valor / 1000000).floor
|
267
|
+
ret = self.numero(milhoes, GENERO_MASC) + ' ' # Milhão e milhões são do gênero masculino
|
268
|
+
|
269
|
+
# Se a o número de milhões for maior que 1, deve-se utilizar a forma flexionada no plural
|
270
|
+
ret += milhoes == 1 ? MILHOES[NUM_SING] : MILHOES[NUM_PLURAL]
|
271
|
+
|
272
|
+
resto = valor % 1000000
|
273
|
+
|
274
|
+
# Chamada recursiva à função para processar resto se este for maior que zero.
|
275
|
+
# O conectivo 'e' é utilizado entre milhões e números entre 1 e 99, bem como antes de centenas exatas.
|
276
|
+
if resto && (resto >= 1 && resto <= 99)
|
277
|
+
ret += ' e ' + self.numero(resto, genero)
|
278
|
+
# Nos demais casos, após o milhão é utilizada a vírgula.
|
279
|
+
elsif resto > 0
|
280
|
+
ret += ', ' + self.numero(resto, genero)
|
281
|
+
end
|
282
|
+
ret
|
283
|
+
|
284
|
+
end
|
285
|
+
|
286
|
+
end
|
287
|
+
|
288
|
+
#######################################################################################################################################
|
289
|
+
|
290
|
+
def self.moeda(
|
291
|
+
valor,
|
292
|
+
casas_decimais = 2,
|
293
|
+
info_unidade = ['Real', 'Reais', GENERO_MASC],
|
294
|
+
info_fracao = ['Centavo', 'Centavos', GENERO_MASC]
|
295
|
+
)
|
296
|
+
|
297
|
+
# Gera a representação por extenso de um valor monetário, maior que zero e menor ou igual a Extenso::VALOR_MAXIMO.
|
298
|
+
#
|
299
|
+
#
|
300
|
+
# PARÂMETROS:
|
301
|
+
# valor (Float) O valor monetário cujo extenso se deseja gerar.
|
302
|
+
# casas_decimais (Integer) [Opcional; valor padrão: 2] Número de casas decimais a serem consideradas como parte fracionária (centavos)
|
303
|
+
#
|
304
|
+
# info_unidade (Array) [Opcional; valor padrão: ['real', 'reais', Extenso::GENERO_MASC]] Fornece informações sobre a moeda a ser
|
305
|
+
# utilizada. O primeiro valor da matriz corresponde ao nome da moeda no singular, o segundo ao nome da moeda no plural e o terceiro
|
306
|
+
# ao gênero gramatical do nome da moeda (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
307
|
+
#
|
308
|
+
# info_fracao (Array) [Opcional; valor padrão: ['centavo', 'centavos', Extenso::GENERO_MASC]] Provê informações sobre a parte fracionária
|
309
|
+
# 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
|
310
|
+
# e o terceiro ao gênero gramatical da parte fracionária (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
311
|
+
#
|
312
|
+
# VALOR DE RETORNO:
|
313
|
+
# (String) O valor monetário por extenso
|
314
|
+
|
315
|
+
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
316
|
+
|
317
|
+
if ! self.is_float?(valor.to_f.round(casas_decimais).to_s)
|
318
|
+
raise "[Exceção em Extenso.moeda] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
|
319
|
+
|
320
|
+
elsif valor <= 0
|
321
|
+
"Zero"
|
322
|
+
|
323
|
+
elsif ! self.is_int(casas_decimais) || casas_decimais < 0
|
324
|
+
raise "[Exceção em Extenso.moeda] Parâmetro 'casas_decimais' não é numérico ou é menor que zero (recebido: '#{casas_decimais}')"
|
325
|
+
|
326
|
+
elsif info_unidade.class != Array || info_unidade.length < 3
|
327
|
+
temp = info_unidade.class == Array ? '[' + info_unidade.join(', ') + ']' : "'#{info_unidade}'"
|
328
|
+
raise "[Exceção em Extenso.moeda] Parâmetro 'info_unidade' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
|
329
|
+
|
330
|
+
elsif info_unidade[POS_GENERO] != GENERO_MASC && info_unidade[POS_GENERO] != GENERO_FEM
|
331
|
+
raise "Exceção em Extenso: valor incorreto para o parâmetro 'info_unidade[POS_GENERO]' (recebido: '#{info_unidade[POS_GENERO]}')"
|
332
|
+
|
333
|
+
elsif info_fracao.class != Array || info_fracao.length < 3
|
334
|
+
temp = info_fracao.class == Array ? '[' + info_fracao.join(', ') + ']' : "'#{info_fracao}'"
|
335
|
+
raise "[Exceção em Extenso.moeda] Parâmetro 'info_fracao' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
|
336
|
+
|
337
|
+
elsif info_fracao[POS_GENERO] != GENERO_MASC && info_fracao[POS_GENERO] != GENERO_FEM
|
338
|
+
raise "[Exceção em Extenso.moeda] valor incorreto para o parâmetro 'info_fracao[POS_GENERO]' (recebido: '#{info_fracao[POS_GENERO]}')."
|
339
|
+
|
340
|
+
end
|
341
|
+
|
342
|
+
# -----------------------------------------------
|
343
|
+
|
344
|
+
ret = ''
|
345
|
+
|
346
|
+
valor = sprintf("%#{casas_decimais.to_f / 100}f", valor)
|
347
|
+
# A parte inteira do valor monetário corresponde ao valor passado antes do '.' no tipo float.
|
348
|
+
parte_inteira = valor.split('.')[0].to_i
|
349
|
+
|
350
|
+
# A parte fracionária ('centavos'), por seu turno, corresponderá ao valor passado depois do '.'
|
351
|
+
fracao = valor.to_s.split('.')[1].to_i
|
352
|
+
|
353
|
+
# os préstimos do método Extenso::numero().
|
354
|
+
if parte_inteira > 0
|
355
|
+
ret = self.numero(parte_inteira, info_unidade[POS_GENERO]) + ((parte_inteira >= 1000000 && (parte_inteira.to_s.chars.reverse[5] == "0" ) ) ? ' de ' : ' ')
|
356
|
+
ret += parte_inteira == 1 ? info_unidade[NUM_SING] : info_unidade[NUM_PLURAL]
|
357
|
+
ret
|
358
|
+
end
|
359
|
+
|
360
|
+
# De forma semelhante, o extenso da fracao somente será gerado se esta for maior que zero. */
|
361
|
+
if fracao > 0
|
362
|
+
# Se a parte_inteira for maior que zero, o extenso para ela já terá sido gerado. Antes de juntar os
|
363
|
+
# centavos, precisamos colocar o conectivo 'e'.
|
364
|
+
if parte_inteira > 0
|
365
|
+
ret += ' e '
|
366
|
+
end
|
367
|
+
ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' '
|
368
|
+
ret += fracao == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL]
|
369
|
+
end
|
370
|
+
|
371
|
+
if valor.to_f == 0
|
372
|
+
ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' '
|
373
|
+
ret += parte_inteira == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL]
|
374
|
+
end
|
375
|
+
|
376
|
+
ret
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
######################################################################################################################################################
|
381
|
+
def self.ordinal (valor, genero = GENERO_MASC)
|
382
|
+
|
383
|
+
# Gera a representação ordinal de um número inteiro de 1 à 1000
|
384
|
+
|
385
|
+
# PARÂMETROS:
|
386
|
+
# valor (Integer) O valor numérico cujo extenso se deseja gerar
|
387
|
+
#
|
388
|
+
# genero (Integer) [Opcional; valor padrão: Extenso::GENERO_MASC] O gênero gramatical (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
389
|
+
# do extenso a ser gerado. Isso possibilita distinguir, por exemplo, entre 'duzentos e dois homens' e 'duzentas e duas mulheres'.
|
390
|
+
#
|
391
|
+
# VALOR DE RETORNO:
|
392
|
+
# (String) O número por extenso
|
393
|
+
|
394
|
+
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
395
|
+
|
396
|
+
if !is_int(valor)
|
397
|
+
raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
|
398
|
+
elsif valor <= 0
|
399
|
+
'Zero'
|
400
|
+
# raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')"
|
401
|
+
elsif valor > VALOR_MAXIMO
|
402
|
+
raise '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')"
|
403
|
+
elsif genero != GENERO_MASC && genero != GENERO_FEM
|
404
|
+
raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
|
405
|
+
# ------------------------------------------------
|
406
|
+
elsif valor >= 1 && valor <= 9
|
407
|
+
return UNIDADES_ORDINAL[genero][valor]
|
408
|
+
elsif valor >= 10 && valor <= 99
|
409
|
+
dezena = valor - (valor % 10)
|
410
|
+
resto = valor - dezena
|
411
|
+
ret = DEZENAS_ORDINAL[genero][dezena]+" "
|
412
|
+
if resto > 0 then ret+= self.ordinal(resto,genero); end
|
413
|
+
return ret
|
414
|
+
elsif valor >= 100 && valor <= 999
|
415
|
+
centena = valor - (valor % 100)
|
416
|
+
resto = valor - centena
|
417
|
+
ret = CENTENAS_ORDINAL[genero][centena]+" "
|
418
|
+
if resto > 0 then ret += self.ordinal(resto, genero); end
|
419
|
+
return ret
|
420
|
+
elsif valor == 1000
|
421
|
+
return MILHAR_ORDINAL[genero][valor]+" "
|
422
|
+
end
|
423
|
+
end
|
424
|
+
|
425
|
+
# Gera o valor em formato de Real
|
426
|
+
#
|
427
|
+
# Exemplo:
|
428
|
+
# Extenso.real_formatado(10) - R$ 10,00
|
429
|
+
# Extenso.real_formatado(1.55) - R$ 1,55
|
430
|
+
#
|
431
|
+
# @params[Object]
|
432
|
+
def self.real_formatado(valor)
|
433
|
+
float_valor = sprintf("%#0.02f", valor)
|
434
|
+
if float_valor.chars.count >= 7
|
435
|
+
float_valor = float_valor.chars.reverse.insert(6, '.').reverse.join
|
436
|
+
end
|
437
|
+
|
438
|
+
if float_valor.chars.count >= 11
|
439
|
+
float_valor = float_valor.chars.reverse.insert(10, '.').reverse.join
|
440
|
+
end
|
441
|
+
|
442
|
+
float_valor = float_valor.chars.reverse
|
443
|
+
float_valor[2] = ','
|
444
|
+
|
445
|
+
"R$ #{float_valor.reverse.join}"
|
446
|
+
end
|
461
447
|
end
|