numrepr 1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +52 -0
- data/README.md +212 -0
- data/lib/numrepr/decimal.rb +296 -0
- data/lib/numrepr/format.rb +301 -0
- data/lib/numrepr/money.rb +337 -0
- data/lib/numrepr/percent.rb +236 -0
- data/lib/numrepr/version.rb +10 -0
- data/lib/numrepr.rb +9 -0
- data/numrepr.gemspec +36 -0
- metadata +54 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#
|
|
2
|
+
# numrepr/percent.rb -- Percentage of monetary amount values
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
require "bigdecimal"
|
|
6
|
+
require "numrepr/format"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
module NumRepr
|
|
10
|
+
|
|
11
|
+
class NoSolutionError < StandardError ; end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class Percent
|
|
15
|
+
|
|
16
|
+
attr_reader :rate
|
|
17
|
+
|
|
18
|
+
CENT = 100
|
|
19
|
+
|
|
20
|
+
class <<self
|
|
21
|
+
|
|
22
|
+
alias parse new
|
|
23
|
+
|
|
24
|
+
def zero ; new nil ; end
|
|
25
|
+
|
|
26
|
+
def as obj
|
|
27
|
+
case obj
|
|
28
|
+
when self then obj
|
|
29
|
+
else new obj
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def initialize rate = nil
|
|
37
|
+
@rate =
|
|
38
|
+
case rate
|
|
39
|
+
when String then parse_str rate
|
|
40
|
+
when Percent then rate.rate
|
|
41
|
+
when nil then 0.to_d
|
|
42
|
+
else rate.to_d
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
private
|
|
47
|
+
|
|
48
|
+
def parse_str rate
|
|
49
|
+
BigDecimal rate =~ /%\s*\z/ ? $` : rate
|
|
50
|
+
rescue ArgumentError
|
|
51
|
+
raise ArgumentError, "Not a Percent value: \"#{rate}\"."
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
public
|
|
55
|
+
|
|
56
|
+
def to_percent ; self ; end
|
|
57
|
+
|
|
58
|
+
def eql? oth ; oth.class == self.class and @rate == oth.rate ; end
|
|
59
|
+
|
|
60
|
+
def hash ; @rate.hash ; end
|
|
61
|
+
|
|
62
|
+
def <=> oth
|
|
63
|
+
case oth
|
|
64
|
+
when Percent then @rate <=> oth.rate
|
|
65
|
+
when nil then @rate.zero? ? 0 : 1
|
|
66
|
+
else to_d <=> oth
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
include Comparable
|
|
70
|
+
|
|
71
|
+
def zero? ; @rate.zero? ; end
|
|
72
|
+
def nonzero? ; @rate.nonzero? and self ; end
|
|
73
|
+
|
|
74
|
+
def factor ; @rate / CENT ; end
|
|
75
|
+
|
|
76
|
+
class <<self
|
|
77
|
+
def diff succeding, base
|
|
78
|
+
succeding, base = succeding.to_d, base.to_d
|
|
79
|
+
f = (succeding - base) / base
|
|
80
|
+
new f * CENT
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def of amount ; amount * factor ; end
|
|
85
|
+
def over amount ; amount + (of amount) ; end
|
|
86
|
+
|
|
87
|
+
def split g
|
|
88
|
+
n, s, r = (g / (factor + 1)), nil, nil
|
|
89
|
+
loop do
|
|
90
|
+
s = of n
|
|
91
|
+
c = n + s
|
|
92
|
+
if c < g then
|
|
93
|
+
n = n.succ
|
|
94
|
+
r = true
|
|
95
|
+
elsif c > g then
|
|
96
|
+
r and raise NoSolutionError, "#{g.inspect} cannot be built from #{inspect}."
|
|
97
|
+
n = n.pred
|
|
98
|
+
else
|
|
99
|
+
break
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
[ n, s]
|
|
103
|
+
rescue NoMethodError
|
|
104
|
+
raise ArgumentError, "Objects of class #{g.class} cannot be splitted into percentages."
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# With plain rounding, some values will be rounded downwards, some
|
|
108
|
+
# upwards.
|
|
109
|
+
#
|
|
110
|
+
# 50.14 / 1.19 #=> 42.134453781512605 -> 42.13
|
|
111
|
+
# 42.13 * 1.19 #=> 50.1347 -> 50.13 # this one would be returned
|
|
112
|
+
# 42.14 * 1.19 #=> 50.1466 -> 50.15
|
|
113
|
+
#
|
|
114
|
+
# 50.07 / 1.19 #=> 42.075630252100844 -> 42.08
|
|
115
|
+
# 42.07 * 1.19 #=> 50.0633 -> 50.06
|
|
116
|
+
# 42.08 * 1.19 #=> 50.0752 -> 50.08 # this one would be returned
|
|
117
|
+
#
|
|
118
|
+
# This method will always return the larger value.
|
|
119
|
+
#
|
|
120
|
+
def split! g
|
|
121
|
+
split g
|
|
122
|
+
rescue NoSolutionError
|
|
123
|
+
_, s = split! g.pred
|
|
124
|
+
[ g - s, s]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def add! oth ; @rate = ((factor + 1) * ((self.class.as oth).factor + 1) - 1) * CENT ; self ; end
|
|
128
|
+
def sub! oth ; @rate = ((factor + 1) / ((self.class.as oth).factor + 1) - 1) * CENT ; self ; end
|
|
129
|
+
def add oth ; dup.add! oth ; end
|
|
130
|
+
def sub oth ; dup.sub! oth ; end
|
|
131
|
+
alias + add
|
|
132
|
+
alias - sub
|
|
133
|
+
|
|
134
|
+
def neg! ; @rate = -@rate ; self ; end
|
|
135
|
+
def neg ; dup.neg! ; end
|
|
136
|
+
def +@ ; self ; end
|
|
137
|
+
def -@ ; neg ; end
|
|
138
|
+
|
|
139
|
+
def sign ; @rate ; end
|
|
140
|
+
def positive? ; @rate.positive? ; end
|
|
141
|
+
def negative? ; @rate.negative? ; end
|
|
142
|
+
alias pos? positive?
|
|
143
|
+
alias neg? negative?
|
|
144
|
+
|
|
145
|
+
def * oth ; oth * to_d ; end
|
|
146
|
+
|
|
147
|
+
def coerce oth ; [ oth, to_d] ; end
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def days! d, leap = nil ; @rate = (1+factor)**(Rational d, (ydays leap)) ; self ; end
|
|
151
|
+
def days d, leap = nil ; dup.days! d, leap ; end
|
|
152
|
+
|
|
153
|
+
def days_lin! d, leap = nil ; @rate *= Rational d, (ydays leap) ; self ; end
|
|
154
|
+
def days_lin d, leap = nil ; dup.days_lin! d, leap ; end
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def ydays leap ; leap ? 366 : 365 ; end
|
|
159
|
+
|
|
160
|
+
public
|
|
161
|
+
|
|
162
|
+
def to_f ; @rate.to_f / CENT ; end
|
|
163
|
+
def to_r ; @rate.to_r / CENT ; end
|
|
164
|
+
def to_d ; @rate.to_d / CENT ; end
|
|
165
|
+
|
|
166
|
+
# :call-seq:
|
|
167
|
+
# prc.raw -> str
|
|
168
|
+
#
|
|
169
|
+
# Build a simple string representation without spaces, group characters,
|
|
170
|
+
# parentheses etc. that can be understood by the classes ::parse method.
|
|
171
|
+
#
|
|
172
|
+
# c = Percent.parse "5%"
|
|
173
|
+
# c.raw #=> "5%"
|
|
174
|
+
#
|
|
175
|
+
def raw
|
|
176
|
+
r = @rate.to_s "F"
|
|
177
|
+
r.slice! /0+\z/
|
|
178
|
+
r.slice! /\.\z/
|
|
179
|
+
r << "%"
|
|
180
|
+
end
|
|
181
|
+
alias to_s raw
|
|
182
|
+
alias inspect raw
|
|
183
|
+
|
|
184
|
+
def make_digits
|
|
185
|
+
@rate.make_digits
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
class Parser
|
|
191
|
+
|
|
192
|
+
class <<self
|
|
193
|
+
|
|
194
|
+
def into_percent str
|
|
195
|
+
check_string str
|
|
196
|
+
ints, frac = decsplit str.dup
|
|
197
|
+
digs = remove_grps [ints, frac]
|
|
198
|
+
Percent.new digs
|
|
199
|
+
rescue ArgumentError, NoMethodError
|
|
200
|
+
raise ArgumentError, "Couldn't parse as percents: #{str}"
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
class Format
|
|
208
|
+
|
|
209
|
+
PERCENT = false # add percent symbol
|
|
210
|
+
|
|
211
|
+
class <<self
|
|
212
|
+
|
|
213
|
+
def from_percent p
|
|
214
|
+
i = from_d p.rate
|
|
215
|
+
i.do_percent
|
|
216
|
+
i
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def do_percent
|
|
222
|
+
@chars << "%" if cls::PERCENT
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def Percent p ; Percent.new p ; end
|
|
229
|
+
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class NilClass ; def to_percent ; NumRepr::Percent.new self ; end ; end
|
|
234
|
+
class Numeric ; def to_percent ; NumRepr::Percent.new self ; end ; end
|
|
235
|
+
class String ; def to_percent ; NumRepr::Percent.new self ; end ; end
|
|
236
|
+
|
data/lib/numrepr.rb
ADDED
data/numrepr.gemspec
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#
|
|
2
|
+
# numrepr.gemspec -- Money amounts as integer
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
lib = "lib"
|
|
6
|
+
$:.unshift lib
|
|
7
|
+
require "numrepr/version"
|
|
8
|
+
|
|
9
|
+
Gem::Specification.new do |s|
|
|
10
|
+
s.name = "numrepr"
|
|
11
|
+
s.version = NumRepr::VERSION
|
|
12
|
+
s.summary = "Convert numbers into and from string. Support for monetary amounts"
|
|
13
|
+
s.description = <<~EOT
|
|
14
|
+
Format numbers, parse numbers.
|
|
15
|
+
Do calculations with monetary and percent values."
|
|
16
|
+
EOT
|
|
17
|
+
s.license = "LicenseRef-BSD-2-Clause-and-DECENT_LANGUAGE"
|
|
18
|
+
|
|
19
|
+
s.authors = [ "Bertram Scharpf"]
|
|
20
|
+
s.email = "<software@bertram-scharpf.de>"
|
|
21
|
+
s.homepage = "http://www.bertram-scharpf.de"
|
|
22
|
+
|
|
23
|
+
s.required_ruby_version = ">= 3.0"
|
|
24
|
+
s.requirements = "Just Ruby"
|
|
25
|
+
|
|
26
|
+
s.require_paths = %w(lib)
|
|
27
|
+
s.bindir = "bin"
|
|
28
|
+
|
|
29
|
+
s.executables = %w()
|
|
30
|
+
s.files = Dir[ "lib/**/*.rb"] + Dir[ "bin/*"]
|
|
31
|
+
s.extra_rdoc_files = %w(LICENSE README.md)
|
|
32
|
+
s.extra_rdoc_files += %w(numrepr.gemspec)
|
|
33
|
+
s.extra_rdoc_files += Dir[ "examples/*"]
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
|
metadata
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: numrepr
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: '1.0'
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Bertram Scharpf
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: |
|
|
13
|
+
Format numbers, parse numbers.
|
|
14
|
+
Do calculations with monetary and percent values."
|
|
15
|
+
email: "<software@bertram-scharpf.de>"
|
|
16
|
+
executables: []
|
|
17
|
+
extensions: []
|
|
18
|
+
extra_rdoc_files:
|
|
19
|
+
- LICENSE
|
|
20
|
+
- README.md
|
|
21
|
+
- numrepr.gemspec
|
|
22
|
+
files:
|
|
23
|
+
- LICENSE
|
|
24
|
+
- README.md
|
|
25
|
+
- lib/numrepr.rb
|
|
26
|
+
- lib/numrepr/decimal.rb
|
|
27
|
+
- lib/numrepr/format.rb
|
|
28
|
+
- lib/numrepr/money.rb
|
|
29
|
+
- lib/numrepr/percent.rb
|
|
30
|
+
- lib/numrepr/version.rb
|
|
31
|
+
- numrepr.gemspec
|
|
32
|
+
homepage: http://www.bertram-scharpf.de
|
|
33
|
+
licenses:
|
|
34
|
+
- LicenseRef-BSD-2-Clause-and-DECENT_LANGUAGE
|
|
35
|
+
metadata: {}
|
|
36
|
+
rdoc_options: []
|
|
37
|
+
require_paths:
|
|
38
|
+
- lib
|
|
39
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
40
|
+
requirements:
|
|
41
|
+
- - ">="
|
|
42
|
+
- !ruby/object:Gem::Version
|
|
43
|
+
version: '3.0'
|
|
44
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
requirements:
|
|
50
|
+
- Just Ruby
|
|
51
|
+
rubygems_version: 3.7.1
|
|
52
|
+
specification_version: 4
|
|
53
|
+
summary: Convert numbers into and from string. Support for monetary amounts
|
|
54
|
+
test_files: []
|