micro-lite-lib 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.
- checksums.yaml +7 -0
- data/micro-lite-lib.gemspec +11 -0
- data/money-7.0.2/CHANGELOG.md +843 -0
- data/money-7.0.2/LICENSE +23 -0
- data/money-7.0.2/README.md +626 -0
- data/money-7.0.2/config/currency_backwards_compatible.json +225 -0
- data/money-7.0.2/config/currency_iso.json +2750 -0
- data/money-7.0.2/config/currency_non_iso.json +146 -0
- data/money-7.0.2/lib/money/bank/base.rb +130 -0
- data/money-7.0.2/lib/money/bank/single_currency.rb +26 -0
- data/money-7.0.2/lib/money/bank/variable_exchange.rb +285 -0
- data/money-7.0.2/lib/money/currency/heuristics.rb +11 -0
- data/money-7.0.2/lib/money/currency/loader.rb +28 -0
- data/money-7.0.2/lib/money/currency.rb +477 -0
- data/money-7.0.2/lib/money/locale_backend/base.rb +9 -0
- data/money-7.0.2/lib/money/locale_backend/currency.rb +13 -0
- data/money-7.0.2/lib/money/locale_backend/errors.rb +8 -0
- data/money-7.0.2/lib/money/locale_backend/i18n.rb +28 -0
- data/money-7.0.2/lib/money/money/allocation.rb +87 -0
- data/money-7.0.2/lib/money/money/arithmetic.rb +346 -0
- data/money-7.0.2/lib/money/money/constructors.rb +86 -0
- data/money-7.0.2/lib/money/money/formatter.rb +361 -0
- data/money-7.0.2/lib/money/money/formatting_rules.rb +92 -0
- data/money-7.0.2/lib/money/money/locale_backend.rb +20 -0
- data/money-7.0.2/lib/money/money.rb +664 -0
- data/money-7.0.2/lib/money/rates_store/memory.rb +122 -0
- data/money-7.0.2/lib/money/version.rb +5 -0
- data/money-7.0.2/lib/money.rb +9 -0
- data/money-7.0.2/money.gemspec +32 -0
- metadata +68 -0
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Money
|
|
4
|
+
module Arithmetic
|
|
5
|
+
# Wrapper for coerced numeric values to distinguish
|
|
6
|
+
# when numeric was on the 1st place in operation.
|
|
7
|
+
CoercedNumeric = Struct.new(:value) do
|
|
8
|
+
# Proxy #zero? method to skip unnecessary typecasts. See #- and #+.
|
|
9
|
+
def zero?
|
|
10
|
+
value.zero?
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Returns a money object with changed polarity.
|
|
15
|
+
#
|
|
16
|
+
# @return [Money]
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# - Money.new(100) #=> #<Money @fractional=-100>
|
|
20
|
+
def -@
|
|
21
|
+
dup_with(fractional: -fractional)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Checks whether two Money objects have the same currency and the same
|
|
25
|
+
# amount. Checks against objects that are not Money or a subclass will
|
|
26
|
+
# always return false.
|
|
27
|
+
#
|
|
28
|
+
# @param [Money] other_money Value to compare with.
|
|
29
|
+
#
|
|
30
|
+
# @return [Boolean]
|
|
31
|
+
#
|
|
32
|
+
# @example
|
|
33
|
+
# Money.new(1_00).eql?(Money.new(1_00)) #=> true
|
|
34
|
+
# Money.new(1_00).eql?(Money.new(1_01)) #=> false
|
|
35
|
+
# Money.new(1_00, "USD").eql?(Money.new(1_00, "GBP")) #=> false
|
|
36
|
+
# Money.new(0, "USD").eql?(Money.new(0, "EUR")) #=> false
|
|
37
|
+
# Money.new(1_00).eql?("1.00") #=> false
|
|
38
|
+
#
|
|
39
|
+
# @see Money.strict_eql_compare
|
|
40
|
+
def eql?(other_money)
|
|
41
|
+
if other_money.is_a?(Money)
|
|
42
|
+
if !Money.strict_eql_compare && fractional == 0 && other_money.fractional == 0
|
|
43
|
+
warn "[DEPRECATION] Comparing 0 #{currency} with 0 " \
|
|
44
|
+
"#{other_money.currency} using `#eql?` will return false in " \
|
|
45
|
+
"future versions of Money. Opt-in to the new behavior by " \
|
|
46
|
+
"setting `Money.strict_eql_compare = true`."
|
|
47
|
+
return true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
fractional == other_money.fractional && currency == other_money.currency
|
|
51
|
+
else
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Compares two Money objects. If money objects have a different currency it
|
|
57
|
+
# will attempt to convert the currency.
|
|
58
|
+
#
|
|
59
|
+
# @param [Money] other Value to compare with.
|
|
60
|
+
#
|
|
61
|
+
# @return [Integer]
|
|
62
|
+
#
|
|
63
|
+
# @raise [TypeError] when other object is not Money
|
|
64
|
+
#
|
|
65
|
+
def <=>(other)
|
|
66
|
+
unless other.is_a?(Money)
|
|
67
|
+
return unless other.respond_to?(:zero?) && other.zero?
|
|
68
|
+
return other.is_a?(CoercedNumeric) ? 0 <=> fractional : fractional <=> 0
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# Always allow comparison with zero
|
|
72
|
+
if zero? || other.zero?
|
|
73
|
+
return fractional <=> other.fractional
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
other = other.exchange_to(currency)
|
|
77
|
+
fractional <=> other.fractional
|
|
78
|
+
rescue Money::Bank::UnknownRate
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Uses Comparable's implementation but raises ArgumentError if non-zero
|
|
82
|
+
# numeric value is given.
|
|
83
|
+
def ==(other)
|
|
84
|
+
if other.is_a?(Numeric) && !other.zero?
|
|
85
|
+
raise ArgumentError, 'Money#== supports only zero numerics'
|
|
86
|
+
end
|
|
87
|
+
super
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Test if the amount is positive. Returns +true+ if the money amount is
|
|
91
|
+
# greater than 0, +false+ otherwise.
|
|
92
|
+
#
|
|
93
|
+
# @return [Boolean]
|
|
94
|
+
#
|
|
95
|
+
# @example
|
|
96
|
+
# Money.new(1).positive? #=> true
|
|
97
|
+
# Money.new(0).positive? #=> false
|
|
98
|
+
# Money.new(-1).positive? #=> false
|
|
99
|
+
def positive?
|
|
100
|
+
fractional > 0
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Test if the amount is negative. Returns +true+ if the money amount is
|
|
104
|
+
# less than 0, +false+ otherwise.
|
|
105
|
+
#
|
|
106
|
+
# @return [Boolean]
|
|
107
|
+
#
|
|
108
|
+
# @example
|
|
109
|
+
# Money.new(-1).negative? #=> true
|
|
110
|
+
# Money.new(0).negative? #=> false
|
|
111
|
+
# Money.new(1).negative? #=> false
|
|
112
|
+
def negative?
|
|
113
|
+
fractional < 0
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# @!method +(other)
|
|
117
|
+
# Returns a new Money object containing the sum of the two operands' monetary
|
|
118
|
+
# values. If +other_money+ has a different currency then its monetary value
|
|
119
|
+
# is automatically exchanged to this object's currency using +exchange_to+.
|
|
120
|
+
#
|
|
121
|
+
# @param [Money] other Other +Money+ object to add.
|
|
122
|
+
# @return [Money]
|
|
123
|
+
#
|
|
124
|
+
# @example
|
|
125
|
+
# Money.new(100) + Money.new(100) #=> #<Money @fractional=200>
|
|
126
|
+
|
|
127
|
+
# @!method -(other)
|
|
128
|
+
# Returns a new Money object containing the difference between the two
|
|
129
|
+
# operands' monetary values. If +other_money+ has a different currency then
|
|
130
|
+
# its monetary value is automatically exchanged to this object's currency
|
|
131
|
+
# using +exchange_to+.
|
|
132
|
+
#
|
|
133
|
+
# @param [Money] other Other +Money+ object to subtract.
|
|
134
|
+
# @return [Money]
|
|
135
|
+
#
|
|
136
|
+
# @example
|
|
137
|
+
# Money.new(100) - Money.new(99) #=> #<Money @fractional=1>
|
|
138
|
+
[:+, :-].each do |op|
|
|
139
|
+
non_zero_message = lambda do |value|
|
|
140
|
+
"Can't add or subtract a non-zero #{value.class.name} value"
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
define_method(op) do |other|
|
|
144
|
+
case other
|
|
145
|
+
when Money
|
|
146
|
+
other = other.exchange_to(currency)
|
|
147
|
+
new_fractional = fractional.public_send(op, other.fractional)
|
|
148
|
+
dup_with(fractional: new_fractional)
|
|
149
|
+
when CoercedNumeric
|
|
150
|
+
raise TypeError, non_zero_message.call(other.value) unless other.zero?
|
|
151
|
+
dup_with(fractional: other.value.public_send(op, fractional))
|
|
152
|
+
when Numeric
|
|
153
|
+
raise TypeError, non_zero_message.call(other) unless other.zero?
|
|
154
|
+
self
|
|
155
|
+
else
|
|
156
|
+
raise TypeError, "Unsupported argument type: #{other.class.name}"
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# Multiplies the monetary value with the given number and returns a new
|
|
162
|
+
# +Money+ object with this monetary value and the same currency.
|
|
163
|
+
#
|
|
164
|
+
# Note that you can't multiply a Money object by an other +Money+ object.
|
|
165
|
+
#
|
|
166
|
+
# @param [Numeric] value Number to multiply by.
|
|
167
|
+
#
|
|
168
|
+
# @return [Money] The resulting money.
|
|
169
|
+
#
|
|
170
|
+
# @raise [TypeError] If +value+ is NOT a number.
|
|
171
|
+
#
|
|
172
|
+
# @example
|
|
173
|
+
# Money.new(100) * 2 #=> #<Money @fractional=200>
|
|
174
|
+
#
|
|
175
|
+
def *(value)
|
|
176
|
+
value = value.value if value.is_a?(CoercedNumeric)
|
|
177
|
+
if value.is_a? Numeric
|
|
178
|
+
dup_with(fractional: fractional * value)
|
|
179
|
+
else
|
|
180
|
+
raise TypeError, "Can't multiply a #{self.class.name} by a #{value.class.name}'s value"
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Divides the monetary value with the given number and returns a new +Money+
|
|
185
|
+
# object with this monetary value and the same currency.
|
|
186
|
+
# Can also divide by another +Money+ object to get a ratio.
|
|
187
|
+
#
|
|
188
|
+
# +Money/Numeric+ returns +Money+. +Money/Money+ returns +Float+.
|
|
189
|
+
#
|
|
190
|
+
# @param [Money, Numeric] value Number to divide by.
|
|
191
|
+
#
|
|
192
|
+
# @return [Money] The resulting money if you divide Money by a number.
|
|
193
|
+
# @return [Float] The resulting number if you divide Money by a Money.
|
|
194
|
+
#
|
|
195
|
+
# @example
|
|
196
|
+
# Money.new(100) / 10 #=> #<Money @fractional=10>
|
|
197
|
+
# Money.new(100) / Money.new(10) #=> 10.0
|
|
198
|
+
#
|
|
199
|
+
def /(value)
|
|
200
|
+
if value.is_a?(self.class)
|
|
201
|
+
exchanged = value.exchange_to(currency)
|
|
202
|
+
raise ZeroDivisionError, "divided by Money(0)" if exchanged.zero?
|
|
203
|
+
fractional / as_d(exchanged.fractional).to_f
|
|
204
|
+
else
|
|
205
|
+
raise TypeError, 'Can not divide by Money' if value.is_a?(CoercedNumeric)
|
|
206
|
+
|
|
207
|
+
value = as_d(value)
|
|
208
|
+
raise ZeroDivisionError, "divided by zero" if value.zero?
|
|
209
|
+
dup_with(fractional: fractional / value)
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Synonym for +#/+.
|
|
214
|
+
#
|
|
215
|
+
# @param [Money, Numeric] value Number to divide by.
|
|
216
|
+
#
|
|
217
|
+
# @return [Money] The resulting money if you divide Money by a number.
|
|
218
|
+
# @return [Float] The resulting number if you divide Money by a Money.
|
|
219
|
+
#
|
|
220
|
+
# @see #/
|
|
221
|
+
#
|
|
222
|
+
def div(value)
|
|
223
|
+
self / value
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
# Divide money by money or fixnum and return array containing quotient and
|
|
227
|
+
# modulus.
|
|
228
|
+
#
|
|
229
|
+
# @param [Money, Integer] val Number to divmod by.
|
|
230
|
+
#
|
|
231
|
+
# @return [Array<Money,Money>,Array<Integer,Money>]
|
|
232
|
+
#
|
|
233
|
+
# @example
|
|
234
|
+
# Money.new(100).divmod(9) #=> [#<Money @fractional=11>, #<Money @fractional=1>]
|
|
235
|
+
# Money.new(100).divmod(Money.new(9)) #=> [11, #<Money @fractional=1>]
|
|
236
|
+
def divmod(val)
|
|
237
|
+
if val.is_a?(Money)
|
|
238
|
+
divmod_money(val)
|
|
239
|
+
else
|
|
240
|
+
divmod_other(val)
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def divmod_money(val)
|
|
245
|
+
cents = val.exchange_to(currency).cents
|
|
246
|
+
raise ZeroDivisionError, "divided by Money(0)" if cents == 0
|
|
247
|
+
quotient, remainder = fractional.divmod(cents)
|
|
248
|
+
[quotient, dup_with(fractional: remainder)]
|
|
249
|
+
end
|
|
250
|
+
private :divmod_money
|
|
251
|
+
|
|
252
|
+
def divmod_other(val)
|
|
253
|
+
val = as_d(val)
|
|
254
|
+
raise ZeroDivisionError, "divided by zero" if val.zero?
|
|
255
|
+
quotient, remainder = fractional.divmod(val)
|
|
256
|
+
[dup_with(fractional: quotient), dup_with(fractional: remainder)]
|
|
257
|
+
end
|
|
258
|
+
private :divmod_other
|
|
259
|
+
|
|
260
|
+
# Equivalent to +self.divmod(val)[1]+
|
|
261
|
+
#
|
|
262
|
+
# @param [Money, Integer] val Number take modulo with.
|
|
263
|
+
#
|
|
264
|
+
# @return [Money]
|
|
265
|
+
#
|
|
266
|
+
# @example
|
|
267
|
+
# Money.new(100).modulo(9) #=> #<Money @fractional=1>
|
|
268
|
+
# Money.new(100).modulo(Money.new(9)) #=> #<Money @fractional=1>
|
|
269
|
+
def modulo(val)
|
|
270
|
+
divmod(val)[1]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Synonym for +#modulo+.
|
|
274
|
+
#
|
|
275
|
+
# @param [Money, Integer] val Number take modulo with.
|
|
276
|
+
#
|
|
277
|
+
# @return [Money]
|
|
278
|
+
#
|
|
279
|
+
# @see #modulo
|
|
280
|
+
def %(val)
|
|
281
|
+
modulo(val)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# If different signs +self.modulo(val) - val+ otherwise +self.modulo(val)+
|
|
285
|
+
#
|
|
286
|
+
# @param [Money, Integer] val Number to rake remainder with.
|
|
287
|
+
#
|
|
288
|
+
# @return [Money]
|
|
289
|
+
#
|
|
290
|
+
# @example
|
|
291
|
+
# Money.new(100).remainder(9) #=> #<Money @fractional=1>
|
|
292
|
+
def remainder(val)
|
|
293
|
+
if val.is_a?(Money) && currency != val.currency
|
|
294
|
+
val = val.exchange_to(currency)
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
if (fractional < 0 && val < 0) || (fractional > 0 && val > 0)
|
|
298
|
+
self.modulo(val)
|
|
299
|
+
else
|
|
300
|
+
self.modulo(val) - (val.is_a?(Money) ? val : dup_with(fractional: val))
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
# Return absolute value of self as a new Money object.
|
|
305
|
+
#
|
|
306
|
+
# @return [Money]
|
|
307
|
+
#
|
|
308
|
+
# @example
|
|
309
|
+
# Money.new(-100).abs #=> #<Money @fractional=100>
|
|
310
|
+
def abs
|
|
311
|
+
dup_with(fractional: fractional.abs)
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Test if the money amount is zero.
|
|
315
|
+
#
|
|
316
|
+
# @return [Boolean]
|
|
317
|
+
#
|
|
318
|
+
# @example
|
|
319
|
+
# Money.new(100).zero? #=> false
|
|
320
|
+
# Money.new(0).zero? #=> true
|
|
321
|
+
def zero?
|
|
322
|
+
fractional == 0
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
# Test if the money amount is non-zero. Returns this money object if it is
|
|
326
|
+
# non-zero, or nil otherwise, like +Numeric#nonzero?+.
|
|
327
|
+
#
|
|
328
|
+
# @return [Money, nil]
|
|
329
|
+
#
|
|
330
|
+
# @example
|
|
331
|
+
# Money.new(100).nonzero? #=> #<Money @fractional=100>
|
|
332
|
+
# Money.new(0).nonzero? #=> nil
|
|
333
|
+
def nonzero?
|
|
334
|
+
fractional != 0 ? self : nil
|
|
335
|
+
end
|
|
336
|
+
|
|
337
|
+
# Used to make Money instance handle the operations when arguments order is reversed
|
|
338
|
+
# @return [Array]
|
|
339
|
+
#
|
|
340
|
+
# @example
|
|
341
|
+
# 2 * Money.new(10) #=> #<Money @fractional=20>
|
|
342
|
+
def coerce(other)
|
|
343
|
+
[self, CoercedNumeric.new(other)]
|
|
344
|
+
end
|
|
345
|
+
end
|
|
346
|
+
end
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Money
|
|
4
|
+
module Constructors
|
|
5
|
+
|
|
6
|
+
# Create a new money object with value 0.
|
|
7
|
+
#
|
|
8
|
+
# @param [Currency, String, Symbol] currency The currency to use.
|
|
9
|
+
#
|
|
10
|
+
# @return [Money]
|
|
11
|
+
#
|
|
12
|
+
# @example
|
|
13
|
+
# Money.empty #=> #<Money @fractional=0>
|
|
14
|
+
def empty(currency = default_currency)
|
|
15
|
+
new(0, currency)
|
|
16
|
+
end
|
|
17
|
+
alias_method :zero, :empty
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# Creates a new Money object of the given value, using the Canadian
|
|
21
|
+
# dollar currency.
|
|
22
|
+
#
|
|
23
|
+
# @param [Integer] cents The cents value.
|
|
24
|
+
#
|
|
25
|
+
# @return [Money]
|
|
26
|
+
#
|
|
27
|
+
# @example
|
|
28
|
+
# n = Money.ca_dollar(100)
|
|
29
|
+
# n.cents #=> 100
|
|
30
|
+
# n.currency #=> #<Money::Currency id: cad>
|
|
31
|
+
def ca_dollar(cents)
|
|
32
|
+
new(cents, "CAD")
|
|
33
|
+
end
|
|
34
|
+
alias_method :cad, :ca_dollar
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
# Creates a new Money object of the given value, using the American dollar
|
|
38
|
+
# currency.
|
|
39
|
+
#
|
|
40
|
+
# @param [Integer] cents The cents value.
|
|
41
|
+
#
|
|
42
|
+
# @return [Money]
|
|
43
|
+
#
|
|
44
|
+
# @example
|
|
45
|
+
# n = Money.us_dollar(100)
|
|
46
|
+
# n.cents #=> 100
|
|
47
|
+
# n.currency #=> #<Money::Currency id: usd>
|
|
48
|
+
def us_dollar(cents)
|
|
49
|
+
new(cents, "USD")
|
|
50
|
+
end
|
|
51
|
+
alias_method :usd, :us_dollar
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Creates a new Money object of the given value, using the Euro currency.
|
|
55
|
+
#
|
|
56
|
+
# @param [Integer] cents The cents value.
|
|
57
|
+
#
|
|
58
|
+
# @return [Money]
|
|
59
|
+
#
|
|
60
|
+
# @example
|
|
61
|
+
# n = Money.euro(100)
|
|
62
|
+
# n.cents #=> 100
|
|
63
|
+
# n.currency #=> #<Money::Currency id: eur>
|
|
64
|
+
def euro(cents)
|
|
65
|
+
new(cents, "EUR")
|
|
66
|
+
end
|
|
67
|
+
alias_method :eur, :euro
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
# Creates a new Money object of the given value, in British pounds.
|
|
71
|
+
#
|
|
72
|
+
# @param [Integer] pence The pence value.
|
|
73
|
+
#
|
|
74
|
+
# @return [Money]
|
|
75
|
+
#
|
|
76
|
+
# @example
|
|
77
|
+
# n = Money.pound_sterling(100)
|
|
78
|
+
# n.fractional #=> 100
|
|
79
|
+
# n.currency #=> #<Money::Currency id: gbp>
|
|
80
|
+
def pound_sterling(pence)
|
|
81
|
+
new(pence, "GBP")
|
|
82
|
+
end
|
|
83
|
+
alias_method :gbp, :pound_sterling
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
end
|