acvwilson-acvwilson-currency 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/COPYING.txt +339 -0
  2. data/ChangeLog +8 -0
  3. data/LICENSE.txt +65 -0
  4. data/Manifest.txt +58 -0
  5. data/README.txt +51 -0
  6. data/Releases.txt +155 -0
  7. data/TODO.txt +9 -0
  8. data/currency.gemspec +18 -0
  9. data/examples/ex1.rb +13 -0
  10. data/examples/xe1.rb +20 -0
  11. data/lib/currency.rb +143 -0
  12. data/lib/currency/active_record.rb +265 -0
  13. data/lib/currency/config.rb +91 -0
  14. data/lib/currency/core_extensions.rb +48 -0
  15. data/lib/currency/currency.rb +175 -0
  16. data/lib/currency/currency/factory.rb +121 -0
  17. data/lib/currency/currency_version.rb +6 -0
  18. data/lib/currency/exception.rb +119 -0
  19. data/lib/currency/exchange.rb +50 -0
  20. data/lib/currency/exchange/rate.rb +214 -0
  21. data/lib/currency/exchange/rate/deriver.rb +157 -0
  22. data/lib/currency/exchange/rate/source.rb +89 -0
  23. data/lib/currency/exchange/rate/source/base.rb +166 -0
  24. data/lib/currency/exchange/rate/source/failover.rb +63 -0
  25. data/lib/currency/exchange/rate/source/federal_reserve.rb +160 -0
  26. data/lib/currency/exchange/rate/source/historical.rb +79 -0
  27. data/lib/currency/exchange/rate/source/historical/rate.rb +184 -0
  28. data/lib/currency/exchange/rate/source/historical/rate_loader.rb +186 -0
  29. data/lib/currency/exchange/rate/source/historical/writer.rb +220 -0
  30. data/lib/currency/exchange/rate/source/new_york_fed.rb +127 -0
  31. data/lib/currency/exchange/rate/source/provider.rb +120 -0
  32. data/lib/currency/exchange/rate/source/test.rb +50 -0
  33. data/lib/currency/exchange/rate/source/the_financials.rb +191 -0
  34. data/lib/currency/exchange/rate/source/timed_cache.rb +198 -0
  35. data/lib/currency/exchange/rate/source/xe.rb +165 -0
  36. data/lib/currency/exchange/time_quantitizer.rb +111 -0
  37. data/lib/currency/formatter.rb +300 -0
  38. data/lib/currency/macro.rb +321 -0
  39. data/lib/currency/money.rb +296 -0
  40. data/lib/currency/money_helper.rb +13 -0
  41. data/lib/currency/parser.rb +193 -0
  42. data/spec/ar_base_spec.rb +140 -0
  43. data/spec/ar_column_spec.rb +69 -0
  44. data/spec/ar_core_spec.rb +64 -0
  45. data/spec/ar_simple_spec.rb +31 -0
  46. data/spec/config_spec.rb +29 -0
  47. data/spec/federal_reserve_spec.rb +75 -0
  48. data/spec/formatter_spec.rb +72 -0
  49. data/spec/historical_writer_spec.rb +187 -0
  50. data/spec/macro_spec.rb +109 -0
  51. data/spec/money_spec.rb +347 -0
  52. data/spec/new_york_fed_spec.rb +73 -0
  53. data/spec/parser_spec.rb +105 -0
  54. data/spec/spec_helper.rb +25 -0
  55. data/spec/time_quantitizer_spec.rb +115 -0
  56. data/spec/timed_cache_spec.rb +95 -0
  57. data/spec/xe_spec.rb +50 -0
  58. metadata +117 -0
data/README.txt ADDED
@@ -0,0 +1,51 @@
1
+ = Currency
2
+
3
+ This is the git@cdscm Currency package.
4
+
5
+ == Installation
6
+
7
+ gem install currency
8
+
9
+ == Documentation
10
+
11
+ "Project Info":http://rubyforge.org/projects/currency/
12
+
13
+ "API Documentation":http://currency.rubyforge.org/
14
+
15
+ The RubyForge package currency
16
+ implements an object-oriented representation of currencies, monetary values, foreign exchanges and rates.
17
+
18
+ Currency::Money uses a scaled integer representation of the monetary value and performs accurate conversions from string values.
19
+
20
+ See also: http://umleta.com/node/5
21
+
22
+ == Home page
23
+
24
+ * {Currency Home}[git@cdscm:currency.git]
25
+
26
+ == Additional directories
27
+
28
+ [./lib/...] the Currency library
29
+ [./test/...] unit and functional test
30
+ [./examples/...] example programs
31
+
32
+ == Credits
33
+
34
+ Currency was developed by:
35
+
36
+ * Kurt Stephens -- ruby-currency(at)umleta.com, sponsored by umleta.com
37
+
38
+ == License
39
+
40
+ * See LICENSE.txt
41
+
42
+ == Copyright
43
+
44
+ * Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
45
+
46
+ == Contributors
47
+
48
+ * Steffen Rusitschka
49
+
50
+
51
+
data/Releases.txt ADDED
@@ -0,0 +1,155 @@
1
+ = Currency Release History
2
+
3
+ == Release 0.4.11: 2007/11/02
4
+
5
+ CRITICAL FIXES
6
+
7
+ * parser.rb - uncommitted typos.
8
+
9
+ == Release 0.4.10: 2007/11/01
10
+
11
+ CRITICAL FIXES
12
+
13
+ * xe.rb - http://xe.com format change: Handle inline div in rates table.
14
+ * bin/currency_historical_rate_load - script for pulling rates from sources into historical rate table.
15
+ * exception.rb - Currency::Exception::Base can take Array with optional key/values.
16
+ * exception.rb - Additional exception classes.
17
+ * ALL - use raise instead of throw throughout.
18
+
19
+
20
+ == Release 0.4.9: 2007/11/01
21
+
22
+ ** IGNORE THIS RELEASE**
23
+
24
+ * Broken rubyforge config.
25
+
26
+ == Release 0.4.7: 2007/06/25
27
+
28
+ CRITICAL FIXES
29
+
30
+ * NewYorkFed: CRITICAL FIX:
31
+
32
+ Rates for USDAUD, USDEUR, USDNZD and USDGBP were reciprocals.
33
+ See http://www.newyorkfed.org/markets/fxrates/noon.cfm
34
+
35
+ * FederalReserve: Added support for historical rates from http://www.federalreserve.gov/releases/H10/hist
36
+ * Provider#get_rate(): Return first rate immediately.
37
+ * Rate::Writable for rate summary computation support.
38
+ * Rate: collect_rate(): fixed rate_date_1.
39
+ * Historical::Rate: to_rate(): takes optional class.
40
+ * Historical::Rate: from_rate(): fixed rate_samples.
41
+
42
+ == Release 0.4.6: 2007/05/29
43
+
44
+ * NewYorkFed: changed FEXtime to FEXTIME.
45
+ * Fixed Rate#collect_rates, source, rate_date_0, rate_date_1.
46
+
47
+ == Release 0.4.5: 2007/05/29
48
+
49
+ * Historical::Rate table name can be configured in Currency::Config.current.historical_table_name
50
+ * Fixed Rate::Source::TheFinancials.
51
+ * Examples: use Currency.Money(), not Currency::Money.new().
52
+
53
+ == Release 0.4.4: 2007/04/01
54
+
55
+ MAY NOT BE BACKWARDS-COMPATIBLE
56
+
57
+ * Fixed TimedCache.
58
+ * Updated documentation.
59
+ * Added support for Parser#time = :now.
60
+ * Added support for Time in Formatter and Parser using Time#xmlschema.
61
+ * Money#inspect now appends Money#time, if set.
62
+
63
+ == Release 0.4.3: 2007/04/01
64
+
65
+ * Added available? checks for NewYorkFed.
66
+ * Created new UnavailableRates exception for rate providers that return no rates (New York Fed on weekends).
67
+ * Fixed xe.com rate dates.
68
+ * Refactored exceptions.
69
+ * Fixed comments.
70
+
71
+ == Release 0.4.2: 2007/03/11
72
+
73
+ * Missing Manifest changes
74
+ * Missing Contributors
75
+
76
+ == Release 0.4.1: 2007/03/10
77
+
78
+ Some changes are not backwards-compatible
79
+
80
+ * Fixed Rate::Source::Xe; site format changed, more robust parser.
81
+ * Added Currency::Config.
82
+ * Support for filtering Float values before casting to Money, based on suggestions for rounding by Steffen Rusitschka.
83
+ * Fixed :allow_nil in ActiveRecord money macro based on fix by Steffen Rusitschka.
84
+ * Fixed package scoping issue in Money.
85
+ * Added support for Formatter#template string
86
+ * 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.
87
+
88
+ == Release 0.4.0: 2007/02/21
89
+
90
+ === MAJOR CHANGES IN THIS RELEASE FOR HISTORICAL RATE DATA
91
+
92
+ Some changes are not backwards-compatible
93
+
94
+ * ActiveRecord::Base.money macro is deprecated, use ActiveRecord::Base.attr_money macro.
95
+ * Currency::Exchange is now Currency::Exchange::Rate::Source
96
+ NOTE: Currency::Exchange::* is reserved for buying/selling currencies, not for providing rate data.
97
+ * Refactored xe.com homepage rate source as a Currency::Exchange::Rate::Source::Xe.
98
+ * Refactored Currency::Exchange::Test as Currency::Exchange::Rate::Source::Test.
99
+ * Support for historical money values and rates using ActiveRecord.
100
+ * Added Rate::Source::Historical::Writer.
101
+ * Added newyorkfed.org XML rate source.
102
+ * Added thefinancials.com XML rate source.
103
+ * Refactored rate deriviation into Currency::Exchange::Rate::Deriver.
104
+ * Refactored rate caching into Currency::Exchange::Rate::Source::TimedCache.
105
+ * Added Money attribute macros for classes not using ActiveRecord.
106
+ * Refactored time-based rate caching into Currency::Exchange::Rate::Source::TimedCache.
107
+ * Refactored Currency::Currency#format into Currency::Formatter.
108
+ NOTE: old formatting options as :no_* no longer supported.
109
+ * Refactored Currency::Currency#parse into Currency::Parser.
110
+ * Currency::CurrencyFactory is now Currency::Currency::Factory.
111
+ * Preliminary Currency::Exchange::Rate::Source::Failover.
112
+ * Added copyright notices: LICENSE.txt, COPYING.txt.
113
+
114
+ == Release 0.3.3: 2006/10/31
115
+
116
+ * Inclusion of README.txt and Releases.txt into documentation.
117
+
118
+ == Release 0.3.2: 2006/10/31
119
+
120
+ * BOO!
121
+ * Added expiration of rates in Xe.
122
+ * Fixed Currency.symbol formatting when Currency.symbol.nil?
123
+ * Added more Money tests.
124
+
125
+ == Release 0.3.1: 2006/10/31
126
+
127
+ * Remove debug puts.
128
+
129
+ == Release 0.3.0: 2006/10/31
130
+
131
+ * ActiveRecord money :*_field options are now named :*_column.
132
+ * More ActiveRecord tests
133
+
134
+ == Release 0.2.1: 2006/10/31
135
+
136
+ * Fixed Manifest.txt
137
+
138
+ == Release 0.2.0: 2006/10/31
139
+
140
+ * Restructured namespace
141
+ * Added more documentation
142
+ * Added ActiveRecord tests
143
+
144
+ == Release 0.1.2: 2006/10/30
145
+
146
+ * Rakefile now uses Hoe
147
+
148
+ == Release 0.1.1: 2006/10/30
149
+
150
+ * Fixes gem packaging errors.
151
+
152
+ == Release 0.1.0: 2006/10/29
153
+
154
+ * Initial Release
155
+
data/TODO.txt ADDED
@@ -0,0 +1,9 @@
1
+
2
+ = Currency To Do List
3
+
4
+ * Clean up and normalize all exceptions:
5
+ ** Rate sources should add :source => source, etc.
6
+ * Refactor all configuration class variables into Currency::Config
7
+ * Refactor all cached values into objects that can be reinstantiated on a per-thread basis
8
+ * Support http://www.xe.com/ucc/full.php rate queries.
9
+
data/currency.gemspec ADDED
@@ -0,0 +1,18 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{acvwilson-currency}
3
+ s.version = "0.5.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Asa Wilson"]
7
+ s.date = %q{2008-11-14}
8
+ s.description = %q{Currency conversions for Ruby}
9
+ s.email = ["acvwilson@gmail.com"]
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"]
12
+ s.has_rdoc = true
13
+ s.homepage = %q{http://currency.rubyforge.org/}
14
+ s.rdoc_options = ["--main", "README.txt"]
15
+ s.require_paths = ["lib"]
16
+ s.rubygems_version = %q{1.3.0}
17
+ s.summary = %q{acvwilson-currency 0.5.0}
18
+ end
data/examples/ex1.rb ADDED
@@ -0,0 +1,13 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'currency'
4
+ require 'currency/exchange/rate/source/test'
5
+
6
+ x = Currency.Money("1,203.43", :USD)
7
+
8
+ puts x.to_s
9
+ puts (x * 10).to_s
10
+ puts (x * 33333).inspect
11
+
12
+ puts x.currency.code.inspect
13
+
data/examples/xe1.rb ADDED
@@ -0,0 +1,20 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'currency'
4
+ require 'currency/exchange/rate/source/xe'
5
+
6
+ ex = Currency::Exchange::Rate::Source::Xe.new()
7
+ Currency::Exchange::Rate::Source.current = ex
8
+
9
+ puts ex.inspect
10
+ puts ex.parse_page_rates.inspect
11
+
12
+ usd = Currency.Money("1", 'USD')
13
+
14
+ puts "usd = #{usd}"
15
+
16
+ cad = usd.convert(:CAD)
17
+ puts "cad = #{cad}"
18
+
19
+
20
+
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,265 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ require 'active_record/base'
5
+ require File.join(File.dirname(__FILE__), '..', 'currency')
6
+
7
+ # See Currency::ActiveRecord::ClassMethods
8
+ class ActiveRecord::Base
9
+ @@money_attributes = { }
10
+
11
+ # Called by money macro when a money attribute
12
+ # is created.
13
+ def self.register_money_attribute(attr_opts)
14
+ (@@money_attributes[attr_opts[:class]] ||= { })[attr_opts[:attr_name]] = attr_opts
15
+ end
16
+
17
+ # Returns an array of option hashes for all the money attributes of
18
+ # this class.
19
+ #
20
+ # Superclass attributes are not included.
21
+ def self.money_attributes_for_class(cls)
22
+ (@@money_atttributes[cls] || { }).values
23
+ end
24
+
25
+
26
+ # Iterates through all known money attributes in all classes.
27
+ #
28
+ # each_money_attribute { | money_opts |
29
+ # ...
30
+ # }
31
+ def self.each_money_attribute(&blk)
32
+ @@money_attributes.each do | cls, hash |
33
+ hash.each do | attr_name, attr_opts |
34
+ yield attr_opts
35
+ end
36
+ end
37
+ end
38
+
39
+ end # class
40
+
41
+
42
+ # See Currency::ActiveRecord::ClassMethods
43
+ module Currency::ActiveRecord
44
+
45
+ def self.append_features(base) # :nodoc:
46
+ # $stderr.puts " Currency::ActiveRecord#append_features(#{base})"
47
+ super
48
+ base.extend(ClassMethods)
49
+ end
50
+
51
+
52
+
53
+ # == ActiveRecord Suppport
54
+ #
55
+ # Support for Money attributes in ActiveRecord::Base subclasses:
56
+ #
57
+ # require 'currency'
58
+ # require 'currency/active_record'
59
+ #
60
+ # class Entry < ActiveRecord::Base
61
+ # attr_money :amount
62
+ # end
63
+ #
64
+ module ClassMethods
65
+
66
+ # Deprecated: use attr_money.
67
+ def money(*args)
68
+ $stderr.puts "WARNING: money(#{args.inspect}) deprecated, use attr_money: in #{caller(1)[0]}"
69
+ attr_money(*args)
70
+ end
71
+
72
+
73
+ # Defines a Money object attribute that is bound
74
+ # to a database column. The database column to store the
75
+ # Money value representation is assumed to be
76
+ # INTEGER and will store Money#rep values.
77
+ #
78
+ # Options:
79
+ #
80
+ # :column => undef
81
+ #
82
+ # Defines the column to use for storing the money value.
83
+ # Defaults to the attribute name.
84
+ #
85
+ # If this column is different from the attribute name,
86
+ # the money object will intercept column=(x) to flush
87
+ # any cached Money object.
88
+ #
89
+ # :currency => currency_code (e.g.: :USD)
90
+ #
91
+ # Defines the Currency to use for storing a normalized Money
92
+ # value.
93
+ #
94
+ # All Money values will be converted to this Currency before
95
+ # storing. This allows SQL summary operations,
96
+ # like SUM(), MAX(), AVG(), etc., to produce meaningful results,
97
+ # regardless of the initial currency specified. If this
98
+ # option is used, subsequent reads will be in the specified
99
+ # normalization :currency.
100
+ #
101
+ # :currency_column => undef
102
+ #
103
+ # Defines the name of the CHAR(3) column used to store and
104
+ # retrieve the Money's Currency code. If this option is used, each
105
+ # record may use a different Currency to store the result, such
106
+ # that SQL summary operations, like SUM(), MAX(), AVG(),
107
+ # may return meaningless results.
108
+ #
109
+ # :currency_preferred_column => undef
110
+ #
111
+ # Defines the name of a CHAR(3) column used to store and
112
+ # retrieve the Money's Currency code. This option can be used
113
+ # with normalized Money values to retrieve the Money value
114
+ # in its original Currency, while
115
+ # allowing SQL summary operations on the normalized Money values
116
+ # to still be valid.
117
+ #
118
+ # :time => undef
119
+ #
120
+ # Defines the name of attribute used to
121
+ # retrieve the Money's time. If this option is used, each
122
+ # Money value will use this attribute during historical Currency
123
+ # conversions.
124
+ #
125
+ # Money values can share a time value with other attributes
126
+ # (e.g. a created_on column).
127
+ #
128
+ # If this option is true, the money time attribute will be named
129
+ # "#{attr_name}_time" and :time_update will be true.
130
+ #
131
+ # :time_update => undef
132
+ #
133
+ # If true, the Money time value is updated upon setting the
134
+ # money attribute.
135
+ #
136
+ def attr_money(attr_name, *opts)
137
+ opts = Hash[*opts]
138
+
139
+ attr_name = attr_name.to_s
140
+ opts[:class] = self
141
+ opts[:table] = self.table_name
142
+ opts[:attr_name] = attr_name.intern
143
+ ::ActiveRecord::Base.register_money_attribute(opts)
144
+
145
+ column = opts[:column] || opts[:attr_name]
146
+ opts[:column] = column
147
+
148
+ if column.to_s != attr_name.to_s
149
+ alias_accessor = <<-"end_eval"
150
+ alias :before_money_#{column}=, :#{column}=
151
+
152
+ def #{column}=(__value)
153
+ @{attr_name} = nil # uncache
154
+ before_money#{column} = __value
155
+ end
156
+
157
+ end_eval
158
+ end
159
+
160
+ currency = opts[:currency]
161
+
162
+ currency_column = opts[:currency_column]
163
+ if currency_column && ! currency_column.kind_of?(String)
164
+ currency_column = currency_column.to_s
165
+ currency_column = "#{column}_currency"
166
+ end
167
+ if currency_column
168
+ read_currency = "read_attribute(:#{currency_column.to_s})"
169
+ write_currency = "write_attribute(:#{currency_column}, #{attr_name}_money.nil? ? nil : #{attr_name}_money.currency.code.to_s)"
170
+ end
171
+ opts[:currency_column] = currency_column
172
+
173
+ currency_preferred_column = opts[:currency_preferred_column]
174
+ if currency_preferred_column
175
+ currency_preferred_column = currency_preferred_column.to_s
176
+ read_preferred_currency = "@#{attr_name} = @#{attr_name}.convert(read_attribute(:#{currency_preferred_column}))"
177
+ write_preferred_currency = "write_attribute(:#{currency_preferred_column}, @#{attr_name}_money.currency.code)"
178
+ end
179
+
180
+ time = opts[:time]
181
+ write_time = ''
182
+ if time
183
+ if time == true
184
+ time = "#{attr_name}_time"
185
+ opts[:time_update] = true
186
+ end
187
+ read_time = "self.#{time}"
188
+ end
189
+ opts[:time] = time
190
+ if opts[:time_update]
191
+ write_time = "self.#{time} = #{attr_name}_money && #{attr_name}_money.time"
192
+ end
193
+
194
+ currency ||= ':USD'
195
+ time ||= 'nil'
196
+
197
+ read_currency ||= currency
198
+ read_time ||= time
199
+
200
+ money_rep ||= "#{attr_name}_money.rep"
201
+
202
+ validate_allow_nil = opts[:allow_nil] ? ', :allow_nil => true' : ''
203
+ validate = "# Validation\n"
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
206
+
207
+
208
+ alias_accessor ||= ''
209
+
210
+ module_eval (opts[:module_eval] = x = <<-"end_eval"), __FILE__, __LINE__
211
+ #{validate}
212
+
213
+ #{alias_accessor}
214
+
215
+ def #{attr_name}
216
+ # $stderr.puts " \#{self.class.name}##{attr_name}"
217
+ unless @#{attr_name}
218
+ #{attr_name}_rep = read_attribute(:#{column})
219
+ unless #{attr_name}_rep.nil?
220
+ @#{attr_name} = ::Currency::Money.new_rep(#{attr_name}_rep, #{read_currency} || #{currency}, #{read_time} || #{time})
221
+ #{read_preferred_currency}
222
+ end
223
+ end
224
+ @#{attr_name}
225
+ end
226
+
227
+ def #{attr_name}=(value)
228
+ if value.nil?
229
+ #{attr_name}_money = nil
230
+ elsif value.kind_of?(Integer) || value.kind_of?(String) || value.kind_of?(Float)
231
+ #{attr_name}_money = ::Currency::Money(value, #{currency})
232
+ #{write_preferred_currency}
233
+ elsif value.kind_of?(::Currency::Money)
234
+ #{attr_name}_money = value
235
+ #{write_preferred_currency}
236
+ #{write_currency ? write_currency : "#{attr_name}_money = #{attr_name}_money.convert(#{currency})"}
237
+ else
238
+ raise ::Currency::Exception::InvalidMoneyValue, value
239
+ end
240
+
241
+ @#{attr_name} = #{attr_name}_money
242
+
243
+ write_attribute(:#{column}, #{attr_name}_money.nil? ? nil : #{money_rep})
244
+ #{write_time}
245
+
246
+ value
247
+ end
248
+
249
+ def #{attr_name}_before_type_cast
250
+ # FIXME: User cannot specify Currency
251
+ x = #{attr_name}
252
+ x &&= x.format(:symbol => false, :currency => false, :thousands => false)
253
+ x
254
+ end
255
+
256
+ end_eval
257
+ # $stderr.puts " CODE = #{x}"
258
+ end
259
+ end
260
+ end
261
+
262
+
263
+ ActiveRecord::Base.class_eval do
264
+ include Currency::ActiveRecord
265
+ end