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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 8259c19e8da47eb88e3750a217fc60057f99551b
4
- data.tar.gz: 2d3447665586e989262a3af7d77d5fd6466ae765
2
+ SHA256:
3
+ metadata.gz: 4c16a2759e6723989331737ab04867c31e50ca3275cefc8fde86652eb9b7a520
4
+ data.tar.gz: 2c66fa8ffd5355bf4f6bb708738a9e931e4e162a2fb95705fbe17510b0c62cc3
5
5
  SHA512:
6
- metadata.gz: 945037856c554adccf8b9a7086e4afaafb61aac02918b4aafd5d22ca777b839a1a030fd8ab5b4d36400ed323a1bfd2d52fa7ef035430ac723a1a556467e77cd1
7
- data.tar.gz: 8ad533d6886f1151f0574c098a458d2739a1eec93881187b312d020691940ffbfc4b4cf0e196fe1c97eee452febd400f0259b0b89038d914d7707098b6b2d19d
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
@@ -8,3 +8,5 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
  *.gem
11
+ .DS_Store
12
+ .byebug_history
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
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 imprimir números ou moedas por extenso como por exemplo em recibos, contratos entre outros.
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, Extenso::GENERO_FEM) # oitocentas e trinta e duas
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
- require 'Extenso.rb'
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
- ## IMPORTANTE: este método recebe um valor inteiro(int), para a contagem das casas decimais!
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
- 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])
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
- ## três mil, quinhentas e setenta pesetas e oitenta e dois cêntimos
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 real de um número, utilize Extenso.real_formatado.
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. Fazer um fork do projeto
56
- 1. Fazer os devidos ajustes com os respectivos testes
57
- 1. Fazer pull request
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 ostermos de licença [MIT License](http://opensource.org/licenses/MIT).
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,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'extensobr'
4
+
5
+ # Extende a classe Float adicionando o metodo por_extenso
6
+ Float.class_eval do
7
+ def por_extenso(*args)
8
+ Extenso.moeda(self, *args)
9
+ end
10
+ 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
@@ -1,3 +1,3 @@
1
1
  module Extensobr
2
- VERSION = "0.1.2"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/extensobr.rb CHANGED
@@ -1,46 +1,29 @@
1
- require "extensobr/version"
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
- # 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
-
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 => 'Milhão',
129
- NUM_PLURAL => 'Milhões'
130
- }
111
+ NUM_SING => 'milhão',
112
+ NUM_PLURAL => 'milhões'
113
+ }.freeze unless Extenso.const_defined?('MILHOES')
131
114
 
132
- UNIDADES_ORDINAL = {
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
- 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
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
- 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}')"
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 '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')"
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
- if resto > 0
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
- if resto > 0
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 <= 999999
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 = self.numero(milhar, GENERO_MASC) + ' ' + MILHAR # 'Mil' é do gênero masculino
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 > 0 && ((resto >= 1 && resto <= 99) || resto % 100 == 0)
281
- ret += ' e ' + self.numero(resto, genero)
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 (resto > 0)
284
- ret += ', ' + self.numero(resto, genero)
287
+ elsif resto.positive?
288
+ ret += ", #{numero(resto, genero)}"
285
289
  end
286
290
  ret
287
291
 
288
- elsif valor >= 100000 && valor <= VALOR_MAXIMO
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 / 1000000).floor
293
- ret = self.numero(milhoes, GENERO_MASC) + ' ' # Milhão e milhões são do gênero masculino
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 % 1000000
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 += ' e ' + self.numero(resto, genero)
307
+ ret += " e #{numero(resto, genero)}"
304
308
  # Nos demais casos, após o milhão é utilizada a vírgula.
305
- elsif resto > 0
306
- ret += ', ' + self.numero(resto, genero)
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
- # 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
- # 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
-
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
- if ! self.is_int(valor)
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
- elsif valor <= 0
351
- raise "[Exceção em Extenso.moeda] Parâmetro valor igual a ou menor que zero (recebido: '#{valor}')"
354
+ if valor <= 0
355
+ 'Zero'
352
356
 
353
- elsif ! self.is_int(casas_decimais) || casas_decimais < 0
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.class == Array ? '[' + info_unidade.join(', ') + ']' : "'#{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.class == Array ? '[' + info_fracao.join(', ') + ']' : "'#{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
- # 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)
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 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)
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 > 0
387
- ret = self.numero(parte_inteira, info_unidade[POS_GENERO]) + ' de '
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 > 0
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 > 0
397
- ret += ' e '
398
- end
399
- ret += self.numero(fracao, info_fracao[POS_GENERO]) + ' '
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 (valor, genero = GENERO_MASC)
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
- if !is_int(valor)
424
- raise "[Exceção em Extenso.numero] Parâmetro 'valor' não é numérico (recebido: '#{valor}')"
425
- elsif valor <= 0
426
- raise "[Exceção em Extenso.numero] Parâmetro 'valor' igual a ou menor que zero (recebido: '#{valor}')"
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 '[Exceção em Extenso::numero] Parâmetro ''valor'' deve ser um inteiro entre 1 e ' + VALOR_MAXIMO.to_s + " (recebido: '#{valor}')"
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
- return UNIDADES_ORDINAL[genero][valor]
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
- if resto > 0 then ret+= self.ordinal(resto,genero); end
439
- return ret
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
- if resto > 0 then ret += self.ordinal(resto, genero); end
445
- return ret
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
- return MILHAR_ORDINAL[genero][valor]+" "
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
- "R$ #{format("%.2f", valor).to_s.gsub('.', ',')}"
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: 0.1.2
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: 2020-05-18 00:00:00.000000000 Z
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: '1.13'
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: '1.13'
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
- rubyforge_project:
81
- rubygems_version: 2.6.14
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: []