mroch-BigMoney 0.1.2 → 0.2.1
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.
- data/History.txt +4 -0
- data/Manifest.txt +10 -0
- data/Rakefile +6 -1
- data/bigmoney.gemspec +29 -24
- data/lib/big_money.rb +5 -1
- data/lib/big_money/big_money.rb +41 -24
- data/lib/big_money/currency.rb +75 -0
- data/lib/big_money/currency/iso4217.rb +1043 -0
- data/lib/big_money/exchange.rb +47 -0
- data/lib/big_money/exchange/yahoo.rb +32 -0
- data/rakelib/cultivate.rake +7 -0
- data/rakelib/iso4217.rake +16 -0
- data/rakelib/iso4217.rb +46 -0
- data/rakelib/iso4217.rb.erb +13 -0
- data/test/test_big_money.rb +35 -17
- data/test/test_currency.rb +23 -0
- data/test/test_exchange.rb +21 -0
- metadata +42 -17
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'bigdecimal'
|
2
|
+
|
3
|
+
class BigMoney
|
4
|
+
|
5
|
+
# Find the exchange rate between two currencies.
|
6
|
+
#
|
7
|
+
# Be aware no caching is done at all at the moment.
|
8
|
+
class Exchange
|
9
|
+
class ExchangeError < StandardError; end
|
10
|
+
class ConversionError < ExchangeError; end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
@@services = []
|
14
|
+
def inherited(service) #:nodoc:
|
15
|
+
@@services << service
|
16
|
+
end
|
17
|
+
|
18
|
+
# Fetch the exchange rate between two currencies. The arguments may be anything that BigMoney::Currency can
|
19
|
+
# parse. The rate is returned as a BigDecimal.
|
20
|
+
def rate(from, to)
|
21
|
+
exchange = [from, to].map do |c|
|
22
|
+
Currency.parse(c) or raise BigMoney::UnknownCurrency
|
23
|
+
end
|
24
|
+
return BigDecimal(1.to_s) if exchange.uniq.length == 1
|
25
|
+
|
26
|
+
service = @@services.reverse.find do |service|
|
27
|
+
!!exchange.reject{|c| service.currencies.include?(c)}
|
28
|
+
end
|
29
|
+
|
30
|
+
service or raise ConversionError # TODO: Message?
|
31
|
+
BigDecimal.new(service.read_rate(*exchange).to_s)
|
32
|
+
end
|
33
|
+
|
34
|
+
protected
|
35
|
+
# Exchange rate from the first currency to the second.
|
36
|
+
def read_rate(from, to)
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
# An array of supported currencies.
|
41
|
+
def currencies
|
42
|
+
raise NotImplementedError
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end # Exchange
|
46
|
+
|
47
|
+
end # Money
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
|
3
|
+
class BigMoney
|
4
|
+
class Exchange
|
5
|
+
|
6
|
+
# Yahoo finance exchange service.
|
7
|
+
#
|
8
|
+
# http://finance.yahoo.com
|
9
|
+
class Yahoo < Exchange
|
10
|
+
class << self
|
11
|
+
protected
|
12
|
+
def read_rate(from, to)
|
13
|
+
s = [from, to].map{|c| c.code}.join
|
14
|
+
open("http://download.finance.yahoo.com/d/quotes.csv?s=#{s}=X&f=l1&e=.csv").read.strip rescue nil
|
15
|
+
end
|
16
|
+
|
17
|
+
def currencies
|
18
|
+
%w{
|
19
|
+
ALL DZD XAL ARS AWG AUD BSD BHD BDT BBD BYR BZD BMD BTN BOB BWP BRL GBP BND BGN BIF KHR CAD CVE KYD XOF XAF
|
20
|
+
CLP CNY COP KMF XCP CRC HRK CUP CYP CZK DKK DJF DOP XCD ECS EGP SVC ERN EEK ETB EUR FKP FJD GMD GHC GIP XAU
|
21
|
+
GTQ GNF GYD HTG HNL HKD HUF ISK INR IDR IRR IQD ILS JMD JPY JOD KZT KES KRW KWD LAK LVL LBP LSL LRD LYD LTL
|
22
|
+
MOP MKD MWK MYR MVR MTL MRO MUR MXN MDL MNT MAD MMK NAD NPR ANG TRY NZD NIO NGN KPW NOK OMR XPF PKR XPD PAB
|
23
|
+
PGK PYG PEN PHP XPT PLN QAR RON RUB RWF WST STD SAR SCR SLL XAG SGD SKK SIT SBD SOS ZAR LKR SHP SDD SZL SEK
|
24
|
+
CHF SYP TWD TZS THB TOP TTD TND USD AED UGX UAH UYU VUV VEB VND YER ZMK ZWD
|
25
|
+
}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end # Yahoo
|
29
|
+
|
30
|
+
end # Exchange
|
31
|
+
end # Money
|
32
|
+
|
@@ -0,0 +1,7 @@
|
|
1
|
+
# Only works on unixy type systems.
|
2
|
+
# http://blog.behindlogic.com/2008/10/auto-generate-your-manifest-and-gemspec.html
|
3
|
+
desc 'Rebuild manifest and gemspec.'
|
4
|
+
task :cultivate do
|
5
|
+
system %q{touch Manifest.txt; rake check_manifest | grep -v "(in " | patch}
|
6
|
+
system %q{rake debug_gem | grep -v "(in " > `basename \`pwd\``.gemspec}
|
7
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
namespace :currency do
|
2
|
+
|
3
|
+
desc 'Create ISO 4217 currency classes from wikipedia ISO 4217 table.'
|
4
|
+
task :iso4217 do
|
5
|
+
dirname = File.dirname(__FILE__)
|
6
|
+
gen = File.join(dirname, %w{iso4217.rb})
|
7
|
+
lib = File.expand_path(File.join(dirname, %w{.. lib big_money currency iso4217.rb}))
|
8
|
+
require gen
|
9
|
+
modules = BigMoney::Task::ISO4217.get
|
10
|
+
File.open(lib, File::CREAT | File::TRUNC | File::WRONLY) do |f|
|
11
|
+
f.write modules
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end # :currency
|
16
|
+
|
data/rakelib/iso4217.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'hpricot'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'erubis'
|
4
|
+
|
5
|
+
class BigMoney
|
6
|
+
module Task
|
7
|
+
module ISO4217
|
8
|
+
def self.get
|
9
|
+
doc = Hpricot(open('http://en.wikipedia.org/wiki/ISO_4217').read)
|
10
|
+
codes = doc.at('//a#Active_codes').parent
|
11
|
+
codes.name =~ /table/ && break while codes = codes.next_sibling
|
12
|
+
to_ruby(codes) if codes
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.to_ruby(codes)
|
16
|
+
currencies = (codes / 'tr').map{|tr| currency tr}.compact
|
17
|
+
currencies.reject!{|c| c[:code] !~ /[A-Z]{3}/ || c[:name] !~ /\w+/}
|
18
|
+
tmpl = File.read(File.join(File.dirname(__FILE__), 'iso4217.rb.erb'))
|
19
|
+
eruby = Erubis::Eruby.new(tmpl)
|
20
|
+
eruby.result(:currencies => currencies)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.currency(tr)
|
24
|
+
values = (tr / 'td')
|
25
|
+
return unless values && values.size >= 4
|
26
|
+
{
|
27
|
+
:code => code(values),
|
28
|
+
:name => name(values),
|
29
|
+
:offset => offset(values)
|
30
|
+
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.code(chunks)
|
34
|
+
chunks[0].inner_html
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.offset(chunks)
|
38
|
+
chunks[2].inner_html.to_i rescue 0
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.name(chunks)
|
42
|
+
(chunks[3] / 'a').inner_html rescue chunks[3].inner_html
|
43
|
+
end
|
44
|
+
end # ISO4217
|
45
|
+
end # Task
|
46
|
+
end # BigMoney
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class BigMoney
|
2
|
+
class Currency
|
3
|
+
<% currencies.each do |currency| -%>
|
4
|
+
class <%= currency[:code].upcase %> < Currency #:nodoc:
|
5
|
+
self.name = %q{<%= currency[:name] %>}
|
6
|
+
self.code = %q{<%= currency[:code] %>}
|
7
|
+
self.offset = <%= currency[:offset] %>
|
8
|
+
end
|
9
|
+
|
10
|
+
<% end -%>
|
11
|
+
end # Currency
|
12
|
+
end # BigMoney
|
13
|
+
|
data/test/test_big_money.rb
CHANGED
@@ -3,47 +3,58 @@ require 'big_money'
|
|
3
3
|
require 'bigdecimal'
|
4
4
|
|
5
5
|
class TestBigMoney < Test::Unit::TestCase
|
6
|
-
|
6
|
+
|
7
7
|
def test_initialize_with_bigdecimal
|
8
8
|
val = BigDecimal.new("1.005")
|
9
9
|
assert_same val, BigMoney.new(val).amount, 'Should not create a clone of the input'
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
def test_initialize_with_string
|
13
13
|
assert_equal BigDecimal.new("1.005"), BigMoney.new("1.005").amount
|
14
14
|
assert_equal BigDecimal.new("10"), BigMoney.new("10").amount
|
15
15
|
assert_equal BigDecimal.new("0"), BigMoney.new("0").amount
|
16
16
|
assert_equal BigDecimal.new("0"), BigMoney.new("foo").amount
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
def test_initialize_with_integer
|
20
20
|
assert_equal BigDecimal.new("100"), BigMoney.new(100).amount
|
21
21
|
assert_equal BigDecimal.new("0"), BigMoney.new(0).amount
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def test_initialize_with_float
|
25
25
|
assert_equal BigDecimal.new("1.005"), BigMoney.new(1.005).amount
|
26
26
|
assert_equal BigDecimal.new("0"), BigMoney.new(0.0).amount
|
27
27
|
end
|
28
|
-
|
28
|
+
|
29
|
+
def test_initialize_without_currency
|
30
|
+
assert_equal BigMoney::Currency::USD.instance, BigMoney.new(1.23).currency
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_initialize_with_currency
|
34
|
+
assert_equal BigMoney::Currency::AUD.instance, BigMoney.new(1.23, :aud).currency
|
35
|
+
assert_raises BigMoney::UnknownCurrency do
|
36
|
+
BigMoney.new(1.23, :fud)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
29
40
|
def test_eql?
|
30
41
|
assert BigMoney.new("1.00", :usd).eql?(BigMoney.new("1.00", :usd))
|
31
42
|
assert !BigMoney.new("1.00", :usd).eql?(BigMoney.new("1.01", :usd))
|
32
43
|
assert !BigMoney.new("1.00", :usd).eql?(BigMoney.new("1.00", :cad))
|
33
44
|
end
|
34
|
-
|
45
|
+
|
35
46
|
def test_compare
|
36
47
|
m1, m2 = BigMoney.new("1.00", :usd), BigMoney.new("1.50", :usd)
|
37
48
|
assert_equal(-1, (m1 <=> m2))
|
38
49
|
assert_equal(0, (m1 <=> m1))
|
39
50
|
assert_equal(1, (m2 <=> m1))
|
40
|
-
|
51
|
+
|
41
52
|
m3 = BigMoney.new("1.00", :cad)
|
42
53
|
assert_raises BigMoney::UncomparableCurrency do
|
43
54
|
m1 <=> m3
|
44
55
|
end
|
45
56
|
end
|
46
|
-
|
57
|
+
|
47
58
|
def test_add
|
48
59
|
m1, m2, m3 = BigMoney.new(1.00, :usd), BigMoney.new(1.50, :usd), BigMoney.new(0, :usd)
|
49
60
|
assert_equal BigDecimal.new("2.50"), (m1 + m2).amount
|
@@ -55,7 +66,7 @@ class TestBigMoney < Test::Unit::TestCase
|
|
55
66
|
assert_equal BigDecimal.new("5.50"), (m2 + 4).amount
|
56
67
|
assert_equal BigDecimal.new("5.50"), (m2 + 4.00).amount
|
57
68
|
end
|
58
|
-
|
69
|
+
|
59
70
|
def test_subtract
|
60
71
|
m1, m2, m3 = BigMoney.new(1.00, :usd), BigMoney.new(1.50, :usd), BigMoney.new(0, :usd)
|
61
72
|
assert_equal BigDecimal.new("-0.50"), (m1 - m2).amount
|
@@ -65,7 +76,7 @@ class TestBigMoney < Test::Unit::TestCase
|
|
65
76
|
assert_equal BigDecimal.new("-2.50"), (m2 - 4).amount
|
66
77
|
assert_equal BigDecimal.new("-2.50"), (m2 - 4.00).amount
|
67
78
|
end
|
68
|
-
|
79
|
+
|
69
80
|
def test_multiply
|
70
81
|
m1, m2, m3 = BigMoney.new(2.00, :usd), BigMoney.new(1.50, :usd), BigMoney.new(0, :usd)
|
71
82
|
assert_equal BigDecimal.new("4.00"), (m1 * m1).amount
|
@@ -77,7 +88,7 @@ class TestBigMoney < Test::Unit::TestCase
|
|
77
88
|
assert_equal BigDecimal.new("3.00"), (m2 * 2).amount
|
78
89
|
assert_equal BigDecimal.new("3.00"), (m2 * 2.00).amount
|
79
90
|
end
|
80
|
-
|
91
|
+
|
81
92
|
def test_divide
|
82
93
|
m1, m2, m3 = BigMoney.new(2.00, :usd), BigMoney.new(1.50, :usd), BigMoney.new(0, :usd)
|
83
94
|
assert_equal BigDecimal.new("1.00"), (m1 / m1).amount
|
@@ -91,13 +102,13 @@ class TestBigMoney < Test::Unit::TestCase
|
|
91
102
|
assert_equal BigDecimal.new("0.75"), (m2 / 2).amount
|
92
103
|
assert_equal BigDecimal.new("0.75"), (m2 / 2.00).amount
|
93
104
|
end
|
94
|
-
|
105
|
+
|
95
106
|
def test_to_s
|
96
107
|
assert_equal '1.00', BigMoney.new(1).to_s
|
97
108
|
assert_equal '1.50', BigMoney.new(1.5).to_s
|
98
109
|
assert_equal '-11.50', BigMoney.new(-11.5).to_s
|
99
110
|
end
|
100
|
-
|
111
|
+
|
101
112
|
def test_to_formatted_s
|
102
113
|
assert_equal '1.00', BigMoney.new(1).to_formatted_s("%.2f")
|
103
114
|
assert_equal '$1.00', BigMoney.new(1).to_formatted_s("$%.2f")
|
@@ -106,23 +117,30 @@ class TestBigMoney < Test::Unit::TestCase
|
|
106
117
|
assert_equal '$1 USD', BigMoney.new(1).to_formatted_s("$%.0f %s")
|
107
118
|
assert_equal '$1.00 <span class="currency">USD</span>', BigMoney.new(1).to_formatted_s('$%.2f <span class="currency">%s</span>')
|
108
119
|
end
|
109
|
-
|
120
|
+
|
110
121
|
def test_to_i
|
111
122
|
assert_equal(1, BigMoney.new(1).to_i)
|
112
123
|
assert_equal(1, BigMoney.new(1.5).to_i)
|
113
124
|
assert_equal(-11, BigMoney.new(-11.5).to_i)
|
114
125
|
end
|
115
|
-
|
126
|
+
|
116
127
|
def test_to_f
|
117
128
|
assert_in_delta(1.0, BigMoney.new(1).to_f, 0.000001)
|
118
129
|
assert_in_delta(1.5, BigMoney.new(1.5).to_f, 0.000001)
|
119
130
|
assert_in_delta(-11.5, BigMoney.new(-11.5).to_f, 0.000001)
|
120
131
|
end
|
121
|
-
|
132
|
+
|
122
133
|
def test_neg
|
123
134
|
assert_equal BigMoney.new(-1), -BigMoney.new(1)
|
124
135
|
assert_equal BigMoney.new(1), -BigMoney.new(-1)
|
125
136
|
assert_equal BigMoney.new(1), -BigMoney.new(-1)
|
126
137
|
end
|
127
138
|
|
128
|
-
|
139
|
+
def test_currency
|
140
|
+
assert_equal BigMoney::Currency::AUD.instance, BigMoney.currency(:aud)
|
141
|
+
end
|
142
|
+
|
143
|
+
def test_exchange
|
144
|
+
assert BigMoney.new(1.50).exchange(:aud)
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'big_money'
|
3
|
+
|
4
|
+
class TestCurrency < Test::Unit::TestCase
|
5
|
+
def test_parse
|
6
|
+
assert_kind_of BigMoney::Currency, BigMoney::Currency.parse(:aud)
|
7
|
+
assert_nil BigMoney::Currency.parse(:fud)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_compare
|
11
|
+
aud = BigMoney::Currency::AUD.instance
|
12
|
+
assert_operator aud, :==, :aud
|
13
|
+
assert_operator aud, :==, :AUD
|
14
|
+
assert_operator aud, :==, 'aud'
|
15
|
+
assert_operator aud, :==, 'AUD'
|
16
|
+
|
17
|
+
# assert_operator aud, '!=', :fud
|
18
|
+
assert aud != :fud
|
19
|
+
assert aud != :FUD
|
20
|
+
assert aud != 'fud'
|
21
|
+
assert aud != 'FUD'
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'big_money'
|
3
|
+
|
4
|
+
class TestExchange < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@aud = BigMoney.currency(:aud)
|
7
|
+
@usd = BigMoney.currency(:usd)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_rate
|
11
|
+
assert_kind_of BigDecimal, BigMoney::Exchange.rate(@aud, @usd)
|
12
|
+
assert_kind_of BigDecimal, BigMoney::Exchange.rate(:aud, :usd)
|
13
|
+
assert_raise BigMoney::UnknownCurrency do
|
14
|
+
BigMoney::Exchange.rate(:aud, :fud)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_equal_rate
|
19
|
+
assert_equal BigDecimal(1.to_s), BigMoney::Exchange.rate(:usd, :usd)
|
20
|
+
end
|
21
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mroch-BigMoney
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marshall Roch
|
@@ -9,34 +9,57 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-
|
12
|
+
date: 2008-10-20 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: hoe
|
17
|
+
version_requirement:
|
18
|
+
version_requirements: !ruby/object:Gem::Requirement
|
19
|
+
requirements:
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.8.0
|
23
|
+
version:
|
24
|
+
description: Represents an amount of money in a particular currency. Backed by BigDecimal, so is safe from float rounding errors.
|
25
|
+
email:
|
26
|
+
- mroch@cmu.edu
|
18
27
|
executables: []
|
19
28
|
|
20
29
|
extensions: []
|
21
30
|
|
22
|
-
extra_rdoc_files:
|
23
|
-
|
24
|
-
files:
|
25
|
-
- bigmoney.gemspec
|
31
|
+
extra_rdoc_files:
|
26
32
|
- History.txt
|
33
|
+
- LICENSE.txt
|
27
34
|
- Manifest.txt
|
35
|
+
- README.txt
|
36
|
+
files:
|
37
|
+
- History.txt
|
28
38
|
- LICENSE.txt
|
29
|
-
-
|
39
|
+
- Manifest.txt
|
30
40
|
- README.txt
|
41
|
+
- Rakefile
|
42
|
+
- bigmoney.gemspec
|
31
43
|
- lib/big_money.rb
|
32
44
|
- lib/big_money/big_money.rb
|
33
45
|
- lib/big_money/core_extensions.rb
|
46
|
+
- lib/big_money/currency.rb
|
47
|
+
- lib/big_money/currency/iso4217.rb
|
48
|
+
- lib/big_money/exchange.rb
|
49
|
+
- lib/big_money/exchange/yahoo.rb
|
50
|
+
- rakelib/cultivate.rake
|
51
|
+
- rakelib/iso4217.rake
|
52
|
+
- rakelib/iso4217.rb
|
53
|
+
- rakelib/iso4217.rb.erb
|
34
54
|
- test/test_big_money.rb
|
35
|
-
|
36
|
-
|
55
|
+
- test/test_currency.rb
|
56
|
+
- test/test_exchange.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage:
|
37
59
|
post_install_message:
|
38
|
-
rdoc_options:
|
39
|
-
|
60
|
+
rdoc_options:
|
61
|
+
- --main
|
62
|
+
- README.txt
|
40
63
|
require_paths:
|
41
64
|
- lib
|
42
65
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -53,10 +76,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
53
76
|
version:
|
54
77
|
requirements: []
|
55
78
|
|
56
|
-
rubyforge_project:
|
79
|
+
rubyforge_project: bigmoney
|
57
80
|
rubygems_version: 1.2.0
|
58
81
|
signing_key:
|
59
82
|
specification_version: 2
|
60
|
-
summary: Represents an amount of money in a particular currency
|
83
|
+
summary: Represents an amount of money in a particular currency
|
61
84
|
test_files:
|
62
85
|
- test/test_big_money.rb
|
86
|
+
- test/test_currency.rb
|
87
|
+
- test/test_exchange.rb
|