big_money 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,7 @@
1
+ *.sw?
2
+ .DS_Store
3
+ coverage
4
+ rdoc
5
+ pkg
6
+ gems/*
7
+ bin/*
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ # vim: syntax=ruby
2
+ bundle_path 'gems'
3
+ disable_rubygems
4
+ disable_system_gems
5
+
6
+ only :development do
7
+ gem 'jeweler'
8
+ gem 'shoulda'
9
+ gem 'hpricot'
10
+ gem 'erubis'
11
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Marshall Roch
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,102 @@
1
+ = BigMoney
2
+
3
+ == Description
4
+
5
+ Represents an amount of money in a particular currency. Backed by BigDecimal, so it's safe from float rounding errors.
6
+
7
+ == Features
8
+
9
+ * Encapsulates an amount with its currency into a single object.
10
+ * Backed by BigDecimal, so it can store arbitrary-precision values without rounding errors. Useful if you're dealing
11
+ with fractional cents.
12
+ * Sensible currency handling.
13
+ * Supports all ISO-4217 currencies.
14
+ * Optional currency exchange.
15
+ * Optional string parsing.
16
+
17
+ == Problems
18
+
19
+ * Does not implement all of Numeric, so doesn't quite act like a real number.
20
+
21
+ == Todo
22
+
23
+ * Has no Money package API compatibility to ease transition (module patch welcome).
24
+ (http://dist.leetsoft.com/api/money/)
25
+
26
+ == Synopsis
27
+
28
+ === Basic
29
+
30
+ require 'big_money'
31
+
32
+ bm = BigMoney.new('3.99', :aud)
33
+ bm.amount #=> BigDecimal.new('3.99')
34
+ bm.currency #=> BigMoney::Currency::AUD
35
+ bm.to_s #=> '3.99'
36
+ bm.to_s('$.2f') #=> '$3.99'
37
+ bm.to_s('$%.2f %s') #=> '$3.99 AUD'
38
+
39
+ # Not recommended but if you must.
40
+ BigMoney::Currency.default = :aud
41
+
42
+ bm = BigMoney.new('3.99')
43
+ bm.amount #=> BigDecimal.new('3.99')
44
+ bm.currency #=> BigMoney::Currency::AUD
45
+
46
+ bm2 = 1.to_big_money
47
+ bm2.amount #=> BigDecimal.new('3.99')
48
+ bm2.currency #=> BigMoney::Currency::AUD
49
+
50
+ === Exchange
51
+
52
+ require 'big_money'
53
+ require 'big_money/exchange/yahoo' # Use yahoo finance exchange service.
54
+
55
+ bm = BigMoney.new('3.99', :usd)
56
+ bm.amount #=> BigDecimal.new('3.99')
57
+ bm.currency #=> BigMoney::Currency::USD
58
+
59
+ bm2 = bm.exchange(:aud)
60
+ bm.amount #=> BigDecimal.new('5.22')
61
+ bm.currency #=> BigMoney::Currency::AUD
62
+
63
+ === Parser
64
+
65
+ require 'big_money'
66
+ require 'big_money/parser'
67
+
68
+ BigMoney.parse('JPY ¥2500') #=> BigMoney.new('2500', :jpy)
69
+ BigMoney.parse('JPY2500') #=> BigMoney.new('2500', :jpy)
70
+ BigMoney.parse('2500JPY') #=> BigMoney.new('2500', :jpy)
71
+ BigMoney.parse('¥2500JPY') #=> BigMoney.new('2500', :jpy)
72
+
73
+ # ISO-4217 BigMoney::Currency::XXX aka 'No currency' will be used if a currency cannot be parsed along with the
74
+ # amount. If you know the currency and just need the amount XXX is always exchanged 1:1 with any currency.
75
+ bm = BigMoney.parse('¥2500') #=> BigMoney.new('2500', :xxx)
76
+ bm.exchange(:jpy) #=> BigMoney.new('2500', :jpy)
77
+
78
+ === Types
79
+
80
+ require 'big_money'
81
+ require 'big_money/types'
82
+
83
+ # Numeric
84
+ 1.to_big_money(:aud) #=> BigMoney.new(1, :aud)
85
+ 12_123.44.to_big_money(:aud) #=> BigMoney.new('12123.44', :aud)
86
+
87
+ # String
88
+ '1'.to_big_money(:aud) #=> BigMoney.new(1, :aud)
89
+
90
+ == Install
91
+
92
+ * Via git:
93
+
94
+ git clone git://github.com/shanna/big_money.git
95
+
96
+ * Via gem:
97
+
98
+ gem install big_money
99
+
100
+ == License
101
+
102
+ See LICENSE.
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ require 'rake/rdoctask'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gem|
10
+ gem.name = 'big_money'
11
+ gem.summary = %q{BigDecimal backed amount of money in a particular currency.}
12
+ gem.email = ['shane.hanna@gmail.com', 'mroch@cmu.edu']
13
+ gem.homepage = 'http://github.com/shanna/big_money'
14
+ gem.authors = ['Shane Hanna', 'Marshall Roch']
15
+ gem.executables = [] # Only ever bundled development executables in bin/*
16
+ end
17
+ Jeweler::GemcutterTasks.new
18
+ rescue LoadError
19
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
20
+ end
21
+
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ Rake::RDocTask.new do |rdoc|
29
+ if File.exist?('VERSION.yml')
30
+ config = YAML.load(File.read('VERSION.yml'))
31
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
32
+ else
33
+ version = ""
34
+ end
35
+
36
+ rdoc.rdoc_dir = 'rdoc'
37
+ rdoc.title = "big_money #{version}"
38
+ rdoc.rdoc_files.include('README*')
39
+ rdoc.rdoc_files.include('lib/**/*.rb')
40
+ end
41
+
42
+ namespace :currency do
43
+ desc 'Create ISO 4217 currency classes from wikipedia ISO 4217 table.'
44
+ task :iso4217 do
45
+ dirname = File.dirname(__FILE__)
46
+ gen = File.join(dirname, 'rakelib', %w{iso4217.rb})
47
+ lib = File.expand_path(File.join(dirname, %w{lib big_money currency iso4217.rb}))
48
+ require gen
49
+ modules = BigMoney::Task::ISO4217.get
50
+ File.open(lib, File::CREAT | File::TRUNC | File::WRONLY) do |f|
51
+ f.write modules
52
+ end
53
+ end
54
+ end
55
+
56
+ task :default => :test
57
+
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 1
3
+ :minor: 1
4
+ :patch: 0
5
+ :build:
@@ -0,0 +1,65 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{big_money}
8
+ s.version = "1.1.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Shane Hanna", "Marshall Roch"]
12
+ s.date = %q{2010-01-22}
13
+ s.email = ["shane.hanna@gmail.com", "mroch@cmu.edu"]
14
+ s.extra_rdoc_files = [
15
+ "LICENSE",
16
+ "README.rdoc"
17
+ ]
18
+ s.files = [
19
+ ".document",
20
+ ".gitignore",
21
+ "Gemfile",
22
+ "LICENSE",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION.yml",
26
+ "big_money.gemspec",
27
+ "lib/big_money.rb",
28
+ "lib/big_money/currency.rb",
29
+ "lib/big_money/currency/iso4217.rb",
30
+ "lib/big_money/exchange.rb",
31
+ "lib/big_money/exchange/yahoo.rb",
32
+ "lib/big_money/parser.rb",
33
+ "lib/big_money/types.rb",
34
+ "rakelib/iso4217.rb",
35
+ "rakelib/iso4217.rb.erb",
36
+ "test/helper.rb",
37
+ "test/test_big_money.rb",
38
+ "test/test_currency.rb",
39
+ "test/test_exchange.rb",
40
+ "test/test_parser.rb"
41
+ ]
42
+ s.homepage = %q{http://github.com/shanna/big_money}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.5}
46
+ s.summary = %q{BigDecimal backed amount of money in a particular currency.}
47
+ s.test_files = [
48
+ "test/test_exchange.rb",
49
+ "test/helper.rb",
50
+ "test/test_currency.rb",
51
+ "test/test_big_money.rb",
52
+ "test/test_parser.rb"
53
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
60
+ else
61
+ end
62
+ else
63
+ end
64
+ end
65
+
@@ -0,0 +1,124 @@
1
+ # encoding: utf-8
2
+ require 'bigdecimal'
3
+ require 'big_money/currency'
4
+ require 'big_money/currency/iso4217'
5
+
6
+ # == Synopsis
7
+ #
8
+ # bm = BigMoney.new('3.99', :aud)
9
+ # bm.amount #=> BigDecimal.new('3.99')
10
+ # bm.currency #=> BigMoney::Currency::AUD
11
+ # bm.to_s #=> '3.99'
12
+ # bm.to_s('$.2f') #=> '$3.99'
13
+ # bm.to_s('$%.2f %s') #=> '$3.99 AUD'
14
+ #
15
+ # === Amount
16
+ #
17
+ # Amounts can be anything Numeric or Strings that are BigDecimal friendly. Keep in mind BigDecimal will silently return
18
+ # 0.0 for unrecognised strings. See BigMoney::Amount.
19
+ #
20
+ # BigMoney.new(BigDecimal.new('12.50')) # BigDecimal
21
+ # BigMoney.new(12) # Fixnum
22
+ # BigMoney.new(12.50) # Float
23
+ # BigMoney.new('12.50') # String
24
+ #
25
+ # === Currency
26
+ #
27
+ # Any currency defined by the current ISO4217 table on Wikipedia is already available. Naturally you may define your
28
+ # own currencies. See BigMoney::Currency.
29
+ #
30
+ # ==== Default
31
+ #
32
+ # A default currency risks exchanging an amount 1:1 between currencies if the default is unintentionally used.
33
+ # BigMoney expects an explicit currency in the constructor and will raise an ArugmentError unless one is given or a
34
+ # default currency set.
35
+ #
36
+ # BigMoney::Currency.default = BigMoney::Currency::AUD # Module
37
+ # BigMoney::Currency.default = 'AUD' # String, ISO4217 3 letter currency code.
38
+ # BigMoney::Currency.default = :aud # Symbol, ISO4217 3 letter currency code.
39
+ class BigMoney
40
+ include Comparable
41
+ attr_reader :amount, :currency
42
+
43
+ # Short form BigMoney::Currency.find(code) to save some typing.
44
+ #
45
+ # ==== Examples
46
+ #
47
+ # BigMoney.currency(:usd) #=> BigMoney::Currency.find(:usd)
48
+ #
49
+ # ==== Parameters
50
+ # code<#to_s>:: An upper or lowercase string or symbol of the ISO-4217 currency code.
51
+ #
52
+ # ==== Returns
53
+ # BigMoney::Currency
54
+ def self.currency(currency)
55
+ Currency.find(currency)
56
+ end
57
+
58
+ # Create a BigMoney instance.
59
+ #
60
+ # ==== Parameters
61
+ # amount<BigDecimal, Numeric, String>:: Numeric or BigDecimal friendly String.
62
+ # currency<BigMoney::Currency, Symbol, String>:: Optional ISO-4217 3 letter currency code. Default BigMoney.currency.default
63
+ #
64
+ # ==== Returns
65
+ # BigMoney
66
+ def initialize(amount, currency = nil)
67
+ @amount = case amount
68
+ when BigDecimal then amount
69
+ when String then BigDecimal.new(amount)
70
+ when Numeric then BigDecimal.new(amount.to_s)
71
+ else raise TypeError.new("Can't convert +amount+ #{amount.class} into BigDecimal.")
72
+ end
73
+
74
+ raise ArgumentError.new("Nil +currency+ without default.") if currency.nil? && !Currency.default?
75
+ unless currency && @currency = Currency.find(currency)
76
+ raise ArgumentError.new("Unknown +currency+ '#{currency.inspect}'.") unless Currency.default?
77
+ @currency = Currency.default
78
+ end
79
+ end
80
+
81
+ def <=>(money)
82
+ money.kind_of?(self.class) ? (currency <=> money.currency).nonzero? || (amount <=> money.amount).nonzero? || 0 : nil
83
+ end
84
+
85
+ def eql?(money)
86
+ money.kind_of?(self.class) &&
87
+ amount == money.amount &&
88
+ currency == money.currency
89
+ end
90
+ alias == eql?
91
+
92
+ def -@
93
+ self.class.new(-amount, currency)
94
+ end
95
+
96
+ [:+, :-, :*, :/].each do |op|
97
+ define_method(op) do |rvalue|
98
+ raise TypeError.new("Currency mismatch, '#{currency}' with '#{rvalue.currency}'.") \
99
+ if rvalue.kind_of?(BigMoney) && currency != rvalue.currency
100
+
101
+ rvalue = case rvalue
102
+ when BigMoney then rvalue.amount
103
+ when BigDecimal then rvalue.dup
104
+ when String then BigDecimal.new(rvalue)
105
+ when Numeric then BigDecimal.new(rvalue.to_s)
106
+ else raise TypeError.new("Can't convert +amount+ #{rvalue.class} into BigDecimal.")
107
+ end
108
+ self.class.new(amount.send(op, rvalue), currency)
109
+ end
110
+ end
111
+
112
+ def to_s(format = nil)
113
+ format ||= "%.#{currency.offset}f"
114
+ format.sub(/%s/, currency.code) % amount
115
+ end
116
+
117
+ def to_i
118
+ amount.to_i
119
+ end
120
+
121
+ def to_f
122
+ amount.to_f
123
+ end
124
+ end # BigMoney
@@ -0,0 +1,75 @@
1
+ require 'set'
2
+
3
+ class BigMoney
4
+ class Currency
5
+ include Comparable
6
+
7
+ attr_accessor :code, :offset, :name
8
+ alias to_s code
9
+
10
+ def hash
11
+ code.hash
12
+ end
13
+
14
+ def eql?(rvalue)
15
+ self.class.equal?(rvalue.class) && code == rvalue.code
16
+ end
17
+ alias == eql?
18
+
19
+ def <=>(rvalue)
20
+ self.class == rvalue.class ? (code <=> rvalue.code) || 0 : nil
21
+ end
22
+
23
+ #--
24
+ # TODO: Validate.
25
+ def initialize(code, offset, name)
26
+ @code, @offset, @name = code.to_s.upcase, offset, name
27
+ end
28
+
29
+ class << self
30
+ def default
31
+ raise "No default currency has been set. See BigMoney::Currency." unless default?
32
+ @@default
33
+ end
34
+
35
+ def default=(currency)
36
+ raise TypeError.new("Expected kind of BigMoney::Currency but got #{currency.class}.") \
37
+ unless currency.kind_of?(Currency)
38
+ @@default = currency
39
+ end
40
+
41
+ def default?
42
+ defined? @@default
43
+ end
44
+
45
+ def all
46
+ @@all ||= Set.new
47
+ end
48
+
49
+ # Find an existing currency module by Object, Symbol or String.
50
+ #
51
+ # ==== Examples
52
+ #
53
+ # AUD = BigMoney::Currency.new(:aud, 2, 'Australian Dollar')
54
+ #
55
+ # BigMoney::Currency.find(:aud)
56
+ # BigMoney::Currency.find('aud')
57
+ # BigMoney::Currency.find('AUD')
58
+ # BigMoney::Currency.find(AUD)
59
+ def find(currency)
60
+ if currency.is_a?(self)
61
+ currency
62
+ else
63
+ currency = currency.to_s.upcase
64
+ all.find{|c| c.code == currency}
65
+ end
66
+ end
67
+
68
+ def register(*args)
69
+ self.all << currency = new(*args).freeze
70
+ currency
71
+ end
72
+ end
73
+ end # Currency
74
+ end # BigMoney
75
+
@@ -0,0 +1,185 @@
1
+ # encoding: utf-8
2
+
3
+ class BigMoney
4
+ class Currency
5
+ AED = Currency.register(%q{AED}, 2, %q{United Arab Emirates dirham})
6
+ AFN = Currency.register(%q{AFN}, 2, %q{Afghani})
7
+ ALL = Currency.register(%q{ALL}, 2, %q{Lek})
8
+ AMD = Currency.register(%q{AMD}, 0, %q{Armenian dram})
9
+ ANG = Currency.register(%q{ANG}, 2, %q{Netherlands Antillean guilder})
10
+ AOA = Currency.register(%q{AOA}, 1, %q{Kwanza})
11
+ ARS = Currency.register(%q{ARS}, 2, %q{Argentine peso})
12
+ AUD = Currency.register(%q{AUD}, 2, %q{Australian dollar})
13
+ AWG = Currency.register(%q{AWG}, 2, %q{Aruban guilder})
14
+ AZN = Currency.register(%q{AZN}, 2, %q{Azerbaijanian manat})
15
+ BAM = Currency.register(%q{BAM}, 2, %q{Convertible marks})
16
+ BBD = Currency.register(%q{BBD}, 2, %q{Barbados dollar})
17
+ BDT = Currency.register(%q{BDT}, 2, %q{Bangladeshi taka})
18
+ BGN = Currency.register(%q{BGN}, 2, %q{Bulgarian lev})
19
+ BHD = Currency.register(%q{BHD}, 3, %q{Bahraini dinar})
20
+ BIF = Currency.register(%q{BIF}, 0, %q{Burundian franc})
21
+ BMD = Currency.register(%q{BMD}, 2, %q{Bermudian dollar})
22
+ BND = Currency.register(%q{BND}, 2, %q{Brunei dollar})
23
+ BOB = Currency.register(%q{BOB}, 2, %q{Boliviano})
24
+ BOV = Currency.register(%q{BOV}, 2, %q{Bolivian Mvdol (funds code)})
25
+ BRL = Currency.register(%q{BRL}, 2, %q{Brazilian real})
26
+ BSD = Currency.register(%q{BSD}, 2, %q{Bahamian dollar})
27
+ BTN = Currency.register(%q{BTN}, 2, %q{Ngultrum})
28
+ BWP = Currency.register(%q{BWP}, 2, %q{Pula})
29
+ BYR = Currency.register(%q{BYR}, 0, %q{Belarusian ruble})
30
+ BZD = Currency.register(%q{BZD}, 2, %q{Belize dollar})
31
+ CAD = Currency.register(%q{CAD}, 2, %q{Canadian dollar})
32
+ CDF = Currency.register(%q{CDF}, 2, %q{Franc Congolais})
33
+ CHE = Currency.register(%q{CHE}, 2, %q{WIR eurocomplementary currency})
34
+ CHF = Currency.register(%q{CHF}, 2, %q{Swiss franc})
35
+ CHW = Currency.register(%q{CHW}, 2, %q{WIR franccomplementary currency})
36
+ CLF = Currency.register(%q{CLF}, 0, %q{Unidad de Fomento})
37
+ CLP = Currency.register(%q{CLP}, 0, %q{Chilean peso})
38
+ CNY = Currency.register(%q{CNY}, 1, %q{Chinese Yuan})
39
+ COP = Currency.register(%q{COP}, 0, %q{Colombian peso})
40
+ COU = Currency.register(%q{COU}, 2, %q{Unidad de Valor Real})
41
+ CRC = Currency.register(%q{CRC}, 2, %q{Costa Rican colon})
42
+ CUC = Currency.register(%q{CUC}, 2, %q{Cuban convertible peso})
43
+ CUP = Currency.register(%q{CUP}, 2, %q{Cuban peso})
44
+ CVE = Currency.register(%q{CVE}, 2, %q{Cape Verde escudo})
45
+ CZK = Currency.register(%q{CZK}, 2, %q{Czech Koruna})
46
+ DJF = Currency.register(%q{DJF}, 0, %q{Djibouti franc})
47
+ DKK = Currency.register(%q{DKK}, 2, %q{Danish krone})
48
+ DOP = Currency.register(%q{DOP}, 2, %q{Dominican peso})
49
+ DZD = Currency.register(%q{DZD}, 2, %q{Algerian dinar})
50
+ EEK = Currency.register(%q{EEK}, 2, %q{Kroon})
51
+ EGP = Currency.register(%q{EGP}, 2, %q{Egyptian pound})
52
+ ERN = Currency.register(%q{ERN}, 2, %q{Nakfa})
53
+ ETB = Currency.register(%q{ETB}, 2, %q{Ethiopian birr})
54
+ EUR = Currency.register(%q{EUR}, 2, %q{euro})
55
+ FJD = Currency.register(%q{FJD}, 2, %q{Fiji dollar})
56
+ FKP = Currency.register(%q{FKP}, 2, %q{Falkland Islands pound})
57
+ GBP = Currency.register(%q{GBP}, 2, %q{Pound sterling})
58
+ GEL = Currency.register(%q{GEL}, 2, %q{Lari})
59
+ GHS = Currency.register(%q{GHS}, 2, %q{Cedi})
60
+ GIP = Currency.register(%q{GIP}, 2, %q{Gibraltar pound})
61
+ GMD = Currency.register(%q{GMD}, 2, %q{Dalasi})
62
+ GNF = Currency.register(%q{GNF}, 0, %q{Guinea franc})
63
+ GTQ = Currency.register(%q{GTQ}, 2, %q{Quetzal})
64
+ GYD = Currency.register(%q{GYD}, 2, %q{Guyana dollar})
65
+ HKD = Currency.register(%q{HKD}, 2, %q{Hong Kong dollar})
66
+ HNL = Currency.register(%q{HNL}, 2, %q{Lempira})
67
+ HRK = Currency.register(%q{HRK}, 2, %q{Croatian kuna})
68
+ HTG = Currency.register(%q{HTG}, 2, %q{Haiti gourde})
69
+ HUF = Currency.register(%q{HUF}, 2, %q{Forint})
70
+ IDR = Currency.register(%q{IDR}, 0, %q{Rupiah})
71
+ ILS = Currency.register(%q{ILS}, 2, %q{Israeli new sheqel})
72
+ INR = Currency.register(%q{INR}, 2, %q{Indian rupee})
73
+ IQD = Currency.register(%q{IQD}, 0, %q{Iraqi dinar})
74
+ IRR = Currency.register(%q{IRR}, 0, %q{Iranian rial})
75
+ ISK = Currency.register(%q{ISK}, 0, %q{Iceland krona})
76
+ JMD = Currency.register(%q{JMD}, 2, %q{Jamaican dollar})
77
+ JOD = Currency.register(%q{JOD}, 3, %q{Jordanian dinar})
78
+ JPY = Currency.register(%q{JPY}, 0, %q{Japanese yen})
79
+ KES = Currency.register(%q{KES}, 2, %q{Kenyan shilling})
80
+ KGS = Currency.register(%q{KGS}, 2, %q{Som})
81
+ KHR = Currency.register(%q{KHR}, 0, %q{Riel})
82
+ KMF = Currency.register(%q{KMF}, 0, %q{Comoro franc})
83
+ KPW = Currency.register(%q{KPW}, 0, %q{North Korean won})
84
+ KRW = Currency.register(%q{KRW}, 0, %q{South Korean won})
85
+ KWD = Currency.register(%q{KWD}, 3, %q{Kuwaiti dinar})
86
+ KYD = Currency.register(%q{KYD}, 2, %q{Cayman Islands dollar})
87
+ KZT = Currency.register(%q{KZT}, 2, %q{Tenge})
88
+ LAK = Currency.register(%q{LAK}, 0, %q{Kip})
89
+ LBP = Currency.register(%q{LBP}, 0, %q{Lebanese pound})
90
+ LKR = Currency.register(%q{LKR}, 2, %q{Sri Lanka rupee})
91
+ LRD = Currency.register(%q{LRD}, 2, %q{Liberian dollar})
92
+ LSL = Currency.register(%q{LSL}, 2, %q{Lesotho loti})
93
+ LTL = Currency.register(%q{LTL}, 2, %q{Lithuanian litas})
94
+ LVL = Currency.register(%q{LVL}, 2, %q{Latvian lats})
95
+ LYD = Currency.register(%q{LYD}, 3, %q{Libyan dinar})
96
+ MAD = Currency.register(%q{MAD}, 2, %q{Moroccan dirham})
97
+ MDL = Currency.register(%q{MDL}, 2, %q{Moldovan leu})
98
+ MGA = Currency.register(%q{MGA}, 0, %q{Malagasy ariary})
99
+ MKD = Currency.register(%q{MKD}, 2, %q{Denar})
100
+ MMK = Currency.register(%q{MMK}, 0, %q{Kyat})
101
+ MNT = Currency.register(%q{MNT}, 2, %q{Tugrik})
102
+ MOP = Currency.register(%q{MOP}, 1, %q{Pataca})
103
+ MRO = Currency.register(%q{MRO}, 0, %q{Ouguiya})
104
+ MUR = Currency.register(%q{MUR}, 2, %q{Mauritius rupee})
105
+ MVR = Currency.register(%q{MVR}, 2, %q{Rufiyaa})
106
+ MWK = Currency.register(%q{MWK}, 2, %q{Kwacha})
107
+ MXN = Currency.register(%q{MXN}, 2, %q{Mexican peso})
108
+ MXV = Currency.register(%q{MXV}, 2, %q{Mexican Unidad de Inversion})
109
+ MYR = Currency.register(%q{MYR}, 2, %q{Malaysian ringgit})
110
+ MZN = Currency.register(%q{MZN}, 2, %q{Metical})
111
+ NAD = Currency.register(%q{NAD}, 2, %q{Namibian dollar})
112
+ NGN = Currency.register(%q{NGN}, 2, %q{Naira})
113
+ NIO = Currency.register(%q{NIO}, 2, %q{Cordoba oro})
114
+ NOK = Currency.register(%q{NOK}, 2, %q{Norwegian krone})
115
+ NPR = Currency.register(%q{NPR}, 2, %q{Nepalese rupee})
116
+ NZD = Currency.register(%q{NZD}, 2, %q{New Zealand dollar})
117
+ OMR = Currency.register(%q{OMR}, 3, %q{Rial Omani})
118
+ PAB = Currency.register(%q{PAB}, 2, %q{Balboa})
119
+ PEN = Currency.register(%q{PEN}, 2, %q{Nuevo sol})
120
+ PGK = Currency.register(%q{PGK}, 2, %q{Kina})
121
+ PHP = Currency.register(%q{PHP}, 2, %q{Philippine peso})
122
+ PKR = Currency.register(%q{PKR}, 2, %q{Pakistan rupee})
123
+ PLN = Currency.register(%q{PLN}, 2, %q{Złoty})
124
+ PYG = Currency.register(%q{PYG}, 0, %q{Guarani})
125
+ QAR = Currency.register(%q{QAR}, 2, %q{Qatari rial})
126
+ RON = Currency.register(%q{RON}, 2, %q{Romanian new leu})
127
+ RSD = Currency.register(%q{RSD}, 2, %q{Serbian dinar})
128
+ RUB = Currency.register(%q{RUB}, 2, %q{Russian rouble})
129
+ RWF = Currency.register(%q{RWF}, 0, %q{Rwanda franc})
130
+ SAR = Currency.register(%q{SAR}, 2, %q{Saudi riyal})
131
+ SBD = Currency.register(%q{SBD}, 2, %q{Solomon Islands dollar})
132
+ SCR = Currency.register(%q{SCR}, 2, %q{Seychelles rupee})
133
+ SDG = Currency.register(%q{SDG}, 2, %q{Sudanese pound})
134
+ SEK = Currency.register(%q{SEK}, 2, %q{Swedish krona})
135
+ SGD = Currency.register(%q{SGD}, 2, %q{Singapore dollar})
136
+ SHP = Currency.register(%q{SHP}, 2, %q{Saint Helena pound})
137
+ SLL = Currency.register(%q{SLL}, 0, %q{Leone})
138
+ SOS = Currency.register(%q{SOS}, 2, %q{Somali shilling})
139
+ SRD = Currency.register(%q{SRD}, 2, %q{Surinam dollar})
140
+ STD = Currency.register(%q{STD}, 0, %q{Dobra})
141
+ SYP = Currency.register(%q{SYP}, 2, %q{Syrian pound})
142
+ SZL = Currency.register(%q{SZL}, 2, %q{Lilangeni})
143
+ THB = Currency.register(%q{THB}, 2, %q{Baht})
144
+ TJS = Currency.register(%q{TJS}, 2, %q{Somoni})
145
+ TMT = Currency.register(%q{TMT}, 2, %q{Manat})
146
+ TND = Currency.register(%q{TND}, 3, %q{Tunisian dinar})
147
+ TOP = Currency.register(%q{TOP}, 2, %q{Pa'anga})
148
+ TRY = Currency.register(%q{TRY}, 2, %q{Turkish lira})
149
+ TTD = Currency.register(%q{TTD}, 2, %q{Trinidad and Tobago dollar})
150
+ TWD = Currency.register(%q{TWD}, 1, %q{New Taiwan dollar})
151
+ TZS = Currency.register(%q{TZS}, 2, %q{Tanzanian shilling})
152
+ UAH = Currency.register(%q{UAH}, 2, %q{Hryvnia})
153
+ UGX = Currency.register(%q{UGX}, 0, %q{Uganda shilling})
154
+ USD = Currency.register(%q{USD}, 2, %q{US dollar})
155
+ USN = Currency.register(%q{USN}, 2, %q{United States dollar (next day) (funds code)})
156
+ USS = Currency.register(%q{USS}, 2, %q{who?})
157
+ UYU = Currency.register(%q{UYU}, 2, %q{Peso Uruguayo})
158
+ UZS = Currency.register(%q{UZS}, 2, %q{Uzbekistan som})
159
+ VEF = Currency.register(%q{VEF}, 2, %q{Venezuelan bolívar fuerte})
160
+ VND = Currency.register(%q{VND}, 0, %q{Vietnamese đồng})
161
+ VUV = Currency.register(%q{VUV}, 0, %q{Vatu})
162
+ WST = Currency.register(%q{WST}, 2, %q{Samoan tala})
163
+ XAF = Currency.register(%q{XAF}, 0, %q{CFA franc BEAC})
164
+ XAG = Currency.register(%q{XAG}, 0, %q{Silvertroy ounce})
165
+ XAU = Currency.register(%q{XAU}, 0, %q{Goldtroy ounce})
166
+ XBA = Currency.register(%q{XBA}, 0, %q{European Composite Unit})
167
+ XBB = Currency.register(%q{XBB}, 0, %q{European Monetary Unit})
168
+ XBC = Currency.register(%q{XBC}, 0, %q{European Unit of Account 9})
169
+ XBD = Currency.register(%q{XBD}, 0, %q{European Unit of Account 17})
170
+ XCD = Currency.register(%q{XCD}, 2, %q{East Caribbean dollar})
171
+ XDR = Currency.register(%q{XDR}, 0, %q{Special Drawing Rights})
172
+ XFU = Currency.register(%q{XFU}, 0, %q{UIC franc})
173
+ XOF = Currency.register(%q{XOF}, 0, %q{CFA Franc BCEAO})
174
+ XPD = Currency.register(%q{XPD}, 0, %q{Palladiumtroy ounce})
175
+ XPF = Currency.register(%q{XPF}, 0, %q{CFP franc})
176
+ XPT = Currency.register(%q{XPT}, 0, %q{Platinumtroy ounce})
177
+ XTS = Currency.register(%q{XTS}, 0, %q{Code reserved for testing purposes})
178
+ XXX = Currency.register(%q{XXX}, 0, %q{No currency})
179
+ YER = Currency.register(%q{YER}, 0, %q{Yemeni rial})
180
+ ZAR = Currency.register(%q{ZAR}, 2, %q{South African rand})
181
+ ZMK = Currency.register(%q{ZMK}, 0, %q{Kwacha})
182
+ ZWL = Currency.register(%q{ZWL}, 2, %q{Zimbabwe dollar})
183
+ end # Currency
184
+ end # BigMoney
185
+
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ require 'bigdecimal'
3
+
4
+ class BigMoney
5
+
6
+ # == Synopsis
7
+ #
8
+ # require 'big_money'
9
+ # require 'big_money/exchange/yahoo' # Use yahoo finance exchange service.
10
+ #
11
+ # bm = BigMoney.new('3.99', :usd)
12
+ # bm.amount #=> BigDecimal.new('3.99')
13
+ # bm.currency #=> BigMoney::Currency::USD
14
+ #
15
+ # bm2 = bm.exchange(:aud)
16
+ # bm.amount #=> BigDecimal.new('5.22')
17
+ # bm.currency #=> BigMoney::Currency::AUD
18
+ module Exchangeable
19
+ # Exchange to a new Currency.
20
+ #
21
+ # ==== Examples
22
+ #
23
+ # BigMoney.new(12.50, :aud).exchange(:usd)
24
+ #
25
+ # ==== Parameters
26
+ # from<BigMoney::Currency, #to_s>:: Anything that BigMoney::Currency#find can find.
27
+ #
28
+ # ==== Returns
29
+ # BigMoney
30
+ def exchange(to)
31
+ ex = amount * Exchange.rate(currency, to)
32
+ self.class.new(ex, to)
33
+ end
34
+ end # Exchangeable
35
+ include Exchangeable
36
+
37
+ # Find the exchange rate between two currencies.
38
+ #
39
+ # Be aware no caching is done at all at the moment.
40
+ #--
41
+ # TODO: Moneta would be ideal for this.
42
+ class Exchange
43
+ class ConversionError < StandardError; end
44
+
45
+ class << self
46
+ @@services = []
47
+ def inherited(service) #:nodoc:
48
+ @@services << service
49
+ end
50
+
51
+ # Fetch the exchange rate between two currencies.
52
+ #
53
+ # ==== Parameters
54
+ # from<BigMoney::Currency, .to_s>:: Anything that BigMoney::Currency#find can find.
55
+ # to<BigMoney::Currency, .to_s>:: Anything that BigMoney::Currency#find can find.
56
+ #
57
+ # ==== Returns
58
+ # BigDecimal
59
+ def rate(from, to)
60
+ exchange = []
61
+ exchange << (Currency.find(from) or raise ArgumentError.new("Unknown +from+ currency #{from.inspect}."))
62
+ exchange << (Currency.find(to) or raise ArgumentError.new("Unknown +to+ currency #{to.inspect}."))
63
+ return BigDecimal.new(1.to_s) if exchange.uniq.size == 1 || exchange.find{|c| c == Currency::XXX}
64
+
65
+ service = @@services.reverse.find do |service|
66
+ !!exchange.reject{|c| service.currencies.include?(c)}
67
+ end
68
+
69
+ service or raise ConversionError # TODO: Message?
70
+ BigDecimal.new(service.read_rate(*exchange).to_s)
71
+ end
72
+
73
+ protected
74
+ # Exchange rate from the first currency to the second.
75
+ #
76
+ # ==== Notes
77
+ # Abstract.
78
+ #
79
+ # ==== Parameters
80
+ # from<BigMoney::Currency>::
81
+ # to<BigMoney::Currency>::
82
+ #
83
+ # ==== Returns
84
+ # BigDecimal
85
+ def read_rate(from, to)
86
+ raise NotImplementedError
87
+ end
88
+
89
+ # Supported currencies.
90
+ #
91
+ # ==== Notes
92
+ # Abstract.
93
+ #
94
+ # ==== Returns
95
+ # Array<BigMoney::Currency, #to_s>:: Anything that BigMoney::Currency#find can find.
96
+ def currencies
97
+ raise NotImplementedError
98
+ end
99
+ end
100
+ end # Exchange
101
+
102
+ end # Money
@@ -0,0 +1,34 @@
1
+ # coding: utf-8
2
+ require 'open-uri'
3
+ require 'big_money/exchange'
4
+
5
+ class BigMoney
6
+ class Exchange
7
+
8
+ # Yahoo finance exchange service.
9
+ #
10
+ # http://finance.yahoo.com
11
+ class Yahoo < Exchange
12
+ class << self
13
+ protected
14
+ def read_rate(from, to)
15
+ s = [from, to].map{|c| c.code}.join
16
+ open("http://download.finance.yahoo.com/d/quotes.csv?s=#{s}=X&f=l1&e=.csv").read.strip rescue nil
17
+ end
18
+
19
+ def currencies
20
+ %w{
21
+ 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
22
+ 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
23
+ 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
24
+ 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
25
+ 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
26
+ CHF SYP TWD TZS THB TOP TTD TND USD AED UGX UAH UYU VUV VEB VND YER ZMK ZWD
27
+ }
28
+ end
29
+ end
30
+ end # Yahoo
31
+
32
+ end # Exchange
33
+ end # Money
34
+
@@ -0,0 +1,66 @@
1
+ # encoding: utf-8
2
+ require 'big_money' # Make it possible to just require 'big_money/parser'.
3
+
4
+ class BigMoney
5
+ # Fuzzy string parsing.
6
+ #
7
+ # Supports scientific notation for amounts and ISO-4217 currency symbols.
8
+ #
9
+ # == Synopsis
10
+ #
11
+ # require 'big_money'
12
+ # require 'big_money/parser' # This module/mixin.
13
+ #
14
+ # BigMoney.parse('JPY ¥2500') #=> BigMoney.new('2500', :jpy)
15
+ # BigMoney.parse('JPY2500') #=> BigMoney.new('2500', :jpy)
16
+ # BigMoney.parse('2500JPY') #=> BigMoney.new('2500', :jpy)
17
+ # BigMoney.parse('¥2500JPY') #=> BigMoney.new('2500', :jpy)
18
+ # BigMoney.parse('¥2500') #=> BigMoney.new('2500', :xxx)
19
+ #
20
+ # == Currency
21
+ #
22
+ # Due to the nature of string parsing it's possible t
23
+ module Parser
24
+ REGEXP = %r{
25
+ (?:^|\b)
26
+ ((?:[a-zA-Z]{3})?)\s* # ISO4217 Currency code.
27
+ [^\d+-]? # Currency symbol.
28
+ ([-+]?) # +-
29
+ [^\d+-]? # Currency symbol.
30
+ \s*(
31
+ (?:(?:\d(?:\d+|[., ]?)*\d)|\d) # Digits and ., or spaces.
32
+ (?:[eE][-+]?\d+)? # Exponents.
33
+ )\s*
34
+ ((?:[a-zA-Z]{3})?) # ISO4217 Currency code.
35
+ (?:$|\b)
36
+ }x
37
+
38
+ # Fuzzy parsing.
39
+ #
40
+ # ==== Parameters
41
+ # money<.to_s>:: The object to parse as money.
42
+ #
43
+ # ==== Currency
44
+ # ISO-4217 BigMoney::Currency::XXX aka 'No currency' will be used if a currency cannot be parsed along with the
45
+ # amount. If you know the currency and just need the amount XXX is always exchanged 1:1 with any currency:
46
+ #
47
+ # money = BigMoney.parse('¥2500') #=> BigMoney.new('2500', :xxx)
48
+ # money.exchange(:jpy) #=> BigMoney.new('2500', :jpy)
49
+ #
50
+ # ==== Returns
51
+ # BigMoney or nil
52
+ def parse(money)
53
+ raise TypeError.new("Can't convert +money+ #{money.class} into String.") unless money.respond_to?(:to_s)
54
+
55
+ match = REGEXP.match(money.to_s) || return
56
+ currency = [match[1], match[4]].find{|c| Currency.find(c)} || Currency::XXX
57
+
58
+ # TODO: Currency should have a .delimiter method I reckon that returns the major/minor delimiter.
59
+ # For now '.' will do and everything else will be stripped.
60
+ money = [match[2], match[3].gsub(/[^0-9.Ee]/, '')].join
61
+ new(money, currency)
62
+ end
63
+ end # Parser
64
+
65
+ extend Parser
66
+ end # BigMoney
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+
3
+ class String
4
+ def to_big_money(currency = nil)
5
+ BigMoney.new(self, currency)
6
+ end
7
+ end
8
+
9
+ class Numeric
10
+ def to_big_money(currency = nil)
11
+ BigMoney.new(self, currency)
12
+ end
13
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ require File.join(File.dirname(__FILE__), '..', 'gems', 'environment')
3
+ require 'hpricot'
4
+ require 'open-uri'
5
+ require 'erubis'
6
+
7
+ class BigMoney
8
+ module Task
9
+ module ISO4217
10
+ def self.get
11
+ doc = Hpricot(open('http://en.wikipedia.org/wiki/ISO_4217').read)
12
+ codes = doc.at('#Active_codes').parent
13
+ codes.name =~ /table/ && break while codes = codes.next_sibling
14
+ to_ruby(codes) if codes
15
+ end
16
+
17
+ def self.to_ruby(codes)
18
+ currencies = (codes / 'tr').map{|tr| currency tr}.compact
19
+ currencies.reject!{|c| c[:code] !~ /[A-Z]{3}/ || c[:name] !~ /\w+/}
20
+ tmpl = File.read(File.join(File.dirname(__FILE__), 'iso4217.rb.erb'))
21
+ eruby = Erubis::Eruby.new(tmpl)
22
+ eruby.result(:currencies => currencies)
23
+ end
24
+
25
+ def self.currency(tr)
26
+ values = (tr / 'td')
27
+ return unless values && values.size >= 4
28
+ {
29
+ :code => code(values),
30
+ :name => name(values),
31
+ :offset => offset(values)
32
+ }
33
+ end
34
+
35
+ def self.code(chunks)
36
+ chunks[0].inner_html
37
+ end
38
+
39
+ def self.offset(chunks)
40
+ chunks[2].inner_html.to_i rescue 0
41
+ end
42
+
43
+ def self.name(chunks)
44
+ name = (chunks[3] / 'a').inner_html rescue nil
45
+ (name.nil? || name.empty?) ? chunks[3].inner_html : name
46
+ end
47
+ end # ISO4217
48
+ end # Task
49
+ end # BigMoney
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ class BigMoney
4
+ class Currency
5
+ <% currencies.each do |currency| -%>
6
+ <%= currency[:code].upcase %> = Currency.register(%q{<%= currency[:code] %>}, <%= currency[:offset] %>, %q{<%= currency[:name] %>})
7
+ <% end -%>
8
+ end # Currency
9
+ end # BigMoney
10
+
@@ -0,0 +1,18 @@
1
+ root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
2
+
3
+ require File.join(root, 'gems', 'environment')
4
+ Bundler.require_env(:development)
5
+ require 'test/unit'
6
+
7
+ begin
8
+ require 'shoulda'
9
+ rescue LoadError
10
+ warn 'Shoulda is required for testing. Use gem bundle to install development gems.'
11
+ exit 1
12
+ end
13
+
14
+ $:.unshift File.join(root, 'lib'), File.dirname(__FILE__)
15
+ require 'big_money'
16
+
17
+ class Test::Unit::TestCase
18
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
3
+
4
+ class TestBigMoney < Test::Unit::TestCase
5
+ context BigMoney do
6
+ setup do
7
+ BigMoney::Currency.default = BigMoney::Currency::USD
8
+ end
9
+
10
+ context '#new' do
11
+ should 'initialize with big decimal' do
12
+ decimal = BigDecimal.new('1.005')
13
+ assert_same decimal, BigMoney.new(decimal).amount, 'Should not create clone of input'
14
+ end
15
+
16
+ should 'initialize with string' do
17
+ assert_equal BigDecimal.new('1.005'), BigMoney.new('1.005').amount
18
+ assert_equal BigDecimal.new('10'), BigMoney.new('10').amount
19
+ assert_equal BigDecimal.new('0'), BigMoney.new('0').amount
20
+ assert_equal BigDecimal.new('0'), BigMoney.new('foo').amount
21
+ end
22
+
23
+ should 'initialize with integer' do
24
+ assert_equal BigDecimal.new("100"), BigMoney.new(100).amount
25
+ assert_equal BigDecimal.new("0"), BigMoney.new(0).amount
26
+ end
27
+
28
+ should 'initialize with float' do
29
+ assert_equal BigDecimal.new('1.005'), BigMoney.new(1.005).amount
30
+ assert_equal BigDecimal.new('0'), BigMoney.new(0.0).amount
31
+ end
32
+ end
33
+
34
+ context 'operators' do
35
+ should 'eql?' do
36
+ m1, m2 = BigMoney.new(1.00), BigMoney.new(1.50)
37
+ assert m1.eql?(m1)
38
+ assert !m1.eql?(m2)
39
+ end
40
+
41
+ should '<=> spaceship' do
42
+ m1, m2 = BigMoney.new(1.00), BigMoney.new(1.50)
43
+ assert_equal(-1, (m1 <=> m2))
44
+ assert_equal(0, (m1 <=> m1))
45
+ assert_equal(1, (m2 <=> m1))
46
+ end
47
+
48
+ should 'add' do
49
+ m1, m2, m3 = BigMoney.new(1.00), BigMoney.new(1.50), BigMoney.new(0)
50
+ assert_equal BigDecimal.new('2.50'), (m1 + m2).amount
51
+ assert_equal BigDecimal.new('2.50'), (m2 + m1).amount
52
+ assert_equal BigDecimal.new('1.00'), (m1 + m3).amount
53
+ assert_equal BigDecimal.new('1.00'), (m3 + m1).amount
54
+ assert_not_same m1, m1 + m3
55
+ assert_not_same m1, m3 + m1
56
+ assert_equal BigDecimal.new('5.50'), (m2 + 4).amount
57
+ assert_equal BigDecimal.new('5.50'), (m2 + 4.00).amount
58
+ end
59
+
60
+ should 'subtract' do
61
+ m1, m2, m3 = BigMoney.new(1.00), BigMoney.new(1.50), BigMoney.new(0)
62
+ assert_equal BigDecimal.new('-0.50'), (m1 - m2).amount
63
+ assert_equal BigDecimal.new('0.50'), (m2 - m1).amount
64
+ assert_equal BigDecimal.new('1.00'), (m1 - m3).amount
65
+ assert_equal BigDecimal.new('-1.00'), (m3 - m1).amount
66
+ assert_equal BigDecimal.new('-2.50'), (m2 - 4).amount
67
+ assert_equal BigDecimal.new('-2.50'), (m2 - 4.00).amount
68
+ end
69
+
70
+ should 'multiply' do
71
+ m1, m2, m3 = BigMoney.new(2.00), BigMoney.new(1.50), BigMoney.new(0)
72
+ assert_equal BigDecimal.new('4.00'), (m1 * m1).amount
73
+ assert_equal BigDecimal.new('3.00'), (m1 * m2).amount
74
+ assert_equal BigDecimal.new('3.00'), (m2 * m1).amount
75
+ assert_equal BigDecimal.new('0'), (m1 * m3).amount
76
+ assert_equal BigDecimal.new('0'), (m3 * m1).amount
77
+ assert_equal BigDecimal.new('0'), (m3 * m3).amount
78
+ assert_equal BigDecimal.new('3.00'), (m2 * 2).amount
79
+ assert_equal BigDecimal.new('3.00'), (m2 * 2.00).amount
80
+ end
81
+
82
+ should 'divide' do
83
+ m1, m2, m3 = BigMoney.new(2.00), BigMoney.new(1.50), BigMoney.new(0)
84
+ assert_equal BigDecimal.new('1.00'), (m1 / m1).amount
85
+ assert_equal BigDecimal.new('0.75'), (m2 / m1).amount
86
+ assert_equal BigDecimal.new('0'), (m3 / m1).amount
87
+ assert((m1 / m3).amount.infinite?)
88
+ assert((m3 / m3).amount.nan?)
89
+ assert((m1 / 0).amount.infinite?)
90
+ assert((m3 / 0).amount.nan?)
91
+ assert_equal BigDecimal.new('0.75'), (m2 / 2).amount
92
+ assert_equal BigDecimal.new('0.75'), (m2 / 2.00).amount
93
+ end
94
+
95
+ should 'negate' do
96
+ assert_equal BigMoney.new(-1), -BigMoney.new(1)
97
+ assert_equal BigMoney.new(1), -BigMoney.new(-1)
98
+ assert_equal BigMoney.new(1), -BigMoney.new(-1)
99
+ end
100
+ end
101
+
102
+ context 'serialization' do
103
+ should '.to_s' do
104
+ assert_equal '1.00', BigMoney.new(1).to_s
105
+ assert_equal '1.50', BigMoney.new(1.5).to_s
106
+ assert_equal '-11.50', BigMoney.new(-11.5).to_s
107
+ end
108
+
109
+ should 'formatted .to_s' do
110
+ assert_equal '1.00', BigMoney.new(1).to_s('%.2f')
111
+ assert_equal '$1.00', BigMoney.new(1).to_s('$%.2f')
112
+ end
113
+
114
+ should '.to_i' do
115
+ assert_equal(1, BigMoney.new(1).to_i)
116
+ assert_equal(1, BigMoney.new(1.5).to_i)
117
+ assert_equal(-11, BigMoney.new(-11.5).to_i)
118
+ end
119
+
120
+ should '.to_f' do
121
+ assert_in_delta(1.0, BigMoney.new(1).to_f, 0.000001)
122
+ assert_in_delta(1.5, BigMoney.new(1.5).to_f, 0.000001)
123
+ assert_in_delta(-11.5, BigMoney.new(-11.5).to_f, 0.000001)
124
+ end
125
+ end
126
+ end
127
+ end
128
+
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
2
+
3
+ class TestCurrency < Test::Unit::TestCase
4
+ context BigMoney::Currency do
5
+ should 'find' do
6
+ assert_kind_of BigMoney::Currency, BigMoney::Currency.find(:aud)
7
+ assert_kind_of BigMoney::Currency, BigMoney::Currency.find(:AUD)
8
+ assert_kind_of BigMoney::Currency, BigMoney::Currency.find('aud')
9
+ assert_kind_of BigMoney::Currency, BigMoney::Currency.find('AUD')
10
+ assert_nil BigMoney::Currency.find(:fud)
11
+ end
12
+
13
+ should 'be comparable' do
14
+ aud = BigMoney::Currency::AUD
15
+ assert_operator aud, :==, BigMoney::Currency::AUD
16
+ assert aud != BigMoney::Currency::USD
17
+ end
18
+
19
+ context 'default' do
20
+ should 'raise exception for bad type' do
21
+ assert_raise(TypeError) { BigMoney::Currency.default = :fud}
22
+ end
23
+
24
+ should 'be settable' do
25
+ assert_nothing_raised{ BigMoney::Currency.default = BigMoney::Currency::AUD}
26
+ assert_kind_of BigMoney::Currency, BigMoney::Currency.default
27
+ assert_equal BigMoney::Currency::AUD, BigMoney::Currency.default
28
+ end
29
+
30
+ should 'be ackowledged' do
31
+ BigMoney::Currency.default = BigMoney::Currency::AUD
32
+ assert BigMoney::Currency.default?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
3
+ require 'big_money/exchange'
4
+
5
+ class TestEx < BigMoney::Exchange
6
+ def self.read_rate(from, to)
7
+ BigDecimal.new('2')
8
+ end
9
+
10
+ def self.currencies
11
+ BigMoney::Currency.all
12
+ end
13
+ end
14
+
15
+ class TestExchange < Test::Unit::TestCase
16
+ context BigMoney::Exchange do
17
+ setup do
18
+ @aud = BigMoney.currency(:aud)
19
+ @usd = BigMoney.currency(:usd)
20
+ end
21
+
22
+ should 'return rate' do
23
+ bd = BigDecimal.new('2')
24
+ assert_equal bd, BigMoney::Exchange.rate(@aud, @usd)
25
+ assert_equal bd, BigMoney::Exchange.rate(:aud, :usd)
26
+ assert_raise(ArgumentError) do
27
+ BigMoney::Exchange.rate(:aud, :fud)
28
+ end
29
+ end
30
+
31
+ should 'return equal rate' do
32
+ assert_equal BigDecimal.new('1'), BigMoney::Exchange.rate(:usd, :usd)
33
+ assert_equal BigDecimal.new('1'), BigMoney::Exchange.rate(:usd, :xxx)
34
+ assert_equal BigDecimal.new('1'), BigMoney::Exchange.rate(:xxx, :usd)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.join(File.dirname(__FILE__), 'helper'))
3
+ require 'big_money/parser'
4
+
5
+ class TestParser < Test::Unit::TestCase
6
+ context BigMoney::Parser do
7
+ setup do
8
+ @xxx = BigMoney.new('1.50', :xxx)
9
+ @aud = BigMoney.new('1.50', :aud)
10
+ @jpy = BigMoney.new('1.50', :jpy)
11
+ end
12
+
13
+ should 'parse' do
14
+ assert_equal @xxx, BigMoney.parse('1.50')
15
+ end
16
+
17
+ should 'parse scientific notation' do
18
+ assert_equal @xxx, BigMoney.parse('0.15E1')
19
+ end
20
+
21
+ should 'parse with leading currency' do
22
+ assert_equal @aud, BigMoney.parse('AUD 1.50')
23
+ assert_equal @aud, BigMoney.parse('AUD1.50')
24
+ assert_equal @aud, BigMoney.parse('AUD 0.15E1')
25
+ assert_equal @aud, BigMoney.parse('AUD0.15E1')
26
+
27
+ assert_equal @jpy, BigMoney.parse('JPY 1.50')
28
+ assert_equal @jpy, BigMoney.parse('JPY1.50')
29
+ assert_equal @jpy, BigMoney.parse('JPY 0.15E1')
30
+ assert_equal @jpy, BigMoney.parse('JPY0.15E1')
31
+ end
32
+
33
+ should 'parse with trailing currency' do
34
+ assert_equal @aud, BigMoney.parse('1.50 AUD')
35
+ assert_equal @aud, BigMoney.parse('1.50AUD')
36
+ assert_equal @aud, BigMoney.parse('0.15E1 AUD')
37
+ assert_equal @aud, BigMoney.parse('0.15E1AUD')
38
+
39
+ assert_equal @jpy, BigMoney.parse('1.50 JPY')
40
+ assert_equal @jpy, BigMoney.parse('1.50JPY')
41
+ assert_equal @jpy, BigMoney.parse('0.15E1 JPY')
42
+ assert_equal @jpy, BigMoney.parse('0.15E1JPY')
43
+ end
44
+
45
+ should 'parse with currency symbols' do
46
+ assert_equal @xxx, BigMoney.parse('$1.50')
47
+ assert_equal @xxx, BigMoney.parse('¤1.50')
48
+ assert_equal @xxx, BigMoney.parse('¥1.50')
49
+
50
+ assert_equal @xxx, BigMoney.parse('$ 1.50')
51
+ assert_equal @xxx, BigMoney.parse('¤ 1.50')
52
+ assert_equal @xxx, BigMoney.parse('¥ 1.50')
53
+ end
54
+
55
+ should 'parse with currency and symbols' do
56
+ assert_equal @aud, BigMoney.parse('AUD ¤ 1.50')
57
+ assert_equal @aud, BigMoney.parse('AUD ¤1.50')
58
+ assert_equal @aud, BigMoney.parse('AUD¤ 1.50')
59
+ assert_equal @aud, BigMoney.parse('AUD¤1.50')
60
+
61
+ assert_equal @aud, BigMoney.parse('¤ 1.50 AUD')
62
+ assert_equal @aud, BigMoney.parse('¤ 1.50AUD')
63
+ assert_equal @aud, BigMoney.parse('¤1.50 AUD')
64
+ assert_equal @aud, BigMoney.parse('¤1.50AUD')
65
+ end
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,84 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: big_money
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shane Hanna
8
+ - Marshall Roch
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2010-01-22 00:00:00 +11:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description:
18
+ email:
19
+ - shane.hanna@gmail.com
20
+ - mroch@cmu.edu
21
+ executables: []
22
+
23
+ extensions: []
24
+
25
+ extra_rdoc_files:
26
+ - LICENSE
27
+ - README.rdoc
28
+ files:
29
+ - .document
30
+ - .gitignore
31
+ - Gemfile
32
+ - LICENSE
33
+ - README.rdoc
34
+ - Rakefile
35
+ - VERSION.yml
36
+ - big_money.gemspec
37
+ - lib/big_money.rb
38
+ - lib/big_money/currency.rb
39
+ - lib/big_money/currency/iso4217.rb
40
+ - lib/big_money/exchange.rb
41
+ - lib/big_money/exchange/yahoo.rb
42
+ - lib/big_money/parser.rb
43
+ - lib/big_money/types.rb
44
+ - rakelib/iso4217.rb
45
+ - rakelib/iso4217.rb.erb
46
+ - test/helper.rb
47
+ - test/test_big_money.rb
48
+ - test/test_currency.rb
49
+ - test/test_exchange.rb
50
+ - test/test_parser.rb
51
+ has_rdoc: true
52
+ homepage: http://github.com/shanna/big_money
53
+ licenses: []
54
+
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --charset=UTF-8
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ version: "0"
65
+ version:
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ version: "0"
71
+ version:
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.5
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: BigDecimal backed amount of money in a particular currency.
79
+ test_files:
80
+ - test/test_exchange.rb
81
+ - test/helper.rb
82
+ - test/test_currency.rb
83
+ - test/test_big_money.rb
84
+ - test/test_parser.rb