acvwilson-acvwilson-currency 0.5.0 → 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{acvwilson-currency}
3
- s.version = "0.5.0"
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_base_spec.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
- s.rubygems_version = %q{1.3.0}
17
- s.summary = %q{acvwilson-currency 0.5.0}
16
+ s.rubygems_version = %q{1.2.0}
17
+ s.summary = %q{#{s.name} #{s.version}}
18
18
  end
data/lib/currency.rb CHANGED
@@ -131,8 +131,8 @@ require 'currency/money'
131
131
  require 'currency/currency'
132
132
  require 'currency/currency/factory'
133
133
  require 'currency/money'
134
- require 'currency/formatter'
135
134
  require 'currency/parser'
135
+ require 'currency/formatter' # require this one before the parser and enjoy the weird bugs!
136
136
  require 'currency/exchange'
137
137
  require 'currency/exchange/rate'
138
138
  require 'currency/exchange/rate/deriver'
@@ -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
-
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,24 +15,13 @@ class Integer
19
15
  end
20
16
  end
21
17
 
22
-
23
-
24
18
  class Float
25
19
  # Inexact conversion to Money representation value.
26
20
  def Money_rep(currency, time = nil)
27
21
  Integer(Currency::Config.current.float_ref_filter.call(self * currency.scale))
28
22
  end
29
-
30
- def round_with_precision(precision = nil)
31
- precision.nil? ? round_without_precision : (self * (10 ** precision)).round_without_precision / (10 ** precision).to_f
32
- end
33
- alias_method :round_without_precision, :round
34
- alias_method :round, :round_with_precision
35
23
  end
36
24
 
37
-
38
-
39
-
40
25
  class String
41
26
  # Exact conversion to Money representation value.
42
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
 
@@ -129,7 +126,7 @@ class Currency::Currency
129
126
  # Formats the Money value as a string using the current Formatter.
130
127
  # See Currency::Formatter#format.
131
128
  def format(m, *opt)
132
- formatter_or_default.format(m, *opt)
129
+ formatter_or_default.format(m, *opt)
133
130
  end
134
131
 
135
132
 
@@ -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})"
@@ -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
- require 'currency'
5
-
6
4
  # The Currency::Exchange package is responsible for
7
5
  # the buying and selling of currencies.
8
6
  #
@@ -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
 
@@ -228,7 +228,15 @@ class Currency::Formatter
228
228
  fraction = x[currency.format_right .. -1]
229
229
 
230
230
  # Round the fraction to the supplied number of decimal places
231
- fraction = ((fraction.to_f / currency.scale).round(@decimals) * (10 ** @decimals)).to_i.to_s
231
+ fraction = (fraction.to_f / currency.scale).round(@decimals).to_s[2..-1]
232
+ # raise "decimals: #{@decimals}, scale_exp: #{currency.scale_exp}, x is: #{x.inspect}, currency.scale_exp is #{currency.scale_exp.inspect}, fraction: #{fraction.inspect}"
233
+ while ( fraction.length < @decimals )
234
+ fraction = fraction + "0"
235
+ end
236
+
237
+
238
+ # raise "x is: #{x.inspect}, currency.scale_exp is #{currency.scale_exp.inspect}, fraction: #{fraction.inspect}"
239
+ # fraction = ((fraction.to_f / currency.scale).round(decimals) * (10 ** decimals)).to_i.to_s
232
240
 
233
241
  # Do thousands.
234
242
  x = whole
@@ -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