nofxx-money 2.3.3 → 2.3.5

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ *.gem
2
+ doc
3
+ *.sqlite3
4
+ *.log
5
+ spec/*.log
6
+ tmp/**/*
7
+ db/**/*
8
+ coverage/*
9
+ *.swp
data/README.rdoc CHANGED
@@ -12,9 +12,10 @@ This library aids one in handling money and different currencies. Features:
12
12
 
13
13
  Resources:
14
14
 
15
- - This fork: http://github.com/nofxx/money
16
15
  - Website: http://money.rubyforge.org
17
16
  - RDoc API: http://money.rubyforge.org
17
+ - This fork: http://github.com/ShadowBelmolve/money
18
+ - Forked from: http://github.com/nofxx/money
18
19
  - Git repository: http://github.com/FooBarWidget/money/tree/master
19
20
 
20
21
 
@@ -56,25 +57,31 @@ Exchanging money is performed through an exchange bank object. The default
56
57
  exchange bank object requires one to manually specify the exchange rate. Here's
57
58
  an example of how it works:
58
59
 
59
- Money.add_rate("USD", "CAD", 1.24515)
60
- Money.add_rate("CAD", "USD", 0.803115)
60
+ Money.add_rate("CAD", 0.803115)
61
+ Money.add_rate("USD", 1.24515)
61
62
 
62
- Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
63
- Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
63
+ Money.us_dollar(100_00).exchange_to("CAD") # => Money.new(15504, "CAD")
64
+ Money.ca_dollar(100_00).exchange_to("USD") # => Money.new(6450, "USD")
64
65
 
65
66
  or
66
67
 
67
- Money.us_dollar(100).to_cad # => Money.new(124, "CAD")
68
- Money.ca_dollar(100).to_usd # => Money.new(80, "USD")
68
+ Money.us_dollar(100).as_cad # => Money.new(155, "CAD")
69
+ Money.ca_dollar(100).as_usd # => Money.new(64, "USD")
69
70
 
70
71
  Comparison and arithmetic operations work as expected:
71
72
 
72
73
  Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
73
74
  Money.new(1000, "EUR") + Money.new(10, "EUR") == Money.new(1010, "EUR")
74
75
 
75
- Money.add_rate("USD", "EUR", 0.5)
76
+ Money.add_rate("EUR", 0.5)
76
77
  Money.new(1000, "EUR") + Money.new(1000, "USD") == Money.new(1500, "EUR")
77
78
 
79
+ Fetch the exchange rates published by the European Bank
80
+
81
+ Money.default_bank.fetch_rates # Fetch the rates
82
+ Money.default_bank.auto_fetch 3600 # Fetch the rates every hour
83
+ Money.default_bank.stop_fetch # Stop auto-fetch
84
+
78
85
  There is nothing stopping you from creating bank objects which scrapes
79
86
  www.xe.com for the current rates or just returns <tt>rand(2)</tt>:
80
87
 
data/Rakefile CHANGED
@@ -1,27 +1,48 @@
1
- %w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
2
- require File.dirname(__FILE__) + '/lib/money'
3
-
4
- # Generate all the Rake tasks
5
- # Run 'rake -T' to see list of generated tasks (from gem root directory)
6
- $hoe = Hoe.new('money', Money::VERSION) do |p|
7
- p.developer('Money Team', 'see@readme')
8
- p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
9
- p.rubyforge_name = p.name
10
- p.summary = "This library aids one in handling money and different currencies."
11
- p.description = "This library aids one in handling money and different currencies."
12
- p.url = "http://github.com/nofxx/money"
13
-
14
-
15
- p.extra_dev_deps = [
16
- ['newgem', ">= #{::Newgem::VERSION}"]
17
- ]
18
-
19
- p.clean_globs |= %w[**/.DS_Store *.log]
20
- path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
21
- p.remote_rdoc_dir = File.join(path.gsub(/^#{p.rubyforge_name}\/?/,''), 'rdoc')
22
- p.rsync_args = '-av --delete --ignore-errors'
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "money"
8
+ gem.summary = "This library aids one in handling money and different currencies."
9
+ gem.description = "This library aids one in handling money and different currencies."
10
+ gem.email = "see@reame"
11
+ gem.homepage = "http://github.com/nofxx/money"
12
+ gem.authors = ["Money Team"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
23
18
  end
24
19
 
25
- require 'newgem/tasks' # load /tasks/*.rake
26
- Dir['tasks/**/*.rake'].each { |t| load t }
20
+ require 'spec/rake/spectask'
21
+ Spec::Rake::SpecTask.new(:spec) do |spec|
22
+ spec.libs << 'lib' << 'spec'
23
+ spec.spec_files = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
27
+ spec.libs << 'lib' << 'spec'
28
+ spec.pattern = 'spec/**/*_spec.rb'
29
+ spec.rcov = true
30
+ end
31
+
32
+ task :default => :spec
33
+
34
+ require 'rake/rdoctask'
35
+ Rake::RDocTask.new do |rdoc|
36
+ if File.exist?('VERSION.yml')
37
+ config = YAML.load(File.read('VERSION.yml'))
38
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
39
+ else
40
+ version = ""
41
+ end
42
+
43
+ rdoc.rdoc_dir = 'rdoc'
44
+ rdoc.title = "money #{version}"
45
+ rdoc.rdoc_files.include('README*')
46
+ rdoc.rdoc_files.include('lib/**/*.rb')
47
+ end
27
48
 
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 2.3.5
@@ -0,0 +1,116 @@
1
+ require 'money/errors'
2
+ require 'net/http'
3
+ require 'rubygems'
4
+ begin
5
+ require "nokogiri"
6
+ Parser = Nokogiri
7
+ rescue
8
+ require "hpricot"
9
+ Parser = Hpricot
10
+ end
11
+ # Class for aiding in exchanging money between different currencies.
12
+ # By default, the Money class uses an object of this class (accessible through
13
+ # Money#bank) for performing currency exchanges.
14
+ #
15
+ # By default, ExchangeBank has no knowledge about conversion rates.
16
+ # One must manually specify them with +add_rate+, after which one can perform
17
+ # exchanges with +exchange+. For example:
18
+ #
19
+ # bank = Money::ExchangeBank.new
20
+ # bank.add_rate("CAD", 0.803115)
21
+ # bank.add_rate("USD", 1.24515)
22
+ #
23
+ # # Exchange 100 CAD to USD:
24
+ # bank.exchange(100_00, "CAD", "USD") # => 15504
25
+ # # Exchange 100 USD to CAD:
26
+ # bank.exchange(100_00, "USD", "CAD") # => 6450
27
+ class Money
28
+ class ExchangeBank
29
+ # Returns the singleton instance of ExchangeBank.
30
+ #
31
+ # By default, <tt>Money.default_bank</tt> returns the same object.
32
+ def self.instance
33
+ @@singleton
34
+ end
35
+
36
+ def initialize
37
+ @rates = {}
38
+ @mutex = Mutex.new
39
+ end
40
+
41
+ def add_rate(*params)
42
+ if rate = params.delete_at(2)
43
+ parse_rate(rate, *params)
44
+ else
45
+ parse_rate(params[1], Money.default_currency, params[0])
46
+ end
47
+ end
48
+
49
+ def parse_rate(rate,from,to)
50
+ return if from.upcase == to.upcase
51
+ @mutex.synchronize do
52
+ @rates["#{from}<>#{to}".upcase] = rate
53
+ @rates["#{to}<>#{from}".upcase] = 1.0/rate
54
+ end
55
+ end
56
+
57
+ def get_rate(from, to = nil)
58
+ from, to = Money.default_currency, from unless to
59
+ @mutex.synchronize do
60
+ @rates["#{from}<>#{to}".upcase]
61
+ end
62
+ end
63
+
64
+ # Given two currency names, checks whether they're both the same currency.
65
+ #
66
+ # bank = ExchangeBank.new
67
+ # bank.same_currency?("usd", "USD") # => true
68
+ # bank.same_currency?("usd", "EUR") # => false
69
+ def same_currency?(currency1, currency2)
70
+ currency1.upcase == currency2.upcase
71
+ end
72
+
73
+ # Exchange the given amount of cents in +from_currency+ to +to_currency+.
74
+ # Returns the amount of cents in +to_currency+ as an integer, rounded down.
75
+ #
76
+ # If the conversion rate is unknown, then Money::UnknownRate will be raised.
77
+ def exchange(cents, from_currency, to_currency)
78
+ rate = get_rate(from_currency, to_currency)
79
+ if !rate
80
+ raise Money::UnknownRate, "No conversion rate known for '#{from_currency}' -> '#{to_currency}'"
81
+ end
82
+ (cents * rate).floor
83
+ end
84
+
85
+ # Fetch rates
86
+ def fetch_rates
87
+ xml = Parser::XML(Net::HTTP.get(URI.parse('http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml')))
88
+ curr = (xml/:Cube).select { |r| r["currency"] == Money.default_currency }.first
89
+ diff = Money.default_currency == "EUR" || !curr ? 1 : curr["rate"].to_f
90
+ (xml/:Cube).each do |x|
91
+ parse_rate x['rate'].to_f / diff, curr ? Money.default_currency : "EUR", x['currency'].upcase if x['currency']
92
+ end
93
+ parse_rate diff, Money.default_currency, "EUR" if curr
94
+ self
95
+ end
96
+
97
+ # Auto fetch the currencies every X seconds
98
+ # if no time is give, will fetch every hour
99
+ def auto_fetch(time = 60*60)
100
+ @auto_fetch.kill if (@auto_fetch && @auto_fetch.alive?)
101
+ @auto_fetch = Thread.new {
102
+ loop do
103
+ self.fetch_rates
104
+ sleep time
105
+ end
106
+ }
107
+ end
108
+
109
+ # stop auto fetch
110
+ def stop_fetch
111
+ @auto_fetch.kill if (@auto_fetch && @auto_fetch.alive?)
112
+ end
113
+
114
+ @@singleton = ExchangeBank.new
115
+ end
116
+ end
data/lib/money/money.rb CHANGED
@@ -1,11 +1,11 @@
1
1
  # -*- coding: utf-8 -*-
2
- require 'money/variable_exchange_bank'
2
+ require 'money/exchange_bank'
3
3
 
4
4
  # Represents an amount of money in a certain currency.
5
5
  class Money
6
6
  include Comparable
7
-
8
7
  attr_reader :cents, :currency, :bank
8
+ alias :to_i :cents
9
9
 
10
10
  class << self
11
11
  # Each Money object is associated to a bank object, which is responsible
@@ -14,12 +14,22 @@ class Money
14
14
  #
15
15
  # bank1 = MyBank.new
16
16
  # bank2 = MyOtherBank.new
17
- #e if VariableExchangeBank.
17
+ #
18
+ # Money.default_bank = bank1
19
+ # money1 = Money.new(10)
20
+ # money1.bank # => bank1
21
+ #
22
+ # Money.default_bank = bank2
23
+ # money2 = Money.new(10)
24
+ # money2.bank # => bank2
25
+ # money1.bank # => bank1
26
+ #
27
+ # The default value for this property is an instance if VariableExchangeBank.
18
28
  # It allows one to specify custom exchange rates:
19
29
  #
20
30
  # Money.default_bank.add_rate("USD", "CAD", 1.24515)
21
31
  # Money.default_bank.add_rate("CAD", "USD", 0.803115)
22
- # Money.us_dollar(100).exchange_to("CAD") # => MONEY.ca_dollar(124)
32
+ # Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
23
33
  # Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
24
34
  attr_accessor :default_bank
25
35
 
@@ -28,7 +38,7 @@ class Money
28
38
  attr_accessor :default_currency
29
39
  end
30
40
 
31
- self.default_bank = VariableExchangeBank.instance
41
+ self.default_bank = ExchangeBank.instance
32
42
  self.default_currency = "USD"
33
43
 
34
44
  CURRENCIES = {
@@ -67,8 +77,8 @@ class Money
67
77
  Money.new(cents, "BRL")
68
78
  end
69
79
 
70
- def self.add_rate(from_currency, to_currency, rate)
71
- Money.default_bank.add_rate(from_currency, to_currency, rate)
80
+ def self.add_rate(*params)
81
+ Money.default_bank.add_rate(*params)
72
82
  end
73
83
 
74
84
  # Creates a new money object.
@@ -84,7 +94,8 @@ class Money
84
94
 
85
95
  # Do two money objects equal? Only works if both objects are of the same currency
86
96
  def ==(other_money)
87
- cents == other_money.cents && bank.same_currency?(currency, other_money.currency)
97
+ other_money.respond_to?(:cents) && cents == other_money.cents &&
98
+ other_money.respond_to?(:currency) && bank.same_currency?(currency, other_money.currency)
88
99
  end
89
100
 
90
101
  def <=>(other_money)
@@ -113,11 +124,6 @@ class Money
113
124
  end
114
125
  end
115
126
 
116
- # get the cents value of the object
117
- def cents
118
- @cents
119
- end
120
-
121
127
  # multiply money by fixnum
122
128
  def *(fixnum)
123
129
  Money.new(cents * fixnum, currency)
@@ -149,6 +155,41 @@ class Money
149
155
  Money.new(rate / 100 / period * cents * count)
150
156
  end
151
157
 
158
+ # Round to nearest coin value
159
+ # basically, we don't have coins for cents in CZK,
160
+ # our smallest fraction is 0.50CZK
161
+ #
162
+ # Money.new(14_58).round_to_coin(50) => 14.50
163
+ #
164
+ def round_to_coin(coin)
165
+ coef = 1.0/coin
166
+ val = (cents * coef).floor / coef
167
+ Money.new(val, currency)
168
+ end
169
+
170
+ # Returns array a where
171
+ # a[0] is price _after_ applying tax (tax base)
172
+ # a[1] is tax
173
+ def tax_breakdown(tax)
174
+ _tax = (cents * (tax / 100.0)).round
175
+ [Money.new(cents + _tax, currency), Money.new(_tax, currency)]
176
+ end
177
+
178
+ #Returns array a where
179
+ # a[0] is price _before_ applying tax (tax base)
180
+ # a[1] is tax
181
+ def tax_reverse_breakdown(tax)
182
+ coef = tax/100.0
183
+ [Money.new((cents / (1+coef)).round, currency),
184
+ Money.new((cents*coef/(1+coef)).round, currency) ]
185
+ end
186
+
187
+ # Just a helper if you got tax inputs in percentage.
188
+ # Ie. add_tax(20) => cents * 1.20
189
+ def add_tax(tax)
190
+ tax_breakdown(tax)[0]
191
+ end
192
+
152
193
  # Split money in number of installments
153
194
  #
154
195
  # Money.new(10_00).split_in_installments(3)
@@ -171,12 +212,6 @@ class Money
171
212
  split_in_installments(cents/other_money.cents, order)
172
213
  end
173
214
 
174
- # Just a helper if you got tax inputs in percentage.
175
- # Ie. add_tax(20) => cents * 1.20
176
- def add_tax(tax)
177
- Money.new(cents + cents / 100 * tax)
178
- end
179
-
180
215
  # Format the price according to several rules
181
216
  # Currently supported are :with_currency, :no_cents, :symbol and :html
182
217
  #
@@ -260,7 +295,6 @@ class Money
260
295
  rules
261
296
  end
262
297
 
263
-
264
298
  # Money.ca_dollar(100).to_s => "1.00"
265
299
  def to_s
266
300
  sprintf("%.2f", cents / 100.0)
@@ -292,7 +326,7 @@ end
292
326
 
293
327
  #
294
328
  # Represent a financial array.
295
- # Investment/Time/Installments...
329
+ # Investment/Time/Installments...TODO...
296
330
  #
297
331
  class Wallet < Array
298
332
 
data/lib/money.rb CHANGED
@@ -23,7 +23,3 @@
23
23
  $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
24
24
  require 'money/money'
25
25
  require 'money/core_extensions'
26
-
27
- class Money
28
- VERSION = "2.3.3"
29
- end
data/money.gemspec CHANGED
@@ -2,36 +2,63 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{money}
5
- s.version = "2.3.3"
5
+ s.version = "2.3.5"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Money Team"]
9
- s.date = %q{2009-03-24}
9
+ s.date = %q{2009-05-29}
10
10
  s.description = %q{This library aids one in handling money and different currencies.}
11
- s.email = ["see@readme"]
12
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
13
- s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "lib/money.rb", "lib/money/acts_as_money.rb", "lib/money/core_extensions.rb", "lib/money/errors.rb", "lib/money/money.rb", "lib/money/variable_exchange_bank.rb", "money.gemspec", "rails/init.rb", "script/console", "script/destroy", "script/generate", "spec/db/database.yml", "spec/db/schema.rb", "spec/money/acts_as_money_spec.rb", "spec/money/core_extensions_spec.rb", "spec/money/exchange_bank_spec.rb", "spec/money/money_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "tmp/acts_as_money.sqlite3"]
14
- s.has_rdoc = true
11
+ s.email = %q{see@reame}
12
+ s.extra_rdoc_files = [
13
+ "README.rdoc"
14
+ ]
15
+ s.files = [
16
+ ".gitignore",
17
+ "History.txt",
18
+ "MIT-LICENSE",
19
+ "Manifest.txt",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "lib/money.rb",
24
+ "lib/money/acts_as_money.rb",
25
+ "lib/money/core_extensions.rb",
26
+ "lib/money/errors.rb",
27
+ "lib/money/exchange_bank.rb",
28
+ "lib/money/money.rb",
29
+ "money.gemspec",
30
+ "rails/init.rb",
31
+ "spec/db/database.yml",
32
+ "spec/db/schema.rb",
33
+ "spec/money/acts_as_money_spec.rb",
34
+ "spec/money/core_extensions_spec.rb",
35
+ "spec/money/exchange_bank_spec.rb",
36
+ "spec/money/money_spec.rb",
37
+ "spec/spec.opts",
38
+ "spec/spec_helper.rb",
39
+ "tmp/.gitignore"
40
+ ]
15
41
  s.homepage = %q{http://github.com/nofxx/money}
16
- s.rdoc_options = ["--main", "README.rdoc"]
42
+ s.rdoc_options = ["--charset=UTF-8"]
17
43
  s.require_paths = ["lib"]
18
- s.rubyforge_project = %q{money}
19
- s.rubygems_version = %q{1.3.1}
44
+ s.rubygems_version = %q{1.3.3}
20
45
  s.summary = %q{This library aids one in handling money and different currencies.}
46
+ s.test_files = [
47
+ "spec/money/exchange_bank_spec.rb",
48
+ "spec/money/acts_as_money_spec.rb",
49
+ "spec/money/money_spec.rb",
50
+ "spec/money/core_extensions_spec.rb",
51
+ "spec/db/schema.rb",
52
+ "spec/spec_helper.rb"
53
+ ]
21
54
 
22
55
  if s.respond_to? :specification_version then
23
56
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
- s.specification_version = 2
57
+ s.specification_version = 3
25
58
 
26
59
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
- s.add_development_dependency(%q<newgem>, [">= 1.3.0"])
28
- s.add_development_dependency(%q<hoe>, [">= 1.8.0"])
29
60
  else
30
- s.add_dependency(%q<newgem>, [">= 1.3.0"])
31
- s.add_dependency(%q<hoe>, [">= 1.8.0"])
32
61
  end
33
62
  else
34
- s.add_dependency(%q<newgem>, [">= 1.3.0"])
35
- s.add_dependency(%q<hoe>, [">= 1.8.0"])
36
63
  end
37
64
  end
@@ -1,8 +1,8 @@
1
1
  require File.dirname(__FILE__) + '/../spec_helper.rb'
2
2
 
3
- describe Money::VariableExchangeBank do
3
+ describe Money::ExchangeBank do
4
4
  before :each do
5
- @bank = Money::VariableExchangeBank.new
5
+ @bank = Money::ExchangeBank.new
6
6
  end
7
7
 
8
8
  it "returns the previously specified conversion rate" do
@@ -12,6 +12,13 @@ describe Money::VariableExchangeBank do
12
12
  @bank.get_rate("EUR", "YEN").should == 122.631477
13
13
  end
14
14
 
15
+ it "returns the previously specified conversion rate" do
16
+ @bank.add_rate("USD", "EUR", 0.788332676)
17
+ @bank.add_rate("EUR", "YEN", 122.631477)
18
+ @bank.get_rate("USD", "EUR").should == 0.788332676
19
+ @bank.get_rate("EUR", "YEN").should == 122.631477
20
+ end
21
+
15
22
  it "treats currency names case-insensitively" do
16
23
  @bank.add_rate("usd", "eur", 1)
17
24
  @bank.get_rate("USD", "EUR").should == 1
@@ -33,12 +40,103 @@ describe Money::VariableExchangeBank do
33
40
  it "rounds the exchanged result down" do
34
41
  @bank.add_rate("USD", "EUR", 0.788332676)
35
42
  @bank.add_rate("EUR", "YEN", 122.631477)
36
- @bank.exchange(10_00, "USD", "EUR").should == 788
43
+ @bank.exchange(10_00, "USD", "EUR").should == 7_88
37
44
  @bank.exchange(500_00, "EUR", "YEN").should == 6131573
38
45
  end
39
46
 
47
+ it "returns the previously specified conversion rate" do
48
+ @bank.add_rate("EUR", 122.631477)
49
+ @bank.get_rate("EUR").should == 122.631477
50
+ end
51
+
52
+ it "treats currency names case-insensitively" do
53
+ @bank.add_rate("yen", 1)
54
+ @bank.get_rate("YEN").should == 1
55
+ @bank.same_currency?("USD", "usd").should be_true
56
+ @bank.same_currency?("EUR", "usd").should be_false
57
+ end
58
+
59
+ it "should work with a different default currency" do
60
+ Money.default_currency = "BRL"
61
+ @bank.add_rate("yen", 10)
62
+ @bank.exchange(5_00, "brl", "yen").should == 50_00
63
+ Money.default_currency = "USD"
64
+ end
65
+
66
+ it "returns nil if the conversion rate is unknown" do
67
+ @bank.get_rate("American Pesos").should be_nil
68
+ end
69
+
70
+ it "exchanges money from one currency to another according to the specified conversion rates" do
71
+ @bank.add_rate("EUR", 0.5)
72
+ @bank.add_rate("YEN", 5)
73
+ @bank.exchange(10_00, "USD", "EUR").should == 5_00
74
+ @bank.exchange(500_00, "USD", "YEN").should == 2500_00
75
+ @bank.exchange(2500_00, "YEN", "USD").should == 500_00
76
+ end
77
+
78
+ it "should deal fine with FOO_TO_FOO" do
79
+ @bank.add_rate("USD", 2.0)
80
+ @bank.get_rate("USD").should be_nil
81
+ end
82
+
83
+ it "should test some more" do
84
+ @bank.add_rate("EUR", 0.788332676)
85
+ @bank.add_rate("YEN", 122.631477)
86
+ @bank.exchange(10_00, "USD", "EUR").should == 788
87
+ @bank.exchange(500_00, "USD", "YEN").should == 6131573
88
+ end
89
+
40
90
  it "raises Money::UnknownRate upon conversion if the conversion rate is unknown" do
41
- block = lambda { @bank.exchange(10, "USD", "EUR") }
91
+ block = lambda { @bank.exchange(10, "USD", "ABC") }
42
92
  block.should raise_error(Money::UnknownRate)
43
93
  end
94
+
95
+ describe "Fetching Data" do
96
+
97
+ before(:each) do
98
+ URI.should_receive(:parse).with("http://www.ecb.int/stats/eurofxref/eurofxref-daily.xml").and_return(:uri)
99
+ Net::HTTP.should_receive(:get).with(:uri).and_return("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<gesmes:Envelope xmlns:gesmes=\"http://www.gesmes.org/xml/2002-08-01\" xmlns=\"http://www.ecb.int/vocabulary/2002-08-01/eurofxref\">\n\t<gesmes:subject>Reference rates</gesmes:subject>\n\t<gesmes:Sender>\n\t\t<gesmes:name>European Central Bank</gesmes:name>\n\t</gesmes:Sender>\n\t<Cube>\n\t\t<Cube time='2009-05-29'>\n\t\t\t<Cube currency='USD' rate='1.4098'/>\n\t\t\t<Cube currency='JPY' rate='135.22'/>\n\t\t\t<Cube currency='BGN' rate='1.9558'/>\n\t\t\t<Cube currency='CZK' rate='26.825'/>\n\t\t\t<Cube currency='DKK' rate='7.4453'/>\n\t\t\t<Cube currency='EEK' rate='15.6466'/>\n\t\t\t<Cube currency='GBP' rate='0.87290'/>\n\t\t\t<Cube currency='HUF' rate='282.48'/>\n\t\t\t<Cube currency='LTL' rate='3.4528'/>\n\t\t\t<Cube currency='LVL' rate='0.7093'/>\n\t\t\t<Cube currency='PLN' rate='4.4762'/>\n\t\t\t<Cube currency='RON' rate='4.1825'/>\n\t\t\t<Cube currency='SEK' rate='10.6678'/>\n\t\t\t<Cube currency='CHF' rate='1.5128'/>\n\t\t\t<Cube currency='NOK' rate='8.8785'/>\n\t\t\t<Cube currency='HRK' rate='7.3500'/>\n\t\t\t<Cube currency='RUB' rate='43.4455'/>\n\t\t\t<Cube currency='TRY' rate='2.1737'/>\n\t\t\t<Cube currency='AUD' rate='1.7671'/>\n\t\t\t<Cube currency='BRL' rate='2.8320'/>\n\t\t\t<Cube currency='CAD' rate='1.5501'/>\n\t\t\t<Cube currency='CNY' rate='9.6263'/>\n\t\t\t<Cube currency='HKD' rate='10.9273'/>\n\t\t\t<Cube currency='IDR' rate='14539.26'/>\n\t\t\t<Cube currency='INR' rate='66.4260'/>\n\t\t\t<Cube currency='KRW' rate='1764.04'/>\n\t\t\t<Cube currency='MXN' rate='18.4340'/>\n\t\t\t<Cube currency='MYR' rate='4.9167'/>\n\t\t\t<Cube currency='NZD' rate='2.2135'/>\n\t\t\t<Cube currency='PHP' rate='66.516'/>\n\t\t\t<Cube currency='SGD' rate='2.0350'/>\n\t\t\t<Cube currency='THB' rate='48.377'/>\n\t\t\t<Cube currency='ZAR' rate='11.2413'/>\n\t\t</Cube>\n\t</Cube>\n</gesmes:Envelope>")
100
+ end
101
+
102
+ it "should fetch data" do
103
+ Money.default_currency = "EUR"
104
+ @bank.fetch_rates
105
+ @bank.get_rate("DKK").should be_close(7.4453, 0.0001)
106
+ @bank.get_rate("BRL").should be_close(2.832, 0.001)
107
+ @bank.exchange(10_00, "EUR", "DKK").should == 74_45
108
+ end
109
+
110
+ it "should fetch diff than eur" do
111
+ Money.default_currency = "BRL"
112
+ @bank.fetch_rates
113
+ @bank.get_rate("DKK").should be_close(2.6289, 0.0001)
114
+ @bank.get_rate("EEK").should be_close(5.5249, 0.0001)
115
+ @bank.get_rate("EUR").should be_close(2.832, 0.001)
116
+ end
117
+
118
+ it "should fetch for an unknown one" do
119
+ Money.default_currency = "XXX"
120
+ @bank.fetch_rates
121
+ @bank.get_rate("DKK").should be_nil
122
+ @bank.get_rate("EUR", "USD").should be_close(1.4098, 0.001)
123
+ Money.default_currency = "USD"
124
+
125
+ end
126
+ end
127
+
128
+ describe "Live Fetching" do
129
+
130
+ if ENV["LIVE"]
131
+
132
+ it "should fetch data live" do
133
+ @bank.fetch_rates
134
+ @bank.get_rate("DKK").should_not be_nil
135
+ @bank.get_rate("EUR").should_not be_nil
136
+ end
137
+
138
+ end
139
+
140
+ end
141
+
44
142
  end
@@ -3,11 +3,12 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
3
3
 
4
4
  describe Money do
5
5
 
6
- it { Money.new(10_00).to_f.should eql(10.0) }
7
- it { Money.new(10_00).to_s.should eql("10.00") }
6
+ it { Money.new(10_00).to_f.should eql(10.0) }
7
+ it { Money.new(10_00).to_s.should eql("10.00") }
8
+ it { Money.new(199).to_i.should eql(199) }
8
9
 
9
- it "is associated to the singleton instance of VariableExchangeBank by default" do
10
- Money.new(0).bank.object_id.should == Money::VariableExchangeBank.instance.object_id
10
+ it "is associated to the singleton instance of ExchangeBank by default" do
11
+ Money.new(0).bank.object_id.should == Money::ExchangeBank.instance.object_id
11
12
  end
12
13
 
13
14
  it "should return the amount of cents passed to the constructor" do
@@ -111,11 +112,30 @@ describe Money do
111
112
 
112
113
  it "shuld sum array" do
113
114
  Money.new(10_00).split_in_installments(3).sum.cents.should eql(1000)
115
+ Money.new(19_99).split_in_installments(3).sum.cents.should eql(1999)
114
116
  end
115
117
 
116
118
  it "should calculate tax" do
117
119
  Money.new(100).add_tax(20).cents.should eql(120)
118
120
  Money.new(100).add_tax(-20).cents.should eql(80)
121
+ Money.new(1218).add_tax(19).cents.should eql(1449)
122
+ Money.new(1218).add_tax(-19).cents.should eql(987)
123
+ Money.new(1000).add_tax(150).cents.should eql(2500)
124
+ Money.new(1000).add_tax(-150).cents.should eql(-500)
125
+ end
126
+
127
+ it "should round to .50 coin" do
128
+ Money.new(14_58).round_to_coin(50).cents.should eql(1450)
129
+ Money.new(14_58).round_to_coin(10).cents.should eql(1450)
130
+ Money.new(14_58).round_to_coin(5).cents.should eql(1455)
131
+ end
132
+
133
+ it "should provide tax breakdown" do
134
+ Money.new(1225).tax_breakdown(19).map{|c| c.to_s}.should eql(['14.58','2.33'])
135
+ end
136
+
137
+ it "should provide reverse tax breakdown" do
138
+ Money.new(-8).tax_reverse_breakdown(19).map{|c| c.to_s}.should eql(['-0.07','-0.01'])
119
139
  end
120
140
 
121
141
  it "shuld to_s wallet" do
@@ -132,11 +152,17 @@ describe Money do
132
152
 
133
153
  describe "Taxes and Interest" do
134
154
 
135
- it "Money.add_rate works" do
155
+ it "Money rate works" do
136
156
  Money.add_rate("EUR", "USD", 10)
137
157
  Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
138
158
  end
139
159
 
160
+ it "Money.add_rate works" do
161
+ Money.add_rate("USD", 1.0)
162
+ Money.add_rate("EUR", 10)
163
+ Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(1_00, "USD")
164
+ end
165
+
140
166
  it "Money method missing exchange" do
141
167
  Money.add_rate("EUR", "BRL", 10)
142
168
  Money.new(10_00, "EUR").as_brl.should == Money.new(100_00, "BRL")
@@ -197,51 +223,55 @@ describe Money do
197
223
  it { Money.new(880000000000, "GBP").format(:no_cents => true).should eql("£8,800,000,000") }
198
224
  it { Money.new(8800000000088, "EUR").format.should eql("€88,000,000,000.88") }
199
225
 
200
- end
201
-
202
-
203
- describe "Actions involving two Money objects" do
204
- describe "if the other Money object has the same currency" do
205
- it "#<=> compares the two objects' amounts" do
206
- (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
207
- (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
208
- (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
209
- end
210
-
211
- it "#+ adds the other object's amount to the current object's amount while retaining the currency" do
212
- (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
213
- end
214
-
215
- it "#- substracts the other object's amount from the current object's amount while retaining the currency" do
216
- (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
217
- end
226
+ it "should fail nicely if symbol can`t be found" do
227
+ Money.default_currency = "XXX"
228
+ Money.new(800).format.should eql("$8.00")
229
+ Money.default_currency = "USD"
218
230
  end
219
231
 
220
- describe "if the other Money object has a different currency" do
221
- it "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
222
- target = Money.new(200_00, "EUR")
223
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
224
- (Money.new(100_00, "USD") <=> target).should < 0
225
-
226
- target = Money.new(200_00, "EUR")
227
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
228
- (Money.new(100_00, "USD") <=> target).should == 0
229
-
230
- target = Money.new(200_00, "EUR")
231
- target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
232
- (Money.new(100_00, "USD") <=> target).should > 0
233
- end
234
-
235
- it "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
236
- other = Money.new(90, "EUR")
237
- other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
238
- (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
232
+ describe "Actions involving two Money objects" do
233
+ describe "if the other Money object has the same currency" do
234
+ it "#<=> compares the two objects' amounts" do
235
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
236
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
237
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
238
+ end
239
+
240
+ it "#+ adds the other object's amount to the current object's amount while retaining the currency" do
241
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
242
+ end
243
+
244
+ it "#- substracts the other object's amount from the current object's amount while retaining the currency" do
245
+ (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
246
+ end
239
247
  end
240
248
 
241
- it "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
242
- other = Money.new(90, "EUR")
243
- other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
244
- (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
249
+ describe "if the other Money object has a different currency" do
250
+ it "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
251
+ target = Money.new(200_00, "EUR")
252
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
253
+ (Money.new(100_00, "USD") <=> target).should < 0
254
+
255
+ target = Money.new(200_00, "EUR")
256
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
257
+ (Money.new(100_00, "USD") <=> target).should == 0
258
+
259
+ target = Money.new(200_00, "EUR")
260
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
261
+ (Money.new(100_00, "USD") <=> target).should > 0
262
+ end
263
+
264
+ it "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
265
+ other = Money.new(90, "EUR")
266
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
267
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
268
+ end
269
+
270
+ it "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
271
+ other = Money.new(90, "EUR")
272
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
273
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
274
+ end
245
275
  end
246
276
  end
247
277
  end
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  begin
2
+ require 'rubygems'
2
3
  require 'spec'
3
4
  require 'active_record'
4
5
  rescue LoadError
@@ -6,8 +7,8 @@ rescue LoadError
6
7
  gem 'rspec'
7
8
  require 'spec'
8
9
  end
9
- require 'active_record'
10
- $:.unshift(File.dirname(__FILE__) + '/../lib')
10
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
11
12
  require 'money'
12
13
 
13
14
  config = YAML.load_file(File.dirname(__FILE__) + '/db/database.yml')
data/tmp/.gitignore ADDED
File without changes
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nofxx-money
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.3
4
+ version: 2.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Money Team
@@ -9,57 +9,34 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-24 00:00:00 -07:00
12
+ date: 2009-05-29 00:00:00 -07:00
13
13
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: newgem
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
- - - ">="
22
- - !ruby/object:Gem::Version
23
- version: 1.3.0
24
- version:
25
- - !ruby/object:Gem::Dependency
26
- name: hoe
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: 1.8.0
34
- version:
14
+ dependencies: []
15
+
35
16
  description: This library aids one in handling money and different currencies.
36
- email:
37
- - see@readme
17
+ email: see@reame
38
18
  executables: []
39
19
 
40
20
  extensions: []
41
21
 
42
22
  extra_rdoc_files:
43
- - History.txt
44
- - Manifest.txt
45
23
  - README.rdoc
46
24
  files:
25
+ - .gitignore
47
26
  - History.txt
48
27
  - MIT-LICENSE
49
28
  - Manifest.txt
50
29
  - README.rdoc
51
30
  - Rakefile
31
+ - VERSION
52
32
  - lib/money.rb
53
33
  - lib/money/acts_as_money.rb
54
34
  - lib/money/core_extensions.rb
55
35
  - lib/money/errors.rb
36
+ - lib/money/exchange_bank.rb
56
37
  - lib/money/money.rb
57
- - lib/money/variable_exchange_bank.rb
58
38
  - money.gemspec
59
39
  - rails/init.rb
60
- - script/console
61
- - script/destroy
62
- - script/generate
63
40
  - spec/db/database.yml
64
41
  - spec/db/schema.rb
65
42
  - spec/money/acts_as_money_spec.rb
@@ -68,13 +45,12 @@ files:
68
45
  - spec/money/money_spec.rb
69
46
  - spec/spec.opts
70
47
  - spec/spec_helper.rb
71
- - tmp/acts_as_money.sqlite3
72
- has_rdoc: true
48
+ - tmp/.gitignore
49
+ has_rdoc: false
73
50
  homepage: http://github.com/nofxx/money
74
51
  post_install_message:
75
52
  rdoc_options:
76
- - --main
77
- - README.rdoc
53
+ - --charset=UTF-8
78
54
  require_paths:
79
55
  - lib
80
56
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -91,10 +67,15 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
67
  version:
92
68
  requirements: []
93
69
 
94
- rubyforge_project: money
70
+ rubyforge_project:
95
71
  rubygems_version: 1.2.0
96
72
  signing_key:
97
- specification_version: 2
73
+ specification_version: 3
98
74
  summary: This library aids one in handling money and different currencies.
99
- test_files: []
100
-
75
+ test_files:
76
+ - spec/money/exchange_bank_spec.rb
77
+ - spec/money/acts_as_money_spec.rb
78
+ - spec/money/money_spec.rb
79
+ - spec/money/core_extensions_spec.rb
80
+ - spec/db/schema.rb
81
+ - spec/spec_helper.rb
@@ -1,72 +0,0 @@
1
- require 'thread'
2
- require 'money/errors'
3
-
4
- # Class for aiding in exchanging money between different currencies.
5
- # By default, the Money class uses an object of this class (accessible through
6
- # Money#bank) for performing currency exchanges.
7
- #
8
- # By default, VariableExchangeBank has no knowledge about conversion rates.
9
- # One must manually specify them with +add_rate+, after which one can perform
10
- # exchanges with +exchange+. For example:
11
- #
12
- # bank = Money::VariableExchangeBank.new
13
- # bank.add_rate("USD", "CAD", 1.24515)
14
- # bank.add_rate("CAD", "USD", 0.803115)
15
- #
16
- # # Exchange 100 CAD to USD:
17
- # bank.exchange(100_00, "CAD", "USD") # => 124
18
- # # Exchange 100 USD to CAD:
19
- # bank.exchange(100_00, "USD", "CAD") # => 80
20
- class Money
21
- class VariableExchangeBank
22
- # Returns the singleton instance of VariableExchangeBank.
23
- #
24
- # By default, <tt>Money.default_bank</tt> returns the same object.
25
- def self.instance
26
- @@singleton
27
- end
28
-
29
- def initialize
30
- @rates = {}
31
- @mutex = Mutex.new
32
- end
33
-
34
- # Registers a conversion rate. +from+ and +to+ are both currency names.
35
- def add_rate(from, to, rate)
36
- @mutex.synchronize do
37
- @rates["#{from}_TO_#{to}".upcase] = rate
38
- end
39
- end
40
-
41
- # Gets the rate for exchanging the currency named +from+ to the currency
42
- # named +to+. Returns nil if the rate is unknown.
43
- def get_rate(from, to)
44
- @mutex.synchronize do
45
- @rates["#{from}_TO_#{to}".upcase]
46
- end
47
- end
48
-
49
- # Given two currency names, checks whether they're both the same currency.
50
- #
51
- # bank = VariableExchangeBank.new
52
- # bank.same_currency?("usd", "USD") # => true
53
- # bank.same_currency?("usd", "EUR") # => false
54
- def same_currency?(currency1, currency2)
55
- currency1.upcase == currency2.upcase
56
- end
57
-
58
- # Exchange the given amount of cents in +from_currency+ to +to_currency+.
59
- # Returns the amount of cents in +to_currency+ as an integer, rounded down.
60
- #
61
- # If the conversion rate is unknown, then Money::UnknownRate will be raised.
62
- def exchange(cents, from_currency, to_currency)
63
- rate = get_rate(from_currency, to_currency)
64
- if !rate
65
- raise Money::UnknownRate, "No conversion rate known for '#{from_currency}' -> '#{to_currency}'"
66
- end
67
- (cents * rate).floor
68
- end
69
-
70
- @@singleton = VariableExchangeBank.new
71
- end
72
- end
data/script/console DELETED
@@ -1,10 +0,0 @@
1
- #!/usr/bin/env ruby
2
- # File: script/console
3
- irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
-
5
- libs = " -r irb/completion"
6
- # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
- # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
- libs << " -r #{File.dirname(__FILE__) + '/../lib/postgis_adapter.rb'}"
9
- puts "Loading postgis_adapter gem"
10
- exec "#{irb} #{libs} --simple-prompt"
data/script/destroy DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
-
4
- begin
5
- require 'rubigen'
6
- rescue LoadError
7
- require 'rubygems'
8
- require 'rubigen'
9
- end
10
- require 'rubigen/scripts/destroy'
11
-
12
- ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
- RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
- RubiGen::Scripts::Destroy.new.run(ARGV)
data/script/generate DELETED
@@ -1,14 +0,0 @@
1
- #!/usr/bin/env ruby
2
- APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
-
4
- begin
5
- require 'rubigen'
6
- rescue LoadError
7
- require 'rubygems'
8
- require 'rubigen'
9
- end
10
- require 'rubigen/scripts/generate'
11
-
12
- ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
- RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
- RubiGen::Scripts::Generate.new.run(ARGV)