money_extensions 0.1.0 → 1.0.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 +5 -5
- data/.gitignore +2 -0
- data/.ruby-version +1 -0
- data/.travis.yml +8 -12
- data/CHANGELOG.md +3 -1
- data/gemfiles/rails5.gemfile +2 -1
- data/gemfiles/{rails4.gemfile → rails6.gemfile} +2 -3
- data/lib/money_extensions.rb +2 -3
- data/lib/money_extensions/active_record/extensions.rb +9 -18
- data/lib/money_extensions/array.rb +3 -1
- data/lib/money_extensions/html_format.rb +37 -0
- data/lib/money_extensions/integer.rb +3 -1
- data/lib/money_extensions/money_field.rb +4 -7
- data/lib/money_extensions/numeric.rb +4 -2
- data/lib/money_extensions/split_between.rb +54 -0
- data/lib/money_extensions/string.rb +4 -2
- data/lib/money_extensions/version.rb +3 -1
- data/money_extensions.gemspec +5 -1
- data/spec/big_decimal_spec.rb +6 -6
- data/spec/html_format_spec.rb +48 -0
- data/spec/money_spec.rb +3 -45
- data/spec/support/coverage_loader.rb +1 -1
- metadata +51 -14
- data/gemfiles/rails3.gemfile +0 -8
- data/lib/money_extensions/big_decimal.rb +0 -12
- data/lib/money_extensions/extensions.rb +0 -189
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 664c218fac6464fdf5789d5a301bd50d5ab9b4270dc537c199f451a4c1c8da1c
|
4
|
+
data.tar.gz: e824d3b3e10bde7a5c20c26c9668db8ca4b09d2f513adddf82466909d14702c1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dbd0b0d8a7f25d7601bea3006156e8324b0a211155431ea2bcfa65a3ce62c24efbfee701429ce544765cf80a1f77bd75518fce0e90647a5000be26a4de6b2b0c
|
7
|
+
data.tar.gz: 6828b8a3401ea874852b0804c695b06f97b107830d610c25f0ad99aed9d1b29db7c91b5594fec8782fe3233173e66fbd84377b7b98c398bae5a599a4c220c3c4
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.6.3
|
data/.travis.yml
CHANGED
@@ -1,22 +1,18 @@
|
|
1
1
|
language: ruby
|
2
2
|
rvm:
|
3
|
-
- 2.2.2
|
4
|
-
- 2.3.0
|
5
3
|
- 2.4
|
4
|
+
- 2.5
|
5
|
+
- 2.6
|
6
6
|
matrix:
|
7
|
-
fast_finish: true
|
8
7
|
exclude:
|
9
8
|
- rvm: 2.4
|
10
|
-
gemfile: gemfiles/
|
9
|
+
gemfile: gemfiles/rails6.gemfile
|
10
|
+
|
11
|
+
script: "bundle exec rake spec"
|
11
12
|
gemfile:
|
12
|
-
- gemfiles/rails3.gemfile
|
13
|
-
- gemfiles/rails4.gemfile
|
14
13
|
- gemfiles/rails5.gemfile
|
15
|
-
|
16
|
-
notifications:
|
17
|
-
email:
|
18
|
-
- support@travellink.com.au
|
19
|
-
flowdock:
|
20
|
-
secure: A0Fr9j0kvKPEWuPbJu/DPMYPvx98UI8k43adKN9UjTB6FRVAQM3kXmKJIL3A495scc2Civrg2KHDkbwNwVThY+HdLeU7q71Bm6obP6ZkCe43MIoc9NiVJymCNguku6+tLEyusdWIceFiBW7P5p/sU1QU66GFj1t4wNTpVq9A4Kw=
|
14
|
+
- gemfiles/rails6.gemfile
|
21
15
|
sudo: false
|
22
16
|
cache: bundler
|
17
|
+
before_install:
|
18
|
+
- gem install bundler
|
data/CHANGELOG.md
CHANGED
data/gemfiles/rails5.gemfile
CHANGED
data/lib/money_extensions.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
module MoneyExtensions
|
2
2
|
require 'money'
|
3
3
|
require 'money_extensions/array'
|
4
|
-
require 'money_extensions/big_decimal'
|
5
4
|
require 'money_extensions/integer'
|
6
|
-
require 'money_extensions/
|
5
|
+
require 'money_extensions/split_between'
|
6
|
+
require 'money_extensions/html_format'
|
7
7
|
require 'money_extensions/money_field'
|
8
8
|
require 'money_extensions/numeric'
|
9
9
|
require 'money_extensions/string'
|
@@ -14,4 +14,3 @@ module MoneyExtensions
|
|
14
14
|
end
|
15
15
|
|
16
16
|
end
|
17
|
-
|
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module Extensions
|
3
|
-
|
4
5
|
def self.included(base)
|
5
6
|
base.extend(ClassMethods)
|
6
7
|
end
|
@@ -18,20 +19,14 @@ module ActiveRecord
|
|
18
19
|
|
19
20
|
field_name = "#{attr_name}_iso_code"
|
20
21
|
|
21
|
-
composed_of attr_name, :
|
22
|
-
|
23
|
-
|
24
|
-
|
22
|
+
composed_of attr_name, class_name: 'Money::Currency',
|
23
|
+
mapping: [field_name, 'iso_code'],
|
24
|
+
allow_nil: true,
|
25
|
+
constructor: proc { |value| Money::Currency.new(value) unless value.blank? }
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
where(:currency_iso_code => currency.iso_code)
|
27
|
+
scope :for_currency, lambda { |currency|
|
28
|
+
where(currency_iso_code: currency.iso_code)
|
29
29
|
}
|
30
|
-
else
|
31
|
-
named_scope :for_currency, lambda{ |currency|
|
32
|
-
{:conditions => {:currency_iso_code => currency.iso_code}}
|
33
|
-
}
|
34
|
-
end
|
35
30
|
|
36
31
|
if options[:default]
|
37
32
|
before_validation :set_default_currency
|
@@ -43,13 +38,9 @@ module ActiveRecord
|
|
43
38
|
METHOD
|
44
39
|
end
|
45
40
|
|
46
|
-
if options[:required]
|
47
|
-
validates_presence_of :currency_iso_code
|
48
|
-
end
|
41
|
+
validates_presence_of :currency_iso_code if options[:required]
|
49
42
|
end
|
50
|
-
|
51
43
|
end
|
52
|
-
|
53
44
|
end
|
54
45
|
end
|
55
46
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string/output_safety'
|
4
|
+
|
5
|
+
module HtmlFormat
|
6
|
+
def format(**rules)
|
7
|
+
html_wrap = rules.delete(:html_wrap)
|
8
|
+
return html_wrap(super(**rules)) if html_wrap
|
9
|
+
|
10
|
+
super(**rules)
|
11
|
+
end
|
12
|
+
|
13
|
+
def as_html(**rules)
|
14
|
+
rules[:html_wrap] = true
|
15
|
+
format(**rules).html_safe
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def html_wrap(str)
|
21
|
+
"<span class=\"money #{direction_class}\">#{str}</span>"
|
22
|
+
end
|
23
|
+
|
24
|
+
def direction_class
|
25
|
+
if cents > 0
|
26
|
+
'positive'
|
27
|
+
elsif cents < 0
|
28
|
+
'negative'
|
29
|
+
else
|
30
|
+
'zero'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Money
|
36
|
+
prepend HtmlFormat
|
37
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
|
+
module MoneyField
|
3
4
|
def self.included(base)
|
4
5
|
base.extend(ClassMethods)
|
5
6
|
end
|
@@ -23,12 +24,10 @@ module MoneyField
|
|
23
24
|
METHOD
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
27
|
def money_fields(*attributes)
|
28
|
-
attributes.each {|a|
|
28
|
+
attributes.each { |a| money_field(a) }
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
31
|
def money(*fields)
|
33
32
|
fields.each do |field|
|
34
33
|
class_eval <<-METHOD
|
@@ -38,7 +37,5 @@ module MoneyField
|
|
38
37
|
METHOD
|
39
38
|
end
|
40
39
|
end
|
41
|
-
|
42
40
|
end
|
43
|
-
|
44
|
-
end
|
41
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class Numeric
|
2
4
|
# Converts this numeric to a Money object in the default currency. It
|
3
5
|
# multiplies the numeric value by 100 and treats that as cents.
|
@@ -11,6 +13,6 @@ class Numeric
|
|
11
13
|
# require 'bigdecimal'
|
12
14
|
# BigDecimal.new('100').to_money => #<Money @cents=10000>
|
13
15
|
def to_money(currency = nil)
|
14
|
-
::Money.new((self * 100).round, currency)
|
16
|
+
::Money.new((self * 100).round, currency || Money.default_currency)
|
15
17
|
end
|
16
|
-
end
|
18
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SplitBetween
|
4
|
+
# Override division -- should not do it, but use split_between
|
5
|
+
def /(*_params)
|
6
|
+
raise "Division of money NOT allowed - use 'split_between' to avoid rounding errors"
|
7
|
+
end
|
8
|
+
|
9
|
+
# Split the money between the specified number - and return an array of money
|
10
|
+
# Remainder in splits are given to the highest value e.g.
|
11
|
+
# $2.00 splits [40, 81, 40] into [49, 102, 49]
|
12
|
+
# $1.01 splits [ 1, 1, 1] into [35, 33, 33]
|
13
|
+
def split_between(params)
|
14
|
+
# if just a number is passed in, then money is split equally
|
15
|
+
if params.is_a?(Integer)
|
16
|
+
divisor = params
|
17
|
+
raise ArgumentError, 'Can only split up over a positive number' if divisor < 1
|
18
|
+
|
19
|
+
rounded_split = lossy_divide(divisor)
|
20
|
+
results = Array.new(divisor, rounded_split) # Create with 'divisor' num elements
|
21
|
+
|
22
|
+
# if an array of monies is passed in, then split in proportions
|
23
|
+
elsif params.is_a?(Array)
|
24
|
+
|
25
|
+
raise ArgumentError, 'Can only split up over at least one ration' if params.empty? && !zero?
|
26
|
+
|
27
|
+
results = params.map { |p| p.is_a?(::Money) ? p.cents : p }
|
28
|
+
|
29
|
+
total = results.inject(:+)
|
30
|
+
if total.zero?
|
31
|
+
return Array.new(results.size, ::Money.new(0)) if zero?
|
32
|
+
|
33
|
+
raise ArgumentError, "Total of ratios should not be zero! You sent in: #{params.inspect}"
|
34
|
+
end
|
35
|
+
|
36
|
+
results.map! do |ratio|
|
37
|
+
::Money.new((cents * (ratio.to_f / total)).round)
|
38
|
+
end
|
39
|
+
else
|
40
|
+
raise 'Either a Integer or array has to be passed in for splitting money'
|
41
|
+
end
|
42
|
+
|
43
|
+
# Distribute rounding to max absolute to avoid a $0 amount getting the rounding
|
44
|
+
biggest_value_index = results.index(results.max_by(&:abs))
|
45
|
+
results[biggest_value_index] += self - results.total_money
|
46
|
+
|
47
|
+
results
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Money
|
52
|
+
alias lossy_divide /
|
53
|
+
include SplitBetween
|
54
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
class String
|
2
4
|
# Converts this string to a float and then to a Money object in the default currency.
|
3
5
|
# It multiplies the converted numeric value by 100 and treats that as cents.
|
@@ -9,6 +11,6 @@ class String
|
|
9
11
|
# '100'.to_money => #<Money @cents=10000>
|
10
12
|
# '100.37'.to_money => #<Money @cents=10037>
|
11
13
|
def to_money(currency = nil)
|
12
|
-
Money.new((
|
14
|
+
Money.new((to_f * 100).round, currency)
|
13
15
|
end
|
14
|
-
end
|
16
|
+
end
|
data/money_extensions.gemspec
CHANGED
@@ -19,8 +19,12 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency 'money', '>=
|
22
|
+
spec.add_dependency 'money', '>= 6.0.0'
|
23
|
+
spec.add_dependency 'activesupport', '>= 5'
|
24
|
+
|
23
25
|
spec.add_development_dependency 'rake'
|
26
|
+
spec.add_development_dependency 'pry'
|
27
|
+
spec.add_development_dependency 'rubocop'
|
24
28
|
spec.add_development_dependency 'rspec'
|
25
29
|
spec.add_development_dependency 'coverage-kit'
|
26
30
|
spec.add_development_dependency 'simplecov-rcov'
|
data/spec/big_decimal_spec.rb
CHANGED
@@ -3,15 +3,15 @@ require 'spec_helper'
|
|
3
3
|
describe BigDecimal do
|
4
4
|
|
5
5
|
it "should allow verifying if it's a positive value" do
|
6
|
-
expect(BigDecimal
|
7
|
-
expect(BigDecimal
|
8
|
-
expect(BigDecimal
|
6
|
+
expect(BigDecimal('-1')).to_not be_positive
|
7
|
+
expect(BigDecimal('0')).to_not be_positive
|
8
|
+
expect(BigDecimal('1')).to be_positive
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should allow verifying if it's a negative value" do
|
12
|
-
expect(BigDecimal
|
13
|
-
expect(BigDecimal
|
14
|
-
expect(BigDecimal
|
12
|
+
expect(BigDecimal('-1')).to be_negative
|
13
|
+
expect(BigDecimal('0')).to_not be_negative
|
14
|
+
expect(BigDecimal('1')).to_not be_negative
|
15
15
|
end
|
16
16
|
|
17
17
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'money'
|
2
|
+
require 'money_extensions/string'
|
3
|
+
require 'money_extensions/html_format'
|
4
|
+
|
5
|
+
RSpec.describe Money do
|
6
|
+
before { Money.locale_backend = nil }
|
7
|
+
after { Money.locale_backend = :legacy }
|
8
|
+
|
9
|
+
let(:money_positive) { Money.new(100) }
|
10
|
+
let(:money_negative) { Money.new(-100) }
|
11
|
+
let(:money_zero) { Money.new(0) }
|
12
|
+
|
13
|
+
subject { money_positive.format(*rules) }
|
14
|
+
|
15
|
+
it "should format the output correctly" do
|
16
|
+
expect(money_negative.format(html_wrap: true, sign_before_symbol: true)).to eq "<span class=\"money negative\">-$1.00</span>"
|
17
|
+
expect(money_positive.format(html_wrap: true)).to eq "<span class=\"money positive\">$1.00</span>"
|
18
|
+
expect(money_zero.format(html_wrap: true)).to eq "<span class=\"money zero\">$0.00</span>"
|
19
|
+
|
20
|
+
expect(money_positive.format(html_wrap: true)).to eq "<span class=\"money positive\">$1.00</span>"
|
21
|
+
expect(money_negative.format(html_wrap: true, sign_before_symbol: true)).to eq "<span class=\"money negative\">-$1.00</span>"
|
22
|
+
expect(money_zero.format(html_wrap: true)).to eq "<span class=\"money zero\">$0.00</span>"
|
23
|
+
|
24
|
+
expect(money_positive.format(signed: true, sign_positive: true, sign_before_symbol: true)).to eq "+$1.00"
|
25
|
+
expect(money_negative.format(signed: true, sign_before_symbol: true)).to eq "-$1.00"
|
26
|
+
expect(money_zero.format(signed: true)).to eq "$0.00"
|
27
|
+
|
28
|
+
expect(money_positive.format(separator: '~')).to eq "$1~00"
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should work with as_html' do
|
32
|
+
expect(money_negative.as_html(sign_before_symbol: true)).to eq "<span class=\"money negative\">-$1.00</span>"
|
33
|
+
expect(money_positive.as_html).to eq "<span class=\"money positive\">$1.00</span>"
|
34
|
+
expect(money_zero.as_html).to eq "<span class=\"money zero\">$0.00</span>"
|
35
|
+
|
36
|
+
expect(money_positive.as_html).to eq "<span class=\"money positive\">$1.00</span>"
|
37
|
+
expect(money_negative.as_html(sign_before_symbol: true)).to eq "<span class=\"money negative\">-$1.00</span>"
|
38
|
+
expect(money_zero.as_html).to eq "<span class=\"money zero\">$0.00</span>"
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should format cents where appropriate' do
|
42
|
+
expect('1.50'.to_money.format(no_cents: true)).to eq '$1'
|
43
|
+
expect('1.00'.to_money.format(no_cents: true)).to eq '$1'
|
44
|
+
|
45
|
+
expect('1.50'.to_money.format(no_cents_if_whole: true)).to eq '$1.50'
|
46
|
+
expect('1.00'.to_money.format(no_cents_if_whole: true)).to eq '$1'
|
47
|
+
end
|
48
|
+
end
|
data/spec/money_spec.rb
CHANGED
@@ -1,23 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Money do
|
4
|
-
it "should get correct direction class" do
|
5
|
-
expect(Money.new(-1).direction_class).to eq 'negative'
|
6
|
-
expect(Money.new(0).direction_class).to eq 'zero'
|
7
|
-
expect(Money.new(1).direction_class).to eq 'positive'
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should round correctly" do
|
11
|
-
money = Money.new(511)
|
12
|
-
expect(money.round.cents).to eq 500
|
13
|
-
expect(money.round(10).cents).to eq 510
|
14
|
-
expect(money.round(1).cents).to eq 511
|
15
|
-
|
16
|
-
expect(money.round(100, 'up').cents).to eq 600
|
17
|
-
expect(money.round(100, 'down').cents).to eq 500
|
18
|
-
expect(money.round(100, 'nearest').cents).to eq 500
|
19
|
-
end
|
20
|
-
|
21
4
|
it "should deny division of money (to prevent rounding errors)" do
|
22
5
|
expect { Money.new(50)/10 }.to raise_error(RuntimeError)
|
23
6
|
end
|
@@ -38,7 +21,7 @@ describe Money do
|
|
38
21
|
expect(money.split_between([1,2])).to eq [33,67].map{ |i| Money.new(i)}
|
39
22
|
|
40
23
|
money_negative = Money.new(-100)
|
41
|
-
expect(money_negative.split_between(3)).to eq [-
|
24
|
+
expect(money_negative.split_between(3)).to eq [-34,-33,-33].map{ |i| Money.new(i)}
|
42
25
|
expect(money_negative.split_between([1,2,2,5])).to eq [-10,-20,-20,-50].map{ |i| Money.new(i)}
|
43
26
|
expect(money_negative.split_between([1,2])).to eq [-33,-67].map{ |i| Money.new(i)}
|
44
27
|
|
@@ -60,14 +43,14 @@ describe Money do
|
|
60
43
|
|
61
44
|
it "should return a nice, Big Decimal if so converted" do
|
62
45
|
money = Money.new(1428)
|
63
|
-
bigdecimal = BigDecimal
|
46
|
+
bigdecimal = BigDecimal("14.28")
|
64
47
|
expect(money.to_d).to eq bigdecimal
|
65
48
|
end
|
66
49
|
|
67
50
|
it "should be createable from strings and numbers" do
|
68
51
|
money = Money.new(100)
|
69
52
|
expect("1".to_money.cents).to eq money.cents
|
70
|
-
expect(BigDecimal
|
53
|
+
expect(BigDecimal('1').to_money.cents).to eq money.cents
|
71
54
|
expect(100.total_money.cents).to eq money.cents
|
72
55
|
end
|
73
56
|
|
@@ -89,29 +72,4 @@ describe Money do
|
|
89
72
|
expect(money_negative.abs).to eq money_positive
|
90
73
|
expect(money_zero.abs).to eq money_zero
|
91
74
|
end
|
92
|
-
|
93
|
-
it "should format the output correctly" do
|
94
|
-
expect(money_positive.format).to eq "<span class=\"money positive\">$1.00</span>"
|
95
|
-
expect(money_negative.format).to eq "<span class=\"money negative\">-$1.00</span>"
|
96
|
-
expect(money_zero.format).to eq "<span class=\"money zero\">$0.00</span>"
|
97
|
-
|
98
|
-
expect(money_positive.format(:html)).to eq "<span class=\"money positive\">$1.00</span>"
|
99
|
-
expect(money_negative.format(:html)).to eq "<span class=\"money negative\">-$1.00</span>"
|
100
|
-
expect(money_zero.format(:html)).to eq "<span class=\"money zero\">$0.00</span>"
|
101
|
-
|
102
|
-
expect(money_positive.format(:signed)).to eq "+$1.00"
|
103
|
-
expect(money_negative.format(:signed)).to eq "-$1.00"
|
104
|
-
expect(money_zero.format(:signed)).to eq "$0.00"
|
105
|
-
|
106
|
-
expect("1.50".to_money.format(:separator => '~')).to eq "$1~50"
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'should format cents where appropriate' do
|
110
|
-
expect('1.50'.to_money.format(:no_cents)).to eq '$1'
|
111
|
-
expect('1.00'.to_money.format(:no_cents)).to eq '$1'
|
112
|
-
|
113
|
-
expect('1.50'.to_money.format(:hide_zero_cents)).to eq '$1.50'
|
114
|
-
expect('1.00'.to_money.format(:hide_zero_cents)).to eq '$1'
|
115
|
-
end
|
116
|
-
|
117
75
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: money_extensions
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Noack
|
@@ -9,16 +9,13 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2019-08-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: money
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
18
|
- - ">="
|
19
|
-
- !ruby/object:Gem::Version
|
20
|
-
version: 3.0.0
|
21
|
-
- - "<"
|
22
19
|
- !ruby/object:Gem::Version
|
23
20
|
version: 6.0.0
|
24
21
|
type: :runtime
|
@@ -26,11 +23,22 @@ dependencies:
|
|
26
23
|
version_requirements: !ruby/object:Gem::Requirement
|
27
24
|
requirements:
|
28
25
|
- - ">="
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
version: 3.0.0
|
31
|
-
- - "<"
|
32
26
|
- !ruby/object:Gem::Version
|
33
27
|
version: 6.0.0
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: activesupport
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '5'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '5'
|
34
42
|
- !ruby/object:Gem::Dependency
|
35
43
|
name: rake
|
36
44
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,6 +53,34 @@ dependencies:
|
|
45
53
|
- - ">="
|
46
54
|
- !ruby/object:Gem::Version
|
47
55
|
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: pry
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rubocop
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
48
84
|
- !ruby/object:Gem::Dependency
|
49
85
|
name: rspec
|
50
86
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,28 +187,29 @@ extra_rdoc_files: []
|
|
151
187
|
files:
|
152
188
|
- ".gitignore"
|
153
189
|
- ".rspec"
|
190
|
+
- ".ruby-version"
|
154
191
|
- ".travis.yml"
|
155
192
|
- CHANGELOG.md
|
156
193
|
- Gemfile
|
157
194
|
- LICENSE
|
158
195
|
- README.md
|
159
196
|
- Rakefile
|
160
|
-
- gemfiles/rails3.gemfile
|
161
|
-
- gemfiles/rails4.gemfile
|
162
197
|
- gemfiles/rails5.gemfile
|
198
|
+
- gemfiles/rails6.gemfile
|
163
199
|
- lib/money_extensions.rb
|
164
200
|
- lib/money_extensions/active_record/extensions.rb
|
165
201
|
- lib/money_extensions/array.rb
|
166
|
-
- lib/money_extensions/
|
167
|
-
- lib/money_extensions/extensions.rb
|
202
|
+
- lib/money_extensions/html_format.rb
|
168
203
|
- lib/money_extensions/integer.rb
|
169
204
|
- lib/money_extensions/money_field.rb
|
170
205
|
- lib/money_extensions/numeric.rb
|
206
|
+
- lib/money_extensions/split_between.rb
|
171
207
|
- lib/money_extensions/string.rb
|
172
208
|
- lib/money_extensions/version.rb
|
173
209
|
- money_extensions.gemspec
|
174
210
|
- rails/init.rb
|
175
211
|
- spec/big_decimal_spec.rb
|
212
|
+
- spec/html_format_spec.rb
|
176
213
|
- spec/money_field_spec.rb
|
177
214
|
- spec/money_spec.rb
|
178
215
|
- spec/schema.rb
|
@@ -197,13 +234,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
197
234
|
- !ruby/object:Gem::Version
|
198
235
|
version: '0'
|
199
236
|
requirements: []
|
200
|
-
|
201
|
-
rubygems_version: 2.6.14.1
|
237
|
+
rubygems_version: 3.0.3
|
202
238
|
signing_key:
|
203
239
|
specification_version: 4
|
204
240
|
summary: Set of extensions to the money gem used by TravelLink Technology.
|
205
241
|
test_files:
|
206
242
|
- spec/big_decimal_spec.rb
|
243
|
+
- spec/html_format_spec.rb
|
207
244
|
- spec/money_field_spec.rb
|
208
245
|
- spec/money_spec.rb
|
209
246
|
- spec/schema.rb
|
data/gemfiles/rails3.gemfile
DELETED
@@ -1,189 +0,0 @@
|
|
1
|
-
require 'money'
|
2
|
-
|
3
|
-
module Extensions
|
4
|
-
|
5
|
-
def self.included(base)
|
6
|
-
base.class_eval do
|
7
|
-
alias_method :to_s_without_currency_hack, :to_s
|
8
|
-
alias_method :to_s, :to_s_with_currency_hack
|
9
|
-
alias_method :to_d_without_currency_hack, :to_d
|
10
|
-
alias_method :to_d, :to_d_with_currency_hack
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
# Override division -- should not do it, but use split_between
|
15
|
-
def /(*params)
|
16
|
-
raise "Division of money NOT allowed - use 'split_between' to avoid rounding errors"
|
17
|
-
end
|
18
|
-
|
19
|
-
def to_d_with_currency_hack
|
20
|
-
BigDecimal.new("#{cents/100.0}")
|
21
|
-
end
|
22
|
-
|
23
|
-
# Split the money between the specified number - and return an array of money
|
24
|
-
# Remainder in splits are given to the highest value e.g.
|
25
|
-
# $2.00 splits [40, 81, 40] into [49, 102, 49]
|
26
|
-
# $1.01 splits [ 1, 1, 1] into [35, 33, 33]
|
27
|
-
def split_between(params)
|
28
|
-
#if just a number is passed in, then money is split equally
|
29
|
-
if params.is_a?(Integer)
|
30
|
-
divisor = params
|
31
|
-
raise ArgumentError, "Can only split up over a positive number" if divisor < 1
|
32
|
-
|
33
|
-
rounded_split = self.lossy_divide(divisor)
|
34
|
-
results = Array.new(divisor, rounded_split) # Create with 'divisor' num elements
|
35
|
-
|
36
|
-
#if an array of monies is passed in, then split in proportions
|
37
|
-
elsif params.is_a?(Array)
|
38
|
-
|
39
|
-
raise ArgumentError, "Can only split up over at least one ration" if params.empty? && !self.zero?
|
40
|
-
|
41
|
-
|
42
|
-
results = params.map { |p| p.is_a?(::Money) ? p.cents : p }
|
43
|
-
|
44
|
-
total = results.inject(:+)
|
45
|
-
if total.zero?
|
46
|
-
return Array.new(results.size, ::Money.new(0)) if self.zero?
|
47
|
-
raise ArgumentError, "Total of ratios should not be zero! You sent in: #{params.inspect}"
|
48
|
-
end
|
49
|
-
|
50
|
-
results.map! do |ratio|
|
51
|
-
::Money.new((self.cents * (ratio.to_f / total)).round)
|
52
|
-
end
|
53
|
-
else
|
54
|
-
raise "Either a Integer or array has to be passed in for splitting money"
|
55
|
-
end
|
56
|
-
|
57
|
-
# Distribute rounding to max absolute to avoid a $0 amount getting the rounding
|
58
|
-
biggest_value_index = results.index(results.max_by(&:abs))
|
59
|
-
results[biggest_value_index] += self - results.total_money
|
60
|
-
|
61
|
-
return results
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
DEFAULT_FORMAT_RULES = [:html]
|
66
|
-
# HACK COZ WE ARE PRETENDING WE DON'T HAVE CURRENCY!!!
|
67
|
-
#
|
68
|
-
# TODO: Make this not a hack...
|
69
|
-
def to_s_with_currency_hack
|
70
|
-
sprintf("%.2f", cents.to_f / 100) #currency.subunit_to_unit)
|
71
|
-
end
|
72
|
-
|
73
|
-
def inspect
|
74
|
-
inbuilt_inspect_style_id = '%x' % (object_id << 1)
|
75
|
-
"\#<Money:0x#{inbuilt_inspect_style_id} $#{self}>"
|
76
|
-
end
|
77
|
-
|
78
|
-
# Money's default formatted is not flexible enought.
|
79
|
-
# - we don't want it to say 'free' when 0 (not correct for 'discounts' and such)
|
80
|
-
def format(*rules)
|
81
|
-
rules = rules.empty? ? DEFAULT_FORMAT_RULES.dup : rules.flatten
|
82
|
-
|
83
|
-
options = {}
|
84
|
-
rules.each do |rule|
|
85
|
-
if rule.is_a? Hash
|
86
|
-
options = rule
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
html_wrap = rules.include?(:html)
|
91
|
-
|
92
|
-
options[:delimiter] ||= ','
|
93
|
-
options[:separator] ||= '.'
|
94
|
-
|
95
|
-
''.tap do |formatted|
|
96
|
-
formatted << "<span class=\"money #{direction_class}\">" if html_wrap
|
97
|
-
|
98
|
-
rules << :signed if cents < 0
|
99
|
-
|
100
|
-
if rules.include?(:signed)
|
101
|
-
formatted << if cents > 0
|
102
|
-
'+'
|
103
|
-
elsif cents < 0
|
104
|
-
'-'
|
105
|
-
else
|
106
|
-
''
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
no_cents = rules.include?(:no_cents) ||
|
111
|
-
(rules.include?(:hide_zero_cents) && cents % 100 == 0)
|
112
|
-
format_string = no_cents ? "$%d" : "$%.2f"
|
113
|
-
amount = format_string % (cents.abs.to_f / 100)
|
114
|
-
amount.gsub!('.', options[:separator])
|
115
|
-
amount.gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{options[:delimiter]}")
|
116
|
-
formatted << amount
|
117
|
-
|
118
|
-
formatted << "</span>" if html_wrap
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
def direction_class
|
123
|
-
if cents > 0
|
124
|
-
'positive'
|
125
|
-
elsif cents < 0
|
126
|
-
'negative'
|
127
|
-
else
|
128
|
-
'zero'
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
def mark_up(mark_up_definition)
|
133
|
-
mark_up_cents = mark_up_definition.cents || 0
|
134
|
-
rounding_direction = mark_up_definition.rounding_direction.try(:to_sym)
|
135
|
-
multiplier = ((100 + mark_up_definition.percent)/100.0)
|
136
|
-
(self * multiplier).round(mark_up_definition.rounding_cents, rounding_direction) + ::Money.new(mark_up_cents)
|
137
|
-
end
|
138
|
-
|
139
|
-
# money = Money.new(501)
|
140
|
-
# money.round
|
141
|
-
# => 500
|
142
|
-
# money.round(10)
|
143
|
-
# => 510
|
144
|
-
# money.round(1)
|
145
|
-
# => 511
|
146
|
-
|
147
|
-
# money.round(100, 'up')
|
148
|
-
# => 600
|
149
|
-
# money.round(100, 'down')
|
150
|
-
# => 500
|
151
|
-
# money.round(100, 'nearest')
|
152
|
-
# => 500
|
153
|
-
def round(round_to_cents = 100, direction = :nearest)
|
154
|
-
round_to_cents = 100 if round_to_cents.nil?
|
155
|
-
case direction.to_sym
|
156
|
-
when :nearest
|
157
|
-
rounded_cents = (cents + round_to_cents/2) / round_to_cents * round_to_cents
|
158
|
-
when :up
|
159
|
-
rounded_cents = (cents + round_to_cents) / round_to_cents * round_to_cents
|
160
|
-
when :down
|
161
|
-
rounded_cents = (cents) / round_to_cents * round_to_cents
|
162
|
-
else
|
163
|
-
end
|
164
|
-
::Money.new(rounded_cents)
|
165
|
-
end
|
166
|
-
|
167
|
-
def abs
|
168
|
-
if cents >= 0
|
169
|
-
self.clone
|
170
|
-
else
|
171
|
-
::Money.new(0 - cents)
|
172
|
-
end
|
173
|
-
end
|
174
|
-
|
175
|
-
def positive?
|
176
|
-
cents > 0
|
177
|
-
end
|
178
|
-
|
179
|
-
def negative?
|
180
|
-
cents < 0
|
181
|
-
end
|
182
|
-
|
183
|
-
end
|
184
|
-
|
185
|
-
::Money.class_eval do
|
186
|
-
alias_method :lossy_divide, :/
|
187
|
-
end
|
188
|
-
|
189
|
-
::Money.send(:include, Extensions)
|