extensobr 0.1.2 → 1.2.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/.github/workflows/codeql-analysis.yml +70 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/CODE_OF_CONDUCT.md +74 -74
- data/Gemfile +4 -4
- data/LICENSE.txt +21 -21
- data/README.md +47 -17
- data/Rakefile +2 -2
- data/SECURITY.md +21 -0
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/extensobr.gemspec +2 -2
- data/lib/core_exts/float.rb +10 -0
- data/lib/core_exts/integer.rb +14 -0
- data/lib/core_exts/string.rb +41 -0
- data/lib/extensobr/version.rb +1 -1
- data/lib/extensobr.rb +203 -185
- data/lib/settings.rb +32 -0
- metadata +29 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4c16a2759e6723989331737ab04867c31e50ca3275cefc8fde86652eb9b7a520
|
4
|
+
data.tar.gz: 2c66fa8ffd5355bf4f6bb708738a9e931e4e162a2fb95705fbe17510b0c62cc3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cec73bb125afb3f8259a762c3448943735add98a341f565ec6a988a4f935ddb58abb04ac27e13b7a50cb99be848264211e1e7bc3696fd98734e7f93a19f5ce65
|
7
|
+
data.tar.gz: 731f65901ed947174eb506549eb16607994a4df289b47c1bc7f68794fd016a8ef0fa25ae227efdb140fa2a7e1bacc9bff9fac467759680451280c745962be8df
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
2
|
+
# to commit it to your repository.
|
3
|
+
#
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
5
|
+
# or to provide custom queries or build logic.
|
6
|
+
#
|
7
|
+
# ******** NOTE ********
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
10
|
+
# supported CodeQL languages.
|
11
|
+
#
|
12
|
+
name: "CodeQL"
|
13
|
+
|
14
|
+
on:
|
15
|
+
push:
|
16
|
+
branches: [ master ]
|
17
|
+
pull_request:
|
18
|
+
# The branches below must be a subset of the branches above
|
19
|
+
branches: [ master ]
|
20
|
+
schedule:
|
21
|
+
- cron: '15 7 * * 5'
|
22
|
+
|
23
|
+
jobs:
|
24
|
+
analyze:
|
25
|
+
name: Analyze
|
26
|
+
runs-on: ubuntu-latest
|
27
|
+
permissions:
|
28
|
+
actions: read
|
29
|
+
contents: read
|
30
|
+
security-events: write
|
31
|
+
|
32
|
+
strategy:
|
33
|
+
fail-fast: false
|
34
|
+
matrix:
|
35
|
+
language: [ 'ruby' ]
|
36
|
+
# CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ]
|
37
|
+
# Learn more about CodeQL language support at https://git.io/codeql-language-support
|
38
|
+
|
39
|
+
steps:
|
40
|
+
- name: Checkout repository
|
41
|
+
uses: actions/checkout@v2
|
42
|
+
|
43
|
+
# Initializes the CodeQL tools for scanning.
|
44
|
+
- name: Initialize CodeQL
|
45
|
+
uses: github/codeql-action/init@v1
|
46
|
+
with:
|
47
|
+
languages: ${{ matrix.language }}
|
48
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
49
|
+
# By default, queries listed here will override any specified in a config file.
|
50
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
51
|
+
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
52
|
+
|
53
|
+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
54
|
+
# If this step fails, then you should remove it and run the build manually (see below)
|
55
|
+
- name: Autobuild
|
56
|
+
uses: github/codeql-action/autobuild@v1
|
57
|
+
|
58
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
59
|
+
# 📚 https://git.io/JvXDl
|
60
|
+
|
61
|
+
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
62
|
+
# and modify them (or add more) to build your code if your project
|
63
|
+
# uses a compiled language
|
64
|
+
|
65
|
+
#- run: |
|
66
|
+
# make bootstrap
|
67
|
+
# make release
|
68
|
+
|
69
|
+
- name: Perform CodeQL Analysis
|
70
|
+
uses: github/codeql-action/analyze@v1
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/CODE_OF_CONDUCT.md
CHANGED
@@ -1,74 +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/
|
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
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
source 'https://rubygems.org'
|
2
|
-
|
3
|
-
# Specify your gem's dependencies in extensobr.gemspec
|
4
|
-
gemspec
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in extensobr.gemspec
|
4
|
+
gemspec
|
data/LICENSE.txt
CHANGED
@@ -1,21 +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.
|
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
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Extensobr
|
2
2
|
|
3
|
-
Esta gem foi desenvolvida para auxiliar no desenvolvimento de aplicações onde é necessário escrever ou
|
3
|
+
Esta gem foi desenvolvida para auxiliar no desenvolvimento de aplicações onde é necessário escrever ou números ou moedas por extenso como por exemplo em recibos, contratos entre outros.
|
4
4
|
|
5
5
|
|
6
6
|
## Instalação
|
@@ -16,48 +16,78 @@ Ou instale você mesmo:
|
|
16
16
|
$ gem install extensobr
|
17
17
|
|
18
18
|
## Exemplos de uso
|
19
|
-
|
20
|
-
Para obter o extenso de um número, utilize Extenso.numero.
|
19
|
+
### IMPORTANTE: este método recebe um valor inteiro(integer)
|
20
|
+
Para obter o extenso de um número, utilize Extenso.numero() OBS: Ovalor deve ser do tipo "INTEGER".
|
21
|
+
Padrão de genero da escrita é passado com um parâmetro do tipo integer, Masculino: 0, Feminino: 1, sendo que o padrão é masculino.
|
21
22
|
|
22
23
|
irb
|
23
24
|
|
24
25
|
require 'Extensobr.rb'
|
25
26
|
|
26
27
|
puts Extenso.numero(832); # oitocentos e trinta e dois
|
27
|
-
puts Extenso.numero(832,
|
28
|
-
|
29
|
-
Para obter o extenso de um valor monetário, utilize Extenso.moeda.
|
28
|
+
puts Extenso.numero(832, 1) # oitocentas e trinta e duas
|
30
29
|
|
31
|
-
|
30
|
+
# Novo método usando a classes do ruby a partir da versão 1.2 em diante.
|
31
|
+
puts 832.por_extenso; # oitocentos e trinta e dois
|
32
|
+
puts 832.por_extenso(1) # oitocentas e trinta e duas
|
33
|
+
puts "832".por_extenso; # oitocentos e trinta e dois
|
34
|
+
puts "832".por_extenso(1) # oitocentas e trinta e duas
|
32
35
|
|
33
|
-
|
36
|
+
### IMPORTANTE: este método recebe um valor decimal(float), para a contagem das casas decimais
|
37
|
+
|
38
|
+
Para obter o extenso de um valor monetário, utilize Extenso.moeda() OBS: Ovalor deve ser do tipo "FLOAT".
|
39
|
+
|
40
|
+
require 'Extenso.rb'
|
41
|
+
|
42
|
+
puts Extenso.moeda(154.02) # cento e cinquenta e quatro reais e dois centavos
|
43
|
+
puts Extenso.moeda(0.47) # quarenta e sete centavos
|
34
44
|
|
35
|
-
|
36
|
-
puts
|
37
|
-
puts
|
45
|
+
# Novos métodos usando a classes do ruby a partir da versão 1.2 em diante.
|
46
|
+
puts 154.02.por_extenso # cento e cinquenta e quatro reais e dois centavos
|
47
|
+
puts 0.47.por_extenso # quarenta e sete centavos
|
48
|
+
puts "154.02".por_extenso # cento e cinquenta e quatro reais e dois centavos
|
49
|
+
puts "0.47".por_extenso # quarenta e sete centavos
|
38
50
|
|
39
|
-
|
51
|
+
### Customize sua moéda passando como parâmetro
|
52
|
+
|
53
|
+
puts Extenso.moeda(3570.82, 2, ['peseta', 'pesetas', Extenso::GENERO_FEM], ['cêntimo', 'cêntimos', Extenso::GENERO_MASC])
|
54
|
+
# Três mil, Quinhentas e Setenta pesetas e Oitenta e Dois cêntimos
|
40
55
|
|
41
|
-
Para obter o valor em
|
56
|
+
### Para obter o valor numérico em reais de um número decimal
|
42
57
|
|
43
58
|
Extenso.real_formatado(154.55) # R$ 154,55
|
44
59
|
Extenso.real_formatado(0) # R$ 0,00
|
45
60
|
Extenso.real_formatado(1) # R$ 1,00
|
46
61
|
|
62
|
+
### Configurando exeptions para valores nulos
|
63
|
+
É possivel que na sua regra de negócio ou caso de uso, seja passado um valor nulo ou vazio para tentar escrever por extenso, nesses casos por padrão será retornado "Zero" para inteiros e "Zero centavos" para decimais. No entanto você pode configurar para receber uma exceção caso seja necessário. Em suas váriáis de ambiente adicione a seguinte chave e valor:
|
64
|
+
|
65
|
+
EXTENSO_RAISE_FOR_NIL=true
|
66
|
+
|
67
|
+
E adicione um arquivo "config/extensobr.yml", com a seguinte configuração:
|
68
|
+
|
69
|
+
raise_for_nil: ENV['EXTENSO_RAISE_FOR_NIL'] || 'false'
|
70
|
+
|
71
|
+
Dessa forma, você pode esperar em seus testes a seguinte excessão:
|
72
|
+
|
73
|
+
RuntimeError: [Exceção em Extenso.numero] Parâmetro 'valor' é nulo
|
74
|
+
|
75
|
+
|
47
76
|
# Developers
|
48
77
|
|
49
78
|
[Henrique Max](https://github.com/rickmax),
|
79
|
+
[Renan Garcia](https://github.com/renan-garcia),
|
50
80
|
[Fausto G. Cintra](https://github.com/goncin),
|
51
81
|
[Victor Eduardo](https://github.com/victoreduardo)
|
52
82
|
|
53
83
|
## Como contribuir?
|
54
84
|
|
55
|
-
1.
|
56
|
-
1.
|
57
|
-
1.
|
85
|
+
1. Faça um fork do projeto;
|
86
|
+
1. Adicione os devidos ajustes ou melhorias com os respectivos testes;
|
87
|
+
1. Envie pull request;
|
58
88
|
|
59
89
|
|
60
90
|
## Licença
|
61
91
|
|
62
|
-
Está Gem esta disponível sob
|
92
|
+
Está Gem esta disponível sob os termos de licença [MIT License](http://opensource.org/licenses/MIT).
|
63
93
|
|
data/Rakefile
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
require "bundler/gem_tasks"
|
2
|
-
task :default => :spec
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
task :default => :spec
|
data/SECURITY.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Security Policy
|
2
|
+
|
3
|
+
## Supported Versions
|
4
|
+
|
5
|
+
Use this section to tell people about which versions of your project are
|
6
|
+
currently being supported with security updates.
|
7
|
+
|
8
|
+
| Version | Supported |
|
9
|
+
| ------- | ------------------ |
|
10
|
+
| 5.1.x | :white_check_mark: |
|
11
|
+
| 5.0.x | :x: |
|
12
|
+
| 4.0.x | :white_check_mark: |
|
13
|
+
| < 4.0 | :x: |
|
14
|
+
|
15
|
+
## Reporting a Vulnerability
|
16
|
+
|
17
|
+
Use this section to tell people how to report a vulnerability.
|
18
|
+
|
19
|
+
Tell them where to go, how often they can expect to get an update on a
|
20
|
+
reported vulnerability, what to expect if the vulnerability is accepted or
|
21
|
+
declined, etc.
|
data/bin/console
CHANGED
@@ -1,14 +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
|
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
CHANGED
@@ -1,8 +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
|
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
CHANGED
@@ -23,7 +23,7 @@ Gem::Specification.new do |spec|
|
|
23
23
|
spec.bindir = "exe"
|
24
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
25
25
|
spec.require_paths = ["lib"]
|
26
|
-
|
27
|
-
spec.add_development_dependency "bundler", "~> 1.13"
|
26
|
+
spec.add_development_dependency "bundler", "~> 2.2.15"
|
28
27
|
spec.add_development_dependency "rake", "~> 12.3.3"
|
28
|
+
spec.add_development_dependency "rspec"
|
29
29
|
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'extensobr'
|
4
|
+
|
5
|
+
# Extende a classe Integer adicionando o metodo por_extenso e por_extenso_ordinal
|
6
|
+
Integer.class_eval do
|
7
|
+
def por_extenso(*args)
|
8
|
+
Extenso.numero(self, *args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def por_extenso_ordinal(*args)
|
12
|
+
Extenso.ordinal(self, *args)
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'extensobr'
|
4
|
+
|
5
|
+
# Extende a classe Integer adicionando o metodo por_extenso, por_extenso_moeda e por_extenso_numero
|
6
|
+
String.class_eval do
|
7
|
+
# Um wapper para o metodo Extenso.numero ou Extenso.moeda
|
8
|
+
# PARÂMETROS:
|
9
|
+
# type (Symbol) O tipo especifico que deseja gerar
|
10
|
+
#
|
11
|
+
# Caso o tipo não seja informado é inferido primeiro tentando encontrar um padrão de Float
|
12
|
+
# caso encontre ele supõe que o tipo é moeda. Caso contrario o tipo será numero.
|
13
|
+
def por_extenso(*args)
|
14
|
+
return por_extenso_numero(*args) if args.include? :numero
|
15
|
+
|
16
|
+
return por_extenso_moeda(*args) if args.include? :moeda
|
17
|
+
|
18
|
+
return por_extenso_ordinal(*args) if args.include? :ordinal
|
19
|
+
|
20
|
+
number = scan(/\d+[,.]\d+/).first
|
21
|
+
return por_extenso_moeda(*args) unless number.nil? || number.empty?
|
22
|
+
|
23
|
+
por_extenso_numero(*args)
|
24
|
+
end
|
25
|
+
|
26
|
+
def por_extenso_moeda(*args)
|
27
|
+
number = gsub('_', '').scan(/\d+[,.]\d+/).first
|
28
|
+
params = args - [:moeda]
|
29
|
+
Extenso.moeda(number.to_f, *params)
|
30
|
+
end
|
31
|
+
|
32
|
+
def por_extenso_numero(*args)
|
33
|
+
number = scan(/\d/)&.join('')
|
34
|
+
Extenso.numero(number&.to_i, *args)
|
35
|
+
end
|
36
|
+
|
37
|
+
def por_extenso_ordinal(*args)
|
38
|
+
number = scan(/\d/)&.join('')
|
39
|
+
Extenso.ordinal(number&.to_i, *args)
|
40
|
+
end
|
41
|
+
end
|
data/lib/extensobr/version.rb
CHANGED
data/lib/extensobr.rb
CHANGED
@@ -1,46 +1,29 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'extensobr/version'
|
4
|
+
require 'settings'
|
5
|
+
|
6
|
+
# ----- CARREGA CONFIGURAÇÃO -----
|
7
|
+
Settings.load_extensobr_settings
|
8
|
+
|
9
|
+
# ----- CARREGA CORE EXTENSÕES -----
|
10
|
+
if Settings.extensobr_settings[:use_core_exts] == 'true'
|
11
|
+
require 'core_exts/float'
|
12
|
+
require 'core_exts/integer'
|
13
|
+
require 'core_exts/string'
|
14
|
+
end
|
15
|
+
|
2
16
|
class Extenso
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
-
|
17
|
+
BRL = { delimiter: '.', separator: ',', unit: 'R$', precision: 2, position: 'before' }.freeze unless Extenso.const_defined?('BRL')
|
18
|
+
|
19
|
+
NUM_SING = 0 unless Extenso.const_defined?('NUM_SING')
|
20
|
+
NUM_PLURAL = 1 unless Extenso.const_defined?('NUM_PLURAL')
|
21
|
+
POS_GENERO = 2 unless Extenso.const_defined?('POS_GENERO')
|
22
|
+
GENERO_MASC = 0 unless Extenso.const_defined?('GENERO_MASC')
|
23
|
+
GENERO_FEM = 1 unless Extenso.const_defined?('GENERO_FEM')
|
24
|
+
|
25
|
+
VALOR_MAXIMO = 999_999_999 unless Extenso.const_defined?('VALOR_MAXIMO')
|
26
|
+
|
44
27
|
# As unidades 1 e 2 variam em gênero, pelo que precisamos de dois conjuntos de strings (masculinas e femininas) para as unidades
|
45
28
|
UNIDADES = {
|
46
29
|
GENERO_MASC => {
|
@@ -65,8 +48,8 @@ class Extenso
|
|
65
48
|
8 => 'Oito',
|
66
49
|
9 => 'Nove'
|
67
50
|
}
|
68
|
-
}
|
69
|
-
|
51
|
+
}.freeze unless Extenso.const_defined?('UNIDADES')
|
52
|
+
|
70
53
|
DE11A19 = {
|
71
54
|
11 => 'Onze',
|
72
55
|
12 => 'Doze',
|
@@ -77,8 +60,8 @@ class Extenso
|
|
77
60
|
17 => 'Dezessete',
|
78
61
|
18 => 'Dezoito',
|
79
62
|
19 => 'Dezenove'
|
80
|
-
}
|
81
|
-
|
63
|
+
}.freeze unless Extenso.const_defined?('DE11A19')
|
64
|
+
|
82
65
|
DEZENAS = {
|
83
66
|
10 => 'Dez',
|
84
67
|
20 => 'Vinte',
|
@@ -89,13 +72,13 @@ class Extenso
|
|
89
72
|
70 => 'Setenta',
|
90
73
|
80 => 'Oitenta',
|
91
74
|
90 => 'Noventa'
|
92
|
-
}
|
93
|
-
|
94
|
-
CENTENA_EXATA = 'Cem'
|
95
|
-
|
75
|
+
}.freeze unless Extenso.const_defined?('DEZENAS')
|
76
|
+
|
77
|
+
CENTENA_EXATA = 'Cem' unless Extenso.const_defined?('CENTENA_EXATA')
|
78
|
+
|
96
79
|
# As centenas, com exceção de 'cento', também variam em gênero. Aqui também se faz
|
97
80
|
# necessário dois conjuntos de strings (masculinas e femininas).
|
98
|
-
|
81
|
+
|
99
82
|
CENTENAS = {
|
100
83
|
GENERO_MASC => {
|
101
84
|
100 => 'Cento',
|
@@ -119,17 +102,17 @@ class Extenso
|
|
119
102
|
800 => 'Oitocentas',
|
120
103
|
900 => 'Novecentas'
|
121
104
|
}
|
122
|
-
}
|
123
|
-
|
124
|
-
#'Mil' é invariável, seja em gênero, seja em número
|
125
|
-
MILHAR = 'mil'
|
105
|
+
}.freeze unless Extenso.const_defined?('CENTENAS')
|
106
|
+
|
107
|
+
# 'Mil' é invariável, seja em gênero, seja em número
|
108
|
+
MILHAR = 'mil' unless Extenso.const_defined?('MILHAR')
|
126
109
|
|
127
110
|
MILHOES = {
|
128
|
-
NUM_SING => '
|
129
|
-
NUM_PLURAL => '
|
130
|
-
}
|
111
|
+
NUM_SING => 'milhão',
|
112
|
+
NUM_PLURAL => 'milhões'
|
113
|
+
}.freeze unless Extenso.const_defined?('MILHOES')
|
131
114
|
|
132
|
-
|
115
|
+
UNIDADES_ORDINAL = {
|
133
116
|
GENERO_MASC => {
|
134
117
|
1 => 'Primeiro',
|
135
118
|
2 => 'Segundo',
|
@@ -139,7 +122,8 @@ class Extenso
|
|
139
122
|
6 => 'Sexto',
|
140
123
|
7 => 'Sétimo',
|
141
124
|
8 => 'Oitavo',
|
142
|
-
9 => 'Nono'
|
125
|
+
9 => 'Nono'
|
126
|
+
},
|
143
127
|
GENERO_FEM => {
|
144
128
|
1 => 'Primeira',
|
145
129
|
2 => 'Segunda',
|
@@ -149,7 +133,9 @@ class Extenso
|
|
149
133
|
6 => 'Sexta',
|
150
134
|
7 => 'Sétima',
|
151
135
|
8 => 'Oitava',
|
152
|
-
9 => 'Nona'
|
136
|
+
9 => 'Nona'
|
137
|
+
}
|
138
|
+
}.freeze unless Extenso.const_defined?('UNIDADES_ORDINAL')
|
153
139
|
|
154
140
|
DEZENAS_ORDINAL = {
|
155
141
|
GENERO_MASC => {
|
@@ -161,7 +147,8 @@ class Extenso
|
|
161
147
|
60 => 'Sexagésimo',
|
162
148
|
70 => 'Septuagésimo',
|
163
149
|
80 => 'Octogésimo',
|
164
|
-
90 => 'Nonagésimo'
|
150
|
+
90 => 'Nonagésimo'
|
151
|
+
},
|
165
152
|
GENERO_FEM => {
|
166
153
|
10 => 'Décima',
|
167
154
|
20 => 'Vigésima',
|
@@ -171,8 +158,10 @@ class Extenso
|
|
171
158
|
60 => 'Sexagésima',
|
172
159
|
70 => 'Septuagésima',
|
173
160
|
80 => 'Octogésima',
|
174
|
-
90 => 'Nonagésima'
|
175
|
-
|
161
|
+
90 => 'Nonagésima'
|
162
|
+
}
|
163
|
+
}.freeze unless Extenso.const_defined?('DEZENAS_ORDINAL')
|
164
|
+
|
176
165
|
CENTENAS_ORDINAL = {
|
177
166
|
GENERO_MASC => {
|
178
167
|
100 => 'Centésimo',
|
@@ -183,7 +172,8 @@ class Extenso
|
|
183
172
|
600 => 'Seiscentésimo',
|
184
173
|
700 => 'Septingentésimo',
|
185
174
|
800 => 'Octingentésimo',
|
186
|
-
900 => 'Noningentésimo'
|
175
|
+
900 => 'Noningentésimo'
|
176
|
+
},
|
187
177
|
GENERO_FEM => {
|
188
178
|
100 => 'Centésima',
|
189
179
|
200 => 'Ducentésima',
|
@@ -193,23 +183,34 @@ class Extenso
|
|
193
183
|
600 => 'Seiscentésima',
|
194
184
|
700 => 'Septingentésima',
|
195
185
|
800 => 'Octingentésima',
|
196
|
-
900 => 'Noningentésima'
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
186
|
+
900 => 'Noningentésima'
|
187
|
+
}
|
188
|
+
}.freeze unless Extenso.const_defined?('CENTENAS_ORDINAL')
|
189
|
+
|
190
|
+
MILHAR_ORDINAL = {
|
191
|
+
GENERO_MASC => {
|
192
|
+
1000 => 'Milésimo'
|
193
|
+
},
|
194
|
+
GENERO_FEM => {
|
195
|
+
1000 => 'Milésima'
|
196
|
+
}
|
197
|
+
}.freeze unless Extenso.const_defined?('MILHAR_ORDINAL')
|
198
|
+
|
199
|
+
def self.int?(payload)
|
200
|
+
!Integer(payload).nil?
|
201
|
+
rescue StandardError
|
202
|
+
false
|
203
|
+
end
|
204
|
+
|
205
|
+
def self.float?(payload)
|
206
|
+
!!Float(payload)
|
207
|
+
rescue StandardError
|
208
|
+
false
|
207
209
|
end
|
208
|
-
|
210
|
+
|
209
211
|
#######################################################################################################################################
|
210
|
-
|
211
|
-
def self.numero (valor, genero = GENERO_MASC)
|
212
212
|
|
213
|
+
def self.numero(valor, genero = GENERO_MASC)
|
213
214
|
# Gera a representação por extenso de um número inteiro, maior que zero e menor ou igual a VALOR_MAXIMO.
|
214
215
|
#
|
215
216
|
# PARÂMETROS:
|
@@ -220,41 +221,46 @@ class Extenso
|
|
220
221
|
#
|
221
222
|
# VALOR DE RETORNO:
|
222
223
|
# (String) O número por extenso
|
223
|
-
|
224
|
-
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
224
|
+
|
225
|
+
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
226
|
+
if valor.nil? || valor == ''
|
227
|
+
raise "[Exceção em Extenso.numero] Parâmetro 'valor' é nulo" if Settings&.extensobr_settings&.dig(:raise_for_nil) == 'true'
|
228
|
+
|
229
|
+
return 'Zero'
|
230
|
+
end
|
231
|
+
|
232
|
+
unless int?(valor) && !valor.nil?
|
233
|
+
"[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
|
234
|
+
end
|
235
|
+
|
236
|
+
if valor <= 0
|
237
|
+
'Zero'
|
230
238
|
elsif valor > VALOR_MAXIMO
|
231
|
-
raise
|
239
|
+
raise "[Exceção em Extenso.numero] Parâmetro '#{valor} deve ser um inteiro entre 1 e #{VALOR_MAXIMO} (recebido: '#{valor}')"
|
232
240
|
elsif genero != GENERO_MASC && genero != GENERO_FEM
|
233
241
|
raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
|
234
242
|
|
235
|
-
|
243
|
+
# ------------------------------------------------
|
236
244
|
|
237
245
|
elsif valor >= 1 && valor <= 9
|
238
246
|
UNIDADES[genero][valor]
|
239
|
-
|
247
|
+
|
240
248
|
elsif valor == 10
|
241
249
|
DEZENAS[valor]
|
242
250
|
|
243
251
|
elsif valor >= 11 && valor <= 19
|
244
252
|
DE11A19[valor]
|
245
|
-
|
253
|
+
|
246
254
|
elsif valor >= 20 && valor <= 99
|
247
255
|
dezena = valor - (valor % 10)
|
248
256
|
ret = DEZENAS[dezena]
|
249
257
|
# Chamada recursiva à função para processar resto se este for maior que zero.
|
250
258
|
# O conectivo 'e' é utilizado entre dezenas e unidades.
|
251
259
|
resto = valor - dezena
|
252
|
-
|
253
|
-
ret += ' e ' + self.numero(resto, genero)
|
254
|
-
end
|
260
|
+
ret += " e #{numero(resto, genero)}" if resto.positive?
|
255
261
|
ret
|
256
262
|
|
257
|
-
elsif valor == 100
|
263
|
+
elsif valor == 100
|
258
264
|
CENTENA_EXATA
|
259
265
|
|
260
266
|
elsif valor >= 101 && valor <= 999
|
@@ -262,151 +268,149 @@ class Extenso
|
|
262
268
|
ret = CENTENAS[genero][centena] # As centenas (exceto 'cento') variam em gênero
|
263
269
|
# Chamada recursiva à função para processar resto se este for maior que zero.
|
264
270
|
# O conectivo 'e' é utilizado entre centenas e dezenas.
|
265
|
-
resto = valor - centena
|
266
|
-
|
267
|
-
ret += ' e ' + self.numero(resto, genero)
|
268
|
-
end
|
271
|
+
resto = valor - centena
|
272
|
+
ret += " e #{numero(resto, genero)}" if resto.positive?
|
269
273
|
ret
|
270
274
|
|
271
|
-
elsif valor >= 1000 && valor <=
|
275
|
+
elsif valor >= 1000 && valor <= 999_999
|
272
276
|
# A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000,
|
273
277
|
# assim determinando a quantidade de milhares. O resultado é enviado a uma chamada recursiva
|
274
278
|
# da função. A palavra 'mil' não se flexiona.
|
275
279
|
milhar = (valor / 1000).floor
|
276
|
-
ret =
|
280
|
+
ret = "#{numero(milhar, GENERO_MASC)} #{MILHAR}" # 'Mil' é do gênero masculino
|
277
281
|
resto = valor % 1000
|
278
282
|
# Chamada recursiva à função para processar resto se este for maior que zero.
|
279
283
|
# O conectivo 'e' é utilizado entre milhares e números entre 1 e 99, bem como antes de centenas exatas.
|
280
|
-
if resto
|
281
|
-
ret +=
|
284
|
+
if resto.positive? && ((resto >= 1 && resto <= 99) || (resto % 100).zero?)
|
285
|
+
ret += " e #{numero(resto, genero)}"
|
282
286
|
# Nos demais casos, após o milhar é utilizada a vírgula.
|
283
|
-
elsif
|
284
|
-
ret +=
|
287
|
+
elsif resto.positive?
|
288
|
+
ret += ", #{numero(resto, genero)}"
|
285
289
|
end
|
286
290
|
ret
|
287
291
|
|
288
|
-
elsif valor >=
|
292
|
+
elsif valor >= 100_000 && valor <= VALOR_MAXIMO
|
289
293
|
# A função 'floor' é utilizada para encontrar o inteiro da divisão de valor por 1000000,
|
290
294
|
# assim determinando a quantidade de milhões. O resultado é enviado a uma chamada recursiva
|
291
295
|
# da função. A palavra 'milhão' flexiona-se no plural.
|
292
|
-
milhoes = (valor /
|
293
|
-
ret =
|
294
|
-
|
296
|
+
milhoes = (valor / 1_000_000).floor
|
297
|
+
ret = "#{numero(milhoes, GENERO_MASC)} " # Milhão e milhões são do gênero masculino
|
298
|
+
|
295
299
|
# Se a o número de milhões for maior que 1, deve-se utilizar a forma flexionada no plural
|
296
300
|
ret += milhoes == 1 ? MILHOES[NUM_SING] : MILHOES[NUM_PLURAL]
|
297
301
|
|
298
|
-
resto = valor %
|
302
|
+
resto = valor % 1_000_000
|
299
303
|
|
300
304
|
# Chamada recursiva à função para processar resto se este for maior que zero.
|
301
305
|
# O conectivo 'e' é utilizado entre milhões e números entre 1 e 99, bem como antes de centenas exatas.
|
302
306
|
if resto && (resto >= 1 && resto <= 99)
|
303
|
-
ret +=
|
307
|
+
ret += " e #{numero(resto, genero)}"
|
304
308
|
# Nos demais casos, após o milhão é utilizada a vírgula.
|
305
|
-
elsif resto
|
306
|
-
ret +=
|
309
|
+
elsif resto.positive?
|
310
|
+
ret += ", #{numero(resto, genero)}"
|
307
311
|
end
|
308
312
|
ret
|
309
313
|
|
310
314
|
end
|
311
|
-
|
312
315
|
end
|
313
|
-
|
316
|
+
|
314
317
|
#######################################################################################################################################
|
315
|
-
|
318
|
+
|
316
319
|
def self.moeda(
|
317
320
|
valor,
|
318
321
|
casas_decimais = 2,
|
319
322
|
info_unidade = ['Real', 'Reais', GENERO_MASC],
|
320
323
|
info_fracao = ['Centavo', 'Centavos', GENERO_MASC]
|
321
|
-
)
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
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
|
-
|
324
|
+
)
|
325
|
+
# Gera a representação por extenso de um valor monetário, maior que zero e menor ou igual a Extenso::VALOR_MAXIMO.
|
326
|
+
#
|
327
|
+
#
|
328
|
+
# PARÂMETROS:
|
329
|
+
# valor (Float) O valor monetário cujo extenso se deseja gerar.
|
330
|
+
# casas_decimais (Integer) [Opcional; valor padrão: 2] Número de casas decimais a serem consideradas como parte fracionária (centavos)
|
331
|
+
#
|
332
|
+
# info_unidade (Array) [Opcional; valor padrão: ['real', 'reais', Extenso::GENERO_MASC]] Fornece informações sobre a moeda a ser
|
333
|
+
# utilizada. O primeiro valor da matriz corresponde ao nome da moeda no singular, o segundo ao nome da moeda no plural e o terceiro
|
334
|
+
# ao gênero gramatical do nome da moeda (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
335
|
+
#
|
336
|
+
# info_fracao (Array) [Opcional; valor padrão: ['centavo', 'centavos', Extenso::GENERO_MASC]] Provê informações sobre a parte fracionária
|
337
|
+
# 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
|
338
|
+
# e o terceiro ao gênero gramatical da parte fracionária (Extenso::GENERO_MASC ou Extenso::GENERO_FEM)
|
339
|
+
#
|
340
|
+
# VALOR DE RETORNO:
|
341
|
+
# (String) O valor monetário por extenso
|
342
|
+
|
345
343
|
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
344
|
+
if valor.nil? || valor == ''
|
345
|
+
raise "[Exceção em Extenso.moeda] Parâmetro 'valor' é nulo" if Settings&.extensobr_settings&.dig(:raise_for_nil) == 'true'
|
346
346
|
|
347
|
-
|
347
|
+
return 'Zero Centavos'
|
348
|
+
end
|
349
|
+
|
350
|
+
unless float?(valor.to_f.round(casas_decimais).to_s)
|
348
351
|
raise "[Exceção em Extenso.moeda] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
|
352
|
+
end
|
349
353
|
|
350
|
-
|
351
|
-
|
354
|
+
if valor <= 0
|
355
|
+
'Zero'
|
352
356
|
|
353
|
-
elsif !
|
357
|
+
elsif !int?(casas_decimais) || casas_decimais.negative?
|
354
358
|
raise "[Exceção em Extenso.moeda] Parâmetro 'casas_decimais' não é numérico ou é menor que zero (recebido: '#{casas_decimais}')"
|
355
359
|
|
356
360
|
elsif info_unidade.class != Array || info_unidade.length < 3
|
357
|
-
temp = info_unidade.
|
361
|
+
temp = info_unidade.instance_of?(Array) ? "[#{info_unidade.join(', ')}]" : "'#{info_unidade}'"
|
358
362
|
raise "[Exceção em Extenso.moeda] Parâmetro 'info_unidade' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
|
359
|
-
|
363
|
+
|
360
364
|
elsif info_unidade[POS_GENERO] != GENERO_MASC && info_unidade[POS_GENERO] != GENERO_FEM
|
361
365
|
raise "Exceção em Extenso: valor incorreto para o parâmetro 'info_unidade[POS_GENERO]' (recebido: '#{info_unidade[POS_GENERO]}')"
|
362
366
|
|
363
367
|
elsif info_fracao.class != Array || info_fracao.length < 3
|
364
|
-
temp = info_fracao.
|
368
|
+
temp = info_fracao.instance_of?(Array) ? "[#{info_fracao.join(', ')}]" : "'#{info_fracao}'"
|
365
369
|
raise "[Exceção em Extenso.moeda] Parâmetro 'info_fracao' não é uma matriz com 3 (três) elementos (recebido: #{temp})"
|
366
|
-
|
370
|
+
|
367
371
|
elsif info_fracao[POS_GENERO] != GENERO_MASC && info_fracao[POS_GENERO] != GENERO_FEM
|
368
372
|
raise "[Exceção em Extenso.moeda] valor incorreto para o parâmetro 'info_fracao[POS_GENERO]' (recebido: '#{info_fracao[POS_GENERO]}')."
|
369
|
-
|
373
|
+
|
370
374
|
end
|
371
375
|
|
372
376
|
# -----------------------------------------------
|
373
377
|
|
374
378
|
ret = ''
|
375
379
|
|
376
|
-
|
377
|
-
#
|
378
|
-
parte_inteira = valor.
|
380
|
+
valor = format("%#{casas_decimais.to_f / 100}f", valor)
|
381
|
+
# A parte inteira do valor monetário corresponde ao valor passado antes do '.' no tipo float.
|
382
|
+
parte_inteira = valor.split('.')[0].to_i
|
379
383
|
|
380
|
-
# A parte fracionária ('centavos'), por seu turno, corresponderá ao
|
381
|
-
|
382
|
-
fracao = valor % (10**casas_decimais)
|
384
|
+
# A parte fracionária ('centavos'), por seu turno, corresponderá ao valor passado depois do '.'
|
385
|
+
fracao = valor.to_s.split('.')[1].to_i
|
383
386
|
|
384
|
-
# O extenso para a parte_inteira somente será gerado se esta for maior que zero. Para tanto, utilizamos
|
385
387
|
# os préstimos do método Extenso::numero().
|
386
|
-
if parte_inteira
|
387
|
-
ret =
|
388
|
+
if parte_inteira.positive?
|
389
|
+
ret = numero(parte_inteira,
|
390
|
+
info_unidade[POS_GENERO]) + (parte_inteira >= 1_000_000 && (parte_inteira.to_s.chars.reverse[5] == '0') ? ' de ' : ' ')
|
388
391
|
ret += parte_inteira == 1 ? info_unidade[NUM_SING] : info_unidade[NUM_PLURAL]
|
389
392
|
ret
|
390
393
|
end
|
391
394
|
|
392
395
|
# De forma semelhante, o extenso da fracao somente será gerado se esta for maior que zero. */
|
393
|
-
if fracao
|
396
|
+
if fracao.positive?
|
394
397
|
# Se a parte_inteira for maior que zero, o extenso para ela já terá sido gerado. Antes de juntar os
|
395
398
|
# centavos, precisamos colocar o conectivo 'e'.
|
396
|
-
if parte_inteira
|
397
|
-
|
398
|
-
|
399
|
-
|
399
|
+
ret += ' e ' if parte_inteira.positive?
|
400
|
+
ret += "#{numero(fracao, info_fracao[POS_GENERO])} "
|
401
|
+
ret += fracao == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL]
|
402
|
+
end
|
403
|
+
|
404
|
+
if valor.to_f.zero?
|
405
|
+
ret += "#{numero(fracao, info_fracao[POS_GENERO])} "
|
400
406
|
ret += parte_inteira == 1 ? info_fracao[NUM_SING] : info_fracao[NUM_PLURAL]
|
401
407
|
end
|
402
408
|
|
403
409
|
ret
|
404
|
-
|
405
410
|
end
|
406
411
|
|
407
412
|
######################################################################################################################################################
|
408
|
-
def self.ordinal
|
409
|
-
|
413
|
+
def self.ordinal(valor, genero = GENERO_MASC)
|
410
414
|
# Gera a representação ordinal de um número inteiro de 1 à 1000
|
411
415
|
|
412
416
|
# PARÂMETROS:
|
@@ -417,34 +421,40 @@ class Extenso
|
|
417
421
|
#
|
418
422
|
# VALOR DE RETORNO:
|
419
423
|
# (String) O número por extenso
|
420
|
-
|
421
|
-
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
424
|
+
|
425
|
+
# ----- VALIDAÇÃO DOS PARÂMETROS DE ENTRADA ----
|
426
|
+
if valor.nil? || valor == ''
|
427
|
+
raise "[Exceção em Extenso.ordinal] Parâmetro 'valor' é nulo" if Settings&.extensobr_settings&.dig(:raise_for_nil) == 'true'
|
428
|
+
|
429
|
+
return 'Zero'
|
430
|
+
end
|
431
|
+
|
432
|
+
raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')" unless int?(valor)
|
433
|
+
|
434
|
+
if valor <= 0
|
435
|
+
'Zero'
|
436
|
+
# raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')"
|
427
437
|
elsif valor > VALOR_MAXIMO
|
428
|
-
raise
|
438
|
+
raise "[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e #{VALOR_MAXIMO} (recebido: '#{valor}')"
|
429
439
|
elsif genero != GENERO_MASC && genero != GENERO_FEM
|
430
440
|
raise "Exceção em Extenso: valor incorreto para o parâmetro 'genero' (recebido: '#{genero}')"
|
431
|
-
|
441
|
+
# ------------------------------------------------
|
432
442
|
elsif valor >= 1 && valor <= 9
|
433
|
-
|
443
|
+
UNIDADES_ORDINAL[genero][valor]
|
434
444
|
elsif valor >= 10 && valor <= 99
|
435
445
|
dezena = valor - (valor % 10)
|
436
446
|
resto = valor - dezena
|
437
|
-
ret = DEZENAS_ORDINAL[genero][dezena]
|
438
|
-
|
439
|
-
|
447
|
+
ret = "#{DEZENAS_ORDINAL[genero][dezena]} "
|
448
|
+
ret += ordinal(resto, genero) if resto.positive?
|
449
|
+
ret.rstrip
|
440
450
|
elsif valor >= 100 && valor <= 999
|
441
451
|
centena = valor - (valor % 100)
|
442
|
-
resto = valor - centena
|
443
|
-
ret = CENTENAS_ORDINAL[genero][centena]
|
444
|
-
|
445
|
-
|
452
|
+
resto = valor - centena
|
453
|
+
ret = "#{CENTENAS_ORDINAL[genero][centena]} "
|
454
|
+
ret += ordinal(resto, genero) if resto.positive?
|
455
|
+
ret.rstrip
|
446
456
|
elsif valor == 1000
|
447
|
-
|
457
|
+
MILHAR_ORDINAL[genero][valor]
|
448
458
|
end
|
449
459
|
end
|
450
460
|
|
@@ -456,6 +466,14 @@ class Extenso
|
|
456
466
|
#
|
457
467
|
# @params[Object]
|
458
468
|
def self.real_formatado(valor)
|
459
|
-
|
469
|
+
float_valor = format('%#0.02f', valor)
|
470
|
+
float_valor = float_valor.chars.reverse.insert(6, '.').reverse.join if float_valor.chars.count >= 7
|
471
|
+
|
472
|
+
float_valor = float_valor.chars.reverse.insert(10, '.').reverse.join if float_valor.chars.count >= 11
|
473
|
+
|
474
|
+
float_valor = float_valor.chars.reverse
|
475
|
+
float_valor[2] = ','
|
476
|
+
|
477
|
+
"R$ #{float_valor.reverse.join}"
|
460
478
|
end
|
461
|
-
end
|
479
|
+
end
|
data/lib/settings.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class Settings
|
6
|
+
class << self
|
7
|
+
attr_reader :extensobr_settings
|
8
|
+
end
|
9
|
+
|
10
|
+
@extensobr_settings = {
|
11
|
+
raise_for_nil: ENV['EXTENSO_RAISE_FOR_NIL'] || 'false',
|
12
|
+
use_core_exts: ENV['EXTENSO_USE_CORE_EXTS'] || 'true'
|
13
|
+
}
|
14
|
+
|
15
|
+
@extensobr_settings_loaded = false
|
16
|
+
|
17
|
+
def self.load_extensobr_settings
|
18
|
+
return if @extensobr_settings_loaded
|
19
|
+
|
20
|
+
if Kernel.const_defined? 'Rails'
|
21
|
+
file_path = "#{__dir__}/config/extensobr.yml"
|
22
|
+
if ::File.exist?(file_path)
|
23
|
+
settings_file = ::YAML.load_file(file_path)
|
24
|
+
@extensobr_settings[:raise_for_nil] = settings_file['extensobr_settings']['raise_for_nil'] || 'false'
|
25
|
+
@extensobr_settings[:use_core_exts] = settings_file['extensobr_settings']['use_core_exts'] || 'true'
|
26
|
+
@extensobr_settings_loaded = true
|
27
|
+
else
|
28
|
+
@extensobr_settings_loaded = false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: extensobr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Henrique Max
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 2.2.15
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 2.2.15
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,6 +38,20 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 12.3.3
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
41
55
|
description: ExtensoBr é uma gem que foi desenvolvida para auxiliar na impressão de
|
42
56
|
números e moedas por extenso em portugês do Brasil.
|
43
57
|
email:
|
@@ -46,23 +60,30 @@ executables: []
|
|
46
60
|
extensions: []
|
47
61
|
extra_rdoc_files: []
|
48
62
|
files:
|
63
|
+
- ".github/workflows/codeql-analysis.yml"
|
49
64
|
- ".gitignore"
|
65
|
+
- ".rspec"
|
50
66
|
- CODE_OF_CONDUCT.md
|
51
67
|
- Gemfile
|
52
68
|
- LICENSE.txt
|
53
69
|
- README.md
|
54
70
|
- Rakefile
|
71
|
+
- SECURITY.md
|
55
72
|
- bin/console
|
56
73
|
- bin/setup
|
57
74
|
- extensobr-0.1.0.gem
|
58
75
|
- extensobr.gemspec
|
76
|
+
- lib/core_exts/float.rb
|
77
|
+
- lib/core_exts/integer.rb
|
78
|
+
- lib/core_exts/string.rb
|
59
79
|
- lib/extensobr.rb
|
60
80
|
- lib/extensobr/version.rb
|
81
|
+
- lib/settings.rb
|
61
82
|
homepage: https://github.com/rickmax/extensobr
|
62
83
|
licenses:
|
63
84
|
- MIT
|
64
85
|
metadata: {}
|
65
|
-
post_install_message:
|
86
|
+
post_install_message:
|
66
87
|
rdoc_options: []
|
67
88
|
require_paths:
|
68
89
|
- lib
|
@@ -77,9 +98,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
98
|
- !ruby/object:Gem::Version
|
78
99
|
version: '0'
|
79
100
|
requirements: []
|
80
|
-
|
81
|
-
|
82
|
-
signing_key:
|
101
|
+
rubygems_version: 3.2.32
|
102
|
+
signing_key:
|
83
103
|
specification_version: 4
|
84
104
|
summary: ExtendoBr escreve números e moeda por extenso.
|
85
105
|
test_files: []
|