brdinheiro 0.0.1
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.
- data/CHANGELOG +0 -0
- data/MIT-LICENSE +20 -0
- data/README +0 -0
- data/Rakefile +100 -0
- data/TODO +5 -0
- data/lib/brdinheiro/dinheiro.rb +349 -0
- data/lib/brdinheiro/dinheiro_active_record.rb +41 -0
- data/lib/brdinheiro/dinheiro_util.rb +43 -0
- data/lib/brdinheiro/excecoes.rb +7 -0
- data/lib/brdinheiro/number_portuguese.rb +163 -0
- data/lib/brdinheiro/version.rb +9 -0
- data/lib/brdinheiro.rb +20 -0
- data/test/br_dinheiro_test.rb +11 -0
- data/test/dinheiro_active_record_test.rb +49 -0
- data/test/dinheiro_test.rb +498 -0
- data/test/test_helper.rb +16 -0
- metadata +86 -0
data/CHANGELOG
ADDED
File without changes
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 [name of plugin creator]
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
File without changes
|
data/Rakefile
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/packagetask'
|
6
|
+
require 'rake/gempackagetask'
|
7
|
+
require 'rake/contrib/sshpublisher'
|
8
|
+
require File.join(File.dirname(__FILE__), 'lib', 'brdinheiro', 'version')
|
9
|
+
|
10
|
+
PKG_BUILD = ENV['PKG_BUILD'] ? '.' + ENV['PKG_BUILD'] : ''
|
11
|
+
PKG_NAME = 'brdinheiro'
|
12
|
+
PKG_VERSION = BrDinheiro::VERSION::STRING + PKG_BUILD
|
13
|
+
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
|
14
|
+
|
15
|
+
RELEASE_NAME = "REL #{PKG_VERSION}"
|
16
|
+
|
17
|
+
RUBY_FORGE_PROJECT = "brdinheiro"
|
18
|
+
RUBY_FORGE_USER = "tapajos"
|
19
|
+
|
20
|
+
desc "Default Task"
|
21
|
+
task :default => [ :test ]
|
22
|
+
|
23
|
+
# Run the unit tests
|
24
|
+
Rake::TestTask.new { |t|
|
25
|
+
t.libs << "test"
|
26
|
+
t.pattern = 'test/*_test.rb'
|
27
|
+
t.verbose = true
|
28
|
+
t.warning = false
|
29
|
+
}
|
30
|
+
|
31
|
+
|
32
|
+
# Generate the RDoc documentation
|
33
|
+
# Rake::RDocTask.new { |rdoc|
|
34
|
+
# rdoc.rdoc_dir = 'doc'
|
35
|
+
# rdoc.title = "Action Mailer -- Easy email delivery and testing"
|
36
|
+
# rdoc.options << '--line-numbers' << '--inline-source' << '-A cattr_accessor=object'
|
37
|
+
# rdoc.options << '--charset' << 'utf-8'
|
38
|
+
# rdoc.template = "#{ENV['template']}.rb" if ENV['template']
|
39
|
+
# rdoc.rdoc_files.include('README', 'CHANGELOG')
|
40
|
+
# rdoc.rdoc_files.include('lib/action_mailer.rb')
|
41
|
+
# rdoc.rdoc_files.include('lib/action_mailer/*.rb')
|
42
|
+
# }
|
43
|
+
|
44
|
+
|
45
|
+
# Create compressed packages
|
46
|
+
spec = Gem::Specification.new do |s|
|
47
|
+
s.platform = Gem::Platform::RUBY
|
48
|
+
s.name = PKG_NAME
|
49
|
+
s.summary = "brdinheiro é uma das gems que compoem o Brazilian Rails"
|
50
|
+
s.description = %q{brdinheiro é uma das gems que compoem o Brazilian Rails}
|
51
|
+
s.version = PKG_VERSION
|
52
|
+
|
53
|
+
s.author = "Marcos Tapajós"
|
54
|
+
s.email = "tapajos@gmail.com"
|
55
|
+
s.rubyforge_project = "brdinheiro"
|
56
|
+
s.homepage = "http://www.improveit.com.br/software_livre/brazilian_rails"
|
57
|
+
|
58
|
+
s.add_dependency('actionpack', '>= 1.4.2')
|
59
|
+
s.add_dependency('activerecord', '>= 1.15.3')
|
60
|
+
|
61
|
+
s.has_rdoc = true
|
62
|
+
s.requirements << 'none'
|
63
|
+
s.require_path = 'lib'
|
64
|
+
# s.autorequire = 'brdinheiro'
|
65
|
+
|
66
|
+
s.files = [ "Rakefile", "README", "CHANGELOG", "TODO", "MIT-LICENSE" ]
|
67
|
+
s.files = s.files + Dir.glob( "lib/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
68
|
+
s.files = s.files + Dir.glob( "test/**/*" ).delete_if { |item| item.include?( "\.svn" ) }
|
69
|
+
end
|
70
|
+
|
71
|
+
Rake::GemPackageTask.new(spec) do |p|
|
72
|
+
p.gem_spec = spec
|
73
|
+
p.need_tar = true
|
74
|
+
p.need_zip = true
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# desc "Publish the API documentation"
|
79
|
+
# task :pgem => [:package] do
|
80
|
+
# Rake::SshFilePublisher.new("wrath.rubyonrails.org", "public_html/gems/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# desc "Publish the API documentation"
|
84
|
+
# task :pdoc => [:rdoc] do
|
85
|
+
# Rake::SshDirPublisher.new("wrath.rubyonrails.org", "public_html/am", "doc").upload
|
86
|
+
# end
|
87
|
+
#
|
88
|
+
|
89
|
+
desc "Publish the release files to RubyForge."
|
90
|
+
task :release => [ :package ] do
|
91
|
+
require 'rubyforge'
|
92
|
+
require 'rake/contrib/rubyforgepublisher'
|
93
|
+
|
94
|
+
packages = %w( gem tgz zip ).collect{ |ext| "pkg/#{PKG_NAME}-#{PKG_VERSION}.#{ext}" }
|
95
|
+
|
96
|
+
rubyforge = RubyForge.new
|
97
|
+
rubyforge.configure
|
98
|
+
rubyforge.login
|
99
|
+
rubyforge.add_release(PKG_NAME, PKG_NAME, "REL #{PKG_VERSION}", *packages)
|
100
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,349 @@
|
|
1
|
+
# == Como usar o Dinheiro em seu ActiveRecord?
|
2
|
+
#
|
3
|
+
# * Arquivo 001_create_lancamentos.rb:
|
4
|
+
#
|
5
|
+
# class CreateLancamentos < ActiveRecord::Migration
|
6
|
+
# def self.up
|
7
|
+
# create_table :lancamentos do |t|
|
8
|
+
# t.column :descricao, :string, :null => false
|
9
|
+
# t.column :valor, :decimal, :precision => 14, :scale => 2
|
10
|
+
# t.column :mensalidade, :decimal, :precision => 14, :scale => 2
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def self.down
|
15
|
+
# drop_table :lancamentos
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# * Arquivo lancamento.rb:
|
20
|
+
#
|
21
|
+
# class Lancamento < ActiveRecord::Base
|
22
|
+
# usar_como_dinheiro :valor, :mensalidade
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# * No console (script/console):
|
26
|
+
#
|
27
|
+
# Loading development environment.
|
28
|
+
# >> lancamento = Lancamento.new
|
29
|
+
# => #<Lancamento:0x9652cd8 @attributes={"descricao"=>nil,
|
30
|
+
# "valor"=>#<BigDecimal:9657008,'0.0',4(4)>,
|
31
|
+
# "mensalidade"=>#<BigDecimal:9656e8c,'0.0',4(4)>},
|
32
|
+
# @new_record=true>
|
33
|
+
# >> lancamento.valor = 100
|
34
|
+
# => 100
|
35
|
+
# >> lancamento.valor
|
36
|
+
# => #<Dinheiro:0x9650f3c @quantia=10000>
|
37
|
+
# >> lancamento.valor.real
|
38
|
+
# => "R$ 100,00"
|
39
|
+
# >> lancamento.valor = 100.50
|
40
|
+
# => 100.5
|
41
|
+
# >> lancamento.valor.real
|
42
|
+
# => "R$ 100,50"
|
43
|
+
# >> lancamento.valor = "250.50"
|
44
|
+
# => "250.50"
|
45
|
+
# >> lancamento.valor.real
|
46
|
+
# => "R$ 250,50"
|
47
|
+
# >> lancamento.valor = 354.58.reais
|
48
|
+
# => #<Dinheiro:0x9646384 @quantia=35458>
|
49
|
+
# >> lancamento.valor.real
|
50
|
+
# => "R$ 354,58"
|
51
|
+
# >> exit
|
52
|
+
#
|
53
|
+
class Dinheiro
|
54
|
+
|
55
|
+
include Comparable
|
56
|
+
|
57
|
+
attr_reader :quantia
|
58
|
+
|
59
|
+
FORMATO_VALIDO_BR = /^([R|r]\$\s*)?(([+-]?\d{1,3}(\.?\d{3})*))?(\,\d{0,2})?$/
|
60
|
+
FORMATO_VALIDO_EUA = /^([R|r]\$\s*)?(([+-]?\d{1,3}(\,?\d{3})*))?(\.\d{0,2})?$/
|
61
|
+
SEPARADOR_MILHAR = "."
|
62
|
+
SEPARADOR_FRACIONARIO = ","
|
63
|
+
QUANTIDADE_DIGITOS = 3
|
64
|
+
PRECISAO_DECIMAL = 100
|
65
|
+
|
66
|
+
def initialize(quantia)
|
67
|
+
self.quantia = quantia
|
68
|
+
end
|
69
|
+
|
70
|
+
# Retorna o valor armazenado em string.
|
71
|
+
#
|
72
|
+
# Exemplo:
|
73
|
+
# 1000.to_s ==> '1.000,00'
|
74
|
+
def to_s
|
75
|
+
inteiro_com_milhar(parte_inteira) + parte_decimal
|
76
|
+
end
|
77
|
+
|
78
|
+
# Compara com outro dinheiro se eh igual.
|
79
|
+
#
|
80
|
+
# Exemplo:
|
81
|
+
# um_real = Dinheiro.new(1)
|
82
|
+
# um_real == Dinheiro.new(1) ==> true
|
83
|
+
# um_real == Dinheiro.new(2) ==> false
|
84
|
+
def ==(outro_dinheiro)
|
85
|
+
begin
|
86
|
+
outro_dinheiro = Dinheiro.new(outro_dinheiro) unless outro_dinheiro.kind_of?(Dinheiro)
|
87
|
+
rescue
|
88
|
+
return false
|
89
|
+
end
|
90
|
+
@quantia == outro_dinheiro.quantia
|
91
|
+
end
|
92
|
+
|
93
|
+
# Compara com outro dinheiro se eh maior ou menor.
|
94
|
+
#
|
95
|
+
# Exemplo:
|
96
|
+
# 1.real < 2.reais ==> true
|
97
|
+
# 1.real > 2.reais ==> false
|
98
|
+
# 2.real < 1.reais ==> false
|
99
|
+
# 2.real > 1.reais ==> true
|
100
|
+
def <=>(outro_dinheiro)
|
101
|
+
outro_dinheiro = Dinheiro.new(outro_dinheiro) unless outro_dinheiro.kind_of?(Dinheiro)
|
102
|
+
@quantia <=> outro_dinheiro.quantia
|
103
|
+
end
|
104
|
+
|
105
|
+
# Retorna a adicao entre dinheiros.
|
106
|
+
#
|
107
|
+
# Exemplo:
|
108
|
+
# 1.real + 1.real == 2.reais
|
109
|
+
# 1.real + 1 == 2.reais
|
110
|
+
def +(outro)
|
111
|
+
Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia + quantia_de(outro)))
|
112
|
+
end
|
113
|
+
|
114
|
+
# Retorna a subtracao entre dinheiros.
|
115
|
+
#
|
116
|
+
# Exemplo:
|
117
|
+
# 10.reais - 2.reais == 8.reais
|
118
|
+
# 10.reais - 2 == 8.reais
|
119
|
+
def -(outro)
|
120
|
+
Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia - quantia_de(outro)))
|
121
|
+
end
|
122
|
+
|
123
|
+
# Retorna a multiplicacao entre dinheiros.
|
124
|
+
#
|
125
|
+
# Exemplo:
|
126
|
+
# 5.reais * 2 == 10.reais
|
127
|
+
# 5.reais * 2.reais == 10.reais
|
128
|
+
def *(outro)
|
129
|
+
return Dinheiro.new(to_f * outro) unless outro.kind_of? Dinheiro
|
130
|
+
outro * to_f
|
131
|
+
end
|
132
|
+
|
133
|
+
# Retorna a divisao entre dinheiros.
|
134
|
+
#
|
135
|
+
# Exemplo:
|
136
|
+
# 5.reais / 2 == (2.5).reais
|
137
|
+
# 5.reais / 2.reais == DivisaPorNaoEscalarError
|
138
|
+
# 5.reais / 0 == ZeroDivisionError
|
139
|
+
#
|
140
|
+
# Veja também o método parcelar
|
141
|
+
def /(outro)
|
142
|
+
raise DivisaPorNaoEscalarError unless outro.kind_of?(Numeric)
|
143
|
+
return @quantia/outro if outro == 0
|
144
|
+
Dinheiro.new(to_f / outro.to_f)
|
145
|
+
end
|
146
|
+
|
147
|
+
# Retorna um array de dinheiro com as parcelas
|
148
|
+
#
|
149
|
+
# Exemplo:
|
150
|
+
# 6.reais.parcelar(2) == [3.reais, 3.reais]
|
151
|
+
# 6.reais.parcelar(2.reais) == DisivaPorNaoEscalarError
|
152
|
+
# 6.reais.parcelar(0) == ZeroDivisionError
|
153
|
+
def parcelar(numero_de_parcelar)
|
154
|
+
Fixnum
|
155
|
+
raise DivisaPorNaoEscalarError unless numero_de_parcelar.kind_of?(Integer)
|
156
|
+
return @quantia/numero_de_parcelar if numero_de_parcelar == 0
|
157
|
+
soma_parcial = Dinheiro.new(0)
|
158
|
+
parcelas = []
|
159
|
+
(numero_de_parcelar-1).times do
|
160
|
+
parcela = Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia/numero_de_parcelar))
|
161
|
+
parcelas << parcela
|
162
|
+
soma_parcial += parcela
|
163
|
+
end
|
164
|
+
parcelas << Dinheiro.new(transforma_em_string_que_represente_a_quantia(@quantia - quantia_de(soma_parcial)))
|
165
|
+
end
|
166
|
+
|
167
|
+
# Escreve o valor por extenso.
|
168
|
+
#
|
169
|
+
# Exemplo:
|
170
|
+
# 1.real.to_extenso ==> 'um real'
|
171
|
+
# (100.58).to_extenso ==> 'cem reais e cinquenta e oito centavos'
|
172
|
+
def to_extenso
|
173
|
+
(@quantia/100.0).por_extenso_em_reais
|
174
|
+
end
|
175
|
+
|
176
|
+
# Alias para o metodo to_extenso.
|
177
|
+
alias_method :por_extenso, :to_extenso
|
178
|
+
|
179
|
+
# Alias para o metodo to_extenso.
|
180
|
+
alias_method :por_extenso_em_reais, :to_extenso
|
181
|
+
|
182
|
+
# Verifica se o valor é zero.
|
183
|
+
def zero?
|
184
|
+
to_f.zero?
|
185
|
+
end
|
186
|
+
|
187
|
+
# Retorna um Float.
|
188
|
+
def to_f
|
189
|
+
to_s.gsub('.', '').gsub(',', '.').to_f
|
190
|
+
end
|
191
|
+
|
192
|
+
def coerce(outro)#:nodoc:
|
193
|
+
[ Dinheiro.new(outro), self ]
|
194
|
+
end
|
195
|
+
|
196
|
+
# Retorna a própria instância/
|
197
|
+
def real
|
198
|
+
self
|
199
|
+
end
|
200
|
+
|
201
|
+
# Alias para real.
|
202
|
+
alias_method :reais, :real
|
203
|
+
|
204
|
+
# Retorna uma string formatada com sigla em valor monetário.
|
205
|
+
# Exemplo:
|
206
|
+
# Dinheiro.new(1).real_formatado ==> 'R$ 1,00'
|
207
|
+
# Dinheiro.new(-1).real_formatado ==> 'R$ -1,00'
|
208
|
+
def real_formatado
|
209
|
+
"R$ #{to_s}"
|
210
|
+
end
|
211
|
+
|
212
|
+
# Alias para real_formatado.
|
213
|
+
alias_method :reais_formatado, :real_formatado
|
214
|
+
|
215
|
+
# Retorna uma string formatada com sigla em valor contábil.
|
216
|
+
#
|
217
|
+
# Exemplo:
|
218
|
+
# Dinheiro.new(1).real_contabil ==> 'R$ 1,00'
|
219
|
+
# Dinheiro.new(-1).real_contabil ==> 'R$ (1,00)'
|
220
|
+
def real_contabil
|
221
|
+
"R$ " + contabil
|
222
|
+
end
|
223
|
+
|
224
|
+
# Alias para real_contabil.
|
225
|
+
alias_method :reais_contabeis, :real_contabil
|
226
|
+
|
227
|
+
# Retorna uma string formatada sem sigla.
|
228
|
+
#
|
229
|
+
# Exemplo:
|
230
|
+
# Dinheiro.new(1).contabil ==> '1,00'
|
231
|
+
# Dinheiro.new(-1).contabil ==> '(1,00)'
|
232
|
+
def contabil
|
233
|
+
if @quantia >= 0
|
234
|
+
to_s
|
235
|
+
else
|
236
|
+
"(" + to_s[1..-1] + ")"
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
# Retorna um BigDecinal.
|
241
|
+
def valor_decimal
|
242
|
+
BigDecimal.new quantia_sem_separacao_milhares.gsub(',','.')
|
243
|
+
end
|
244
|
+
|
245
|
+
def method_missing(symbol, *args) #:nodoc:
|
246
|
+
#Ex: Chama ao método valor_decimal()
|
247
|
+
if (symbol.to_s =~ /^(.*)_decimal$/) && args.size == 0
|
248
|
+
BigDecimal.new quantia_sem_separacao_milhares.gsub(',','.')
|
249
|
+
else
|
250
|
+
super.method_missing(symbol, *args)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
def quantia_de(outro)
|
256
|
+
outro = outro.to_f if outro.kind_of?(BigDecimal)
|
257
|
+
return outro.quantia if outro.kind_of?(Dinheiro)
|
258
|
+
(outro * 100).round
|
259
|
+
end
|
260
|
+
|
261
|
+
def transforma_em_string_que_represente_a_quantia(quantia)
|
262
|
+
if /^([+-]?)(\d)$/ =~ quantia.to_s
|
263
|
+
return "#{$1}0.0#{$2}"
|
264
|
+
end
|
265
|
+
/^([+-]?)(\d*)(\d\d)$/ =~ quantia.to_s
|
266
|
+
"#{$1}#{$2.to_i}.#{$3}"
|
267
|
+
end
|
268
|
+
|
269
|
+
def quantia=(quantia)
|
270
|
+
raise DinheiroInvalidoError unless quantia_valida?(quantia)
|
271
|
+
quantia = quantia.to_f if quantia.kind_of?(BigDecimal)
|
272
|
+
@quantia = (quantia * 100).round if quantia.kind_of?(Numeric)
|
273
|
+
@quantia = extrai_quantia_como_inteiro(quantia) if quantia.kind_of?(String)
|
274
|
+
end
|
275
|
+
|
276
|
+
def parte_inteira
|
277
|
+
quantia_sem_separacao_milhares[0,quantia_sem_separacao_milhares.length-QUANTIDADE_DIGITOS]
|
278
|
+
end
|
279
|
+
|
280
|
+
def parte_decimal
|
281
|
+
quantia_sem_separacao_milhares[-QUANTIDADE_DIGITOS, QUANTIDADE_DIGITOS]
|
282
|
+
end
|
283
|
+
|
284
|
+
def inteiro_com_milhar(inteiro)
|
285
|
+
return inteiro if quantidade_de_passos(inteiro) == 0
|
286
|
+
resultado = ""
|
287
|
+
quantidade_de_passos(inteiro).times do |passo|
|
288
|
+
resultado = "." + inteiro[-QUANTIDADE_DIGITOS + passo * -QUANTIDADE_DIGITOS, QUANTIDADE_DIGITOS] + resultado
|
289
|
+
end
|
290
|
+
resultado = inteiro[0, digitos_que_sobraram(inteiro)] + resultado
|
291
|
+
resultado.gsub(/^(-?)\./, '\1')
|
292
|
+
end
|
293
|
+
|
294
|
+
def quantia_sem_separacao_milhares
|
295
|
+
sprintf("%.2f", (@quantia.to_f / PRECISAO_DECIMAL)).gsub(SEPARADOR_MILHAR, SEPARADOR_FRACIONARIO)
|
296
|
+
end
|
297
|
+
|
298
|
+
def quantidade_de_passos(inteiro)
|
299
|
+
resultado = inteiro.length / QUANTIDADE_DIGITOS
|
300
|
+
resultado = (resultado - 1) if inteiro.length % QUANTIDADE_DIGITOS == 0
|
301
|
+
resultado
|
302
|
+
end
|
303
|
+
|
304
|
+
def digitos_que_sobraram(inteiro)
|
305
|
+
inteiro.length - (quantidade_de_passos(inteiro) * QUANTIDADE_DIGITOS)
|
306
|
+
end
|
307
|
+
|
308
|
+
def quantia_valida?(quantia)
|
309
|
+
return false if quantia.kind_of?(String) && !quantia_respeita_formato?(quantia)
|
310
|
+
quantia.kind_of?(String) || quantia.kind_of?(Numeric)
|
311
|
+
end
|
312
|
+
|
313
|
+
def extrai_quantia_como_inteiro(quantia)
|
314
|
+
if FORMATO_VALIDO_BR =~ quantia
|
315
|
+
return sem_milhar($2, $5, '.')
|
316
|
+
end
|
317
|
+
if FORMATO_VALIDO_EUA =~ quantia
|
318
|
+
return sem_milhar($2, $5, ',')
|
319
|
+
end
|
320
|
+
end
|
321
|
+
|
322
|
+
def sem_milhar(parte_inteira, parte_decimal, delimitador_de_milhar)
|
323
|
+
(inteiro(parte_inteira, delimitador_de_milhar) + decimal(parte_decimal)).to_i
|
324
|
+
end
|
325
|
+
|
326
|
+
def inteiro(inteiro_com_separador_milhar, separador)
|
327
|
+
return inteiro_com_separador_milhar.gsub(separador, '') unless inteiro_com_separador_milhar.blank?
|
328
|
+
""
|
329
|
+
end
|
330
|
+
|
331
|
+
def decimal(parte_fracionaria)
|
332
|
+
unless parte_fracionaria.blank?
|
333
|
+
return sem_delimitador_decimal(parte_fracionaria) if parte_fracionaria.length == 3
|
334
|
+
return sem_delimitador_decimal(parte_fracionaria) + "0" if parte_fracionaria.length == 2
|
335
|
+
end
|
336
|
+
"00"
|
337
|
+
end
|
338
|
+
|
339
|
+
def sem_delimitador_decimal(parte_fracionaria)
|
340
|
+
"#{parte_fracionaria}".gsub(/[.|,]/, '')
|
341
|
+
end
|
342
|
+
|
343
|
+
|
344
|
+
def quantia_respeita_formato?(quantia)
|
345
|
+
return true if FORMATO_VALIDO_BR.match(quantia) || FORMATO_VALIDO_EUA.match(quantia)
|
346
|
+
false
|
347
|
+
end
|
348
|
+
|
349
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module DinheiroActiveRecord#:nodoc:
|
2
|
+
def self.included(base)#:nodoc:
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
module ClassMethods#:nodoc:
|
6
|
+
def usar_como_dinheiro(*args)#:nodoc:
|
7
|
+
unless args.size.zero?
|
8
|
+
args.each do |name|
|
9
|
+
composed_of name, :class_name => 'Dinheiro', :mapping => [name.to_s, "valor_decimal"], :allow_nil => true
|
10
|
+
|
11
|
+
name = name.to_s
|
12
|
+
module_eval <<-ADICIONANDO_METODO
|
13
|
+
validate :#{name}_valido?
|
14
|
+
|
15
|
+
def #{name}_valido?
|
16
|
+
begin
|
17
|
+
@#{name}.to_s.reais
|
18
|
+
rescue Exception => e
|
19
|
+
self.errors.add('#{name}', e.message)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def #{name}=(value)
|
24
|
+
if value.nil?
|
25
|
+
write_attribute('#{name}', nil)
|
26
|
+
elsif value.kind_of?(Dinheiro)
|
27
|
+
write_attribute('#{name}', value.valor_decimal)
|
28
|
+
else
|
29
|
+
begin
|
30
|
+
write_attribute('#{name}', value.reais.valor_decimal)
|
31
|
+
rescue
|
32
|
+
@#{name} = value
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
ADICIONANDO_METODO
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module DinheiroUtil
|
2
|
+
# Transforma numero em dinheiro
|
3
|
+
#
|
4
|
+
# Exemplo:
|
5
|
+
# 1.para_dinheiro.class ==> Dinheiro
|
6
|
+
def para_dinheiro
|
7
|
+
Dinheiro.new(self)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Alias para para_dinheiro
|
11
|
+
alias_method :reais, :para_dinheiro
|
12
|
+
|
13
|
+
# Alias para para_dinheiro
|
14
|
+
alias_method :real, :para_dinheiro
|
15
|
+
|
16
|
+
# Retorna string formatada com simbolo monetario
|
17
|
+
#
|
18
|
+
# Exemplo:
|
19
|
+
# 1.real_contabil ==> 'R$ 1,00'
|
20
|
+
# -1.real_contabil ==> 'R$ (1,00)'
|
21
|
+
def real_contabil
|
22
|
+
Dinheiro.new(self).real_contabil
|
23
|
+
end
|
24
|
+
|
25
|
+
# Retorna string formatada com simbolo monetario
|
26
|
+
#
|
27
|
+
# Exemplo:
|
28
|
+
# 2.reais_contabeis ==> 'R$ 2,00'
|
29
|
+
# -2.reais_contabeis ==> 'R$ 2,00'
|
30
|
+
def reais_contabeis
|
31
|
+
Dinheiro.new(self).reais_contabeis
|
32
|
+
end
|
33
|
+
|
34
|
+
# Retorna string formatada com simbolo monetario
|
35
|
+
#
|
36
|
+
# Exemplo:
|
37
|
+
# 1.contabil ==> '1,00'
|
38
|
+
# -1.contabil ==> '(1,00)'
|
39
|
+
def contabil
|
40
|
+
Dinheiro.new(self).contabil
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
def cria_excecao(classe, mensagem)
|
2
|
+
eval "class #{classe}; def initialize; super('#{mensagem}'); end; end"
|
3
|
+
end
|
4
|
+
|
5
|
+
cria_excecao("DinheiroInvalidoError < ArgumentError", "O valor deve estar preenchido e no formato correto. Ex.: 100.00 .")
|
6
|
+
cria_excecao("DivisaPorNaoEscalarError < ArgumentError", "So eh possivel dividir dinheiro por numeros.")
|
7
|
+
|