currency 0.3.3 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|
|