acvwilson-currency 0.5.2 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/currency.gemspec CHANGED
@@ -1,18 +1,18 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = %q{currency}
3
- s.version = "0.5.2"
3
+ s.version = "0.6.0"
4
4
 
5
5
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
6
  s.authors = ["Asa Wilson"]
7
- s.date = %q{2008-11-14}
7
+ s.date = %q{#{Date.today}}
8
8
  s.description = %q{Currency conversions for Ruby}
9
9
  s.email = ["acvwilson@gmail.com"]
10
10
  s.extra_rdoc_files = ["ChangeLog", "COPYING.txt", "LICENSE.txt", "Manifest.txt", "README.txt", "Releases.txt", "TODO.txt"]
11
- s.files = ["COPYING.txt", "currency.gemspec", "examples/ex1.rb", "examples/xe1.rb", "lib/currency/active_record.rb", "lib/currency/config.rb", "lib/currency/core_extensions.rb", "lib/currency/currency/factory.rb", "lib/currency/currency.rb", "lib/currency/currency_version.rb", "lib/currency/exception.rb", "lib/currency/exchange/rate/deriver.rb", "lib/currency/exchange/rate/source/base.rb", "lib/currency/exchange/rate/source/failover.rb", "lib/currency/exchange/rate/source/federal_reserve.rb", "lib/currency/exchange/rate/source/historical/rate.rb", "lib/currency/exchange/rate/source/historical/rate_loader.rb", "lib/currency/exchange/rate/source/historical/writer.rb", "lib/currency/exchange/rate/source/historical.rb", "lib/currency/exchange/rate/source/new_york_fed.rb", "lib/currency/exchange/rate/source/provider.rb", "lib/currency/exchange/rate/source/test.rb", "lib/currency/exchange/rate/source/the_financials.rb", "lib/currency/exchange/rate/source/timed_cache.rb", "lib/currency/exchange/rate/source/xe.rb", "lib/currency/exchange/rate/source.rb", "lib/currency/exchange/rate.rb", "lib/currency/exchange/time_quantitizer.rb", "lib/currency/exchange.rb", "lib/currency/formatter.rb", "lib/currency/macro.rb", "lib/currency/money.rb", "lib/currency/money_helper.rb", "lib/currency/parser.rb", "lib/currency.rb", "LICENSE.txt", "Manifest.txt", "README.txt", "Releases.txt", "spec/ar_spec_helper.rb", "spec/ar_column_spec.rb", "spec/ar_core_spec.rb", "spec/ar_simple_spec.rb", "spec/config_spec.rb", "spec/federal_reserve_spec.rb", "spec/formatter_spec.rb", "spec/historical_writer_spec.rb", "spec/macro_spec.rb", "spec/money_spec.rb", "spec/new_york_fed_spec.rb", "spec/parser_spec.rb", "spec/spec_helper.rb", "spec/time_quantitizer_spec.rb", "spec/timed_cache_spec.rb", "spec/xe_spec.rb", "TODO.txt"]
11
+ s.files = ["COPYING.txt", "currency.gemspec", "examples/ex1.rb", "examples/xe1.rb", "lib/currency/active_record.rb", "lib/currency/config.rb", "lib/currency/core_extensions.rb", "lib/currency/currency/factory.rb", "lib/currency/currency.rb", "lib/currency/currency_version.rb", "lib/currency/exception.rb", "lib/currency/exchange/rate/deriver.rb", "lib/currency/exchange/rate/source/base.rb", "lib/currency/exchange/rate/source/failover.rb", "lib/currency/exchange/rate/source/federal_reserve.rb", "lib/currency/exchange/rate/source/historical/rate.rb", "lib/currency/exchange/rate/source/historical/rate_loader.rb", "lib/currency/exchange/rate/source/historical/writer.rb", "lib/currency/exchange/rate/source/historical.rb", "lib/currency/exchange/rate/source/new_york_fed.rb", "lib/currency/exchange/rate/source/provider.rb", "lib/currency/exchange/rate/source/test.rb", "lib/currency/exchange/rate/source/the_financials.rb", "lib/currency/exchange/rate/source/timed_cache.rb", "lib/currency/exchange/rate/source/xe.rb", "lib/currency/exchange/rate/source.rb", "lib/currency/exchange/rate.rb", "lib/currency/exchange/time_quantitizer.rb", "lib/currency/exchange.rb", "lib/currency/formatter.rb", "lib/currency/macro.rb", "lib/currency/money.rb", "lib/currency/money_helper.rb", "lib/currency/parser.rb", "lib/currency.rb", "LICENSE.txt", "Manifest.txt", "README.txt", "Releases.txt", "spec/ar_spec_helper.rb", "spec/ar_column_spec.rb", "spec/ar_simple_spec.rb", "spec/config_spec.rb", "spec/federal_reserve_spec.rb", "spec/formatter_spec.rb", "spec/historical_writer_spec.rb", "spec/macro_spec.rb", "spec/money_spec.rb", "spec/new_york_fed_spec.rb", "spec/parser_spec.rb", "spec/spec_helper.rb", "spec/time_quantitizer_spec.rb", "spec/timed_cache_spec.rb", "spec/xe_spec.rb", "TODO.txt"]
12
12
  s.has_rdoc = true
13
13
  s.homepage = %q{http://currency.rubyforge.org/}
14
14
  s.rdoc_options = ["--main", "README.txt"]
15
15
  s.require_paths = ["lib"]
16
16
  s.rubygems_version = %q{1.2.0}
17
- s.summary = %q{currency 0.5.2}
17
+ s.summary = %q{#{s.name} #{s.version}}
18
18
  end
data/lib/currency.rb CHANGED
@@ -140,4 +140,4 @@ require 'currency/exchange/rate/source'
140
140
  require 'currency/exchange/rate/source/test'
141
141
  require 'currency/exchange/time_quantitizer'
142
142
  require 'currency/core_extensions'
143
- require 'active_support'
143
+ require 'active_support' # high(-er) precision rounding
@@ -7,38 +7,35 @@
7
7
  # TO DO:
8
8
  #
9
9
  # Migrate all class variable configurations to this object.
10
+ # Rewrite this whole class. It is not working at all after first config
11
+ # Threads are bad. Use the Singleton library when rewriting this
10
12
  class Currency::Config
11
- @@default = nil
12
-
13
13
  # Returns the default Currency::Config object.
14
14
  #
15
15
  # If one is not specfied an instance is
16
16
  # created. This is a global, not thread-local.
17
17
  def self.default
18
- @@default ||=
19
- self.new
18
+ @@default ||= self.new
20
19
  end
21
20
 
22
21
  # Sets the default Currency::Config object.
23
22
  def self.default=(x)
24
23
  @@default = x
24
+ Currency::Currency::Factory.reset
25
+ @@default
25
26
  end
26
27
 
27
- # Returns the current Currency::Config object used during
28
- # in the current thread.
29
- #
28
+ # Returns the current Currency::Config object
30
29
  # If #current= has not been called and #default= has not been called,
31
30
  # then UndefinedExchange is raised.
32
31
  def self.current
33
- Thread.current[:Currency__Config] ||=
34
- self.default ||
35
- (raise ::Currency::Exception::UndefinedConfig, "Currency::Config.default not defined")
32
+ self.default || (raise ::Currency::Exception::UndefinedConfig, "Currency::Config.default not defined")
36
33
  end
37
34
 
38
35
  # Sets the current Currency::Config object used
39
36
  # in the current thread.
40
37
  def self.current=(x)
41
- Thread.current[:Currency__Config] = x
38
+ self.default = x
42
39
  end
43
40
 
44
41
  # Clones the current configuration and makes it current
@@ -49,36 +46,29 @@ class Currency::Config
49
46
  # c.float_ref_filter = Proc.new { | x | x.round }
50
47
  # "123.448".money.rep == 12345
51
48
  # end
49
+ # TODO: rewrite from scratch
52
50
  def self.configure(&blk)
53
51
  c_prev = current
54
52
  c_new = self.current = current.clone
55
53
  result = nil
56
54
  begin
57
55
  result = yield c_new
58
- ensure
56
+ rescue
59
57
  self.current = c_prev
60
58
  end
61
59
  result
62
60
  end
63
61
 
64
62
 
65
- @@identity = Proc.new { |x| x } # :nodoc:
66
-
67
63
  # Returns the current Float conversion filter.
68
64
  # Can be used to set rounding or truncation policies when converting
69
65
  # Float values to Money values.
70
66
  # Defaults to an identity function.
71
67
  # See Float#Money_rep.
68
+ attr_accessor :float_ref_filter
72
69
  def float_ref_filter
73
- @float_ref_filter ||=
74
- @@identity
75
- end
76
-
77
- # Sets the current Float conversion filter.
78
- def float_ref_filter=(x)
79
- @float_ref_filter = x
70
+ @float_ref_filter ||= Proc.new { |x| x }
80
71
  end
81
-
82
72
 
83
73
  # Defines the table name for Historical::Rate records.
84
74
  # Defaults to 'currency_historical_rates'.
@@ -86,6 +76,18 @@ class Currency::Config
86
76
  def historical_table_name
87
77
  @historical_table_name ||= 'currency_historical_rates'
88
78
  end
79
+
80
+ attr_accessor :scale_exp
81
+ def scale_exp=(val)
82
+ raise ArgumentError, "Invalid scale exponent" unless val.integer?
83
+ raise ArgumentError, "Invalid scale: zero" if val.zero?
84
+ @scale_exp = val
85
+ Currency::Currency::Factory.reset
86
+ end
89
87
 
90
- end # module
91
-
88
+ attr_reader :scale
89
+ def scale
90
+ 10 ** (scale_exp || 2)
91
+ end
92
+
93
+ end
@@ -1,8 +1,6 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
-
5
-
6
4
  class Object
7
5
  # Exact conversion to Money representation value.
8
6
  def money(*opts)
@@ -10,8 +8,6 @@ class Object
10
8
  end
11
9
  end
12
10
 
13
-
14
-
15
11
  class Integer
16
12
  # Exact conversion to Money representation value.
17
13
  def Money_rep(currency, time = nil)
@@ -19,59 +15,13 @@ class Integer
19
15
  end
20
16
  end
21
17
 
22
- # module Asa
23
- # module Rounding
24
- # def self.included(base) #:nodoc:
25
- # puts "included by #{base.inspect}"
26
- # base.class_eval do
27
- # alias_method :round_without_precision, :round
28
- # alias_method :round, :round_with_precision
29
- # end
30
- # end
31
- #
32
- # # Rounds the float with the specified precision.
33
- # #
34
- # # x = 1.337
35
- # # x.round # => 1
36
- # # x.round(1) # => 1.3
37
- # # x.round(2) # => 1.34
38
- # def round_with_precision(precision = nil)
39
- # precision.nil? ? round_without_precision : (self * (10 ** precision)).round / (10 ** precision).to_f
40
- # end
41
- #
42
- # end
43
- # end
44
- #
45
- # class Float
46
- # include Asa::Rounding
47
- # # Inexact conversion to Money representation value.
48
- # def Money_rep(currency, time = nil)
49
- # Integer(Currency::Config.current.float_ref_filter.call(self * currency.scale))
50
- # end
51
- # end
52
-
53
18
  class Float
54
19
  # Inexact conversion to Money representation value.
55
20
  def Money_rep(currency, time = nil)
56
21
  Integer(Currency::Config.current.float_ref_filter.call(self * currency.scale))
57
22
  end
58
-
59
- # def round_with_awesome_precision(precision = nil)
60
- # # puts "self: #{self.inspect}"
61
- # # puts "precision: #{precision.inspect}"
62
- # # puts "round_without_precision: #{round_without_precision.inspect}"
63
- # # puts "self * (10 ** precision): #{(self * (10 ** precision)).inspect}"
64
- # # puts "(self * (10 ** precision)).round_without_precision: #{((self * (10 ** precision)).round_without_precision).inspect}"
65
- # # self.to_s.to_f.round_without_precision
66
- # precision.nil? ? round_without_awesome_precision : (self * (10 ** precision)).round_without_awesome_precision / (10 ** precision).to_f
67
- # end
68
- # alias_method :round_without_awesome_precision, :round
69
- # alias_method :round, :round_with_awesome_precision
70
23
  end
71
24
 
72
-
73
-
74
-
75
25
  class String
76
26
  # Exact conversion to Money representation value.
77
27
  def Money_rep(currency, time = nil)
@@ -44,14 +44,11 @@ class Currency::Currency
44
44
 
45
45
  # Create a new currency.
46
46
  # This should only be called from Currency::Currency::Factory.
47
- def initialize(code, symbol = nil, scale = 1000000)
47
+ # def initialize(code, symbol = nil, scale = 1000000)
48
+ def initialize(code, symbol = nil, scale = Currency::Config.current.scale)
48
49
  self.code = code
49
50
  self.symbol = symbol
50
51
  self.scale = scale
51
-
52
- @formatter =
53
- @parser =
54
- nil
55
52
  end
56
53
 
57
54
 
@@ -22,6 +22,16 @@ class Currency::Currency::Factory
22
22
  @currency = nil
23
23
  end
24
24
 
25
+ def self.reset
26
+ default.reset
27
+ end
28
+
29
+ def reset
30
+ @currency_by_code = { }
31
+ @currency_by_symbol = { }
32
+ @currency = nil
33
+ end
34
+
25
35
 
26
36
  # Lookup Currency by code.
27
37
  def get_by_code(x)
@@ -60,19 +70,19 @@ class Currency::Currency::Factory
60
70
  # $stderr.puts "load('USD')"
61
71
  currency.code = :USD
62
72
  currency.symbol = '$'
63
- currency.scale = 1000000
73
+ # currency.scale = 1000000
64
74
  elsif currency.code == :CAD
65
75
  # $stderr.puts "load('CAD')"
66
76
  currency.symbol = '$'
67
- currency.scale = 1000000
77
+ # currency.scale = 1000000
68
78
  elsif currency.code == :EUR
69
79
  # $stderr.puts "load('CAD')"
70
80
  currency.symbol = nil
71
81
  currency.symbol_html = '&#8364;'
72
- currency.scale = 1000000
82
+ # currency.scale = 1000000
73
83
  else
74
84
  currency.symbol = nil
75
- currency.scale = 1000000
85
+ # currency.scale = 1000000
76
86
  end
77
87
 
78
88
  # $stderr.puts "AFTER: load(#{currency.inspect})"
@@ -41,7 +41,7 @@ class Currency::Exchange::Rate::Source::Base
41
41
  end
42
42
 
43
43
 
44
- def __subclass_responsibility(meth)
44
+ def __subclass_responsibility(method)
45
45
  raise ::Currency::Exception::SubclassResponsibility,
46
46
  [
47
47
  "#{self.class}#\#{meth}",
@@ -61,7 +61,7 @@ class Currency::Exchange::Rate::Source::Base
61
61
  m
62
62
  else
63
63
  rate = rate(c1, c2, time)
64
- # raise ::Currency::Exception::UnknownRate, "#{c1} #{c2} #{time}" unless rate
64
+ raise ::Currency::Exception::UnknownRate, "Cannot convert #{m} from #{c1} to #{c2} at time #{time}" unless rate
65
65
 
66
66
  rate && ::Currency::Money(rate.convert(m, c1), c2, time)
67
67
  end
@@ -1,12 +1,11 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
- require 'currency/exchange/rate/source/provider'
4
+ require File.dirname(__FILE__) + '/provider'
5
5
 
6
6
  require 'net/http'
7
7
  require 'open-uri'
8
8
 
9
-
10
9
  # Connects to http://www.federalreserve.gov/releases/H10/hist/dat00_<country>.txtb
11
10
  # Parses all known currency files.
12
11
  #
@@ -26,13 +25,11 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
26
25
  super(*opt)
27
26
  end
28
27
 
29
-
30
28
  # Returns 'federalreserve.gov'.
31
29
  def name
32
30
  'federalreserve.gov'
33
31
  end
34
32
 
35
-
36
33
  # FIXME?
37
34
  #def available?(time = nil)
38
35
  # time ||= Time.now
@@ -44,7 +41,6 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
44
41
  @raw_rates = nil
45
42
  super
46
43
  end
47
-
48
44
 
49
45
  def raw_rates
50
46
  rates
@@ -56,8 +52,7 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
56
52
  # See http://www.jhall.demon.co.uk/currency/by_country.html
57
53
  #
58
54
  # Some data files list reciprocal rates!
59
- @@country_to_currency =
60
- {
55
+ @@country_to_currency = {
61
56
  'al' => [ :AUD, :USD ],
62
57
  # 'au' => :ASH, # AUSTRIAN SHILLING: pre-EUR?
63
58
  'bz' => [ :USD, :BRL ],
@@ -84,7 +79,6 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
84
79
  've' => [ :USD, :VEB ],
85
80
  }
86
81
 
87
-
88
82
  # Parses text file for rates.
89
83
  def parse_rates(data = nil)
90
84
  data = get_page_content unless data
@@ -122,7 +116,7 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
122
116
 
123
117
  rate = m[4].to_f
124
118
 
125
- STDERR.puts "#{c1} #{c2} #{rate}\t#{date}" if @verbose
119
+ # STDERR.puts "#{c1} #{c2} #{rate}\t#{date}" if @verbose
126
120
 
127
121
  rates << new_rate(c1, c2, rate, date)
128
122
 
@@ -140,7 +134,6 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
140
134
  rates
141
135
  end
142
136
 
143
-
144
137
  # Return a list of known base rates.
145
138
  def load_rates(time = nil)
146
139
  # $stderr.puts "#{self}: load_rates(#{time})" if @verbose
@@ -152,8 +145,6 @@ class Currency::Exchange::Rate::Source::FederalReserve < ::Currency::Exchange::R
152
145
  end
153
146
  rates
154
147
  end
155
-
156
-
157
148
  end # class
158
149
 
159
150
 
@@ -1,8 +1,7 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
- require 'currency/exchange/rate/source'
5
-
4
+ require File.dirname(__FILE__) + '/../source'
6
5
 
7
6
  # Base class for rate data providers.
8
7
  # Assumes that rate sources provide more than one rate per query.
@@ -31,6 +30,7 @@ class Currency::Exchange::Rate::Source::Provider < Currency::Exchange::Rate::Sou
31
30
 
32
31
  # Returns the date to query for rates.
33
32
  # Defaults to yesterday.
33
+ # TODO: use ActiveSupport here?
34
34
  def date
35
35
  @date || (Time.now - 24 * 60 * 60) # yesterday.
36
36
  end
@@ -56,19 +56,14 @@ class Currency::Exchange::Rate::Source::Provider < Currency::Exchange::Rate::Sou
56
56
 
57
57
  # Returns the URI string as evaluated with this object.
58
58
  def get_uri
59
- uri = self.uri
60
- uri = "\"#{uri}\""
61
- uri = instance_eval(uri)
59
+ uri = instance_eval("\"#{self.uri}\"")
62
60
  $stderr.puts "#{self}: uri = #{uri.inspect}" if @verbose
63
61
  uri
64
62
  end
65
63
 
66
-
67
64
  # Returns the URI content.
68
65
  def get_page_content
69
- data = open(get_uri) { |data| data.read }
70
-
71
- data
66
+ open(get_uri) { |data| data.read }
72
67
  end
73
68
 
74
69
 
@@ -96,10 +91,12 @@ class Currency::Exchange::Rate::Source::Provider < Currency::Exchange::Rate::Sou
96
91
 
97
92
  # Return a matching base rate.
98
93
  def get_rate(c1, c2, time)
94
+ # puts "Getting rates for c1: #{c1} and c2: #{c2} at #{time}\n rates: #{rates.map{|r| "#{r.c1}->#{r.c2}"}.inspect}"
99
95
  rates.each do | rate |
96
+ # puts " >#{rate.c1} == #{c1} && #{rate.c2} == #{c2} #{rate.c1 == c1} && #{rate.c2.to_s == c2.to_s}< "
100
97
  return rate if
101
98
  rate.c1 == c1 &&
102
- rate.c2 == c2 &&
99
+ rate.c2.to_s == c2.to_s && # FIXME: understand why this second param needs to be cast to String for specs to pass
103
100
  (! time || normalize_time(rate.date) == time)
104
101
  end
105
102
 
@@ -293,8 +293,6 @@ class Currency::Formatter
293
293
  # => "1,234,567.89 USD"
294
294
  #
295
295
  def format(m, opt = @@empty_hash)
296
- # raise "huh: #{opt.inspect}"
297
-
298
296
  fmt = self
299
297
 
300
298
  unless opt.empty?
@@ -48,16 +48,13 @@ class Currency::Money
48
48
  # See #Money_rep(currency) mixin.
49
49
  #
50
50
  def initialize(x, currency = nil, time = nil)
51
- opts ||= @@empty_hash
52
-
53
- # Set ivars.
54
- currency = ::Currency::Currency.get(currency)
55
- @currency = currency
51
+ @currency = ::Currency::Currency.get(currency)
56
52
  @time = time || ::Currency::Money.default_time
57
53
  @time = ::Currency::Money.now if @time == :now
54
+
58
55
  if x.kind_of?(String)
59
- if currency
60
- m = currency.parser_or_default.parse(x, :currency => currency)
56
+ if @currency
57
+ m = @currency.parser_or_default.parse(x, :currency => @currency)
61
58
  else
62
59
  m = ::Currency::Parser.default.parse(x)
63
60
  end
@@ -237,8 +234,6 @@ class Currency::Money
237
234
 
238
235
  # Formats the Money value as a String.
239
236
  def to_s(*opt)
240
- # raise "huh: #{opt.inspect}"
241
-
242
237
  @currency.format(self, *opt)
243
238
  end
244
239
 
@@ -1,6 +1,5 @@
1
1
  require File.dirname(__FILE__) + '/ar_spec_helper'
2
2
 
3
-
4
3
  ##################################################
5
4
  # Basic CurrenyTest AR::B class
6
5
  #
@@ -24,6 +24,7 @@ def ar_setup
24
24
 
25
25
  end
26
26
 
27
+ # DB Connection info
27
28
  def database_spec
28
29
  # TODO: Get from ../config/database.yml:test
29
30
  # Create test database on:
@@ -59,6 +60,7 @@ def database_spec
59
60
 
60
61
  end
61
62
 
63
+ # Run AR migrations UP
62
64
  def schema_up
63
65
  return unless @currency_test_migration
64
66
  begin
@@ -68,6 +70,8 @@ def schema_up
68
70
  end
69
71
  end
70
72
 
73
+
74
+ # Run AR migrations DOWN
71
75
  def schema_down
72
76
  return unless @currency_test_migration
73
77
  begin
@@ -77,10 +81,7 @@ def schema_down
77
81
  end
78
82
  end
79
83
 
80
- ##################################################
81
- # Scaffold
82
- #
83
-
84
+ # Scaffold: insert stuff into DB so we can test AR integration
84
85
  def insert_records
85
86
  delete_records
86
87
 
@@ -99,6 +100,7 @@ end
99
100
 
100
101
  ##################################################
101
102
 
103
+ # TODO: need this?
102
104
  def assert_equal_money(a,b)
103
105
  a.should_not be_nil
104
106
  b.should_not be_nil
@@ -114,7 +116,7 @@ def assert_equal_money(a,b)
114
116
  b.amount.rep.should == a.amount.convert(b.amount.currency).rep
115
117
  end
116
118
 
117
-
119
+ # TODO: need this?
118
120
  def assert_equal_currency(a,b)
119
121
  assert_equal_money a, b
120
122
 
data/spec/config_spec.rb CHANGED
@@ -22,8 +22,49 @@ describe Currency::Config do
22
22
  end
23
23
 
24
24
  end
25
+
26
+ describe "the scale expression is configurable" do
27
+ before(:all) do
28
+ @config = Currency::Config.new
29
+ end
30
+
31
+ before(:each) do
32
+ Currency::Config.current = nil
33
+ Currency::Config.send(:class_variable_set, "@@default", nil)
34
+ end
35
+
36
+ it "should have a scale_exp setter" do
37
+ Currency::Config.current.should respond_to(:scale_exp=)
38
+ end
39
+
40
+ it "has a 'scale' reader" do
41
+ Currency::Config.current.should respond_to(:scale)
42
+ end
43
+
44
+ it "uses the scale reader from the config when creating new Money object" do
45
+ Currency::Config.should_receive(:current).and_return(@config)
46
+ @config.should_receive(:scale).and_return(100)
47
+ 10.money
48
+ end
49
+
50
+ it "can be configured using a block" do
51
+ Currency::Config.configure do |config|
52
+ config.scale_exp = 6
53
+ end
25
54
 
26
- end # class
27
-
28
-
55
+ 10.money.currency.scale_exp.should == 6
56
+
57
+ Currency::Config.configure do |config|
58
+ config.scale_exp = 4
59
+ end
60
+ 10.money.currency.scale_exp.should == 4
61
+ end
62
+
63
+ it "can be configured using straight setters" do
64
+ 10.money(:USD).currency.scale_exp.should == 2
65
+ Currency::Config.current.scale_exp = 6
66
+ 10.money(:USD).currency.scale_exp.should == 6
67
+ end
68
+ end
29
69
 
70
+ end
@@ -1,75 +1,71 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
3
 
4
- require 'test/test_base'
4
+ require File.dirname(__FILE__) + '/spec_helper'
5
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/federal_reserve'
5
6
 
6
- require 'currency' # For :type => :money
7
- require 'currency/exchange/rate/source/federal_reserve'
7
+ # Uncomment to avoid hitting the FED for every testrun
8
+ Currency::Exchange::Rate::Source::FederalReserve.class_eval do
9
+ def get_page_content
10
+ %Q{
8
11
 
9
- module Currency
12
+ SPOT EXCHANGE RATE - DISNEYLAND
10
13
 
11
- class FederalReserveTest < TestBase
12
- before do
13
- super
14
+ ------------------------------
15
+ 14-Nov-08 1.1
16
+ }
14
17
  end
18
+ end
15
19
 
16
-
17
- @@available = nil
18
-
19
- # New York Fed rates are not available on Saturday and Sunday.
20
+ include Currency
21
+ describe "FederalReserve" do
20
22
  def available?
21
- if @@available == nil
22
- @@available = @source.available?
23
- STDERR.puts "Warning: FederalReserve unavailable on Saturday and Sunday, skipping tests." unless @@available
23
+ unless @available
24
+ @available = @source.available?
25
+ STDERR.puts "Warning: FederalReserve unavailable on Saturday and Sunday, skipping tests." unless @available
24
26
  end
25
- @@available
27
+ @available
26
28
  end
27
-
28
-
29
- def get_rate_source
30
- # Force FederalReserve Exchange.
31
- verbose = false
32
- source = @source = Exchange::Rate::Source::FederalReserve.new(:verbose => verbose)
33
- deriver = Exchange::Rate::Deriver.new(:source => source, :verbose => source.verbose)
29
+
30
+ # Called by the before(:all) in spec_helper
31
+ # Overriding here to force FederalReserve Exchange.
32
+ # TODO: when refactoring the whole spec to test only specific FedralReserve Stuff, make sure this one goes away
33
+ def get_rate_source(source = nil)
34
+ @source ||= Exchange::Rate::Source::FederalReserve.new(:verbose => false)
35
+ @deriver ||= Exchange::Rate::Deriver.new(:source => @source, :verbose => @source.verbose)
34
36
  end
35
-
36
-
37
-
38
- it "usd cad" do
39
- return unless available?
40
-
41
- # yesterday = Time.now.to_date - 1
42
-
43
- rates = Exchange::Rate::Source.default.source.raw_rates.should_not == nil
44
- #assert_not_nil rates[:USD]
45
- #assert_not_nil usd_cad = rates[:USD][:CAD]
46
-
47
- usd = Money.new(123.45, :USD).should_not == nil
48
- cad = usd.convert(:CAD).should_not == nil
49
-
50
- # assert_kind_of Numeric, m = (cad.to_f / usd.to_f)
51
- # $stderr.puts "m = #{m}"
52
- # assert_equal_float usd_cad, m, 0.001
37
+
38
+ def get_rates
39
+ @rates ||= @source.raw_rates
53
40
  end
54
-
55
-
56
- it "cad eur" do
57
- return unless available?
58
-
59
- rates = Exchange::Rate::Source.default.source.raw_rates.should_not == nil
60
- #assert_not_nil rates[:USD]
61
- #assert_not_nil usd_cad = rates[:USD][:CAD]
62
- #assert_not_nil usd_eur = rates[:USD][:EUR]
63
-
64
- cad = Money.new(123.45, :CAD).should_not == nil
65
- eur = cad.convert(:EUR).should_not == nil
66
-
67
- #assert_kind_of Numeric, m = (eur.to_f / cad.to_f)
68
- # $stderr.puts "m = #{m}"
69
- #assert_equal_float (1.0 / usd_cad) * usd_eur, m, 0.001
41
+
42
+ before(:all) do
43
+ get_rate_source
44
+ get_rates
45
+ end
46
+
47
+ before(:each) do
48
+ get_rate_source
49
+ end
50
+
51
+ it "can retrieve rates from the FED" do
52
+ @rates.should_not be_nil
70
53
  end
71
54
 
72
- end
73
-
74
- end # module
55
+ it "can convert from USD to CAD" do
56
+ usd = Money.new(123.45, :USD)
75
57
 
58
+ cad = usd.convert(:CAD)
59
+ cad.should_not be_nil
60
+ cad.to_f.should be_kind_of(Numeric)
61
+ end
62
+
63
+ it "can do conversions from AUD to USD to JPY" do
64
+ aud = Money.new(123.45, :AUD)
65
+ usd = aud.convert(:USD)
66
+ jpy = usd.convert(:JPY)
67
+ jpy.should_not be_nil
68
+ jpy.to_f.should be_kind_of(Numeric)
69
+ end
70
+
71
+ end
@@ -1,56 +1,42 @@
1
1
  # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
2
  # See LICENSE.txt for details.
3
+ require File.dirname(__FILE__) + '/ar_spec_helper'
3
4
 
4
- require 'test/ar_test_base'
5
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/historical'
6
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/historical/writer'
7
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/xe'
8
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/new_york_fed'
5
9
 
6
- require 'rubygems'
7
- require 'active_record'
8
- require 'active_record/migration'
10
+ include Currency
11
+ RATE_CLASS = Exchange::Rate::Source::Historical::Rate
12
+ TABLE_NAME = RATE_CLASS.table_name
9
13
 
10
- require 'currency' # For :type => :money
11
-
12
- require 'currency/exchange/rate/source/historical'
13
- require 'currency/exchange/rate/source/historical/writer'
14
- require 'currency/exchange/rate/source/xe'
15
- require 'currency/exchange/rate/source/new_york_fed'
16
-
17
-
18
- module Currency
19
-
20
- class HistoricalWriterTest < ArTestBase
21
-
22
- RATE_CLASS = Exchange::Rate::Source::Historical::Rate
23
- TABLE_NAME = RATE_CLASS.table_name
24
-
25
- class HistoricalRateMigration < AR_M
26
- def self.up
27
- RATE_CLASS.__create_table(self)
28
- end
29
-
30
- def self.down
31
- drop_table TABLE_NAME.intern
32
- end
14
+ class HistoricalRateMigration < ActiveRecord::Migration
15
+ def self.up
16
+ RATE_CLASS.__create_table(self)
33
17
  end
34
18
 
35
-
36
- def initialize(*args)
37
- @currency_test_migration = HistoricalRateMigration
38
- super
39
-
40
- @src = Exchange::Rate::Source::Xe.new
41
- @src2 = Exchange::Rate::Source::NewYorkFed.new
19
+ def self.down
20
+ drop_table TABLE_NAME.to_sym
42
21
  end
22
+ end
43
23
 
44
-
45
- before do
46
- super
47
-
24
+ describe "HistoricalWriter" do
25
+ before(:all) do
26
+ ActiveRecord::Base.establish_connection(database_spec)
27
+ @currency_test_migration ||= HistoricalRateMigration
28
+ schema_down
29
+ schema_up
30
+ @xe_src = Exchange::Rate::Source::Xe.new
31
+ @fed_src = Exchange::Rate::Source::NewYorkFed.new
48
32
  end
49
-
50
33
 
51
- it "writer" do
52
- src = @src.should_not == nil
53
- writer = Exchange::Rate::Source::Historical::Writer.new().should_not == nil
34
+ after(:all) do
35
+ schema_down
36
+ end
37
+
38
+ def setup_writer(source)
39
+ writer = Exchange::Rate::Source::Historical::Writer.new
54
40
  writer.time_quantitizer = :current
55
41
  writer.required_currencies = [ :USD, :GBP, :EUR, :CAD ]
56
42
  writer.base_currencies = [ :USD ]
@@ -58,130 +44,78 @@ class HistoricalWriterTest < ArTestBase
58
44
  writer.reciprocal_rates = true
59
45
  writer.all_rates = true
60
46
  writer.identity_rates = false
61
-
47
+ writer.source = source
62
48
  writer
63
49
  end
64
50
 
65
-
66
- def writer_src
67
- writer = test_writer
68
- writer.source = @src
69
- rates = writer.write_rates
70
- rates.should_not == nil
71
- rates.size.should > 0
72
- 12, rates.size.should_not == nil
73
- assert_h_rates(rates, writer)
74
- end
75
-
76
-
77
- def writer_src2
78
- writer = test_writer
79
- writer.source = @src2
80
- return unless writer.source.available?
51
+ it "can read, parse and write XE data" do
52
+ writer = setup_writer(@xe_src)
81
53
  rates = writer.write_rates
82
- rates.should_not == nil
83
- rates.size.should > 0
84
54
  rates.size.should == 12
85
55
  assert_h_rates(rates, writer)
86
56
  end
87
-
88
-
89
- def xxx_test_required_failure
90
- writer = Exchange::Rate::Source::Historical::Writer.new().should_not == nil
91
- src = @src.should_not == nil
92
- writer.source = src
93
- writer.required_currencies = [ :USD, :GBP, :EUR, :CAD, :ZZZ ]
94
- writer.preferred_currencies = writer.required_currencies
95
- assert_raises(::RuntimeError) { writer.selected_rates }
96
- end
97
-
98
-
99
- it "historical rates" do
100
- # Make sure there are historical Rates avail for today.
101
- writer_src
102
- writer_src2
103
-
104
- # Force Historical Rate Source.
105
- source = Exchange::Rate::Source::Historical.new
106
- deriver = Exchange::Rate::Deriver.new(:source => source)
107
- Exchange::Rate::Source.default = deriver
108
-
109
- rates = source.get_raw_rates.should_not == nil
110
- rates.empty?.should_not == true
111
- # $stderr.puts "historical rates = #{rates.inspect}"
112
-
113
- rates = source.get_rates.should_not == nil
114
- rates.empty?.should_not == true
115
- # $stderr.puts "historical rates = #{rates.inspect}"
116
-
117
- m_usd = ::Currency.Money('1234.56', :USD, :now).should_not == nil
118
- # $stderr.puts "m_usd = #{m_usd.to_s(:code => true)}"
119
- m_eur = m_usd.convert(:EUR).should_not == nil
120
- # $stderr.puts "m_eur = #{m_eur.to_s(:code => true)}"
121
-
57
+
58
+ it "can read, parse and write NewYorkFed data (will fail on weekends)" do
59
+ if @fed_src.available?
60
+ writer = setup_writer(@fed_src)
61
+ rates = writer.write_rates
62
+ rates.size.should == 12
63
+ assert_h_rates(rates, writer)
64
+ end
122
65
  end
123
-
124
-
66
+
125
67
  def assert_h_rates(rates, writer = nil)
126
- hr0 = rates[0].should_not == nil
68
+ hr0 = rates[0]
69
+ hr0.should_not be_nil
127
70
  rates.each do | hr |
128
71
  found_hr = nil
129
72
  begin
130
- found_hr = hr.find_matching_this(:first).should_not == nil
73
+ found_hr = hr.find_matching_this(:first)
74
+ found_hr.should_not be_nil
131
75
  rescue Object => err
132
76
  raise "#{hr.inspect}: #{err}:\n#{err.backtrace.inspect}"
133
77
  end
134
-
135
- hr0.should_not == nil
136
-
137
- hr.date.should == hr0.date
138
- hr.date_0.should == hr0.date_0
139
- hr.date_1.should == hr0.date_1
140
- hr.source.should == hr0.source
141
-
142
78
  assert_equal_rate(hr, found_hr)
143
79
  assert_rate_defaults(hr, writer)
80
+
81
+ hr.instance_eval do
82
+ date.should == hr0.date
83
+ date_0.should == hr0.date_0
84
+ date_1.should == hr0.date_1
85
+ source.should == hr0.source
86
+ end
144
87
  end
145
88
  end
146
89
 
147
-
148
90
  def assert_equal_rate(hr0, hr)
91
+ tollerance = 0.00001
149
92
  hr.c1.to_s.should == hr0.c1.to_s
150
93
  hr.c2.to_s.should == hr0.c2.to_s
151
94
  hr.source.should == hr0.source
152
- assert_equal_float hr0.rate, hr.rate
153
- assert_equal_float hr0.rate_avg, hr.rate_avg
154
- hr.rate_samples.should == hr0.rate_samples
155
- assert_equal_float hr0.rate_lo, hr.rate_lo
156
- assert_equal_float hr0.rate_hi, hr.rate_hi
157
- assert_equal_float hr0.rate_date_0, hr.rate_date_0
158
- assert_equal_float hr0.rate_date_1, hr.rate_date_1
159
- hr.date.should == hr0.date
160
- hr.date_0.should == hr0.date_0
161
- hr.date_1.should == hr0.date_1
162
- hr.derived.should == hr0.derived
95
+
96
+ hr0.rate.should be_close(hr.rate, tollerance)
97
+ hr0.rate_avg.should be_close(hr.rate_avg, tollerance)
98
+ hr0.rate_samples.should == hr.rate_samples.should
99
+
100
+ hr0.rate_lo.should be_close(hr.rate_lo, tollerance)
101
+ hr0.rate_hi.should be_close(hr.rate_hi, tollerance)
102
+ hr0.rate_date_0.should be_close(hr.rate_date_0, tollerance)
103
+ hr0.rate_date_1.should be_close(hr.rate_date_1, tollerance)
104
+
105
+ hr0.date.should == hr.date
106
+ hr0.date_0.should == hr.date_0
107
+ hr0.date_1.should == hr.date_1
108
+ hr0.derived.should == hr.derived
163
109
  end
164
110
 
165
-
166
111
  def assert_rate_defaults(hr, writer)
167
- hr.source if writer.should == writer.source.name
168
- hr.rate_avg.should == hr.rate
169
- 1.should == hr.rate_samples
170
- hr.rate_lo.should == hr.rate
171
- hr.rate_hi.should == hr.rate
172
- hr.rate_date_0.should == hr.rate
173
- hr.rate_date_1.should == hr.rate
112
+ hr.source.should == writer.source.name
113
+ hr.rate_avg.should == hr.rate
114
+ hr.rate_samples.should == 1
115
+ hr.rate_lo.should == hr.rate
116
+ hr.rate_hi.should == hr.rate
117
+ hr.rate_date_0.should == hr.rate
118
+ hr.rate_date_1.should == hr.rate
174
119
  end
175
120
 
176
-
177
- def assert_equal_float(x1, x2, eps = 0.00001)
178
- eps = (x1 * eps).abs
179
- assert((x1 - eps) <= x2)
180
- assert((x1 + eps) >= x2)
181
- end
182
-
183
-
184
- end
185
-
186
- end # module
187
-
121
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,16 +5,16 @@ require 'spec'
5
5
  require File.dirname(__FILE__) + '/../lib/currency'
6
6
  require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/test'
7
7
 
8
- def setup
9
- rate_source ||= get_rate_source
8
+ def setup(source = nil)
9
+ rate_source ||= get_rate_source(source)
10
10
  Currency::Exchange::Rate::Source.default = rate_source
11
11
 
12
12
  # Force non-historical money values.
13
13
  Currency::Money.default_time = nil
14
14
  end
15
15
 
16
- def get_rate_source
17
- source = Currency::Exchange::Rate::Source::Test.instance
16
+ def get_rate_source(source = nil)
17
+ source ||= Currency::Exchange::Rate::Source::Test.instance
18
18
  Currency::Exchange::Rate::Deriver.new(:source => source)
19
19
  end
20
20
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acvwilson-currency
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Asa Wilson
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-14 00:00:00 -08:00
12
+ date: 2008-11-18 06:18:56.586682 -08:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -70,7 +70,6 @@ files:
70
70
  - Releases.txt
71
71
  - spec/ar_spec_helper.rb
72
72
  - spec/ar_column_spec.rb
73
- - spec/ar_core_spec.rb
74
73
  - spec/ar_simple_spec.rb
75
74
  - spec/config_spec.rb
76
75
  - spec/federal_reserve_spec.rb
@@ -112,6 +111,6 @@ rubyforge_project:
112
111
  rubygems_version: 1.2.0
113
112
  signing_key:
114
113
  specification_version: 2
115
- summary: currency 0.5.2
114
+ summary: "#{s.name} #{s.version}"
116
115
  test_files: []
117
116
 
data/spec/ar_core_spec.rb DELETED
@@ -1,68 +0,0 @@
1
- # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
- # See LICENSE.txt for details.
3
-
4
-
5
- # =================================================================
6
- # = TODO: IS THIS STUFF ACTUALLY NEEDED? IF SO, MOVE TO AR HELPER =
7
- # =================================================================
8
- require 'test/ar_test_base'
9
-
10
- module Currency
11
-
12
- class ArTestCore < ArTestBase
13
-
14
- ##################################################
15
- # Basic CurrenyTest AR::B class
16
- #
17
-
18
- TABLE_NAME = 'currency_test'
19
-
20
- class CurrencyTestMigration < AR_M
21
- def self.up
22
- create_table TABLE_NAME.intern do |t|
23
- t.column :name, :string
24
- t.column :amount, :integer # Money
25
- end
26
- end
27
-
28
- def self.down
29
- drop_table TABLE_NAME.intern
30
- end
31
- end
32
-
33
-
34
- class CurrencyTest < AR_B
35
- set_table_name TABLE_NAME
36
- attr_money :amount
37
- end
38
-
39
-
40
- ##################################################
41
-
42
-
43
- before do
44
- @currency_test_migration ||= CurrencyTestMigration
45
- @currency_test ||= CurrencyTest
46
- super
47
- end
48
-
49
-
50
- def teardown
51
- super
52
- # schema_down
53
- end
54
-
55
-
56
- ##################################################
57
- #
58
- #
59
-
60
-
61
- it "insert" do
62
- insert_records
63
- end
64
-
65
- end
66
-
67
- end # module
68
-