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.
@@ -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
+
@@ -0,0 +1,10 @@
1
+ #
2
+ # numrepr/version.rb -- Metadata
3
+ #
4
+
5
+ module NumRepr
6
+
7
+ NumRepr::VERSION = "1.0".freeze
8
+
9
+ end
10
+
data/lib/numrepr.rb ADDED
@@ -0,0 +1,9 @@
1
+ #
2
+ # numrepr.rb -- Get them all
3
+ #
4
+
5
+ require "numrepr/version"
6
+ require "numrepr/format"
7
+ require "numrepr/money"
8
+ require "numrepr/percent"
9
+
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: []