currency 0.4.0 → 0.4.1
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/Manifest.txt +2 -0
- data/Rakefile +5 -5
- data/Releases.txt +12 -0
- data/lib/currency.rb +1 -0
- data/lib/currency/active_record.rb +3 -2
- data/lib/currency/config.rb +68 -0
- data/lib/currency/core_extensions.rb +1 -1
- data/lib/currency/currency_version.rb +1 -1
- data/lib/currency/exchange/rate/source/xe.rb +41 -66
- data/lib/currency/formatter.rb +111 -13
- data/lib/currency/money.rb +1 -1
- data/test/config_test.rb +36 -0
- data/test/formatter_test.rb +5 -5
- data/test/money_test.rb +3 -1
- data/test/test_base.rb +5 -2
- data/test/xe_test.rb +3 -1
- metadata +6 -4
data/Manifest.txt
CHANGED
@@ -10,6 +10,7 @@ examples/ex1.rb
|
|
10
10
|
examples/xe1.rb
|
11
11
|
lib/currency.rb
|
12
12
|
lib/currency/active_record.rb
|
13
|
+
lib/currency/config.rb
|
13
14
|
lib/currency/core_extensions.rb
|
14
15
|
lib/currency/currency.rb
|
15
16
|
lib/currency/currency/factory.rb
|
@@ -40,6 +41,7 @@ test/ar_column_test.rb
|
|
40
41
|
test/ar_simple_test.rb
|
41
42
|
test/ar_test_base.rb
|
42
43
|
test/ar_test_core.rb
|
44
|
+
test/config_test.rb
|
43
45
|
test/formatter_test.rb
|
44
46
|
test/historical_writer_test.rb
|
45
47
|
test/macro_test.rb
|
data/Rakefile
CHANGED
@@ -19,15 +19,15 @@ require 'rubygems'
|
|
19
19
|
require 'hoe'
|
20
20
|
|
21
21
|
PKG_Name = 'Currency'
|
22
|
-
PKG_DESCRIPTION = %{Currency models currencies, monetary values, foreign exchanges
|
23
|
-
Pulls live rates from http://xe.com/.
|
24
|
-
|
22
|
+
PKG_DESCRIPTION = %{Currency models currencies, monetary values, foreign exchanges rates.
|
23
|
+
Pulls live and historical rates from http://xe.com/, http://newyorkfed.org/, http://thefinancials.com/.
|
24
|
+
Can store/retrieve historical rate data from database using ActiveRecord.
|
25
|
+
Can store/retrieve Money values using ActiveRecord.
|
25
26
|
|
26
27
|
For more details, see:
|
27
28
|
|
28
|
-
http://currency.rubyforge.org/files/lib/currency_rb.html
|
29
|
-
http://currency.rubyforge.org/files/README.txt
|
30
29
|
http://currency.rubyforge.org/
|
30
|
+
http://currency.rubyforge.org/files/README.txt
|
31
31
|
|
32
32
|
}
|
33
33
|
|
data/Releases.txt
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
= Currency Release History
|
2
2
|
|
3
|
+
== Release 0.4.1: 2007/03/10
|
4
|
+
|
5
|
+
Some changes are not backwards-compatible
|
6
|
+
|
7
|
+
* Fixed Rate::Source::Xe; site format changed, more robust parser.
|
8
|
+
* Added Currency::Config.
|
9
|
+
* Support for filtering Float values before casting to Money, based on suggestions for rounding by Steffen Rusitschka.
|
10
|
+
* Fixed :allow_nil in ActiveRecord money macro based on fix by Steffen Rusitschka.
|
11
|
+
* Fixed package scoping issue in Money.
|
12
|
+
* Added support for Formatter#template string
|
13
|
+
* Money format template default changed to '#{code}#{code && " "}#{symbol}#{sign}#{whole}#{fraction}'. THIS MAY BREAK EXISTING CLIENTS. See http://www.jhall.demon.co.uk/currency/ for rationale.
|
14
|
+
|
3
15
|
== Release 0.4.0: 2007/02/21
|
4
16
|
|
5
17
|
=== MAJOR CHANGES IN THIS RELEASE FOR HISTORICAL RATE DATA
|
data/lib/currency.rb
CHANGED
@@ -123,6 +123,7 @@ end
|
|
123
123
|
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
124
124
|
|
125
125
|
require 'currency/currency_version'
|
126
|
+
require 'currency/config'
|
126
127
|
require 'currency/exception'
|
127
128
|
require 'currency/money'
|
128
129
|
require 'currency/currency'
|
@@ -199,9 +199,10 @@ end_eval
|
|
199
199
|
|
200
200
|
money_rep ||= "#{attr_name}_money.rep"
|
201
201
|
|
202
|
+
validate_allow_nil = opts[:allow_nil] ? ', :allow_nil => true' : ''
|
202
203
|
validate = "# Validation\n"
|
203
|
-
validate << "\nvalidates_numericality_of :#{attr_name}\n"
|
204
|
-
validate << "\nvalidates_format_of :#{currency_column}, :with => /^[A-Z][A-Z][A-Z]
|
204
|
+
validate << "\nvalidates_numericality_of :#{attr_name}#{validate_allow_nil}\n"
|
205
|
+
validate << "\nvalidates_format_of :#{currency_column}, :with => /^[A-Z][A-Z][A-Z]$/#{validate_allow_nil}\n" if currency_column
|
205
206
|
|
206
207
|
|
207
208
|
alias_accessor ||= ''
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
# The Currency::Config class is responsible for
|
5
|
+
# maintaining global configuration for the Currency package.
|
6
|
+
#
|
7
|
+
class Currency::Config
|
8
|
+
@@default = nil
|
9
|
+
|
10
|
+
# Returns the default Currency::Config object.
|
11
|
+
#
|
12
|
+
# If one is not specfied an instance is
|
13
|
+
# created. This is a global, not thread-local.
|
14
|
+
def self.default
|
15
|
+
@@default ||= self.new
|
16
|
+
end
|
17
|
+
|
18
|
+
# Sets the default Currency::Config object.
|
19
|
+
def self.default=(x)
|
20
|
+
@@default = x
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the current Currency::Config object used during
|
24
|
+
# in the current thread.
|
25
|
+
#
|
26
|
+
# If #current= has not been called and #default= has not been called,
|
27
|
+
# then UndefinedExchange is raised.
|
28
|
+
def self.current
|
29
|
+
Thread.current[:currency_config] ||= self.default || (raise ::Currency::Exception::UndefinedConfig.new("Currency::Config.default not defined"))
|
30
|
+
end
|
31
|
+
|
32
|
+
# Sets the current Currency::Config object used
|
33
|
+
# in the current thread.
|
34
|
+
def self.current=(x)
|
35
|
+
Thread.current[:currency_config] = x
|
36
|
+
end
|
37
|
+
|
38
|
+
# Clones the current configuration and makes it current
|
39
|
+
# during the execution of a block. After block completes,
|
40
|
+
# the previous configuration is restored.
|
41
|
+
#
|
42
|
+
# Currency::Config.configure do | c |
|
43
|
+
# c.float_ref_filter = Proc.new { | x | x.round }
|
44
|
+
# "123.448".money.rep == 12345
|
45
|
+
# end
|
46
|
+
def self.configure(&blk)
|
47
|
+
c_prev = current
|
48
|
+
c_new = self.current = current.clone
|
49
|
+
result = nil
|
50
|
+
begin
|
51
|
+
result = yield c_new
|
52
|
+
ensure
|
53
|
+
self.current = c_prev
|
54
|
+
end
|
55
|
+
result
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
def float_ref_filter
|
61
|
+
@float_ref_filter ||= Proc.new { |x| x }
|
62
|
+
end
|
63
|
+
|
64
|
+
def float_ref_filter=(x)
|
65
|
+
@float_ref_filter = x
|
66
|
+
end
|
67
|
+
end # module
|
68
|
+
|
@@ -5,6 +5,8 @@ require 'currency/exchange/rate/source/base'
|
|
5
5
|
|
6
6
|
require 'net/http'
|
7
7
|
require 'open-uri'
|
8
|
+
# Cant use REXML because of missing </form> tags -- 2007/03/11
|
9
|
+
# require 'rexml/document'
|
8
10
|
|
9
11
|
# Connects to http://xe.com and parses "XE.com Quick Cross Rates"
|
10
12
|
# from home page HTML.
|
@@ -12,6 +14,8 @@ require 'open-uri'
|
|
12
14
|
# This is for demonstration purposes.
|
13
15
|
#
|
14
16
|
class Currency::Exchange::Rate::Source::Xe < ::Currency::Exchange::Rate::Source::Provider
|
17
|
+
class ParserError < ::Currency::Exception::Base; end
|
18
|
+
|
15
19
|
# Defines the pivot currency for http://xe.com/.
|
16
20
|
PIVOT_CURRENCY = :USD
|
17
21
|
|
@@ -37,7 +41,7 @@ class Currency::Exchange::Rate::Source::Xe < ::Currency::Exchange::Rate::Source:
|
|
37
41
|
|
38
42
|
# Returns a cached Hash of rates:
|
39
43
|
#
|
40
|
-
# xe.
|
44
|
+
# xe.raw_rates[:USD][:CAD] => 1.0134
|
41
45
|
#
|
42
46
|
def raw_rates
|
43
47
|
# Force load of rates
|
@@ -51,96 +55,67 @@ class Currency::Exchange::Rate::Source::Xe < ::Currency::Exchange::Rate::Source:
|
|
51
55
|
def parse_page_rates(data = nil)
|
52
56
|
data = get_page_content unless data
|
53
57
|
|
54
|
-
data = data.split(
|
55
|
-
|
56
|
-
@rate_timestamp = nil
|
57
|
-
|
58
|
-
# Chomp after
|
59
|
-
until data.empty?
|
60
|
-
line = data.pop
|
61
|
-
break if line =~ /Need More currencies\?/
|
62
|
-
end
|
63
|
-
|
64
|
-
# Chomp before Quick Cross Rates
|
65
|
-
until data.empty?
|
66
|
-
line = data.shift
|
67
|
-
break if line =~ /XE.com Quick Cross Rates/
|
68
|
-
end
|
58
|
+
@lines = data = data.split(/\n/);
|
69
59
|
|
70
|
-
|
71
|
-
md = nil
|
72
|
-
until data.empty?
|
73
|
-
line = data.shift
|
74
|
-
break if md = /rates as of (\d\d\d\d)\.(\d\d)\.(\d\d)\s+(\d\d):(\d\d).*GMT/.match(line)
|
75
|
-
end
|
76
|
-
if md
|
77
|
-
yyyy, mm, dd, h, m = md[1].to_i, md[2].to_i, md[3].to_i, md[4].to_i, md[5].to_i
|
78
|
-
@rate_timestamp = Time.gm(yyyy, mm, dd, h, m, 0, 0) rescue nil
|
79
|
-
#$stderr.puts "parsed #{md[0].inspect} => #{yyyy}, #{mm}, #{dd}, #{h}, #{m}"
|
80
|
-
#$stderr.puts " => #{@rate_timestamp && @rate_timestamp.xmlschema}"
|
81
|
-
end
|
60
|
+
@rate_timestamp = nil
|
82
61
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
end
|
87
|
-
|
88
|
-
until data.empty?
|
89
|
-
line = data.shift
|
90
|
-
break if line =~ /^\s*<\/tr>/i
|
91
|
-
end
|
92
|
-
# $stderr.puts "#{data[0..4].inspect}"
|
62
|
+
eat_lines_until /More currencies\.\.\.<\/a>/i
|
63
|
+
eat_lines_until /^\s*<tr>/i
|
64
|
+
eat_lines_until /^\s*<tr>/i
|
93
65
|
|
94
66
|
# Read first table row to get position for each currency
|
95
67
|
currency = [ ]
|
96
|
-
|
97
|
-
|
98
|
-
break if line =~ /^\s*<\/tr>/i
|
99
|
-
if md = /<td><IMG .+ ALT="([A-Z][A-Z][A-Z])"/i.match(line) #"
|
68
|
+
eat_lines_until /^\s*<\/tr>/i do
|
69
|
+
if md = /<td[^>]+?>.*?\/> ([A-Z][A-Z][A-Z])<\/td>/.match(@line)
|
100
70
|
cur = md[1].intern
|
101
71
|
cur_i = currency.size
|
102
72
|
currency.push(cur)
|
103
|
-
|
73
|
+
$stderr.puts "Found currency header: #{cur.inspect} at #{cur_i}" if @verbose
|
104
74
|
end
|
105
75
|
end
|
76
|
+
raise ParseError, "Currencies header not found" if currency.empty?
|
106
77
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
line = data.shift
|
112
|
-
break if line =~ /^\s*<td>.+1.+USD.+=/
|
113
|
-
end
|
114
|
-
|
115
|
-
until data.empty?
|
116
|
-
line = data.shift
|
117
|
-
break if line =~ /^\s*<\/tr>/i
|
118
|
-
end
|
119
|
-
|
120
|
-
# $stderr.puts "#{data[0..4].inspect}"
|
121
|
-
|
78
|
+
|
79
|
+
# Skip until "1 USD ="
|
80
|
+
eat_lines_until /^\s*<td[^>]+?> 1 +USD =/
|
81
|
+
|
122
82
|
# Read first row of 1 USD = ...
|
123
|
-
|
124
83
|
rate = { }
|
125
|
-
cur_i = -1
|
126
|
-
|
127
|
-
|
128
|
-
break if cur_i < 0 && line =~ /^\s*<\/tr>/i
|
129
|
-
if md = /<td>\s+(\d+\.\d+)\s+<\/td>/.match(line)
|
84
|
+
cur_i = -1
|
85
|
+
eat_lines_until /^\s*<\/tr>/i do
|
86
|
+
if md = /<td[^>]+?>\s*?(\d+\.\d+)\s*?<\/td>/i.match(@line)
|
130
87
|
usd_to_cur = md[1].to_f
|
131
88
|
cur_i = cur_i + 1
|
132
89
|
cur = currency[cur_i]
|
133
|
-
|
90
|
+
raise ParseError, "Currency not found at column #{cur_i}" unless cur
|
134
91
|
next if cur.to_s == PIVOT_CURRENCY.to_s
|
135
92
|
(rate[PIVOT_CURRENCY] ||= {})[cur] = usd_to_cur
|
136
93
|
(rate[cur] ||= { })[PIVOT_CURRENCY] ||= 1.0 / usd_to_cur
|
137
94
|
$stderr.puts "#{cur.inspect} => #{usd_to_cur}" if @verbose
|
138
95
|
end
|
139
96
|
end
|
97
|
+
raise ParseError, "Currency rates not found" if rate.keys.empty?
|
98
|
+
raise ParseError, "Not all rates found" if rate.keys.size != currency.size
|
140
99
|
|
100
|
+
@lines = @line = nil
|
101
|
+
|
141
102
|
rate
|
142
103
|
end
|
143
|
-
|
104
|
+
|
105
|
+
|
106
|
+
def eat_lines_until(rx)
|
107
|
+
until @lines.empty?
|
108
|
+
@line = @lines.shift
|
109
|
+
if md = rx.match(@line)
|
110
|
+
$stderr.puts "\nMATCHED #{@line.inspect} WITH #{rx.inspect} AT LINES:\n#{@lines[0..4].inspect}" if @verbose
|
111
|
+
return md
|
112
|
+
end
|
113
|
+
yield @line if block_given?
|
114
|
+
end
|
115
|
+
raise ParseError, rx.inspect
|
116
|
+
false
|
117
|
+
end
|
118
|
+
|
144
119
|
|
145
120
|
# Return a list of known base rates.
|
146
121
|
def load_rates(time = nil)
|
data/lib/currency/formatter.rb
CHANGED
@@ -5,6 +5,68 @@
|
|
5
5
|
# This class formats a Money value as a String.
|
6
6
|
# Each Currency has a default Formatter.
|
7
7
|
class Currency::Formatter
|
8
|
+
# The underlying object for Currency::Formatter#format.
|
9
|
+
# This object is cloned and initialized with strings created
|
10
|
+
# from Formatter#format.
|
11
|
+
# It handles the Formatter#format string interpolation.
|
12
|
+
class Template
|
13
|
+
@@empty_hash = { }
|
14
|
+
@@empty_hash.freeze
|
15
|
+
|
16
|
+
# The template string.
|
17
|
+
attr_accessor :template
|
18
|
+
|
19
|
+
# The Currency::Money object being formatted.
|
20
|
+
attr_accessor :money
|
21
|
+
# The Currency::Currency object being formatted.
|
22
|
+
attr_accessor :currency
|
23
|
+
|
24
|
+
# The sign: '-' or nil.
|
25
|
+
attr_accessor :sign
|
26
|
+
# The whole part of the value, with thousands_separator or nil.
|
27
|
+
attr_accessor :whole
|
28
|
+
# The fraction part of the value, with decimal_separator or nil.
|
29
|
+
attr_accessor :fraction
|
30
|
+
# The currency symbol or nil.
|
31
|
+
attr_accessor :symbol
|
32
|
+
# The currency code or nil.
|
33
|
+
attr_accessor :code
|
34
|
+
|
35
|
+
|
36
|
+
def initialize(opts = @@empty_hash)
|
37
|
+
opts.each_pair{ | k, v | self.send("#{k}=", v) }
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
# Sets the template string and uncaches the template_proc.
|
42
|
+
def template=(x)
|
43
|
+
if @template != x
|
44
|
+
@template_proc = nil
|
45
|
+
end
|
46
|
+
@template = x
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Defines a the self._format template procedure using
|
51
|
+
# the template as a string to be interpolated.
|
52
|
+
def template_proc(template = @template)
|
53
|
+
return @template_proc if @template_proc
|
54
|
+
@template_proc = template || ''
|
55
|
+
# @template_proc = @template_proc.gsub(/[\\"']/) { | x | "\\" + x }
|
56
|
+
@template_proc = "def self._format; \"#{@template_proc}\"; end"
|
57
|
+
self.instance_eval @template_proc
|
58
|
+
@template_proc
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
# Formats the current state using the template.
|
63
|
+
def format
|
64
|
+
template_proc
|
65
|
+
_format
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
8
70
|
# Defaults to ','
|
9
71
|
attr_accessor :thousands_separator
|
10
72
|
|
@@ -27,9 +89,14 @@ class Currency::Formatter
|
|
27
89
|
#
|
28
90
|
# Currency::Money(12.45, :EUR).to_s(:html => true; :code => true)
|
29
91
|
# => "€12.45 <span class=\"currency_code\">EUR</span>"
|
30
|
-
|
31
92
|
attr_accessor :html
|
32
93
|
|
94
|
+
# A template string used to format a money value.
|
95
|
+
# Defaults to:
|
96
|
+
#
|
97
|
+
# '#{code}#{code && " "}#{symbol}#{sign}#{whole}#{fraction}'
|
98
|
+
attr_accessor :template
|
99
|
+
|
33
100
|
|
34
101
|
# If passed true, formats for an input field (i.e.: as a number).
|
35
102
|
def as_input_value=(x)
|
@@ -42,6 +109,7 @@ class Currency::Formatter
|
|
42
109
|
self.code = false
|
43
110
|
self.html = false
|
44
111
|
end
|
112
|
+
x
|
45
113
|
end
|
46
114
|
|
47
115
|
|
@@ -66,6 +134,7 @@ class Currency::Formatter
|
|
66
134
|
@symbol = true
|
67
135
|
@code = false
|
68
136
|
@html = false
|
137
|
+
@template = '#{code}#{code && " "}#{symbol}#{sign}#{whole}#{fraction}'
|
69
138
|
|
70
139
|
opt.each_pair{ | k, v | self.send("#{k}=", v) }
|
71
140
|
end
|
@@ -76,16 +145,45 @@ class Currency::Formatter
|
|
76
145
|
end
|
77
146
|
|
78
147
|
|
148
|
+
# Sets the template and the Template#template.
|
149
|
+
def template=(x)
|
150
|
+
if @template_object
|
151
|
+
@template_object.template = x
|
152
|
+
end
|
153
|
+
@template = x
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# Returns the Template object.
|
158
|
+
def template_object
|
159
|
+
return @template_object if @template_object
|
160
|
+
|
161
|
+
@template_object = Template.new
|
162
|
+
@template_object.template = @template if @template
|
163
|
+
# $stderr.puts "template.template = #{@template_object.template.inspect}"
|
164
|
+
@template_object.template_proc # pre-cache before clone.
|
165
|
+
|
166
|
+
@template_object
|
167
|
+
end
|
168
|
+
|
169
|
+
|
79
170
|
def _format(m, currency = nil) # :nodoc:
|
80
171
|
# Get currency.
|
81
172
|
currency ||= m.currency
|
82
173
|
|
174
|
+
# Setup template
|
175
|
+
tmpl = self.template_object.clone
|
176
|
+
# $stderr.puts "template.template = #{tmpl.template.inspect}"
|
177
|
+
tmpl.money = m
|
178
|
+
tmpl.currency = currency
|
179
|
+
|
83
180
|
# Get scaled integer representation for this Currency.
|
84
181
|
# $stderr.puts "m.currency = #{m.currency}, currency => #{currency}"
|
85
182
|
x = m.Money_rep(currency)
|
86
183
|
|
87
184
|
# Remove sign.
|
88
185
|
x = - x if ( neg = x < 0 )
|
186
|
+
tmpl.sign = neg ? '-' : nil
|
89
187
|
|
90
188
|
# Convert to String.
|
91
189
|
x = x.to_s
|
@@ -97,9 +195,9 @@ class Currency::Formatter
|
|
97
195
|
|
98
196
|
# Insert decimal place.
|
99
197
|
whole = x[0 .. currency.format_left]
|
100
|
-
|
198
|
+
fraction = x[currency.format_right .. -1]
|
101
199
|
|
102
|
-
# Do
|
200
|
+
# Do thousands.
|
103
201
|
x = whole
|
104
202
|
if @thousands && (@thousands_separator && ! @thousands_separator.empty?)
|
105
203
|
x.reverse!
|
@@ -108,20 +206,20 @@ class Currency::Formatter
|
|
108
206
|
x.reverse!
|
109
207
|
end
|
110
208
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
209
|
+
# Put whole and fractional parts.
|
210
|
+
tmpl.whole = x
|
211
|
+
tmpl.fraction = @cents && @decimal_separator ? @decimal_separator + fraction : nil
|
212
|
+
|
213
|
+
|
116
214
|
# Add symbol?
|
117
|
-
|
215
|
+
tmpl.symbol = @symbol ? ((@html && currency.symbol_html) || currency.symbol) : nil
|
216
|
+
|
118
217
|
|
119
218
|
# Suffix with currency code.
|
120
|
-
|
121
|
-
x << (' ' + _format_Currency(currency))
|
122
|
-
end
|
219
|
+
tmpl.code = @code ? _format_Currency(currency) : nil
|
123
220
|
|
124
|
-
|
221
|
+
# Ask template to format the components.
|
222
|
+
tmpl.format
|
125
223
|
end
|
126
224
|
|
127
225
|
|
data/lib/currency/money.rb
CHANGED
data/test/config_test.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
|
5
|
+
require 'test/test_base'
|
6
|
+
require 'currency'
|
7
|
+
|
8
|
+
module Currency
|
9
|
+
|
10
|
+
class ConfigTest < TestBase
|
11
|
+
def setup
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
############################################
|
16
|
+
# Simple stuff.
|
17
|
+
#
|
18
|
+
|
19
|
+
def test_config
|
20
|
+
assert_kind_of Money, m = Money.new(1.999)
|
21
|
+
assert_equal 199, m.rep
|
22
|
+
|
23
|
+
Config.configure do | c |
|
24
|
+
c.float_ref_filter = Proc.new { | x | x.round }
|
25
|
+
|
26
|
+
assert_kind_of Money, m = Money.new(1.999)
|
27
|
+
assert_equal 200, m.rep
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end # class
|
33
|
+
|
34
|
+
end # module
|
35
|
+
|
36
|
+
|
data/test/formatter_test.rb
CHANGED
@@ -55,22 +55,22 @@ class FormatterTest < TestBase
|
|
55
55
|
def test_code
|
56
56
|
m = test_default
|
57
57
|
assert_equal "$1,234,567.89", m.to_s(:code => false)
|
58
|
-
assert_equal "$1,234,567.89
|
58
|
+
assert_equal "USD $1,234,567.89", m.to_s(:code => true)
|
59
59
|
|
60
60
|
m
|
61
61
|
end
|
62
62
|
|
63
63
|
def test_misc
|
64
64
|
m = ::Currency::Money(12.45, :USD)
|
65
|
-
assert_equal "
|
65
|
+
assert_equal "<span class=\"currency_code\">USD</span> $12.45",
|
66
66
|
m.to_s(:html => true, :code => true)
|
67
67
|
|
68
68
|
m = ::Currency::Money(12.45, :EUR)
|
69
|
-
assert_equal "
|
69
|
+
assert_equal "<span class=\"currency_code\">EUR</span> €12.45",
|
70
70
|
m.to_s(:html => true, :code => true)
|
71
71
|
|
72
|
-
m = ::Currency::Money(
|
73
|
-
assert_equal "
|
72
|
+
m = ::Currency::Money(12345.45, :EUR)
|
73
|
+
assert_equal "<span class=\"currency_code\">EUR</span> €12_345.45",
|
74
74
|
m.to_s(:html => true, :code => true, :thousands_separator => '_')
|
75
75
|
end
|
76
76
|
|
data/test/money_test.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
1
3
|
|
2
4
|
|
3
5
|
require 'test/test_base'
|
@@ -293,7 +295,7 @@ class MoneyTest < TestBase
|
|
293
295
|
assert usd.time == usd2.time
|
294
296
|
end
|
295
297
|
|
296
|
-
end
|
298
|
+
end # class
|
297
299
|
|
298
300
|
end # module
|
299
301
|
|
data/test/test_base.rb
CHANGED
@@ -14,6 +14,9 @@ class TestBase < Test::Unit::TestCase
|
|
14
14
|
super
|
15
15
|
@rate_source ||= get_rate_source
|
16
16
|
Exchange::Rate::Source.default = @rate_source
|
17
|
+
|
18
|
+
# Force non-historical money values.
|
19
|
+
Money.default_time = nil
|
17
20
|
end
|
18
21
|
|
19
22
|
|
@@ -31,8 +34,8 @@ class TestBase < Test::Unit::TestCase
|
|
31
34
|
# Helpers.
|
32
35
|
def assert_equal_float(x, y, eps = 1.0e-8)
|
33
36
|
d = (x * eps).abs
|
34
|
-
assert
|
35
|
-
assert
|
37
|
+
assert((x - d) <= y)
|
38
|
+
assert(y <= (x + d))
|
36
39
|
end
|
37
40
|
|
38
41
|
end # class
|
data/test/xe_test.rb
CHANGED
@@ -16,7 +16,9 @@ class XeTest < TestBase
|
|
16
16
|
|
17
17
|
def get_rate_source
|
18
18
|
source = Exchange::Rate::Source::Xe.new
|
19
|
+
# source.verbose = true
|
19
20
|
deriver = Exchange::Rate::Deriver.new(:source => source)
|
21
|
+
deriver
|
20
22
|
end
|
21
23
|
|
22
24
|
|
@@ -45,7 +47,7 @@ class XeTest < TestBase
|
|
45
47
|
|
46
48
|
assert_kind_of Numeric, m = (eur.to_f / cad.to_f)
|
47
49
|
# $stderr.puts "m = #{m}"
|
48
|
-
assert_equal_float
|
50
|
+
assert_equal_float((1.0 / usd_cad) * usd_eur, m, 0.001)
|
49
51
|
end
|
50
52
|
|
51
53
|
end
|
metadata
CHANGED
@@ -3,16 +3,16 @@ rubygems_version: 0.9.0
|
|
3
3
|
specification_version: 1
|
4
4
|
name: currency
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.4.
|
7
|
-
date: 2007-
|
8
|
-
summary: "Currency models currencies, monetary values, foreign exchanges
|
6
|
+
version: 0.4.1
|
7
|
+
date: 2007-03-11 00:00:00 -06:00
|
8
|
+
summary: "Currency models currencies, monetary values, foreign exchanges rates. Pulls live and historical rates from http://xe.com/, http://newyorkfed.org/, http://thefinancials.com/. Can store/retrieve historical rate data from database using ActiveRecord. Can store/retrieve Money values using ActiveRecord. For more details, see: http://currency.rubyforge.org/ http://currency.rubyforge.org/files/README.txt"
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
11
|
- test
|
12
12
|
email: ruby-currency@umleta.com
|
13
13
|
homepage: http://rubyforge.org/projects/currency
|
14
14
|
rubyforge_project: currency
|
15
|
-
description: "Currency models currencies, monetary values, foreign exchanges
|
15
|
+
description: "Currency models currencies, monetary values, foreign exchanges rates. Pulls live and historical rates from http://xe.com/, http://newyorkfed.org/, http://thefinancials.com/. Can store/retrieve historical rate data from database using ActiveRecord. Can store/retrieve Money values using ActiveRecord. For more details, see: http://currency.rubyforge.org/ http://currency.rubyforge.org/files/README.txt"
|
16
16
|
autorequire:
|
17
17
|
default_executable:
|
18
18
|
bindir: bin
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- examples/xe1.rb
|
43
43
|
- lib/currency.rb
|
44
44
|
- lib/currency/active_record.rb
|
45
|
+
- lib/currency/config.rb
|
45
46
|
- lib/currency/core_extensions.rb
|
46
47
|
- lib/currency/currency.rb
|
47
48
|
- lib/currency/currency/factory.rb
|
@@ -72,6 +73,7 @@ files:
|
|
72
73
|
- test/ar_simple_test.rb
|
73
74
|
- test/ar_test_base.rb
|
74
75
|
- test/ar_test_core.rb
|
76
|
+
- test/config_test.rb
|
75
77
|
- test/formatter_test.rb
|
76
78
|
- test/historical_writer_test.rb
|
77
79
|
- test/macro_test.rb
|