acvwilson-currency 0.5.2 → 0.6.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.
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
-