Class: GOBL::Num::Amount
Overview
Represents a numeric quantity with optional decimal places that determine accuracy
Direct Known Subclasses
Instance Attribute Summary collapse
-
#exp ⇒ Object
readonly
The exponent, or number of significant figures of the amount.
-
#value ⇒ Object
readonly
The integer value of the amount.
Class Method Summary collapse
-
.rescale_pair(a1, a2) ⇒ Array(Amount, Amount)
Rescales each Amount in the pair ensuring both have the same exponent.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Returns whether the current amount is equal to another one.
-
#add(a2) ⇒ Amount
Adds the current amount to a given one.
-
#as_json ⇒ Object
@api private.
-
#as_s ⇒ String
Returns the string representation of the current amount.
-
#compare(other) ⇒ Integer
Compares the current amount with another one.
-
#divide(a2) ⇒ Amount
Divides the current amount by the given one.
-
#initialize(data) ⇒ Amount
constructor
Creates a new Amount from the given data object.
-
#invert ⇒ Amount
Inverts the sign of the current amount.
-
#multiply(a2) ⇒ Amount
Multiplies a given Amount with the current one.
-
#rescale(e) ⇒ Amount
Changes the exponent of the Amount multipling or dividing its value as necessary.
-
#split(x) ⇒ Array(Amount, Amount)
Splits the current amount into equal ‘x` parts providing a second amount with the remainder.
-
#subtract(a2) ⇒ Amount
Subtracts a given Amount from the current one.
-
#to_s ⇒ String
Returns the string representation of the current amount.
-
#zero? ⇒ Boolean
Returns whether the current amount is equal to zero.
Methods inherited from Struct
from_data, from_json!, #to_json
Constructor Details
#initialize(data) ⇒ Amount
Creates a new GOBL::Num::Amount from the given data object
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/gobl/num/amount.rb', line 20 def initialize(data) if data.is_a?(String) parse(data) elsif data.is_a?(Hash) @value = data[:value] @exp = data[:exp] || 0 elsif data.is_a?(self.class) @value = data.value @exp = data.exp elsif data.respond_to?(:to_s) parse(data.to_s) else raise 'Unsupported input amount' end end |
Instance Attribute Details
#exp ⇒ Object (readonly)
The exponent, or number of significant figures of the amount
11 12 13 |
# File 'lib/gobl/num/amount.rb', line 11 def exp @exp end |
#value ⇒ Object (readonly)
The integer value of the amount
8 9 10 |
# File 'lib/gobl/num/amount.rb', line 8 def value @value end |
Class Method Details
.rescale_pair(a1, a2) ⇒ Array(Amount, Amount)
Rescales each GOBL::Num::Amount in the pair ensuring both have the same exponent
64 65 66 67 68 |
# File 'lib/gobl/num/amount.rb', line 64 def self.rescale_pair(a1, a2) exp = a1.exp exp = a2.exp if a2.exp > exp [a1.rescale(exp), a2.rescale(exp)] end |
Instance Method Details
#==(other) ⇒ Boolean
Returns whether the current amount is equal to another one
95 96 97 |
# File 'lib/gobl/num/amount.rb', line 95 def ==(other) compare(other).zero? end |
#add(a2) ⇒ Amount
Adds the current amount to a given one
134 135 136 137 |
# File 'lib/gobl/num/amount.rb', line 134 def add(a2) a2 = a2.rescale(exp) self.class.new(value: value + a2.value, exp: exp) end |
#as_json ⇒ Object
@api private
191 192 193 |
# File 'lib/gobl/num/amount.rb', line 191 def as_json(*) to_s end |
#as_s ⇒ String
Returns the string representation of the current amount
48 49 50 51 52 53 54 55 56 |
# File 'lib/gobl/num/amount.rb', line 48 def as_s return value.to_s if exp.zero? raise 'exponent too high' if exp > 100 p = 10**exp v1, v2 = value.abs.divmod(p) sign = value.negative? ? '-' : '' format('%s%d.%0*d', sign, v1, exp, v2) end |
#compare(other) ⇒ Integer
Compares the current amount with another one
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/gobl/num/amount.rb', line 79 def compare(other) a1, a2 = self.class.rescale_pair(self, other) if a1.value < a2.value -1 elsif a1.value > a2.value 1 else 0 # same end end |
#divide(a2) ⇒ Amount
Divides the current amount by the given one
164 165 166 167 |
# File 'lib/gobl/num/amount.rb', line 164 def divide(a2) v = (value.to_f * (10**a2.exp)) / a2.value.to_f self.class.new(value: v.round, exp: exp) end |
#invert ⇒ Amount
Inverts the sign of the current amount
186 187 188 |
# File 'lib/gobl/num/amount.rb', line 186 def invert self.class.new(value: -value, exp: exp) end |
#multiply(a2) ⇒ Amount
Multiplies a given GOBL::Num::Amount with the current one
154 155 156 157 |
# File 'lib/gobl/num/amount.rb', line 154 def multiply(a2) v = (value * a2.value) / (10**a2.exp) self.class.new(value: v, exp: exp) end |
#rescale(e) ⇒ Amount
Changes the exponent of the GOBL::Num::Amount multipling or dividing its value as necessary. A lower exponent implies loosing accuracy.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
# File 'lib/gobl/num/amount.rb', line 105 def rescale(e) if exp > e # divide x = exp - e v = (value.to_f / (10**x)).round self.class.new(value: v, exp: e) elsif exp < e # multiply x = e - exp v = value * (10**x) self.class.new(value: v, exp: e) else # nothing self end end |
#split(x) ⇒ Array(Amount, Amount)
Splits the current amount into equal ‘x` parts providing a second amount with the remainder. This is like #divide, but will correctly account for rounding errors.
176 177 178 179 180 181 |
# File 'lib/gobl/num/amount.rb', line 176 def split(x) a2 = divide(self.class.new(value: x, exp: 0)) a3 = a2.multiply(self.class.new(value: x - 1, exp: 0)) a3 = subtract(a3) [a2, a3] end |
#subtract(a2) ⇒ Amount
Subtracts a given GOBL::Num::Amount from the current one
144 145 146 147 |
# File 'lib/gobl/num/amount.rb', line 144 def subtract(a2) a2 = a2.rescale(exp) self.class.new(value: value - a2.value, exp: exp) end |
#to_s ⇒ String
Returns the string representation of the current amount
41 42 43 |
# File 'lib/gobl/num/amount.rb', line 41 def to_s as_s end |
#zero? ⇒ Boolean
Returns whether the current amount is equal to zero
125 126 127 |
# File 'lib/gobl/num/amount.rb', line 125 def zero? value.zero? end |