big_money 1.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.
@@ -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