mumboe-currency 0.5

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.
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
+