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 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
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
@@ -0,0 +1,3 @@
1
+ require "monetize/core_extensions/numeric"
2
+ require "monetize/core_extensions/string"
3
+ require "monetize/core_extensions/symbol"
@@ -0,0 +1,5 @@
1
+ class Numeric
2
+ def to_money(currency = nil)
3
+ Monetize.from_numeric(self, currency || Money.default_currency)
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ class String
2
+ def to_money(currency = nil)
3
+ Monetize.parse(self, currency)
4
+ end
5
+
6
+ def to_currency
7
+ Money::Currency.new(self)
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Symbol
2
+ def to_currency
3
+ Money::Currency.new(self)
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ module Monetize
2
+ VERSION = "0.1.0"
3
+ 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
@@ -0,0 +1,3 @@
1
+ RSpec.configure do |config|
2
+ config.order = "random"
3
+ end
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