mroch-BigMoney 0.1.2 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+
@@ -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
+
@@ -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
- end
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.2
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-08-09 00:00:00 -07:00
12
+ date: 2008-10-20 00:00:00 -07:00
13
13
  default_executable:
14
- dependencies: []
15
-
16
- description: Represents an amount of money in a particular currency. Backed by BigDecimal, so is safe from float rounding errors.
17
- email: mroch@cmu.edu
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
- - Rakefile
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
- has_rdoc: false
36
- homepage: http://github.com/mroch/bigmoney
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