monetize 0.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/.gitignore +17 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/lib/monetize.rb +135 -0
- data/lib/monetize/core_extensions.rb +3 -0
- data/lib/monetize/core_extensions/numeric.rb +5 -0
- data/lib/monetize/core_extensions/string.rb +9 -0
- data/lib/monetize/core_extensions/symbol.rb +5 -0
- data/lib/monetize/version.rb +3 -0
- data/monetize.gemspec +26 -0
- data/spec/core_extensions_spec.rb +161 -0
- data/spec/monetize_spec.rb +323 -0
- data/spec/spec_helper.rb +3 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c1c2a9a44b80e3d27927f8d5a0771ecd796f7061
|
4
|
+
data.tar.gz: da0255a4102dec917a27f22808b4ec2f6535fa12
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28eb3b256dc924f5d643c61dcd3b17e0f7d9df444c4daca6077b7ac0dff29741149ad1b5ddc55d83e8d12fe79abe45d1c595638f52a77af6db129bbfa59761b3
|
7
|
+
data.tar.gz: 800592844fdfdf4fb66df3855b14c51240a7516f44c687eaea16bd6a7a27d713b41f4a2ea8096e4eb43aa64137e318efbc930921afea5e7e9bbbb90943cc018c
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Shane Emmons
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Monetize
|
2
|
+
|
3
|
+
A library for converting various objects into `Money` objects.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'monetize'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install monetize
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
# Coming Soon
|
23
|
+
```
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/lib/monetize.rb
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
require "money"
|
2
|
+
require "monetize/version"
|
3
|
+
|
4
|
+
module Monetize
|
5
|
+
def self.parse(input, currency = Money.default_currency)
|
6
|
+
input = input.to_s.strip
|
7
|
+
|
8
|
+
computed_currency = if Money.assume_from_symbol && input =~ /^(\$|€|£)/
|
9
|
+
case input
|
10
|
+
when /^\$/ then "USD"
|
11
|
+
when /^€/ then "EUR"
|
12
|
+
when /^£/ then "GBP"
|
13
|
+
end
|
14
|
+
else
|
15
|
+
input[/[A-Z]{2,3}/]
|
16
|
+
end
|
17
|
+
|
18
|
+
currency = computed_currency || currency || Money.default_currency
|
19
|
+
currency = Money::Currency.wrap(currency)
|
20
|
+
|
21
|
+
fractional = extract_cents(input, currency)
|
22
|
+
Money.new(fractional, currency)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.from_string(value, currency = Money.default_currency)
|
26
|
+
value = BigDecimal.new(value.to_s)
|
27
|
+
from_bigdecimal(value, currency)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.from_fixnum(value, currency = Money.default_currency)
|
31
|
+
currency = Money::Currency.wrap(currency)
|
32
|
+
value = value * currency.subunit_to_unit
|
33
|
+
Money.new(value, currency)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.from_float(value, currency = Money.default_currency)
|
37
|
+
value = BigDecimal.new(value.to_s)
|
38
|
+
from_bigdecimal(value, currency)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.from_bigdecimal(value, currency = Money.default_currency)
|
42
|
+
currency = Money::Currency.wrap(currency)
|
43
|
+
value = value * currency.subunit_to_unit
|
44
|
+
value = value.round unless Money.infinite_precision
|
45
|
+
Money.new(value, currency)
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.from_numeric(value, currency = Money.default_currency)
|
49
|
+
case value
|
50
|
+
when Fixnum
|
51
|
+
from_fixnum(value, currency)
|
52
|
+
when Numeric
|
53
|
+
value = BigDecimal.new(value.to_s)
|
54
|
+
from_bigdecimal(value, currency)
|
55
|
+
else
|
56
|
+
raise ArgumentError, "'value' should be a type of Numeric"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.extract_cents(input, currency = Money.default_currency)
|
61
|
+
num = input.gsub(/[^\d.,'-]/, '')
|
62
|
+
|
63
|
+
negative = num =~ /^-|-$/ ? true : false
|
64
|
+
|
65
|
+
decimal_char = currency.decimal_mark
|
66
|
+
|
67
|
+
num = num.sub(/^-|-$/, '') if negative
|
68
|
+
|
69
|
+
if num.include?('-')
|
70
|
+
raise ArgumentError, "Invalid currency amount (hyphen)"
|
71
|
+
end
|
72
|
+
|
73
|
+
num.chop! if num.match(/[\.|,]$/)
|
74
|
+
|
75
|
+
used_delimiters = num.scan(/[^\d]/)
|
76
|
+
|
77
|
+
case used_delimiters.uniq.length
|
78
|
+
when 0
|
79
|
+
major, minor = num, 0
|
80
|
+
when 2
|
81
|
+
thousands_separator, decimal_mark = used_delimiters.uniq
|
82
|
+
|
83
|
+
major, minor = num.gsub(thousands_separator, '').split(decimal_mark)
|
84
|
+
min = 0 unless min
|
85
|
+
when 1
|
86
|
+
decimal_mark = used_delimiters.first
|
87
|
+
|
88
|
+
if decimal_char == decimal_mark
|
89
|
+
major, minor = num.split(decimal_char)
|
90
|
+
else
|
91
|
+
if num.scan(decimal_mark).length > 1 # multiple matches; treat as decimal_mark
|
92
|
+
major, minor = num.gsub(decimal_mark, ''), 0
|
93
|
+
else
|
94
|
+
possible_major, possible_minor = num.split(decimal_mark)
|
95
|
+
possible_major ||= "0"
|
96
|
+
possible_minor ||= "00"
|
97
|
+
|
98
|
+
if possible_minor.length != 3 # thousands_separator
|
99
|
+
major, minor = possible_major, possible_minor
|
100
|
+
else
|
101
|
+
if possible_major.length > 3
|
102
|
+
major, minor = possible_major, possible_minor
|
103
|
+
else
|
104
|
+
if decimal_mark == '.'
|
105
|
+
major, minor = possible_major, possible_minor
|
106
|
+
else
|
107
|
+
major, minor = "#{possible_major}#{possible_minor}", 0
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
else
|
114
|
+
raise ArgumentError, "Invalid currency amount"
|
115
|
+
end
|
116
|
+
|
117
|
+
cents = major.to_i * currency.subunit_to_unit
|
118
|
+
minor = minor.to_s
|
119
|
+
minor = if minor.size < currency.decimal_places
|
120
|
+
(minor + ("0" * currency.decimal_places))[0,currency.decimal_places].to_i
|
121
|
+
elsif minor.size > currency.decimal_places
|
122
|
+
if minor[currency.decimal_places,1].to_i >= 5
|
123
|
+
minor[0,currency.decimal_places].to_i+1
|
124
|
+
else
|
125
|
+
minor[0,currency.decimal_places].to_i
|
126
|
+
end
|
127
|
+
else
|
128
|
+
minor.to_i
|
129
|
+
end
|
130
|
+
|
131
|
+
cents += minor
|
132
|
+
|
133
|
+
negative ? cents * -1 : cents
|
134
|
+
end
|
135
|
+
end
|
data/monetize.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require "monetize/version"
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "monetize"
|
8
|
+
spec.version = Monetize::VERSION
|
9
|
+
spec.authors = ["Shane Emmons"]
|
10
|
+
spec.email = ["shane@emmons.io"]
|
11
|
+
spec.description = "A library for converting various objects into `Money` objects."
|
12
|
+
spec.summary = "A library for converting various objects into `Money` objects."
|
13
|
+
spec.homepage = "https://github.com/RubyMoney/monetize"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_dependency "money", "~> 6.0"
|
22
|
+
|
23
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
24
|
+
spec.add_development_dependency "rake"
|
25
|
+
spec.add_development_dependency "rspec", "~> 3.0.0.beta1"
|
26
|
+
end
|
@@ -0,0 +1,161 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "monetize"
|
3
|
+
require "monetize/core_extensions"
|
4
|
+
|
5
|
+
describe Monetize, "core extensions" do
|
6
|
+
describe Numeric do
|
7
|
+
describe "#to_money" do
|
8
|
+
it "work as documented" do
|
9
|
+
money = 1234.to_money
|
10
|
+
expect(money.cents).to eq 1234_00
|
11
|
+
expect(money.currency).to eq Money.default_currency
|
12
|
+
|
13
|
+
money = 100.37.to_money
|
14
|
+
expect(money.cents).to eq 100_37
|
15
|
+
expect(money.currency).to eq Money.default_currency
|
16
|
+
|
17
|
+
money = BigDecimal.new('1234').to_money
|
18
|
+
expect(money.cents).to eq 1234_00
|
19
|
+
expect(money.currency).to eq Money.default_currency
|
20
|
+
end
|
21
|
+
|
22
|
+
it "accepts optional currency" do
|
23
|
+
expect(1234.to_money('USD')).to eq Money.new(123400, 'USD')
|
24
|
+
expect(1234.to_money('EUR')).to eq Money.new(123400, 'EUR')
|
25
|
+
end
|
26
|
+
|
27
|
+
it "respects :subunit_to_unit currency property" do
|
28
|
+
expect(10.to_money('USD')).to eq Money.new(10_00, 'USD')
|
29
|
+
expect(10.to_money('TND')).to eq Money.new(10_000, 'TND')
|
30
|
+
expect(10.to_money('CLP')).to eq Money.new(10, 'CLP')
|
31
|
+
end
|
32
|
+
|
33
|
+
specify "GH-15" do
|
34
|
+
amount = 555.55.to_money
|
35
|
+
expect(amount).to eq Money.new(55555)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe String do
|
41
|
+
describe "#to_money" do
|
42
|
+
|
43
|
+
STRING_TO_MONEY = {
|
44
|
+
"20.15" => Money.new(20_15) ,
|
45
|
+
"100" => Money.new(100_00) ,
|
46
|
+
"100.37" => Money.new(100_37) ,
|
47
|
+
"100,37" => Money.new(100_37) ,
|
48
|
+
"100 000" => Money.new(100_000_00) ,
|
49
|
+
"100,000.00" => Money.new(100_000_00) ,
|
50
|
+
"1,000" => Money.new(1_000_00) ,
|
51
|
+
"-1,000" => Money.new(-1_000_00) ,
|
52
|
+
"1,000.5" => Money.new(1_000_50) ,
|
53
|
+
"1,000.51" => Money.new(1_000_51) ,
|
54
|
+
"1,000.505" => Money.new(1_000_51) ,
|
55
|
+
"1,000.504" => Money.new(1_000_50) ,
|
56
|
+
"1,000.0000" => Money.new(1_000_00) ,
|
57
|
+
"1,000.5000" => Money.new(1_000_50) ,
|
58
|
+
"1,000.5099" => Money.new(1_000_51) ,
|
59
|
+
"1.550" => Money.new(1_55) ,
|
60
|
+
"25." => Money.new(25_00) ,
|
61
|
+
".75" => Money.new(75) ,
|
62
|
+
|
63
|
+
"100 USD" => Money.new(100_00, "USD") ,
|
64
|
+
"-100 USD" => Money.new(-100_00, "USD") ,
|
65
|
+
"100 EUR" => Money.new(100_00, "EUR") ,
|
66
|
+
"100.37 EUR" => Money.new(100_37, "EUR") ,
|
67
|
+
"100,37 EUR" => Money.new(100_37, "EUR") ,
|
68
|
+
"100,000.00 USD" => Money.new(100_000_00, "USD") ,
|
69
|
+
"100.000,00 EUR" => Money.new(100_000_00, "EUR") ,
|
70
|
+
"1,000 USD" => Money.new(1_000_00, "USD") ,
|
71
|
+
"-1,000 USD" => Money.new(-1_000_00, "USD") ,
|
72
|
+
"1,000.5500 USD" => Money.new(1_000_55, "USD") ,
|
73
|
+
"-1,000.6500 USD" => Money.new(-1_000_65, "USD") ,
|
74
|
+
"1.550 USD" => Money.new(1_55, "USD") ,
|
75
|
+
|
76
|
+
"USD 100" => Money.new(100_00, "USD") ,
|
77
|
+
"EUR 100" => Money.new(100_00, "EUR") ,
|
78
|
+
"EUR 100.37" => Money.new(100_37, "EUR") ,
|
79
|
+
"CAD -100.37" => Money.new(-100_37, "CAD") ,
|
80
|
+
"EUR 100,37" => Money.new(100_37, "EUR") ,
|
81
|
+
"EUR -100,37" => Money.new(-100_37, "EUR") ,
|
82
|
+
"USD 100,000.00" => Money.new(100_000_00, "USD") ,
|
83
|
+
"EUR 100.000,00" => Money.new(100_000_00, "EUR") ,
|
84
|
+
"USD 1,000" => Money.new(1_000_00, "USD") ,
|
85
|
+
"USD -1,000" => Money.new(-1_000_00, "USD") ,
|
86
|
+
"USD 1,000.9000" => Money.new(1_000_90, "USD") ,
|
87
|
+
"USD -1,000.090" => Money.new(-1_000_09, "USD") ,
|
88
|
+
"USD 1.5500" => Money.new(1_55, "USD") ,
|
89
|
+
|
90
|
+
"$100 USD" => Money.new(100_00, "USD") ,
|
91
|
+
"$1,194.59 USD" => Money.new(1_194_59, "USD") ,
|
92
|
+
"$-1,955 USD" => Money.new(-1_955_00, "USD") ,
|
93
|
+
"$1,194.5900 USD" => Money.new(1_194_59, "USD") ,
|
94
|
+
"$-1,955.000 USD" => Money.new(-1_955_00, "USD") ,
|
95
|
+
"$1.99000 USD" => Money.new(1_99, "USD") ,
|
96
|
+
}
|
97
|
+
|
98
|
+
it "works as documented" do
|
99
|
+
STRING_TO_MONEY.each do |string, money|
|
100
|
+
expect(string.to_money).to eq money
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "coerces input to string" do
|
105
|
+
expect(Monetize.parse(20, "USD")).to eq Money.new(20_00, "USD")
|
106
|
+
end
|
107
|
+
|
108
|
+
it "accepts optional currency" do
|
109
|
+
expect("10.10".to_money('USD')).to eq Money.new(1010, 'USD')
|
110
|
+
expect("10.10".to_money('EUR')).to eq Money.new(1010, 'EUR')
|
111
|
+
expect("10.10 USD".to_money('USD')).to eq Money.new(1010, 'USD')
|
112
|
+
end
|
113
|
+
|
114
|
+
it "uses parsed currency, even if currency is passed" do
|
115
|
+
expect("10.10 USD".to_money("EUR")).to eq(Money.new(1010, "USD"))
|
116
|
+
end
|
117
|
+
|
118
|
+
it "ignores unrecognized data" do
|
119
|
+
expect("hello 2000 world".to_money).to eq Money.new(2000_00)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "respects :subunit_to_unit currency property" do
|
123
|
+
expect("1".to_money("USD")).to eq Money.new(1_00, "USD")
|
124
|
+
expect("1".to_money("TND")).to eq Money.new(1_000, "TND")
|
125
|
+
expect("1".to_money("CLP")).to eq Money.new(1, "CLP")
|
126
|
+
expect("1.5".to_money("KWD").cents).to eq 1500
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe "#to_currency" do
|
131
|
+
it "converts String to Currency" do
|
132
|
+
expect("USD".to_currency).to eq Money::Currency.new("USD")
|
133
|
+
expect("EUR".to_currency).to eq Money::Currency.new("EUR")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "raises Money::Currency::UnknownCurrency with unknown Currency" do
|
137
|
+
expect { "XXX".to_currency }.to raise_error(Money::Currency::UnknownCurrency)
|
138
|
+
expect { " ".to_currency }.to raise_error(Money::Currency::UnknownCurrency)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe Symbol do
|
144
|
+
describe "#to_currency" do
|
145
|
+
it "converts Symbol to Currency" do
|
146
|
+
expect(:usd.to_currency).to eq Money::Currency.new("USD")
|
147
|
+
expect(:ars.to_currency).to eq Money::Currency.new("ARS")
|
148
|
+
end
|
149
|
+
|
150
|
+
it "is case-insensitive" do
|
151
|
+
expect(:EUR.to_currency).to eq Money::Currency.new("EUR")
|
152
|
+
end
|
153
|
+
|
154
|
+
it "raises Money::Currency::UnknownCurrency with unknown Currency" do
|
155
|
+
expect { :XXX.to_currency }.to raise_error(Money::Currency::UnknownCurrency)
|
156
|
+
expect { :" ".to_currency }.to raise_error(Money::Currency::UnknownCurrency)
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require "monetize"
|
3
|
+
|
4
|
+
describe Monetize do
|
5
|
+
|
6
|
+
bar = '{ "priority": 1, "iso_code": "BAR", "iso_numeric": "840", "name": "Dollar with 4 decimal places", "symbol": "$", "subunit": "Cent", "subunit_to_unit": 10000, "symbol_first": true, "html_entity": "$", "decimal_mark": ".", "thousands_separator": "," }'
|
7
|
+
eu4 = '{ "priority": 1, "iso_code": "EU4", "iso_numeric": "841", "name": "Euro with 4 decimal places", "symbol": "€", "subunit": "Cent", "subunit_to_unit": 10000, "symbol_first": true, "html_entity": "€", "decimal_mark": ",", "thousands_separator": "." }'
|
8
|
+
|
9
|
+
describe ".parse" do
|
10
|
+
|
11
|
+
it "parses european-formatted inputs under 10EUR" do
|
12
|
+
expect(Monetize.parse('EUR 5,95')).to eq Money.new(595, 'EUR')
|
13
|
+
end
|
14
|
+
|
15
|
+
it "parses european-formatted inputs with multiple thousands-seperators" do
|
16
|
+
expect(Monetize.parse('EUR 1.234.567,89')).to eq Money.new(123456789, 'EUR')
|
17
|
+
expect(Monetize.parse('EUR 1.111.234.567,89')).to eq Money.new(111123456789, 'EUR')
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'currency assumption' do
|
21
|
+
context 'opted in' do
|
22
|
+
before do
|
23
|
+
Money.assume_from_symbol = true
|
24
|
+
end
|
25
|
+
|
26
|
+
it "parses formatted inputs with the currency passed as a symbol" do
|
27
|
+
original_currency = Money.default_currency
|
28
|
+
Money.default_currency = "EUR"
|
29
|
+
Money.default_currency = original_currency
|
30
|
+
expect(Monetize.parse("€5.95")).to eq Money.new(595, 'EUR')
|
31
|
+
expect(Monetize.parse(" €5.95 ")).to eq Money.new(595, 'EUR')
|
32
|
+
expect(Monetize.parse("£9.99")).to eq Money.new(999, 'GBP')
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should assume default currency if not a recognised symbol' do
|
36
|
+
expect(Monetize.parse("L9.99")).to eq Money.new(999, 'USD')
|
37
|
+
end
|
38
|
+
end
|
39
|
+
context 'opted out' do
|
40
|
+
before do
|
41
|
+
Money.assume_from_symbol = false
|
42
|
+
end
|
43
|
+
it "parses formatted inputs with the currency passed as a symbol but ignores the symbol" do
|
44
|
+
expect(Monetize.parse("$5.95")).to eq Money.new(595, 'USD')
|
45
|
+
expect(Monetize.parse("€5.95")).to eq Money.new(595, 'USD')
|
46
|
+
expect(Monetize.parse(" €5.95 ")).to eq Money.new(595, 'USD')
|
47
|
+
expect(Monetize.parse("£9.99")).to eq Money.new(999, 'USD')
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
it 'should opt out by default' do
|
52
|
+
expect(Money.assume_from_symbol).to be false
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "parses USD-formatted inputs under $10" do
|
57
|
+
five_ninety_five = Money.new(595, 'USD')
|
58
|
+
|
59
|
+
expect(Monetize.parse(5.95)).to eq five_ninety_five
|
60
|
+
expect(Monetize.parse('5.95')).to eq five_ninety_five
|
61
|
+
expect(Monetize.parse('$5.95')).to eq five_ninety_five
|
62
|
+
expect(Monetize.parse("\n $5.95 \n")).to eq five_ninety_five
|
63
|
+
expect(Monetize.parse('$ 5.95')).to eq five_ninety_five
|
64
|
+
expect(Monetize.parse('$5.95 ea.')).to eq five_ninety_five
|
65
|
+
expect(Monetize.parse('$5.95, each')).to eq five_ninety_five
|
66
|
+
end
|
67
|
+
|
68
|
+
it "parses USD-formatted inputs with multiple thousands-seperators" do
|
69
|
+
expect(Monetize.parse('1,234,567.89')).to eq Money.new(123456789, 'USD')
|
70
|
+
expect(Monetize.parse('1,111,234,567.89')).to eq Money.new(111123456789, 'USD')
|
71
|
+
end
|
72
|
+
|
73
|
+
it "does not return a price if there is a price range" do
|
74
|
+
expect { Monetize.parse('$5.95-10.95') }.to raise_error ArgumentError
|
75
|
+
expect { Monetize.parse('$5.95 - 10.95') }.to raise_error ArgumentError
|
76
|
+
expect { Monetize.parse('$5.95 - $10.95') }.to raise_error ArgumentError
|
77
|
+
end
|
78
|
+
|
79
|
+
it "does not return a price for completely invalid input" do
|
80
|
+
expect(Monetize.parse(nil)).to eq Money.empty
|
81
|
+
expect(Monetize.parse('hellothere')).to eq Money.empty
|
82
|
+
expect(Monetize.parse('')).to eq Money.empty
|
83
|
+
end
|
84
|
+
|
85
|
+
it "handles negative inputs" do
|
86
|
+
five_ninety_five = Money.new(-595, 'USD')
|
87
|
+
|
88
|
+
expect(Monetize.parse("$-5.95")).to eq five_ninety_five
|
89
|
+
expect(Monetize.parse("-$5.95")).to eq five_ninety_five
|
90
|
+
expect(Monetize.parse("$5.95-")).to eq five_ninety_five
|
91
|
+
end
|
92
|
+
|
93
|
+
it "raises ArgumentError when unable to detect polarity" do
|
94
|
+
expect { Monetize.parse('-$5.95-') }.to raise_error ArgumentError
|
95
|
+
end
|
96
|
+
|
97
|
+
it "parses correctly strings with exactly 3 decimal digits" do
|
98
|
+
expect(Monetize.parse("6,534", "EUR")).to eq Money.new(653, "EUR")
|
99
|
+
end
|
100
|
+
|
101
|
+
context "custom currencies with 4 decimal places" do
|
102
|
+
before :each do
|
103
|
+
Money::Currency.register(JSON.parse(bar, :symbolize_names => true))
|
104
|
+
Money::Currency.register(JSON.parse(eu4, :symbolize_names => true))
|
105
|
+
end
|
106
|
+
|
107
|
+
after :each do
|
108
|
+
Money::Currency.unregister(JSON.parse(bar, :symbolize_names => true))
|
109
|
+
Money::Currency.unregister(JSON.parse(eu4, :symbolize_names => true))
|
110
|
+
end
|
111
|
+
|
112
|
+
# String#to_money(Currency) is equivalent to Monetize.parse(String, Currency)
|
113
|
+
it "parses strings respecting subunit to unit, decimal and thousands separator" do
|
114
|
+
expect("$0.4".to_money("BAR")).to eq Money.new(4000, "BAR")
|
115
|
+
expect("€0,4".to_money("EU4")).to eq Money.new(4000, "EU4")
|
116
|
+
|
117
|
+
expect("$0.04".to_money("BAR")).to eq Money.new(400, "BAR")
|
118
|
+
expect("€0,04".to_money("EU4")).to eq Money.new(400, "EU4")
|
119
|
+
|
120
|
+
expect("$0.004".to_money("BAR")).to eq Money.new(40, "BAR")
|
121
|
+
expect("€0,004".to_money("EU4")).to eq Money.new(40, "EU4")
|
122
|
+
|
123
|
+
expect("$0.0004".to_money("BAR")).to eq Money.new(4, "BAR")
|
124
|
+
expect("€0,0004".to_money("EU4")).to eq Money.new(4, "EU4")
|
125
|
+
|
126
|
+
expect("$0.0024".to_money("BAR")).to eq Money.new(24, "BAR")
|
127
|
+
expect("€0,0024".to_money("EU4")).to eq Money.new(24, "EU4")
|
128
|
+
|
129
|
+
expect("$0.0324".to_money("BAR")).to eq Money.new(324, "BAR")
|
130
|
+
expect("€0,0324".to_money("EU4")).to eq Money.new(324, "EU4")
|
131
|
+
|
132
|
+
expect("$0.5324".to_money("BAR")).to eq Money.new(5324, "BAR")
|
133
|
+
expect("€0,5324".to_money("EU4")).to eq Money.new(5324, "EU4")
|
134
|
+
|
135
|
+
expect("$6.5324".to_money("BAR")).to eq Money.new(65324, "BAR")
|
136
|
+
expect("€6,5324".to_money("EU4")).to eq Money.new(65324, "EU4")
|
137
|
+
|
138
|
+
expect("$86.5324".to_money("BAR")).to eq Money.new(865324, "BAR")
|
139
|
+
expect("€86,5324".to_money("EU4")).to eq Money.new(865324, "EU4")
|
140
|
+
|
141
|
+
expect("$186.5324".to_money("BAR")).to eq Money.new(1865324, "BAR")
|
142
|
+
expect("€186,5324".to_money("EU4")).to eq Money.new(1865324, "EU4")
|
143
|
+
|
144
|
+
expect("$3,331.0034".to_money("BAR")).to eq Money.new(33310034, "BAR")
|
145
|
+
expect("€3.331,0034".to_money("EU4")).to eq Money.new(33310034, "EU4")
|
146
|
+
|
147
|
+
expect("$8,883,331.0034".to_money("BAR")).to eq Money.new(88833310034, "BAR")
|
148
|
+
expect("€8.883.331,0034".to_money("EU4")).to eq Money.new(88833310034, "EU4")
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
describe ".from_string" do
|
154
|
+
it "converts given amount to cents" do
|
155
|
+
expect(Monetize.from_string("1")).to eq Money.new(1_00)
|
156
|
+
expect(Monetize.from_string("1")).to eq Money.new(1_00, "USD")
|
157
|
+
expect(Monetize.from_string("1", "EUR")).to eq Money.new(1_00, "EUR")
|
158
|
+
end
|
159
|
+
|
160
|
+
it "respects :subunit_to_unit currency property" do
|
161
|
+
expect(Monetize.from_string("1", "USD")).to eq Money.new(1_00, "USD")
|
162
|
+
expect(Monetize.from_string("1", "TND")).to eq Money.new(1_000, "TND")
|
163
|
+
expect(Monetize.from_string("1", "CLP")).to eq Money.new(1, "CLP")
|
164
|
+
end
|
165
|
+
|
166
|
+
it "accepts a currency options" do
|
167
|
+
m = Monetize.from_string("1")
|
168
|
+
expect(m.currency).to eq Money.default_currency
|
169
|
+
|
170
|
+
m = Monetize.from_string("1", Money::Currency.wrap("EUR"))
|
171
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
172
|
+
|
173
|
+
m = Monetize.from_string("1", "EUR")
|
174
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
describe ".from_fixnum" do
|
179
|
+
it "converts given amount to cents" do
|
180
|
+
expect(Monetize.from_fixnum(1)).to eq Money.new(1_00)
|
181
|
+
expect(Monetize.from_fixnum(1)).to eq Money.new(1_00, "USD")
|
182
|
+
expect(Monetize.from_fixnum(1, "EUR")).to eq Money.new(1_00, "EUR")
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should respect :subunit_to_unit currency property" do
|
186
|
+
expect(Monetize.from_fixnum(1, "USD")).to eq Money.new(1_00, "USD")
|
187
|
+
expect(Monetize.from_fixnum(1, "TND")).to eq Money.new(1_000, "TND")
|
188
|
+
expect(Monetize.from_fixnum(1, "CLP")).to eq Money.new(1, "CLP")
|
189
|
+
end
|
190
|
+
|
191
|
+
it "accepts a currency options" do
|
192
|
+
m = Monetize.from_fixnum(1)
|
193
|
+
expect(m.currency).to eq Money.default_currency
|
194
|
+
|
195
|
+
m = Monetize.from_fixnum(1, Money::Currency.wrap("EUR"))
|
196
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
197
|
+
|
198
|
+
m = Monetize.from_fixnum(1, "EUR")
|
199
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
describe ".from_float" do
|
204
|
+
it "converts given amount to cents" do
|
205
|
+
expect(Monetize.from_float(1.2)).to eq Money.new(1_20)
|
206
|
+
expect(Monetize.from_float(1.2)).to eq Money.new(1_20, "USD")
|
207
|
+
expect(Monetize.from_float(1.2, "EUR")).to eq Money.new(1_20, "EUR")
|
208
|
+
end
|
209
|
+
|
210
|
+
it "respects :subunit_to_unit currency property" do
|
211
|
+
expect(Monetize.from_float(1.2, "USD")).to eq Money.new(1_20, "USD")
|
212
|
+
expect(Monetize.from_float(1.2, "TND")).to eq Money.new(1_200, "TND")
|
213
|
+
expect(Monetize.from_float(1.2, "CLP")).to eq Money.new(1, "CLP")
|
214
|
+
end
|
215
|
+
|
216
|
+
it "accepts a currency options" do
|
217
|
+
m = Monetize.from_float(1.2)
|
218
|
+
expect(m.currency).to eq Money.default_currency
|
219
|
+
|
220
|
+
m = Monetize.from_float(1.2, Money::Currency.wrap("EUR"))
|
221
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
222
|
+
|
223
|
+
m = Monetize.from_float(1.2, "EUR")
|
224
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
describe ".from_bigdecimal" do
|
229
|
+
it "converts given amount to cents" do
|
230
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"))).to eq Money.new(1_00)
|
231
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"))).to eq Money.new(1_00, "USD")
|
232
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"), "EUR")).to eq Money.new(1_00, "EUR")
|
233
|
+
end
|
234
|
+
|
235
|
+
it "respects :subunit_to_unit currency property" do
|
236
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"), "USD")).to eq Money.new(1_00, "USD")
|
237
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"), "TND")).to eq Money.new(1_000, "TND")
|
238
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1"), "CLP")).to eq Money.new(1, "CLP")
|
239
|
+
end
|
240
|
+
|
241
|
+
it "accepts a currency options" do
|
242
|
+
m = Monetize.from_bigdecimal(BigDecimal.new("1"))
|
243
|
+
expect(m.currency).to eq Money.default_currency
|
244
|
+
|
245
|
+
m = Monetize.from_bigdecimal(BigDecimal.new("1"), Money::Currency.wrap("EUR"))
|
246
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
247
|
+
|
248
|
+
m = Monetize.from_bigdecimal(BigDecimal.new("1"), "EUR")
|
249
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
250
|
+
end
|
251
|
+
|
252
|
+
context "infinite_precision = true" do
|
253
|
+
before do
|
254
|
+
Money.infinite_precision = true
|
255
|
+
end
|
256
|
+
|
257
|
+
after do
|
258
|
+
Money.infinite_precision = false
|
259
|
+
end
|
260
|
+
|
261
|
+
it "keeps precision" do
|
262
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1.23456"))).to eq Money.new(123.456)
|
263
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("-1.23456"))).to eq Money.new(-123.456)
|
264
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1.23456"))).to eq Money.new(123.456, "USD")
|
265
|
+
expect(Monetize.from_bigdecimal(BigDecimal.new("1.23456"), "EUR")).to eq Money.new(123.456, "EUR")
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
describe ".from_numeric" do
|
271
|
+
it "converts given amount to cents" do
|
272
|
+
expect(Monetize.from_numeric(1)).to eq Money.new(1_00)
|
273
|
+
expect(Monetize.from_numeric(1.0)).to eq Money.new(1_00)
|
274
|
+
expect(Monetize.from_numeric(BigDecimal.new("1"))).to eq Money.new(1_00)
|
275
|
+
end
|
276
|
+
|
277
|
+
it "raises ArgumentError with unsupported argument" do
|
278
|
+
expect { Monetize.from_numeric("100") }.to raise_error(ArgumentError)
|
279
|
+
end
|
280
|
+
|
281
|
+
it "optimizes workload" do
|
282
|
+
expect(Monetize).to receive(:from_fixnum).with(1, "USD").and_return(Money.new(1_00, "USD"))
|
283
|
+
expect(Monetize.from_numeric(1, "USD")).to eq Money.new(1_00, "USD")
|
284
|
+
expect(Monetize).to receive(:from_bigdecimal).with(BigDecimal.new("1.0"), "USD").and_return(Money.new(1_00, "USD"))
|
285
|
+
expect(Monetize.from_numeric(1.0, "USD")).to eq Money.new(1_00, "USD")
|
286
|
+
end
|
287
|
+
|
288
|
+
it "respects :subunit_to_unit currency property" do
|
289
|
+
expect(Monetize.from_numeric(1, "USD")).to eq Money.new(1_00, "USD")
|
290
|
+
expect(Monetize.from_numeric(1, "TND")).to eq Money.new(1_000, "TND")
|
291
|
+
expect(Monetize.from_numeric(1, "CLP")).to eq Money.new(1, "CLP")
|
292
|
+
end
|
293
|
+
|
294
|
+
it "accepts a bank option" do
|
295
|
+
expect(Monetize.from_numeric(1)).to eq Money.new(1_00)
|
296
|
+
expect(Monetize.from_numeric(1)).to eq Money.new(1_00, "USD")
|
297
|
+
expect(Monetize.from_numeric(1, "EUR")).to eq Money.new(1_00, "EUR")
|
298
|
+
end
|
299
|
+
|
300
|
+
it "accepts a currency options" do
|
301
|
+
m = Monetize.from_numeric(1)
|
302
|
+
expect(m.currency).to eq Money.default_currency
|
303
|
+
|
304
|
+
m = Monetize.from_numeric(1, Money::Currency.wrap("EUR"))
|
305
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
306
|
+
|
307
|
+
m = Monetize.from_numeric(1, "EUR")
|
308
|
+
expect(m.currency).to eq Money::Currency.wrap("EUR")
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
describe ".extract_cents" do
|
313
|
+
it "correctly treats pipe marks '|' in input (regression test)" do
|
314
|
+
expect(Monetize.extract_cents('100|0')).to eq Monetize.extract_cents('100!0')
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
context "given the same inputs to .parse and .from_*" do
|
319
|
+
it "gives the same results" do
|
320
|
+
expect(4.635.to_money).to eq "4.635".to_money
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: monetize
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Shane Emmons
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-12-29 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: money
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bundler
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.3'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
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: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 3.0.0.beta1
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 3.0.0.beta1
|
69
|
+
description: A library for converting various objects into `Money` objects.
|
70
|
+
email:
|
71
|
+
- shane@emmons.io
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- .gitignore
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/monetize.rb
|
82
|
+
- lib/monetize/core_extensions.rb
|
83
|
+
- lib/monetize/core_extensions/numeric.rb
|
84
|
+
- lib/monetize/core_extensions/string.rb
|
85
|
+
- lib/monetize/core_extensions/symbol.rb
|
86
|
+
- lib/monetize/version.rb
|
87
|
+
- monetize.gemspec
|
88
|
+
- spec/core_extensions_spec.rb
|
89
|
+
- spec/monetize_spec.rb
|
90
|
+
- spec/spec_helper.rb
|
91
|
+
homepage: https://github.com/RubyMoney/monetize
|
92
|
+
licenses:
|
93
|
+
- MIT
|
94
|
+
metadata: {}
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - '>='
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '>='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: '0'
|
109
|
+
requirements: []
|
110
|
+
rubyforge_project:
|
111
|
+
rubygems_version: 2.0.14
|
112
|
+
signing_key:
|
113
|
+
specification_version: 4
|
114
|
+
summary: A library for converting various objects into `Money` objects.
|
115
|
+
test_files:
|
116
|
+
- spec/core_extensions_spec.rb
|
117
|
+
- spec/monetize_spec.rb
|
118
|
+
- spec/spec_helper.rb
|