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,301 @@
|
|
|
1
|
+
#
|
|
2
|
+
# numrepr/format.rb -- Format numbers
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
require "supplement"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module NumRepr
|
|
9
|
+
|
|
10
|
+
class Parser
|
|
11
|
+
|
|
12
|
+
GRP = ",.'\u{2019}\u{202f}"
|
|
13
|
+
DEC = ".,\u{b7}"
|
|
14
|
+
|
|
15
|
+
class <<self
|
|
16
|
+
|
|
17
|
+
def into_i str
|
|
18
|
+
check_string str
|
|
19
|
+
Integer remove_grp str
|
|
20
|
+
rescue ArgumentError, NoMethodError
|
|
21
|
+
raise ArgumentError, "Couldn't parse as an integer: #{str}"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def into_f str
|
|
25
|
+
digs = prepare_float str
|
|
26
|
+
Float digs
|
|
27
|
+
rescue ArgumentError, NoMethodError
|
|
28
|
+
raise ArgumentError, "Couldn't parse as a float: #{str}"
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def into_d str
|
|
32
|
+
digs = prepare_float str
|
|
33
|
+
BigDecimal digs
|
|
34
|
+
rescue ArgumentError, NoMethodError
|
|
35
|
+
raise ArgumentError, "Couldn't parse as a decimal: #{str}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def prepare_float str
|
|
41
|
+
check_string str
|
|
42
|
+
digs, exp = str.split /e/i
|
|
43
|
+
ints, frac = decsplit digs
|
|
44
|
+
digs = remove_grps [ints, frac]
|
|
45
|
+
digs << "e" << exp if exp
|
|
46
|
+
digs
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def check_string str
|
|
50
|
+
String === str or raise "Not a string: #{str.inspect}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def remove_grp str
|
|
54
|
+
str = str.dup
|
|
55
|
+
self::GRP.each_char { |g| str.gsub! g, "_" }
|
|
56
|
+
str
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def remove_grps strs
|
|
60
|
+
strs.map { |s| remove_grp s }.join "."
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def decsplit digs
|
|
64
|
+
ps = []
|
|
65
|
+
self::DEC.each_char { |dec|
|
|
66
|
+
if (digs.count dec) == 1 then
|
|
67
|
+
p = digs.rindex dec
|
|
68
|
+
end
|
|
69
|
+
ps.push p
|
|
70
|
+
}
|
|
71
|
+
m = nil
|
|
72
|
+
ps.each { |p|
|
|
73
|
+
p or next
|
|
74
|
+
if not m or p > m then
|
|
75
|
+
m = p
|
|
76
|
+
end
|
|
77
|
+
}
|
|
78
|
+
if m then
|
|
79
|
+
ints = digs.slice! 0, m
|
|
80
|
+
digs.slice! 0, 1
|
|
81
|
+
else
|
|
82
|
+
ints = digs.slice! /.*\d/
|
|
83
|
+
end
|
|
84
|
+
[ints, digs]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class Format
|
|
93
|
+
|
|
94
|
+
NUMDIGITS = nil # minimum number of digits in integer part (builds leading zeroes)
|
|
95
|
+
POS = false # plus sign if positive (still none for 0)
|
|
96
|
+
GRP = false # group three digits
|
|
97
|
+
CHGRP = "," # group character
|
|
98
|
+
WIDTH = nil # minimum length of integer part (builds leading spaces)
|
|
99
|
+
|
|
100
|
+
class <<self
|
|
101
|
+
|
|
102
|
+
def method_missing sym, *args, **kwargs
|
|
103
|
+
if sym =~ /\Abuild_/ then
|
|
104
|
+
(send :"from_#$'", *args, **kwargs).to_s
|
|
105
|
+
else
|
|
106
|
+
super
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def from_i n
|
|
111
|
+
ints, = n.make_digits
|
|
112
|
+
i = new ints
|
|
113
|
+
i.do_int n.sign, true
|
|
114
|
+
i
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def initialize chars
|
|
120
|
+
@chars = chars
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def to_s ; @chars ; end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
alias cls class
|
|
127
|
+
|
|
128
|
+
# Please load the "supplement" gem.
|
|
129
|
+
def notempty? ; @chars.notempty? rescue @chars.emtpy? ? nil : @chars ; end
|
|
130
|
+
|
|
131
|
+
def reverse! ; @chars.reverse! ; end
|
|
132
|
+
|
|
133
|
+
def pad0 n ; pad n, "0" ; end
|
|
134
|
+
def pad_ n ; pad n, " " if n ; end
|
|
135
|
+
def pad n, chr
|
|
136
|
+
p = n - @chars.length
|
|
137
|
+
@chars << chr * p if p > 0
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def group
|
|
141
|
+
if cls::GRP then
|
|
142
|
+
l, e = 3, ""
|
|
143
|
+
loop do
|
|
144
|
+
e << (@chars.slice! 0, l)
|
|
145
|
+
break if @chars.empty?
|
|
146
|
+
e << cls::CHGRP
|
|
147
|
+
end
|
|
148
|
+
@chars.replace e
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def do_sign n
|
|
153
|
+
if n.negative? then
|
|
154
|
+
@chars << "-"
|
|
155
|
+
elsif n.positive? then
|
|
156
|
+
@chars << "+" if cls::POS
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def do_int nsig, finite
|
|
161
|
+
if finite then
|
|
162
|
+
pad0 cls::NUMDIGITS||1
|
|
163
|
+
group
|
|
164
|
+
end
|
|
165
|
+
do_sign nsig
|
|
166
|
+
pad_ cls::WIDTH
|
|
167
|
+
reverse!
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def do_decimal frac
|
|
172
|
+
sep = cls.new ""
|
|
173
|
+
frc = cls.new frac
|
|
174
|
+
yield sep, frc
|
|
175
|
+
@chars << sep.to_s << frc.to_s
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
DEC = false # force decimal character
|
|
180
|
+
CHDEC = "." # character before decimal places
|
|
181
|
+
NUMPLACES = nil # minimum number of places (builds trailing zeroes)
|
|
182
|
+
ZSIGN = false # respect zero sign (determinable only in BigDecimal)
|
|
183
|
+
RWIDTH = nil # minimum width to the right (builds trailing spaces)
|
|
184
|
+
|
|
185
|
+
class <<self
|
|
186
|
+
|
|
187
|
+
def from_d d
|
|
188
|
+
ints, frac = d.make_digits
|
|
189
|
+
i = new ints
|
|
190
|
+
i.do_bd frac, (self::ZSIGN ? d.sign : d)
|
|
191
|
+
i
|
|
192
|
+
end
|
|
193
|
+
alias from_f from_d
|
|
194
|
+
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def sep needs
|
|
198
|
+
@chars << cls::CHDEC if needs or cls::DEC
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def do_bd frac, nsig
|
|
202
|
+
do_int nsig, frac
|
|
203
|
+
do_decimal frac||"" do |s,f|
|
|
204
|
+
if frac then
|
|
205
|
+
f.pad0 cls::NUMPLACES||0
|
|
206
|
+
f.group
|
|
207
|
+
s.sep f.notempty?
|
|
208
|
+
end
|
|
209
|
+
f.pad_ cls::RWIDTH
|
|
210
|
+
s.pad_ cls::RWIDTH&&1
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
end
|
|
215
|
+
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
class Numeric
|
|
221
|
+
|
|
222
|
+
def split
|
|
223
|
+
_, r = (coerce 0.0)
|
|
224
|
+
r.split
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def sign ; self ; end
|
|
228
|
+
|
|
229
|
+
def make_digits
|
|
230
|
+
case
|
|
231
|
+
when nan? then "NaN".reverse
|
|
232
|
+
when infinite? then "Inf".reverse
|
|
233
|
+
when zero? then [ "", ""]
|
|
234
|
+
else
|
|
235
|
+
_, digits, _, exp = *split
|
|
236
|
+
f = exp - digits.length
|
|
237
|
+
if f >= 0 then
|
|
238
|
+
digits << "0" * f
|
|
239
|
+
digits.reverse!
|
|
240
|
+
[ digits, ""]
|
|
241
|
+
else
|
|
242
|
+
if exp >= 0 then
|
|
243
|
+
i = digits.slice! 0, exp
|
|
244
|
+
i.reverse!
|
|
245
|
+
else
|
|
246
|
+
i = ""
|
|
247
|
+
digits.prepend "0" * -exp
|
|
248
|
+
end
|
|
249
|
+
[ i, digits]
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class Integer < Numeric
|
|
258
|
+
|
|
259
|
+
def make_digits
|
|
260
|
+
if zero? then
|
|
261
|
+
""
|
|
262
|
+
else
|
|
263
|
+
abs.to_s.reverse
|
|
264
|
+
end
|
|
265
|
+
end or begin # If written in C, this one would be faster.
|
|
266
|
+
r = ""
|
|
267
|
+
n = abs
|
|
268
|
+
while n.nonzero? do
|
|
269
|
+
n, d = n.divmod 10
|
|
270
|
+
r << (d + "0".ord).chr
|
|
271
|
+
end
|
|
272
|
+
r
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
class Float < Numeric
|
|
279
|
+
|
|
280
|
+
# There seems to be no legal way to retrieve the negative sign of -0.0.
|
|
281
|
+
# If you really need it, convert the number to BigDecimal.
|
|
282
|
+
#
|
|
283
|
+
# -0.0.to_f.to_d.sign #=> -1
|
|
284
|
+
def sign ; super ; end
|
|
285
|
+
|
|
286
|
+
# analogous to BigDecimal#split
|
|
287
|
+
def split
|
|
288
|
+
m, e = abs.to_s.split /e/i
|
|
289
|
+
e = e.to_i
|
|
290
|
+
d, f = m.split "."
|
|
291
|
+
d.lstrip! "0" rescue d.slice! /\A0+/ # before Ruby 4.0
|
|
292
|
+
e += d.count "0-9"
|
|
293
|
+
if f then
|
|
294
|
+
f.rstrip! "0" rescue f.slice! /0+\z/ # before Ruby 4.0
|
|
295
|
+
d << f
|
|
296
|
+
end
|
|
297
|
+
[ (negative? ? -1 : 1), d, 10, e]
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
end
|
|
301
|
+
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
#
|
|
2
|
+
# numrepr/money.rb -- Money amount values
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
require "numrepr/format"
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module NumRepr
|
|
9
|
+
|
|
10
|
+
class Money
|
|
11
|
+
|
|
12
|
+
attr_reader :cents
|
|
13
|
+
alias cent cents
|
|
14
|
+
|
|
15
|
+
PLACES = 2
|
|
16
|
+
CENTS = 10 ** PLACES
|
|
17
|
+
|
|
18
|
+
class <<self
|
|
19
|
+
|
|
20
|
+
alias parse new
|
|
21
|
+
|
|
22
|
+
def zero ; new nil ; end
|
|
23
|
+
|
|
24
|
+
def as obj
|
|
25
|
+
case obj
|
|
26
|
+
when self then obj
|
|
27
|
+
else new obj
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def norm cents
|
|
32
|
+
case cents
|
|
33
|
+
when Integer then cents
|
|
34
|
+
else cents.round.to_i
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def initialize val = nil
|
|
42
|
+
@cents =
|
|
43
|
+
case val
|
|
44
|
+
when String then parse_str val
|
|
45
|
+
when Money then val.cents
|
|
46
|
+
when nil then 0
|
|
47
|
+
else Money.norm CENTS * val
|
|
48
|
+
end
|
|
49
|
+
rescue ArgumentError, TypeError
|
|
50
|
+
raise ArgumentError, "Not a Money value: \"#{val}\"."
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def parse_str val
|
|
56
|
+
v = val.dup
|
|
57
|
+
v.slice! /(?:\b[A-Z]{3}\b|[$\u{a2}-\u{a5}\u{20a0}-\u{20cf}])/ # unit
|
|
58
|
+
v.strip!
|
|
59
|
+
n = v.slice! /\A\s*-/
|
|
60
|
+
f = v.slice! /\..*/
|
|
61
|
+
v.gsub! ",", "_" # PostgreSQL's money type actually returns this.
|
|
62
|
+
r = v.empty? ? 0 : (Integer v) * CENTS
|
|
63
|
+
r += ((Float "0#{f}0") * CENTS).round if f
|
|
64
|
+
r *= -1 if n
|
|
65
|
+
r
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
public
|
|
69
|
+
|
|
70
|
+
def eql? oth ; oth.class == self.class and oth.cents == @cents ; end
|
|
71
|
+
|
|
72
|
+
def hash ; @cents.hash ; end
|
|
73
|
+
|
|
74
|
+
public
|
|
75
|
+
|
|
76
|
+
def to_money ; self ; end
|
|
77
|
+
|
|
78
|
+
def to_f ; @cents/CENTS.to_f ; end
|
|
79
|
+
def to_i ; to_f.round ; end
|
|
80
|
+
def to_r ; Rational @cents, CENTS ; end
|
|
81
|
+
def to_d ; (BigDecimal @cents) / CENTS ; end
|
|
82
|
+
|
|
83
|
+
def succ! ; @cents = @cents.succ ; self ; end
|
|
84
|
+
def pred! ; @cents = @cents.pred ; self ; end
|
|
85
|
+
def succ ; dup.succ! ; end
|
|
86
|
+
def pred ; dup.pred! ; end
|
|
87
|
+
|
|
88
|
+
def zero? ; @cents.zero? ; end
|
|
89
|
+
def nonzero? ; @cents.nonzero? and self ; end
|
|
90
|
+
|
|
91
|
+
def sign ; @cents ; end
|
|
92
|
+
def positive? ; @cents.positive? ; end
|
|
93
|
+
def negative? ; @cents.negative? ; end
|
|
94
|
+
alias pos? positive?
|
|
95
|
+
alias neg? negative?
|
|
96
|
+
|
|
97
|
+
def add! oth ; @cents += (self.class.as oth).cents ; self ; end
|
|
98
|
+
def sub! oth ; @cents -= (self.class.as oth).cents ; self ; end
|
|
99
|
+
def add oth ; dup.add! oth ; end
|
|
100
|
+
def sub oth ; dup.sub! oth ; end
|
|
101
|
+
|
|
102
|
+
def mul! oth
|
|
103
|
+
c = case oth
|
|
104
|
+
when Money then
|
|
105
|
+
raise ArgumentError, "Currencies cannot be multiplied together"
|
|
106
|
+
when Integer then
|
|
107
|
+
Rational @cents * oth
|
|
108
|
+
else
|
|
109
|
+
@cents * oth
|
|
110
|
+
end
|
|
111
|
+
@cents = Money.norm c
|
|
112
|
+
self
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def mul oth ; dup.mul! oth ; end
|
|
116
|
+
|
|
117
|
+
def div! oth
|
|
118
|
+
c = case oth
|
|
119
|
+
when Money then
|
|
120
|
+
raise ArgumentError, "Currency cannot be reduced by another one"
|
|
121
|
+
when Integer, Rational then
|
|
122
|
+
Rational @cents, oth
|
|
123
|
+
else
|
|
124
|
+
@cents / oth
|
|
125
|
+
end
|
|
126
|
+
@cents = Money.norm c
|
|
127
|
+
self
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def div oth
|
|
131
|
+
case oth
|
|
132
|
+
when Money then Rational @cents, oth.cents
|
|
133
|
+
else dup.div! oth
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
alias + add
|
|
138
|
+
alias - sub
|
|
139
|
+
alias * mul
|
|
140
|
+
alias / div
|
|
141
|
+
|
|
142
|
+
def neg! ; @cents = -@cents ; self ; end
|
|
143
|
+
def neg ; dup.neg! ; end
|
|
144
|
+
def +@ ; self ; end
|
|
145
|
+
def -@ ; neg ; end
|
|
146
|
+
|
|
147
|
+
def abs ; @cents >= 0 ? self : neg ; end
|
|
148
|
+
|
|
149
|
+
def <=> oth
|
|
150
|
+
case oth
|
|
151
|
+
when Money then @cents <=> oth.cents
|
|
152
|
+
when Numeric then @cents <=> oth*CENTS
|
|
153
|
+
when nil then @cents.zero? ? 0 : 1
|
|
154
|
+
else to_r <=> oth
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
include Comparable
|
|
158
|
+
|
|
159
|
+
def coerce oth ; [ oth, to_r] ; end
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def make_digits
|
|
163
|
+
r = @cents.make_digits
|
|
164
|
+
l = 2 - r.length
|
|
165
|
+
r << "0" * l if l > 0
|
|
166
|
+
f = r.slice! 0, 2
|
|
167
|
+
f.reverse!
|
|
168
|
+
[r, f]
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# :call-seq:
|
|
172
|
+
# cur.raw -> str
|
|
173
|
+
#
|
|
174
|
+
# Build a simple string representation without spaces, group characters,
|
|
175
|
+
# parentheses etc. that can be understood by the classes ::parse method
|
|
176
|
+
# and, hopefully, by other programming languages (Some SQL, for example).
|
|
177
|
+
#
|
|
178
|
+
# c = Money.parse "$1,234.00"
|
|
179
|
+
# c.raw #=> "$1234.00"
|
|
180
|
+
#
|
|
181
|
+
|
|
182
|
+
def raw
|
|
183
|
+
b, c = make_digits
|
|
184
|
+
b << "0" if b.empty?
|
|
185
|
+
b.reverse!
|
|
186
|
+
r = "$"
|
|
187
|
+
r << "-" if negative?
|
|
188
|
+
r << b << "." << c
|
|
189
|
+
end
|
|
190
|
+
alias to_s raw
|
|
191
|
+
alias inspect raw
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
class Parser
|
|
196
|
+
|
|
197
|
+
DASH = "-\u{2013}"
|
|
198
|
+
IDASH = DASH
|
|
199
|
+
NEG_TRAILING = true
|
|
200
|
+
NEG_PAREN = true
|
|
201
|
+
|
|
202
|
+
class <<self
|
|
203
|
+
|
|
204
|
+
def into_money str
|
|
205
|
+
check_string str
|
|
206
|
+
ints, frac = decsplit str.dup
|
|
207
|
+
unless ints =~ /\d/ then
|
|
208
|
+
self::IDASH.each_char { |d|
|
|
209
|
+
if ints.end_with? d then
|
|
210
|
+
ints.slice! ints.length-1
|
|
211
|
+
break
|
|
212
|
+
end
|
|
213
|
+
}
|
|
214
|
+
end
|
|
215
|
+
unless frac =~ /\d/ then
|
|
216
|
+
self::DASH.each_char { |d|
|
|
217
|
+
if frac.start_with? d then
|
|
218
|
+
frac.slice! 0
|
|
219
|
+
break
|
|
220
|
+
end
|
|
221
|
+
}
|
|
222
|
+
end
|
|
223
|
+
digs = remove_grps [ints, frac]
|
|
224
|
+
if self::NEG_TRAILING then
|
|
225
|
+
digs.sub! /(\d.*)-/ do "-#$1" end
|
|
226
|
+
end
|
|
227
|
+
if self::NEG_PAREN then
|
|
228
|
+
digs.sub! /\((\d.*?)\)/ do "-#$1" end
|
|
229
|
+
end
|
|
230
|
+
Money.new digs
|
|
231
|
+
rescue ArgumentError, NoMethodError
|
|
232
|
+
raise ArgumentError, "Couldn't parse as a monetary: #{str}"
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
class Format
|
|
240
|
+
|
|
241
|
+
DASH = false # dash for zero in decimal part
|
|
242
|
+
IDASH = false # dash for zero in integer part
|
|
243
|
+
CHDASH = "-" # dash character (default '-')
|
|
244
|
+
NEG = :l # negative values: :p, :par = parentheses; :r, :right = right minus
|
|
245
|
+
CURSYM = "$" # currency symbol
|
|
246
|
+
SYMPOS = :l # symbol position: :l/:left (default), :r/:right, :n/:none
|
|
247
|
+
SYMSPC = false # space before/after currency symbol
|
|
248
|
+
|
|
249
|
+
class <<self
|
|
250
|
+
|
|
251
|
+
def from_money m
|
|
252
|
+
ints, frac = m.make_digits
|
|
253
|
+
i = new ints
|
|
254
|
+
i.do_curr frac, m.sign
|
|
255
|
+
i
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def dash need
|
|
261
|
+
need or return
|
|
262
|
+
if @chars =~ /\A0+\z/ then
|
|
263
|
+
l = @chars.length
|
|
264
|
+
@chars.clear
|
|
265
|
+
@chars << cls::CHDASH
|
|
266
|
+
pad l, " "
|
|
267
|
+
end
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def cursym rev
|
|
271
|
+
if rev then
|
|
272
|
+
case cls::SYMPOS
|
|
273
|
+
when :n, :none then return
|
|
274
|
+
when :r, :right then return
|
|
275
|
+
else nil
|
|
276
|
+
end
|
|
277
|
+
else
|
|
278
|
+
case cls::SYMPOS
|
|
279
|
+
when :n, :none then return
|
|
280
|
+
when :r, :right then nil
|
|
281
|
+
else return
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
cs = cls::CURSYM
|
|
285
|
+
cs = cs.reverse if rev
|
|
286
|
+
@chars << " " if cls::SYMSPC
|
|
287
|
+
@chars << cs
|
|
288
|
+
end
|
|
289
|
+
|
|
290
|
+
def curpresign n
|
|
291
|
+
if n.negative? then
|
|
292
|
+
case cls::NEG
|
|
293
|
+
when :p, :paren then @chars << "("
|
|
294
|
+
when :r, :right then nil
|
|
295
|
+
else @chars << "-"
|
|
296
|
+
end
|
|
297
|
+
end
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def curpostsign n
|
|
301
|
+
if n.negative? then
|
|
302
|
+
case cls::NEG
|
|
303
|
+
when :p, :paren then @chars << ")"
|
|
304
|
+
when :r, :right then @chars << "-"
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def do_curr frac, nsig
|
|
310
|
+
pad0 cls::NUMDIGITS||1
|
|
311
|
+
dash cls::IDASH
|
|
312
|
+
group
|
|
313
|
+
curpresign nsig
|
|
314
|
+
cursym true
|
|
315
|
+
pad_ cls::WIDTH
|
|
316
|
+
reverse!
|
|
317
|
+
do_decimal frac do |s,f|
|
|
318
|
+
f.dash cls::DASH
|
|
319
|
+
f.curpostsign nsig
|
|
320
|
+
f.cursym false
|
|
321
|
+
f.pad_ cls::RWIDTH
|
|
322
|
+
s.sep true
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
def Money v ; Money.new v ; end
|
|
330
|
+
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
|
|
334
|
+
class NilClass ; def to_money ; NumRepr::Money.new self ; end ; end
|
|
335
|
+
class Numeric ; def to_money ; NumRepr::Money.new self ; end ; end
|
|
336
|
+
class String ; def to_money ; NumRepr::Money.new self ; end ; end
|
|
337
|
+
|