mumboe-currency 0.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/bin/currency_historical_rate_load +105 -0
  2. data/examples/ex1.rb +13 -0
  3. data/examples/xe1.rb +20 -0
  4. data/lib/currency/active_record.rb +265 -0
  5. data/lib/currency/config.rb +91 -0
  6. data/lib/currency/core_extensions.rb +41 -0
  7. data/lib/currency/currency/factory.rb +228 -0
  8. data/lib/currency/currency.rb +175 -0
  9. data/lib/currency/currency_version.rb +6 -0
  10. data/lib/currency/exception.rb +119 -0
  11. data/lib/currency/exchange/rate/deriver.rb +157 -0
  12. data/lib/currency/exchange/rate/source/base.rb +166 -0
  13. data/lib/currency/exchange/rate/source/failover.rb +63 -0
  14. data/lib/currency/exchange/rate/source/federal_reserve.rb +160 -0
  15. data/lib/currency/exchange/rate/source/historical/rate.rb +184 -0
  16. data/lib/currency/exchange/rate/source/historical/rate_loader.rb +186 -0
  17. data/lib/currency/exchange/rate/source/historical/writer.rb +220 -0
  18. data/lib/currency/exchange/rate/source/historical.rb +79 -0
  19. data/lib/currency/exchange/rate/source/new_york_fed.rb +127 -0
  20. data/lib/currency/exchange/rate/source/provider.rb +120 -0
  21. data/lib/currency/exchange/rate/source/test.rb +50 -0
  22. data/lib/currency/exchange/rate/source/the_financials.rb +191 -0
  23. data/lib/currency/exchange/rate/source/timed_cache.rb +198 -0
  24. data/lib/currency/exchange/rate/source/xe.rb +165 -0
  25. data/lib/currency/exchange/rate/source.rb +89 -0
  26. data/lib/currency/exchange/rate.rb +214 -0
  27. data/lib/currency/exchange/time_quantitizer.rb +111 -0
  28. data/lib/currency/exchange.rb +50 -0
  29. data/lib/currency/formatter.rb +290 -0
  30. data/lib/currency/macro.rb +321 -0
  31. data/lib/currency/money.rb +295 -0
  32. data/lib/currency/money_helper.rb +13 -0
  33. data/lib/currency/parser.rb +151 -0
  34. data/lib/currency.rb +143 -0
  35. data/test/string_test.rb +54 -0
  36. data/test/test_base.rb +44 -0
  37. metadata +90 -0
@@ -0,0 +1,295 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ #
5
+ # Represents an amount of money in a particular currency.
6
+ #
7
+ # A Money object stores its value using a scaled Integer representation
8
+ # and a Currency object.
9
+ #
10
+ # A Money object also has a time, which is used in conversions
11
+ # against historical exchange rates.
12
+ #
13
+ class Currency::Money
14
+ include Comparable
15
+
16
+ @@default_time = nil
17
+ def self.default_time
18
+ @@default_time
19
+ end
20
+ def self.default_time=(x)
21
+ @@default_time = x
22
+ end
23
+
24
+ @@empty_hash = { }
25
+ @@empty_hash.freeze
26
+
27
+ #
28
+ # DO NOT CALL THIS DIRECTLY:
29
+ #
30
+ # See Currency.Money() function.
31
+ #
32
+ # Construct a Money value object
33
+ # from a pre-scaled external representation:
34
+ # where x is a Float, Integer, String, etc.
35
+ #
36
+ # If a currency is not specified, Currency.default is used.
37
+ #
38
+ # x.Money_rep(currency)
39
+ #
40
+ # is invoked to coerce x into a Money representation value.
41
+ #
42
+ # For example:
43
+ #
44
+ # 123.Money_rep(:USD) => 12300
45
+ #
46
+ # Because the USD Currency object has a #scale of 100
47
+ #
48
+ # See #Money_rep(currency) mixin.
49
+ #
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
56
+ @time = time || ::Currency::Money.default_time
57
+ @time = ::Currency::Money.now if @time == :now
58
+ if x.kind_of?(String)
59
+ if currency
60
+ m = currency.parser_or_default.parse(x, :currency => currency)
61
+ else
62
+ m = ::Currency::Parser.default.parse(x)
63
+ end
64
+ @currency = m.currency unless @currency
65
+ @time = m.time if m.time
66
+ @rep = m.rep
67
+ else
68
+ @currency = ::Currency::Currency.default unless @currency
69
+ @rep = x.Money_rep(@currency)
70
+ end
71
+
72
+ end
73
+
74
+ # Returns a Time.new
75
+ # Can be modifed for special purposes.
76
+ def self.now
77
+ Time.new
78
+ end
79
+
80
+ # Compatibility with Money package.
81
+ def self.us_dollar(x)
82
+ self.new(x, :USD)
83
+ end
84
+
85
+
86
+ # Compatibility with Money package.
87
+ def cents
88
+ @rep
89
+ end
90
+
91
+
92
+ # Construct from post-scaled internal representation.
93
+ def self.new_rep(r, currency = nil, time = nil)
94
+ x = self.new(0, currency, time)
95
+ x.set_rep(r)
96
+ x
97
+ end
98
+
99
+
100
+ # Construct from post-scaled internal representation.
101
+ # using the same currency.
102
+ #
103
+ # x = Currency.Money("1.98", :USD)
104
+ # x.new_rep(123) => USD $1.23
105
+ #
106
+ # time defaults to self.time.
107
+ def new_rep(r, time = nil)
108
+ time ||= @time
109
+ x = self.class.new(0, @currency, time)
110
+ x.set_rep(r)
111
+ x
112
+ end
113
+
114
+ # Do not call this method directly.
115
+ # CLIENTS SHOULD NEVER CALL set_rep DIRECTLY.
116
+ # You have been warned in ALL CAPS.
117
+ def set_rep(r) # :nodoc:
118
+ r = r.to_i unless r.kind_of?(Integer)
119
+ @rep = r
120
+ end
121
+
122
+ # Do not call this method directly.
123
+ # CLIENTS SHOULD NEVER CALL set_time DIRECTLY.
124
+ # You have been warned in ALL CAPS.
125
+ def set_time(time) # :nodoc:
126
+ @time = time
127
+ end
128
+
129
+ # Returns the Money representation (usually an Integer).
130
+ def rep
131
+ @rep
132
+ end
133
+
134
+ # Get the Money's Currency.
135
+ def currency
136
+ @currency
137
+ end
138
+
139
+ # Get the Money's time.
140
+ def time
141
+ @time
142
+ end
143
+
144
+ # Convert Money to another Currency.
145
+ # currency can be a Symbol or a Currency object.
146
+ # If currency is nil, the Currency.default is used.
147
+ def convert(currency, time = nil)
148
+ currency = ::Currency::Currency.default if currency.nil?
149
+ currency = ::Currency::Currency.get(currency) unless currency.kind_of?(Currency)
150
+ if @currency == currency
151
+ self
152
+ else
153
+ time = self.time if time == :money
154
+ ::Currency::Exchange::Rate::Source.current.convert(self, currency, time)
155
+ end
156
+ end
157
+
158
+
159
+ # Hash for hash table: both value and currency.
160
+ # See #eql? below.
161
+ def hash
162
+ @rep.hash ^ @currency.hash
163
+ end
164
+
165
+
166
+ # True if money values have the same value and currency.
167
+ def eql?(x)
168
+ self.class == x.class &&
169
+ @rep == x.rep &&
170
+ @currency == x.currency
171
+ end
172
+
173
+ # True if money values have the same value and currency.
174
+ def ==(x)
175
+ self.class == x.class &&
176
+ @rep == x.rep &&
177
+ @currency == x.currency
178
+ end
179
+
180
+ # Compares Money values.
181
+ # Will convert x to self.currency before comparision.
182
+ def <=>(x)
183
+ if @currency == x.currency
184
+ @rep <=> x.rep
185
+ else
186
+ @rep <=> convert(@currency, @time).rep
187
+ end
188
+ end
189
+
190
+
191
+ # - Money => Money
192
+ #
193
+ # Negates a Money value.
194
+ def -@
195
+ new_rep(- @rep)
196
+ end
197
+
198
+ # Money + (Money | Number) => Money
199
+ #
200
+ # Right side may be coerced to left side's Currency.
201
+ def +(x)
202
+ new_rep(@rep + x.Money_rep(@currency))
203
+ end
204
+
205
+ # Money - (Money | Number) => Money
206
+ #
207
+ # Right side may be coerced to left side's Currency.
208
+ def -(x)
209
+ new_rep(@rep - x.Money_rep(@currency))
210
+ end
211
+
212
+ # Money * Number => Money
213
+ #
214
+ # Right side must be Number.
215
+ def *(x)
216
+ new_rep(@rep * x)
217
+ end
218
+
219
+ # Money / Money => Float (ratio)
220
+ # Money / Number => Money
221
+ #
222
+ # Right side must be Money or Number.
223
+ # Right side Integers are not coerced to Float before
224
+ # division.
225
+ def /(x)
226
+ if x.kind_of?(self.class)
227
+ (@rep.to_f) / (x.Money_rep(@currency).to_f)
228
+ else
229
+ new_rep(@rep / x)
230
+ end
231
+ end
232
+
233
+ # Formats the Money value as a String using the Currency's Formatter.
234
+ def format(*opt)
235
+ @currency.format(self, *opt)
236
+ end
237
+
238
+ # Formats the Money value as a String.
239
+ def to_s(*opt)
240
+ @currency.format(self, *opt)
241
+ end
242
+
243
+ # Coerces the Money's value to a Float.
244
+ # May cause loss of precision.
245
+ def to_f
246
+ Float(@rep) / @currency.scale
247
+ end
248
+
249
+ # Coerces the Money's value to an Integer.
250
+ # May cause loss of precision.
251
+ def to_i
252
+ @rep / @currency.scale
253
+ end
254
+
255
+ # True if the Money's value is zero.
256
+ def zero?
257
+ @rep == 0
258
+ end
259
+
260
+ # True if the Money's value is greater than zero.
261
+ def positive?
262
+ @rep > 0
263
+ end
264
+
265
+ # True if the Money's value is less than zero.
266
+ def negative?
267
+ @rep < 0
268
+ end
269
+
270
+ # Returns the Money's value representation in another currency.
271
+ def Money_rep(currency, time = nil)
272
+ # Attempt conversion?
273
+ if @currency != currency || (time && @time != time)
274
+ self.convert(currency, time).rep
275
+ # raise ::Currency::Exception::Generic, "Incompatible Currency: #{@currency} != #{currency}"
276
+ else
277
+ @rep
278
+ end
279
+ end
280
+
281
+ # Basic inspection, with symbol, currency code and time.
282
+ # The standard #inspect method is available as #inspect_deep.
283
+ def inspect(*opts)
284
+ self.format(:symbol => true, :code => true, :time => true)
285
+ end
286
+
287
+ # How to alias a method defined in an object superclass in a different class:
288
+ define_method(:inspect_deep, Object.instance_method(:inspect))
289
+ # How call a method defined in a superclass from a method with a different name:
290
+ # def inspect_deep(*opts)
291
+ # self.class.superclass.instance_method(:inspect).bind(self).call
292
+ # end
293
+
294
+ end # class
295
+
@@ -0,0 +1,13 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ module ActionView::Helpers::MoneyHelper
5
+ # Creates a suitable HTML element for a Money value field.
6
+ def money_field(object, method, options = {})
7
+ InstanceTag.new(object, method, self).to_input_field_tag("text", options)
8
+ end
9
+ end
10
+
11
+
12
+ ActionView::Base.load_helper(File.dirname(__FILE__))
13
+
@@ -0,0 +1,151 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+
5
+ require 'rss/rss' # Time#xmlschema
6
+
7
+
8
+ # This class parses a Money value from a String.
9
+ # Each Currency has a default Parser.
10
+ class Currency::Parser
11
+
12
+ SYMBOLS_FOR_PATTERN = Currency::Currency::Factory::UNIQUE_SYMBOLS.collect {|symbol| symbol.split("").collect {|c| c =~ /[a-z]/i ? c : '\\'+c }.join }.join("|")
13
+ VALID_MONEY_PATTERN = /^(([a-zA-z][a-zA-z][a-zA-z])|(#{SYMBOLS_FOR_PATTERN}))?\s*([\-\+\d,\.]+)\s*(([a-zA-z][a-zA-z][a-zA-z])|(#{SYMBOLS_FOR_PATTERN}))?(\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?Z)?$/
14
+
15
+ # The default Currency to use if no Currency is specified.
16
+ attr_accessor :currency
17
+
18
+ # If true and a parsed string contains a ISO currency code
19
+ # that is not the same as currency,
20
+ # #parse() will raise IncompatibleCurrency.
21
+ # Defaults to false.
22
+ attr_accessor :enforce_currency
23
+
24
+ # The default Time to use if no Time is specified in the string.
25
+ # If :now, time is set to Time.new.
26
+ attr_accessor :time
27
+
28
+ @@default = nil
29
+ # Get the default Formatter.
30
+ def self.default
31
+ @@default ||=
32
+ self.new
33
+ end
34
+
35
+
36
+ # Set the default Formatter.
37
+ def self.default=(x)
38
+ @@default = x
39
+ end
40
+
41
+
42
+ def initialize(opt = { })
43
+ @time =
44
+ @enforce_currency =
45
+ @currency =
46
+ nil
47
+ opt.each_pair{ | k, v | self.send("#{k}=", v) }
48
+ end
49
+
50
+ def _parse(str) # :nodoc:
51
+ x = str
52
+ md = nil
53
+ time = nil
54
+
55
+ convert_currency = nil
56
+ md = VALID_MONEY_PATTERN.match(x)
57
+ if md && !@currency
58
+ symbol = md[3] || md[7]
59
+ code = md[2] || md[6]
60
+ curr = Currency::Currency.get(code ? code.upcase : nil) || (symbol ? Currency::Currency::Factory.get_currency_from_symbol(symbol) : Currency::Currency.default)
61
+ x = md[4]
62
+ time = Time.xmlschema(md[8]) if md[8]
63
+ time ||= @time
64
+ time = Time.new if time == :now
65
+ currency = curr
66
+ else
67
+ currency = @currency || ::Currency::Currency.default
68
+ currency = ::Currency::Currency.get(currency)
69
+ end
70
+
71
+ # Remove placeholders and symbol.
72
+ x.gsub!(/[, ]/, '')
73
+ symbol = currency.symbol if symbol.nil?
74
+ x.gsub!(symbol, '') if symbol
75
+
76
+ # Match: whole Currency value.
77
+ if md = /^([-+]?\d+)\.?$/.match(x)
78
+ x = ::Currency::Money.new_rep(md[1].to_i * currency.scale, currency, @time)
79
+
80
+ # Match: fractional Currency value.
81
+ elsif md = /^([-+]?)(\d*)\.(\d+)$/.match(x)
82
+ sign = md[1]
83
+ whole = md[2]
84
+ part = md[3]
85
+
86
+ if part.length != currency.scale
87
+ currency.scale = 10**part.length if part.length > 1
88
+
89
+ # Pad decimal places with additional '0'
90
+ while part.length < currency.scale_exp
91
+ part << '0'
92
+ end
93
+
94
+ # Truncate to Currency's decimal size.
95
+ part = part[0 ... currency.scale_exp]
96
+ end
97
+
98
+ # Put the string back together:
99
+ whole = sign + whole + part
100
+
101
+ x = whole.to_i
102
+ x = ::Currency::Money.new_rep(x, currency, time)
103
+ else
104
+ raise ::Currency::Exception::InvalidMoneyString,
105
+ [
106
+ "#{str.inspect} #{currency} #{x.inspect}",
107
+ :string, str,
108
+ :currency, currency,
109
+ :state, x,
110
+ ]
111
+ end
112
+
113
+ # Do conversion.
114
+ if convert_currency
115
+ x = x.convert(convert_currency)
116
+ end
117
+
118
+ x
119
+ end
120
+
121
+ @@empty_hash = { }
122
+ @@empty_hash.freeze
123
+
124
+ # Parse a Money string in this Currency.
125
+ #
126
+ # "123.45".money # Using default Currency.
127
+ # => USD $123.45
128
+ #
129
+ # "$123.45 USD".money # Explicit Currency.
130
+ # => USD $123.45
131
+ #
132
+ # "CAD 123.45".money
133
+ # => CAD $123.45
134
+ #
135
+ # "123.45 CAD".money(:USD) # Incompatible explicit Currency.
136
+ # !!! "123.45 CAD" USD (Currency::Exception::IncompatibleCurrency)
137
+ #
138
+ def parse(str, opt = @@empty_hash)
139
+ prs = self
140
+
141
+ unless opt.empty?
142
+ prs = prs.clone
143
+ opt.each_pair{ | k, v | prs.send("#{k}=", v) }
144
+ end
145
+
146
+ prs._parse(str)
147
+ end
148
+
149
+ end # class
150
+
151
+
data/lib/currency.rb ADDED
@@ -0,0 +1,143 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ #
3
+ # See LICENSE.txt for details.
4
+ #
5
+ # = Currency
6
+ #
7
+ # The Currency package provides an object-oriented model of:
8
+ #
9
+ # * currencies
10
+ # * exchanges
11
+ # * exchange rates
12
+ # * exchange rate sources
13
+ # * monetary values
14
+ #
15
+ # The core classes are:
16
+ #
17
+ # * Currency::Money - uses a scaled integer representation of a monetary value and performs accurate conversions to and from string values.
18
+ # * Currency::Currency - provides an object-oriented representation of a currency.
19
+ # * Currency::Exchange::Base - the base class for a currency exchange rate provider.
20
+ # * Currency::Exchange::Rate::Source::Base - the base class for an on-demand currency exchange rate data provider.
21
+ # * Currency::Exchange::Rate::Source::Provider - the base class for a bulk exchange rate data provider.
22
+ # * Currency::Exchange::Rate - represents a exchange rate between two currencies.
23
+ #
24
+ #
25
+ # The example below uses Currency::Exchange::Xe to automatically get
26
+ # exchange rates from http://xe.com/ :
27
+ #
28
+ # require 'currency'
29
+ # require 'currency/exchange/rate/deriver'
30
+ # require 'currency/exchange/rate/source/xe'
31
+ # require 'currency/exchange/rate/source/timed_cache'
32
+ #
33
+ # # Rate source initialization
34
+ # provider = Currency::Exchange::Rate::Source::Xe.new
35
+ # deriver = Currency::Exchange::Rate::Deriver.new(:source => provider)
36
+ # cache = Currency::Exchange::Rate::Source::TimedCache.new(:source => deriver)
37
+ # Currency::Exchange::Rate::Source.default = cache
38
+ #
39
+ # usd = Currency::Money('6.78', :USD)
40
+ # puts "usd = #{usd.format}"
41
+ # cad = usd.convert(:CAD)
42
+ # puts "cad = #{cad.format}"
43
+ #
44
+ # == ActiveRecord Suppport
45
+ #
46
+ # This package also contains ActiveRecord support for money values:
47
+ #
48
+ # require 'currency'
49
+ # require 'currency/active_record'
50
+ #
51
+ # class Entry < ActiveRecord::Base
52
+ # money :amount
53
+ # end
54
+ #
55
+ # In the example above, the entries.amount database column is an INTEGER that represents US cents.
56
+ # The currency code of the money value can be stored in an additional database column or a default currency can be used.
57
+ #
58
+ # == Recent Enhancements
59
+ #
60
+ # === Storage and retrival of historical exchange rates
61
+ #
62
+ # * See Currency::Exchange::Rate::Source::Historical
63
+ # * See Currency::Exchange::Rate::Source::Historical::Writer
64
+ #
65
+ # === Automatic derivation of rates from base rates.
66
+ #
67
+ # * See Currency::Exchange::Rate::Deriver
68
+ #
69
+ # === Rate caching
70
+ #
71
+ # * See Currency::Exchange::Rate::Source::TimedCache
72
+ #
73
+ # === Rate Providers
74
+ #
75
+ # * See Currency::Exchange::Rate::Source::Xe
76
+ # * See Currency::Exchange::Rate::Source::NewYorkFed
77
+ # * See Currency::Exchange::Rate::Source::TheFinancials
78
+ #
79
+ # === Customizable formatting and parsing
80
+ #
81
+ # * See Currency::Formatter
82
+ # * See Currency::Parser
83
+ #
84
+ # == Future Enhancements
85
+ #
86
+ # * Support for inflationary rates within a currency, e.g. $10 USD in the year 1955 converted to 2006 USD.
87
+ #
88
+ # == SVN Repo
89
+ #
90
+ # svn checkout svn://rubyforge.org/var/svn/currency/currency/trunk
91
+ #
92
+ # == Examples
93
+ #
94
+ # See the examples/ and test/ directorys
95
+ #
96
+ # == Author
97
+ #
98
+ # Kurt Stephens http://kurtstephens.com
99
+ #
100
+ # == Support
101
+ #
102
+ # http://rubyforge.org/forum/forum.php?forum_id=7643
103
+ #
104
+ # == Copyright
105
+ #
106
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
107
+ #
108
+ # See LICENSE.txt for details.
109
+ #
110
+ module Currency
111
+ # Use this function instead of Money#new:
112
+ #
113
+ # Currency::Money("12.34", :CAD)
114
+ #
115
+ # Do not do this:
116
+ #
117
+ # Currency::Money.new("12.34", :CAD)
118
+ #
119
+ # See Money#new.
120
+ def self.Money(*opts)
121
+ Money.new(*opts)
122
+ end
123
+ end
124
+
125
+ $:.unshift(File.expand_path(File.dirname(__FILE__))) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
126
+
127
+ require 'currency/currency_version'
128
+ require 'currency/config'
129
+ require 'currency/exception'
130
+ require 'currency/money'
131
+ require 'currency/currency'
132
+ require 'currency/currency/factory'
133
+ require 'currency/money'
134
+ require 'currency/formatter'
135
+ require 'currency/parser'
136
+ require 'currency/exchange'
137
+ require 'currency/exchange/rate'
138
+ require 'currency/exchange/rate/deriver'
139
+ require 'currency/exchange/rate/source'
140
+ require 'currency/exchange/rate/source/test'
141
+ require 'currency/exchange/time_quantitizer'
142
+ require 'currency/core_extensions'
143
+
@@ -0,0 +1,54 @@
1
+ # various tests to verify latest revisions
2
+ require "test/test_base"
3
+ require 'currency'
4
+
5
+ module Currency
6
+
7
+ class StringTest < TestBase
8
+ def setup
9
+ super
10
+ end
11
+
12
+ def test_beginning_with_code
13
+ assert_equal "¥424,535,953.00", "CNY424,535,953".money.to_s
14
+ end
15
+
16
+ def test_beginning_with_symbol
17
+ assert_equal "₡42,525,924.87", "₡ 42525924.87".money.to_s
18
+ end
19
+
20
+ def test_ending_with_code
21
+ assert_equal "₱324,402,482.00", "324402482 CUP".money.to_s
22
+ end
23
+
24
+ def test_ending_with_symbol
25
+ assert_equal "IRR 2,445.00", "2445﷼".money.to_s(:symbol => false, :code => true)
26
+ end
27
+
28
+ def test_unknown_code
29
+ assert_equal "CFA 15,000.00", "15000CFA".money.to_s(:symbol => true, :code => true)
30
+ end
31
+
32
+ def test_invalid_symbol
33
+ assert_raise ::Currency::Exception::InvalidMoneyString do
34
+ "Σ424,000".money
35
+ end
36
+ end
37
+
38
+ def test_invalid_format
39
+ assert_raise ::Currency::Exception::InvalidMoneyString do
40
+ "17 dollars".money
41
+ end
42
+ end
43
+
44
+ def test_does_not_truncate_precision
45
+ assert_equal "$425.002", "425.002".money.to_s
46
+ end
47
+
48
+ def test_pads_precision
49
+ assert_equal "$0.50", "0.5".money.to_s
50
+ end
51
+
52
+ end
53
+
54
+ end
data/test/test_base.rb ADDED
@@ -0,0 +1,44 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ # Base Test class
5
+
6
+ require 'test/unit'
7
+ require 'currency'
8
+ require 'currency/exchange/rate/source/test'
9
+
10
+ module Currency
11
+
12
+ class TestBase < Test::Unit::TestCase
13
+ def setup
14
+ super
15
+ @rate_source ||= get_rate_source
16
+ Exchange::Rate::Source.default = @rate_source
17
+
18
+ # Force non-historical money values.
19
+ Money.default_time = nil
20
+ end
21
+
22
+
23
+ def get_rate_source
24
+ source = Exchange::Rate::Source::Test.instance
25
+ deriver = Exchange::Rate::Deriver.new(:source => source)
26
+ end
27
+
28
+ # Avoid "No test were specified" error.
29
+ def test_foo
30
+ assert true
31
+ end
32
+
33
+
34
+ # Helpers.
35
+ def assert_equal_float(x, y, eps = 1.0e-8)
36
+ d = (x * eps).abs
37
+ assert((x - d) <= y)
38
+ assert(y <= (x + d))
39
+ end
40
+
41
+ end # class
42
+
43
+ end # module
44
+