lare_round 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +7 -8
- data/README.md +2 -2
- data/Rakefile +2 -3
- data/lare_round.gemspec +26 -13
- data/lib/lare_round.rb +107 -36
- data/lib/lare_round/version.rb +1 -1
- data/test/lare_round_test.rb +94 -59
- data/test/test_helper.rb +8 -4
- metadata +55 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 22cc87361ca388e9fea449cc3fc775bba6c4869a
|
4
|
+
data.tar.gz: 5b837592bedcd9da1f528fdabf5a328896422860
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 92fc9fcefcdb98717afbd19cc8b2c2423f23dd53e2e195af746fe50183422c6518abe76a31260a1d1ef0d77fde661f27cd4d251841e3c6222e6e8da841a6ff15
|
7
|
+
data.tar.gz: cbd9d9df3a74c4f7a7a66d49f60923468e47066ffd615f421e055b732798c80b627c32f7ff12b03df05210cf5f04b9da51e41d32263f2d9c3d1daa1e9f6eae01
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -93,13 +93,13 @@ Item (unrounded)| Price (unrounded) | LareRound | Financial
|
|
93
93
|
tax ( 8.23%) | 0.823 | 0.82 | 0.83
|
94
94
|
**Total** | **10.823** | **10.82** | **10.83**
|
95
95
|
|
96
|
-
*
|
96
|
+
* refactoring ^^
|
97
97
|
|
98
98
|
## Installation
|
99
99
|
|
100
100
|
Add this line to your application's Gemfile:
|
101
101
|
|
102
|
-
gem 'lare_round',
|
102
|
+
gem 'lare_round', '~> 0.0.1'
|
103
103
|
|
104
104
|
And then execute:
|
105
105
|
|
data/Rakefile
CHANGED
data/lare_round.gemspec
CHANGED
@@ -4,21 +4,34 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'lare_round/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name =
|
7
|
+
spec.name = 'lare_round'
|
8
8
|
spec.version = LareRound::VERSION
|
9
|
-
spec.authors = [
|
10
|
-
spec.email = [
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
spec.authors = ['Carsten Wirth']
|
10
|
+
spec.email = ['carsten.wirth@blacklane.com']
|
11
|
+
|
12
|
+
spec.description = <<-DESCRIPTION
|
13
|
+
A collection of BigDecimal items e.g. invoice items can be rounded for
|
14
|
+
displaying them in views. Rounding may apply a rounding error to the
|
15
|
+
items such as the summed up rounded items will show deviation towards
|
16
|
+
an invoice total with summed unrounded items. Which might cause
|
17
|
+
confusion for customers and finance departments alike.
|
18
|
+
|
19
|
+
Application of the largest remainder method can help to preserve the
|
20
|
+
total sum for fractionated parts thus eliminating this confusion.
|
21
|
+
DESCRIPTION
|
22
|
+
|
23
|
+
spec.summary = 'gem for rounding BigDecimal items by preserving its sum'
|
24
|
+
spec.homepage = ''
|
25
|
+
spec.license = 'MIT'
|
16
26
|
|
17
27
|
spec.files = `git ls-files`.split($/)
|
18
|
-
spec.executables = spec.files.grep(
|
19
|
-
spec.test_files = spec.files.grep(
|
20
|
-
spec.require_paths = [
|
28
|
+
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
29
|
+
spec.test_files = spec.files.grep(/^(test|spec|features)\//)
|
30
|
+
spec.require_paths = ['lib']
|
21
31
|
|
22
|
-
spec.add_development_dependency
|
23
|
-
spec.add_development_dependency
|
32
|
+
spec.add_development_dependency 'bundler', '~> 1.3'
|
33
|
+
spec.add_development_dependency 'rake'
|
34
|
+
spec.add_development_dependency 'rubocop'
|
35
|
+
spec.add_development_dependency 'minitest'
|
36
|
+
spec.add_development_dependency 'simplecov'
|
24
37
|
end
|
data/lib/lare_round.rb
CHANGED
@@ -1,54 +1,125 @@
|
|
1
1
|
require 'bigdecimal'
|
2
2
|
|
3
3
|
module LareRound
|
4
|
+
def self.round(values, precision)
|
5
|
+
# although it is the senders responsibility to ensure that correct messages
|
6
|
+
# are sent to this module it might not be quite obvious so i provide some
|
7
|
+
# help here with errors if input is invalid
|
8
|
+
array_of_values = values.is_a?(Hash) ? values.values : values
|
9
|
+
handle_value_errors(array_of_values)
|
10
|
+
handle_precision_errors(precision)
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
values
|
16
|
-
|
12
|
+
process(values, precision)
|
13
|
+
end
|
14
|
+
|
15
|
+
# StandardError for dealing with application level errors
|
16
|
+
class LareRoundError < StandardError; end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def self.process(values, precision)
|
21
|
+
if values.is_a? Hash
|
22
|
+
process_hash(values, precision)
|
23
|
+
else
|
24
|
+
round_array_of_values(values, precision)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.process_hash(values, precision)
|
29
|
+
rounded_values = round_array_of_values(values.values, precision)
|
30
|
+
values.tap do |hash|
|
31
|
+
hash.keys.each_with_index do |key, index|
|
32
|
+
hash[key] = rounded_values[index]
|
17
33
|
end
|
18
|
-
return values
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
22
|
-
|
23
|
-
|
37
|
+
def self.handle_value_errors(values)
|
38
|
+
fail LareRoundError, 'values must not be nil' if values.nil?
|
39
|
+
fail LareRoundError, 'values must not be empty' if values.empty?
|
40
|
+
fail LareRoundError, 'values must be an array' unless values.is_a? Array
|
24
41
|
|
42
|
+
numbers_invalid = values.map { |i| i.is_a? Numeric }
|
43
|
+
.reject { |i| i == true }.size
|
44
|
+
if numbers_invalid > 0
|
45
|
+
error = <<-ERROR.strip.gsub(/\s+/, ' ')
|
46
|
+
values contains not numeric values (#{numbers_invalid})
|
47
|
+
ERROR
|
48
|
+
fail LareRoundError, error
|
49
|
+
end
|
50
|
+
|
51
|
+
if values.map { |i| i.is_a? BigDecimal }.reject { |i| i == true }.size > 0
|
52
|
+
warning = <<-WARNING.strip.gsub(/\s+/, ' ')
|
53
|
+
values contains non decimal values,
|
54
|
+
you might loose precision or even get wrong rounding results
|
55
|
+
WARNING
|
56
|
+
warn warning
|
57
|
+
end
|
25
58
|
end
|
26
59
|
|
27
|
-
|
28
|
-
|
29
|
-
raise LareRoundError.new("array_of_values must be an array") unless array_of_values.is_a? Array
|
30
|
-
number_of_invalid_values = array_of_values.map{|i| i.is_a? Numeric}.reject{|i| i == true}.size
|
31
|
-
raise LareRoundError.new("values contains not numeric values (#{number_of_invalid_values})") if number_of_invalid_values > 0
|
32
|
-
warn "values contains non decimal values, you might loose precision or even get wrong rounding results" if array_of_values.map{|i| i.is_a? BigDecimal}.reject{|i| i == true}.size > 0
|
33
|
-
|
34
|
-
#prevention of can't omit precision for a Rational
|
35
|
-
decimal_shift = BigDecimal.new (10 ** precision.to_i)
|
36
|
-
rounded_total = array_of_values.reduce(:+).round(precision) * decimal_shift
|
37
|
-
array_of_values = array_of_values.map{|v| ((v.is_a? BigDecimal) ? v : BigDecimal.new(v.to_s))}
|
38
|
-
unrounded_values = array_of_values.map{|v| v * decimal_shift }
|
60
|
+
def self.handle_precision_errors(precision)
|
61
|
+
fail LareRoundError, 'precision must not be nil' if precision.nil?
|
39
62
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
# elsewise if negative
|
44
|
-
rounded_values = array_of_values.map{|v| v < 0 ? v.round(precision, BigDecimal::ROUND_UP) * decimal_shift : v.round(precision, BigDecimal::ROUND_DOWN) * decimal_shift }
|
63
|
+
unless precision.is_a? Numeric
|
64
|
+
fail LareRoundError, 'precision must be a number'
|
65
|
+
end
|
45
66
|
|
46
|
-
|
47
|
-
|
48
|
-
|
67
|
+
if precision < 0
|
68
|
+
fail LareRoundError, 'precision must be greater or equal to 0'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Struct.new(
|
73
|
+
'IntermediaryResults',
|
74
|
+
:decimal_shift,
|
75
|
+
:rounded_total,
|
76
|
+
:array_of_values,
|
77
|
+
:unrounded_values,
|
78
|
+
:precision,
|
79
|
+
:rounded_values
|
80
|
+
)
|
81
|
+
|
82
|
+
def self.round_array_of_values(array_of_values, precision)
|
83
|
+
mrc = Struct::IntermediaryResults.new
|
84
|
+
mrc.precision = precision
|
85
|
+
mrc.decimal_shift = BigDecimal.new(10**precision.to_i)
|
86
|
+
mrc.rounded_total = array_of_values.reduce(:+)
|
87
|
+
.round(precision) * mrc.decimal_shift
|
88
|
+
mrc.array_of_values = array_of_values.map do |v|
|
89
|
+
((v.is_a? BigDecimal) ? v : BigDecimal.new(v.to_s))
|
90
|
+
end
|
91
|
+
mrc.unrounded_values = array_of_values.map { |v| v * mrc.decimal_shift }
|
92
|
+
|
93
|
+
largest_remainder_method(mrc)
|
94
|
+
|
95
|
+
mrc.rounded_values
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.largest_remainder_method(mrc)
|
99
|
+
mrc.rounded_values = mrc.array_of_values.map do |v|
|
100
|
+
largest_remainder_round(v, mrc)
|
49
101
|
end
|
50
102
|
|
51
|
-
|
103
|
+
until mrc.rounded_values.reduce(:+) >= mrc.rounded_total
|
104
|
+
fractions = mrc.unrounded_values.zip(mrc.rounded_values).map do |x, y|
|
105
|
+
x - y
|
106
|
+
end
|
107
|
+
mrc.rounded_values[fractions.index(fractions.max)] += 1
|
108
|
+
end
|
109
|
+
|
110
|
+
mrc.rounded_values.map! { |v| v / mrc.decimal_shift }
|
52
111
|
end
|
53
112
|
|
113
|
+
def self.largest_remainder_round(v, mrc)
|
114
|
+
# items needed to be rounded down if positiv:
|
115
|
+
# 0.7 + 0.7 + 0.7 = ( 2.1 ).round(0) = 2
|
116
|
+
# (0.7).round(0) + (0.7).round(0) + (0.7).round(0) = 1 + 1 + 1 = 3
|
117
|
+
# elsewise if negative
|
118
|
+
rounding_strategy = if v < 0
|
119
|
+
BigDecimal::ROUND_UP
|
120
|
+
else
|
121
|
+
BigDecimal::ROUND_DOWN
|
122
|
+
end
|
123
|
+
v.round(mrc.precision, rounding_strategy) * mrc.decimal_shift
|
124
|
+
end
|
54
125
|
end
|
data/lib/lare_round/version.rb
CHANGED
data/test/lare_round_test.rb
CHANGED
@@ -2,115 +2,150 @@ require_relative 'test_helper'
|
|
2
2
|
require 'bigdecimal'
|
3
3
|
require 'securerandom'
|
4
4
|
|
5
|
-
class LareRoundTest < MiniTest::
|
5
|
+
class LareRoundTest < MiniTest::Spec
|
6
|
+
def test_has_static_method_round
|
7
|
+
assert_equal(true, LareRound.respond_to?(:round))
|
8
|
+
end
|
6
9
|
|
7
|
-
def
|
8
|
-
|
10
|
+
def create_big_decimal(precision, digit)
|
11
|
+
BigDecimal.new('0.' + '3' * precision + "#{digit}")
|
9
12
|
end
|
10
13
|
|
11
14
|
(1..9).each do |digit|
|
12
15
|
(1..23).each do |items|
|
13
16
|
(0..10).each do |precision|
|
14
17
|
|
15
|
-
method_name =
|
18
|
+
method_name = <<-TESTMETHOD.strip.gsub(/\s+/, '_')
|
19
|
+
test #{items} items with last digit of #{digit}
|
20
|
+
should sum up to rounded total of BigDecimal items
|
21
|
+
with precision of #{precision} if passed as array
|
22
|
+
TESTMETHOD
|
16
23
|
define_method method_name do
|
17
|
-
|
18
|
-
arr = Array.new(items){decimal}
|
24
|
+
arr = Array.new(items) { create_big_decimal(precision, digit) }
|
19
25
|
rounded_total = arr.reduce(:+).round(precision)
|
20
|
-
assert_equal(
|
26
|
+
assert_equal(
|
27
|
+
rounded_total,
|
28
|
+
LareRound.round(arr, precision).reduce(:+).round(precision)
|
29
|
+
)
|
21
30
|
end
|
22
31
|
|
23
|
-
method_name =
|
32
|
+
method_name = <<-TESTMETHOD.strip.gsub(/\s+/, '_')
|
33
|
+
test #{items} rounded items with last digit of #{digit}
|
34
|
+
should sum up to rounded total of BigDecimal items
|
35
|
+
with precision of #{precision} if passed as hash
|
36
|
+
TESTMETHOD
|
24
37
|
define_method method_name do
|
25
|
-
|
26
|
-
|
38
|
+
hash = Hash[
|
39
|
+
(1..items).map do
|
40
|
+
|x| [x, create_big_decimal(precision, digit)]
|
41
|
+
end
|
42
|
+
]
|
27
43
|
rounded_total = hash.values.reduce(:+).round(precision)
|
28
|
-
assert_equal(
|
44
|
+
assert_equal(
|
45
|
+
rounded_total,
|
46
|
+
LareRound.round(hash, precision).values.reduce(:+).round(precision)
|
47
|
+
)
|
29
48
|
end
|
30
49
|
|
31
|
-
method_name =
|
50
|
+
method_name = <<-TESTMETHOD.strip.gsub(/\s+/, '_')
|
51
|
+
test #{items} rounded items with last digit of #{digit}
|
52
|
+
and precision of #{precision}
|
53
|
+
if passed as hash should not change order
|
54
|
+
TESTMETHOD
|
32
55
|
define_method method_name do
|
33
|
-
|
34
|
-
|
35
|
-
|
56
|
+
hash = Hash[
|
57
|
+
(1..items).map.with_index do |x, i|
|
58
|
+
[x, create_big_decimal(precision, digit) + BigDecimal.new(i)]
|
59
|
+
end
|
60
|
+
]
|
61
|
+
rounded_hash = LareRound.round(hash.clone, precision)
|
36
62
|
hash.keys.each do |key|
|
37
|
-
assert(
|
63
|
+
assert((((hash[key] - rounded_hash[key]) * 10**precision).abs < 1))
|
38
64
|
end
|
39
65
|
end
|
40
66
|
|
41
|
-
method_name =
|
67
|
+
method_name = <<-TESTMETHOD.strip.gsub(/\s+/, '_')
|
68
|
+
test #{items} rounded negative items with last digit of #{digit}
|
69
|
+
should sum up to rounded total of BigDecimal items with precision
|
70
|
+
of #{precision} if passed as array
|
71
|
+
TESTMETHOD
|
42
72
|
define_method method_name do
|
43
|
-
|
44
|
-
|
73
|
+
arr = Array.new(items) do
|
74
|
+
BigDecimal.new(-1 * create_big_decimal(precision, digit))
|
75
|
+
end
|
45
76
|
rounded_total = arr.reduce(:+).round(precision)
|
46
|
-
assert_equal(
|
77
|
+
assert_equal(
|
78
|
+
rounded_total,
|
79
|
+
LareRound.round(arr, precision).reduce(:+).round(precision)
|
80
|
+
)
|
47
81
|
end
|
48
82
|
|
49
|
-
method_name =
|
83
|
+
method_name = <<-TESTMETHOD.strip.gsub(/\s+/, '_')
|
84
|
+
test #{items} rounded mixed (+/-) items with last digit of #{digit}
|
85
|
+
should sum up to rounded total of BigDecimal items with precision
|
86
|
+
of #{precision} if passed as array
|
87
|
+
TESTMETHOD
|
50
88
|
define_method method_name do
|
51
|
-
|
52
|
-
arr
|
89
|
+
arr = Array.new(items) { create_big_decimal(precision, digit) }
|
90
|
+
arr.map! { |i| SecureRandom.random_number(1).even? ? i : -1 * i }
|
53
91
|
rounded_total = arr.reduce(:+).round(precision)
|
54
|
-
assert_equal(
|
92
|
+
assert_equal(
|
93
|
+
rounded_total,
|
94
|
+
LareRound.round(arr, precision).reduce(:+).round(precision)
|
95
|
+
)
|
55
96
|
end
|
56
|
-
|
57
97
|
end
|
58
98
|
end
|
59
99
|
end
|
60
100
|
|
101
|
+
let(:default_array) { Array.new(3) { BigDecimal.new('0.1234') } }
|
102
|
+
|
61
103
|
def test_should_raise_if_precision_is_nil
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
}
|
67
|
-
assert_equal("precision must not be nil", exception.message)
|
104
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
105
|
+
LareRound.round(default_array, nil)
|
106
|
+
end
|
107
|
+
assert_equal('precision must not be nil', exception.message)
|
68
108
|
end
|
69
109
|
|
70
110
|
def test_should_raise_if_precision_is_less_than_zero
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
}
|
76
|
-
assert_equal("precision must be greater or equal to 0", exception.message)
|
111
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
112
|
+
LareRound.round(default_array, -1)
|
113
|
+
end
|
114
|
+
assert_equal('precision must be greater or equal to 0', exception.message)
|
77
115
|
end
|
78
116
|
|
79
117
|
def test_should_raise_if_precision_is_not_a_number
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
}
|
85
|
-
assert_equal("precision must be a number", exception.message)
|
118
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
119
|
+
LareRound.round(default_array, 'not_a_number')
|
120
|
+
end
|
121
|
+
assert_equal('precision must be a number', exception.message)
|
86
122
|
end
|
87
123
|
|
88
124
|
def test_should_raise_if_values_is_nil
|
89
|
-
exception = assert_raises(LareRound::LareRoundError)
|
90
|
-
LareRound.round(nil,2)
|
91
|
-
|
92
|
-
assert_equal(
|
125
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
126
|
+
LareRound.round(nil, 2)
|
127
|
+
end
|
128
|
+
assert_equal('values must not be nil', exception.message)
|
93
129
|
end
|
94
130
|
|
95
131
|
def test_should_raise_if_values_is_empty
|
96
|
-
exception = assert_raises(LareRound::LareRoundError)
|
97
|
-
LareRound.round([],2)
|
98
|
-
|
99
|
-
assert_equal(
|
132
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
133
|
+
LareRound.round([], 2)
|
134
|
+
end
|
135
|
+
assert_equal('values must not be empty', exception.message)
|
100
136
|
end
|
101
137
|
|
102
138
|
def test_should_raise_if_values_contains_invalid_values
|
103
|
-
exception = assert_raises(LareRound::LareRoundError)
|
104
|
-
LareRound.round([3.2, 1,
|
105
|
-
|
106
|
-
assert_equal(
|
139
|
+
exception = assert_raises(LareRound::LareRoundError) do
|
140
|
+
LareRound.round([3.2, 1, 'not_a_number', Exception.new, nil], 2)
|
141
|
+
end
|
142
|
+
assert_equal('values contains not numeric values (3)', exception.message)
|
107
143
|
end
|
108
144
|
|
109
145
|
def test_should_warn_if_numbers_not_big_decimals
|
110
|
-
|
111
|
-
LareRound.round([1.2132, 12.21212, 323.23],2)
|
146
|
+
_out, err = capture_io do
|
147
|
+
LareRound.round([1.2132, 12.21212, 323.23], 2)
|
112
148
|
end
|
113
|
-
assert_match(/
|
149
|
+
assert_match(/you might loose precision/, err)
|
114
150
|
end
|
115
|
-
|
116
151
|
end
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,12 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
4
|
+
base_dir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
5
|
+
lib_dir = File.join(base_dir, 'lib')
|
4
6
|
|
5
7
|
$LOAD_PATH.unshift(lib_dir)
|
6
8
|
|
7
|
-
require '
|
9
|
+
require 'minitest/spec'
|
10
|
+
require 'minitest/autorun'
|
11
|
+
|
8
12
|
require 'lare_round'
|
metadata
CHANGED
@@ -1,16 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lare_round
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
Carsten Wirth
|
9
|
-
|
7
|
+
- Carsten Wirth
|
10
8
|
autorequire:
|
11
9
|
bindir: bin
|
12
10
|
cert_chain: []
|
13
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-22 00:00:00.000000000 Z
|
14
12
|
dependencies:
|
15
13
|
- !ruby/object:Gem::Dependency
|
16
14
|
name: bundler
|
@@ -40,15 +38,59 @@ dependencies:
|
|
40
38
|
- - ">="
|
41
39
|
- !ruby/object:Gem::Version
|
42
40
|
version: '0'
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: minitest
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: simplecov
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: |2
|
84
|
+
A collection of BigDecimal items e.g. invoice items can be rounded for
|
85
|
+
displaying them in views. Rounding may apply a rounding error to the
|
86
|
+
items such as the summed up rounded items will show deviation towards
|
87
|
+
an invoice total with summed unrounded items. Which might cause
|
88
|
+
confusion for customers and finance departments alike.
|
89
|
+
|
90
|
+
Application of the largest remainder method can help to preserve the
|
91
|
+
total sum for fractionated parts thus eliminating this confusion.
|
49
92
|
email:
|
50
|
-
-
|
51
|
-
carsten.wirth@blacklane.com
|
93
|
+
- carsten.wirth@blacklane.com
|
52
94
|
executables: []
|
53
95
|
extensions: []
|
54
96
|
extra_rdoc_files: []
|