currency 0.3.3 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING.txt +339 -0
- data/LICENSE.txt +62 -0
- data/Manifest.txt +37 -14
- data/README.txt +8 -0
- data/Rakefile +42 -8
- data/Releases.txt +26 -0
- data/TODO.txt +1 -0
- data/examples/ex1.rb +3 -3
- data/examples/xe1.rb +3 -2
- data/lib/currency.rb +71 -9
- data/lib/currency/active_record.rb +138 -21
- data/lib/currency/core_extensions.rb +7 -5
- data/lib/currency/currency.rb +94 -177
- data/lib/currency/{currency_factory.rb → currency/factory.rb} +46 -25
- data/lib/currency/currency_version.rb +3 -3
- data/lib/currency/exception.rb +14 -14
- data/lib/currency/exchange.rb +14 -12
- data/lib/currency/exchange/rate.rb +159 -28
- data/lib/currency/exchange/rate/deriver.rb +146 -0
- data/lib/currency/exchange/rate/source.rb +84 -0
- data/lib/currency/exchange/rate/source/base.rb +156 -0
- data/lib/currency/exchange/rate/source/failover.rb +57 -0
- data/lib/currency/exchange/rate/source/historical.rb +79 -0
- data/lib/currency/exchange/rate/source/historical/rate.rb +181 -0
- data/lib/currency/exchange/rate/source/historical/writer.rb +203 -0
- data/lib/currency/exchange/rate/source/new_york_fed.rb +91 -0
- data/lib/currency/exchange/rate/source/provider.rb +105 -0
- data/lib/currency/exchange/rate/source/test.rb +50 -0
- data/lib/currency/exchange/rate/source/the_financials.rb +190 -0
- data/lib/currency/exchange/rate/source/timed_cache.rb +144 -0
- data/lib/currency/exchange/rate/source/xe.rb +166 -0
- data/lib/currency/exchange/time_quantitizer.rb +111 -0
- data/lib/currency/formatter.rb +159 -0
- data/lib/currency/macro.rb +321 -0
- data/lib/currency/money.rb +90 -64
- data/lib/currency/money_helper.rb +6 -5
- data/lib/currency/parser.rb +153 -0
- data/test/ar_column_test.rb +6 -3
- data/test/ar_simple_test.rb +5 -2
- data/test/ar_test_base.rb +39 -33
- data/test/ar_test_core.rb +64 -0
- data/test/formatter_test.rb +81 -0
- data/test/historical_writer_test.rb +184 -0
- data/test/macro_test.rb +109 -0
- data/test/money_test.rb +72 -4
- data/test/new_york_fed_test.rb +57 -0
- data/test/parser_test.rb +60 -0
- data/test/test_base.rb +13 -3
- data/test/time_quantitizer_test.rb +136 -0
- data/test/xe_test.rb +29 -5
- metadata +41 -18
- data/lib/currency/exchange/base.rb +0 -84
- data/lib/currency/exchange/test.rb +0 -39
- data/lib/currency/exchange/xe.rb +0 -250
data/README.txt
CHANGED
@@ -35,6 +35,14 @@ Currency was developed by:
|
|
35
35
|
|
36
36
|
* Kurt Stephens -- ruby-currency(at)umleta.com, sponsored by umleta.com
|
37
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
|
+
|
38
46
|
== Contributors
|
39
47
|
|
40
48
|
Maybe you?
|
data/Rakefile
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
# Rakefile for currency -*- ruby -*-
|
2
2
|
# Adapted from RubyGems/Rakefile
|
3
|
-
|
3
|
+
|
4
|
+
# For release
|
5
|
+
"
|
6
|
+
svn status
|
7
|
+
rake make_manifest
|
8
|
+
rake update_version
|
9
|
+
rake package
|
10
|
+
rake release VERSION=x.x.x
|
11
|
+
rake svn_release
|
12
|
+
rake publish_docs
|
13
|
+
rake announce
|
14
|
+
"
|
4
15
|
|
5
16
|
#################################################################
|
6
17
|
|
@@ -8,10 +19,16 @@ require 'rubygems'
|
|
8
19
|
require 'hoe'
|
9
20
|
|
10
21
|
PKG_Name = 'Currency'
|
11
|
-
PKG_DESCRIPTION = %{Currency models currencies, monetary values, foreign exchanges and rates.
|
22
|
+
PKG_DESCRIPTION = %{Currency models currencies, monetary values, foreign exchanges and rates.
|
23
|
+
Pulls live rates from http://xe.com/.
|
12
24
|
Supports ActiveRecord.
|
13
25
|
|
14
|
-
|
26
|
+
For more details, see:
|
27
|
+
|
28
|
+
http://currency.rubyforge.org/files/lib/currency_rb.html
|
29
|
+
http://currency.rubyforge.org/files/README.txt
|
30
|
+
http://currency.rubyforge.org/
|
31
|
+
|
15
32
|
}
|
16
33
|
|
17
34
|
#################################################################
|
@@ -24,7 +41,7 @@ def get_release_notes(relfile = "Releases.txt")
|
|
24
41
|
notes = [ ]
|
25
42
|
|
26
43
|
File.open(relfile) do |f|
|
27
|
-
while line = f.readline
|
44
|
+
while ! f.eof && line = f.readline
|
28
45
|
if md = /^== Release ([\d\.]+)/i.match(line)
|
29
46
|
release = md[1]
|
30
47
|
notes << line
|
@@ -32,7 +49,7 @@ def get_release_notes(relfile = "Releases.txt")
|
|
32
49
|
end
|
33
50
|
end
|
34
51
|
|
35
|
-
while line = f.readline
|
52
|
+
while ! f.eof && line = f.readline
|
36
53
|
if md = /^== Release ([\d\.]+)/i.match(line)
|
37
54
|
break
|
38
55
|
end
|
@@ -47,6 +64,8 @@ end
|
|
47
64
|
|
48
65
|
PKG_NAME = PKG_Name.gsub(/[a-z][A-Z]/) {|x| "#{x[0,1]}_#{x[1,1]}"}.downcase
|
49
66
|
|
67
|
+
PKG_SVN_ROOT="svn+ssh://rubyforge.org/var/svn/#{PKG_NAME}/#{PKG_NAME}"
|
68
|
+
|
50
69
|
release, release_notes = get_release_notes
|
51
70
|
|
52
71
|
hoe = Hoe.new("currency", release) do |p|
|
@@ -75,12 +94,12 @@ version_rb = "lib/#{PKG_NAME}/#{PKG_NAME}_version.rb"
|
|
75
94
|
task :update_version do
|
76
95
|
announce "Updating #{PKG_Name} version to #{PKG_VERSION}: #{version_rb}"
|
77
96
|
open(version_rb, "w") do |f|
|
78
|
-
f.puts "# DO NOT EDIT"
|
79
|
-
f.puts "# This file is auto-generated by build scripts."
|
80
|
-
f.puts "# See: rake update_version"
|
81
97
|
f.puts "module #{PKG_Name}"
|
82
98
|
f.puts " #{PKG_Name}Version = '#{PKG_VERSION}'"
|
83
99
|
f.puts "end"
|
100
|
+
f.puts "# DO NOT EDIT"
|
101
|
+
f.puts "# This file is auto-generated by build scripts."
|
102
|
+
f.puts "# See: rake update_version"
|
84
103
|
end
|
85
104
|
if ENV['RELTEST']
|
86
105
|
announce "Release Task Testing, skipping commiting of new version"
|
@@ -91,6 +110,14 @@ end
|
|
91
110
|
|
92
111
|
task version_rb => :update_version
|
93
112
|
|
113
|
+
#################################################################
|
114
|
+
# SVN
|
115
|
+
#
|
116
|
+
|
117
|
+
task :svn_release do
|
118
|
+
sh %{svn cp -m 'Release #{PKG_VERSION}' . #{PKG_SVN_ROOT}/release/#{PKG_VERSION}}
|
119
|
+
end
|
120
|
+
|
94
121
|
# task :test => :update_version
|
95
122
|
|
96
123
|
|
@@ -126,3 +153,10 @@ task :rubyfiles do
|
|
126
153
|
puts Dir['bin/*'].reject { |fn| fn =~ /CVS|.svn|(~$)|(\.rb$)/ }
|
127
154
|
end
|
128
155
|
|
156
|
+
task :make_manifest do
|
157
|
+
open("Manifest.txt", "w") do |f|
|
158
|
+
f.puts Dir['**/*'].reject { |fn| ! test(?f, fn) || fn =~ /CVS|.svn|([#~]$)|(.gem$)|(^pkg\/)|(^doc\/)/ }.sort.join("\n") + "\n"
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
|
data/Releases.txt
CHANGED
@@ -1,5 +1,31 @@
|
|
1
1
|
= Currency Release History
|
2
2
|
|
3
|
+
== Release 0.4.0: 2007/02/21
|
4
|
+
|
5
|
+
=== MAJOR CHANGES IN THIS RELEASE FOR HISTORICAL RATE DATA
|
6
|
+
|
7
|
+
Some changes are not backwards-compatible
|
8
|
+
|
9
|
+
* ActiveRecord::Base.money macro is deprecated, use ActiveRecord::Base.attr_money macro.
|
10
|
+
* Currency::Exchange is now Currency::Exchange::Rate::Source
|
11
|
+
NOTE: Currency::Exchange::* is reserved for buying/selling currencies, not for providing rate data.
|
12
|
+
* Refactored xe.com homepage rate source as a Currency::Exchange::Rate::Source::Xe.
|
13
|
+
* Refactored Currency::Exchange::Test as Currency::Exchange::Rate::Source::Test.
|
14
|
+
* Support for historical money values and rates using ActiveRecord.
|
15
|
+
* Added Rate::Source::Historical::Writer.
|
16
|
+
* Added newyorkfed.org XML rate source.
|
17
|
+
* Added thefinancials.com XML rate source.
|
18
|
+
* Refactored rate deriviation into Currency::Exchange::Rate::Deriver.
|
19
|
+
* Refactored rate caching into Currency::Exchange::Rate::Source::TimedCache.
|
20
|
+
* Added Money attribute macros for classes not using ActiveRecord.
|
21
|
+
* Refactored time-based rate caching into Currency::Exchange::Rate::Source::TimedCache.
|
22
|
+
* Refactored Currency::Currency#format into Currency::Formatter.
|
23
|
+
NOTE: old formatting options as :no_* no longer supported.
|
24
|
+
* Refactored Currency::Currency#parse into Currency::Parser.
|
25
|
+
* Currency::CurrencyFactory is now Currency::Currency::Factory.
|
26
|
+
* Preliminary Currency::Exchange::Rate::Source::Failover.
|
27
|
+
* Added copyright notices: LICENSE.txt, COPYING.txt.
|
28
|
+
|
3
29
|
== Release 0.3.3: 2006/10/31
|
4
30
|
|
5
31
|
* Inclusion of README.txt and Releases.txt into documentation.
|
data/TODO.txt
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
|
data/examples/ex1.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
|
3
3
|
require 'currency'
|
4
|
-
require 'currency/exchange/test'
|
4
|
+
require 'currency/exchange/rate/source/test'
|
5
5
|
|
6
|
-
x = Currency::Money.new("1,203.43",
|
6
|
+
x = Currency::Money.new("1,203.43", :USD)
|
7
7
|
|
8
8
|
puts x.to_s
|
9
9
|
puts (x * 10).to_s
|
10
|
-
puts (x * 33333).
|
10
|
+
puts (x * 33333).inspect
|
11
11
|
|
12
12
|
puts x.currency.code.inspect
|
13
13
|
|
data/examples/xe1.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
2
|
|
3
3
|
require 'currency'
|
4
|
-
require 'currency/exchange/xe'
|
4
|
+
require 'currency/exchange/rate/source/xe'
|
5
5
|
|
6
|
-
ex = Currency::Exchange::Xe.new()
|
6
|
+
ex = Currency::Exchange::Rate::Source::Xe.new()
|
7
|
+
Currency::Exchange::Rate::Source.current = ex
|
7
8
|
|
8
9
|
puts ex.inspect
|
9
10
|
puts ex.parse_page_rates.inspect
|
data/lib/currency.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
#
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
#
|
3
|
+
# See LICENSE.txt for details.
|
2
4
|
#
|
3
5
|
# = Currency
|
4
6
|
#
|
@@ -7,6 +9,7 @@
|
|
7
9
|
# * currencies
|
8
10
|
# * exchanges
|
9
11
|
# * exchange rates
|
12
|
+
# * exchange rate sources
|
10
13
|
# * monetary values
|
11
14
|
#
|
12
15
|
# The core classes are:
|
@@ -14,6 +17,8 @@
|
|
14
17
|
# * Currency::Money - uses a scaled integer representation of a monetary value and performs accurate conversions to and from string values.
|
15
18
|
# * Currency::Currency - provides an object-oriented representation of a currency.
|
16
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.
|
17
22
|
# * Currency::Exchange::Rate - represents a exchange rate between two currencies.
|
18
23
|
#
|
19
24
|
#
|
@@ -21,8 +26,14 @@
|
|
21
26
|
# exchange rates from http://xe.com/ :
|
22
27
|
#
|
23
28
|
# require 'currency'
|
24
|
-
# require 'currency/exchange/xe'
|
29
|
+
# require 'currency/exchange/rate/source/xe'
|
25
30
|
#
|
31
|
+
# # Rate source initialization
|
32
|
+
# provider = Currency::Exchange::Rate::Source::Xe.new
|
33
|
+
# deriver = Currency::Exchange::Rate::Deriver.new(:source => provider)
|
34
|
+
# cache = Currency::Exchange::Rate::Source::TimedCache.new(:source => deriver)
|
35
|
+
# Currency::Exchange::Rate::Source.default = cache
|
36
|
+
#
|
26
37
|
# usd = Currency::Money('6.78', :USD)
|
27
38
|
# puts "usd = #{usd.format}"
|
28
39
|
# cad = usd.convert(:CAD)
|
@@ -42,11 +53,35 @@
|
|
42
53
|
# In the example above, the entries.amount database column is an INTEGER that represents US cents.
|
43
54
|
# The currency code of the money value can be stored in an additional database column or a default currency can be used.
|
44
55
|
#
|
56
|
+
# == Recent Enhancements
|
57
|
+
#
|
58
|
+
# === Storage and retrival of historical exchange rates
|
59
|
+
#
|
60
|
+
# * See Currency::Exchange::Rate::Source::Historical
|
61
|
+
# * See Currency::Exchange::Rate::Source::Historical::Writer
|
62
|
+
#
|
63
|
+
# === Automatic derivation of rates from base rates.
|
64
|
+
#
|
65
|
+
# * See Currency::Exchange::Rate::Deriver
|
66
|
+
#
|
67
|
+
# === Rate caching
|
68
|
+
#
|
69
|
+
# * See Currency::Exchange::Rate::Source::TimedCache
|
70
|
+
#
|
71
|
+
# === Rate Providers
|
72
|
+
#
|
73
|
+
# * See Currency::Exchange::Rate::Source::Xe
|
74
|
+
# * See Currency::Exchange::Rate::Source::NewYorkFed
|
75
|
+
# * See Currency::Exchange::Rate::Source::TheFinancials
|
76
|
+
#
|
77
|
+
# === Customizable formatting and parsing
|
78
|
+
#
|
79
|
+
# * See Currency::Formatter
|
80
|
+
# * See Currency::Parser
|
81
|
+
#
|
45
82
|
# == Future Enhancements
|
46
83
|
#
|
47
|
-
# *
|
48
|
-
# * exchange rate polling for population of historical rates
|
49
|
-
# * support for inflationary rates within a currency, e.g. $10 USD in the year 1955 in 2006 USD.
|
84
|
+
# * Support for inflationary rates within a currency, e.g. $10 USD in the year 1955 converted to 2006 USD.
|
50
85
|
#
|
51
86
|
# == SVN Repo
|
52
87
|
#
|
@@ -62,17 +97,44 @@
|
|
62
97
|
#
|
63
98
|
# == Support
|
64
99
|
#
|
65
|
-
#
|
100
|
+
# http://rubyforge.org/forum/forum.php?forum_id=7643
|
101
|
+
#
|
102
|
+
# == Copyright
|
103
|
+
#
|
104
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
105
|
+
#
|
106
|
+
# See LICENSE.txt for details.
|
66
107
|
#
|
108
|
+
module Currency
|
109
|
+
# Use this function instead of Money#new:
|
110
|
+
#
|
111
|
+
# Currency::Money("12.34", :CAD)
|
112
|
+
#
|
113
|
+
# Do not do this:
|
114
|
+
#
|
115
|
+
# Currency::Money.new("12.34", :CAD)
|
116
|
+
#
|
117
|
+
# See Money#new.
|
118
|
+
def self.Money(*opts)
|
119
|
+
Money.new(*opts)
|
120
|
+
end
|
121
|
+
end
|
67
122
|
|
68
|
-
$:.unshift(File.dirname(__FILE__)) unless
|
69
|
-
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
123
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__))) unless $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
70
124
|
|
125
|
+
require 'currency/currency_version'
|
71
126
|
require 'currency/exception'
|
72
127
|
require 'currency/money'
|
73
|
-
require 'currency/currency_factory'
|
74
128
|
require 'currency/currency'
|
129
|
+
require 'currency/currency/factory'
|
75
130
|
require 'currency/money'
|
131
|
+
require 'currency/formatter'
|
132
|
+
require 'currency/parser'
|
76
133
|
require 'currency/exchange'
|
134
|
+
require 'currency/exchange/rate'
|
135
|
+
require 'currency/exchange/rate/deriver'
|
136
|
+
require 'currency/exchange/rate/source'
|
137
|
+
require 'currency/exchange/rate/source/test'
|
138
|
+
require 'currency/exchange/time_quantitizer'
|
77
139
|
require 'currency/core_extensions'
|
78
140
|
|
@@ -1,14 +1,54 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
1
4
|
require 'active_record/base'
|
2
5
|
require File.join(File.dirname(__FILE__), '..', 'currency')
|
3
6
|
|
4
|
-
|
5
|
-
|
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
|
+
|
6
45
|
def self.append_features(base) # :nodoc:
|
7
46
|
# $stderr.puts " Currency::ActiveRecord#append_features(#{base})"
|
8
47
|
super
|
9
48
|
base.extend(ClassMethods)
|
10
49
|
end
|
11
|
-
|
50
|
+
|
51
|
+
|
12
52
|
|
13
53
|
# == ActiveRecord Suppport
|
14
54
|
#
|
@@ -18,29 +58,45 @@ module Currency
|
|
18
58
|
# require 'currency/active_record'
|
19
59
|
#
|
20
60
|
# class Entry < ActiveRecord::Base
|
21
|
-
#
|
61
|
+
# attr_money :amount
|
22
62
|
# end
|
23
63
|
#
|
24
64
|
module ClassMethods
|
25
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
|
+
|
26
73
|
# Defines a Money object attribute that is bound
|
27
74
|
# to a database column. The database column to store the
|
28
75
|
# Money value representation is assumed to be
|
29
|
-
# INTEGER.
|
76
|
+
# INTEGER and will store Money#rep values.
|
30
77
|
#
|
31
78
|
# Options:
|
32
79
|
#
|
33
|
-
# :
|
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)
|
34
90
|
#
|
35
91
|
# Defines the Currency to use for storing a normalized Money
|
36
|
-
# value.
|
92
|
+
# value.
|
37
93
|
#
|
38
94
|
# All Money values will be converted to this Currency before
|
39
|
-
# storing
|
95
|
+
# storing. This allows SQL summary operations,
|
40
96
|
# like SUM(), MAX(), AVG(), etc., to produce meaningful results,
|
41
97
|
# regardless of the initial currency specified. If this
|
42
98
|
# option is used, subsequent reads will be in the specified
|
43
|
-
# normalization :currency.
|
99
|
+
# normalization :currency.
|
44
100
|
#
|
45
101
|
# :currency_column => undef
|
46
102
|
#
|
@@ -59,22 +115,60 @@ module Currency
|
|
59
115
|
# allowing SQL summary operations on the normalized Money values
|
60
116
|
# to still be valid.
|
61
117
|
#
|
62
|
-
|
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)
|
63
137
|
opts = Hash[*opts]
|
64
138
|
|
65
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
|
66
159
|
|
67
160
|
currency = opts[:currency]
|
68
161
|
|
69
162
|
currency_column = opts[:currency_column]
|
70
163
|
if currency_column && ! currency_column.kind_of?(String)
|
71
164
|
currency_column = currency_column.to_s
|
72
|
-
currency_column = "#{
|
165
|
+
currency_column = "#{column}_currency"
|
73
166
|
end
|
74
167
|
if currency_column
|
75
168
|
read_currency = "read_attribute(:#{currency_column.to_s})"
|
76
169
|
write_currency = "write_attribute(:#{currency_column}, #{attr_name}_money.nil? ? nil : #{attr_name}_money.currency.code.to_s)"
|
77
170
|
end
|
171
|
+
opts[:currency_column] = currency_column
|
78
172
|
|
79
173
|
currency_preferred_column = opts[:currency_preferred_column]
|
80
174
|
if currency_preferred_column
|
@@ -83,23 +177,46 @@ module Currency
|
|
83
177
|
write_preferred_currency = "write_attribute(:#{currency_preferred_column}, @#{attr_name}_money.currency.code)"
|
84
178
|
end
|
85
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
|
+
|
86
194
|
currency ||= ':USD'
|
195
|
+
time ||= 'nil'
|
87
196
|
|
88
197
|
read_currency ||= currency
|
198
|
+
read_time ||= time
|
199
|
+
|
200
|
+
money_rep ||= "#{attr_name}_money.rep"
|
89
201
|
|
90
202
|
validate = "# Validation\n"
|
91
203
|
validate << "\nvalidates_numericality_of :#{attr_name}\n" unless opts[:allow_nil]
|
92
204
|
validate << "\nvalidates_format_of :#{currency_column}, :with => /^[A-Z][A-Z][A-Z]$/\n" if currency_column && ! opts[:allow_nil]
|
93
205
|
|
94
|
-
|
206
|
+
|
207
|
+
alias_accessor ||= ''
|
208
|
+
|
209
|
+
module_eval (opts[:module_eval] = x = <<-"end_eval"), __FILE__, __LINE__
|
95
210
|
#{validate}
|
96
211
|
|
212
|
+
#{alias_accessor}
|
213
|
+
|
97
214
|
def #{attr_name}
|
98
215
|
# $stderr.puts " \#{self.class.name}##{attr_name}"
|
99
216
|
unless @#{attr_name}
|
100
|
-
#{attr_name}_rep = read_attribute(:#{
|
217
|
+
#{attr_name}_rep = read_attribute(:#{column})
|
101
218
|
unless #{attr_name}_rep.nil?
|
102
|
-
@#{attr_name} = Currency::Money.new_rep(#{attr_name}_rep, #{read_currency} || #{currency})
|
219
|
+
@#{attr_name} = ::Currency::Money.new_rep(#{attr_name}_rep, #{read_currency} || #{currency}, #{read_time} || #{time})
|
103
220
|
#{read_preferred_currency}
|
104
221
|
end
|
105
222
|
end
|
@@ -108,21 +225,22 @@ end
|
|
108
225
|
|
109
226
|
def #{attr_name}=(value)
|
110
227
|
if value.nil?
|
111
|
-
|
228
|
+
#{attr_name}_money = nil
|
112
229
|
elsif value.kind_of?(Integer) || value.kind_of?(String) || value.kind_of?(Float)
|
113
|
-
#{attr_name}_money = Currency::Money
|
230
|
+
#{attr_name}_money = ::Currency::Money(value, #{currency})
|
114
231
|
#{write_preferred_currency}
|
115
|
-
elsif value.kind_of?(Money)
|
232
|
+
elsif value.kind_of?(::Currency::Money)
|
116
233
|
#{attr_name}_money = value
|
117
234
|
#{write_preferred_currency}
|
118
235
|
#{write_currency ? write_currency : "#{attr_name}_money = #{attr_name}_money.convert(#{currency})"}
|
119
236
|
else
|
120
|
-
throw Currency::Exception::InvalidMoneyValue.new(value)
|
237
|
+
throw ::Currency::Exception::InvalidMoneyValue.new(value)
|
121
238
|
end
|
122
239
|
|
123
240
|
@#{attr_name} = #{attr_name}_money
|
124
241
|
|
125
|
-
write_attribute(:#{
|
242
|
+
write_attribute(:#{column}, #{attr_name}_money.nil? ? nil : #{money_rep})
|
243
|
+
#{write_time}
|
126
244
|
|
127
245
|
value
|
128
246
|
end
|
@@ -130,7 +248,7 @@ end
|
|
130
248
|
def #{attr_name}_before_type_cast
|
131
249
|
# FIXME: User cannot specify Currency
|
132
250
|
x = #{attr_name}
|
133
|
-
x &&= x.format(:
|
251
|
+
x &&= x.format(:symbol => false, :currency => false, :thousands => false)
|
134
252
|
x
|
135
253
|
end
|
136
254
|
|
@@ -138,7 +256,6 @@ end_eval
|
|
138
256
|
# $stderr.puts " CODE = #{x}"
|
139
257
|
end
|
140
258
|
end
|
141
|
-
end
|
142
259
|
end
|
143
260
|
|
144
261
|
|