mumboe-currency 0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/currency_historical_rate_load +105 -0
- data/examples/ex1.rb +13 -0
- data/examples/xe1.rb +20 -0
- data/lib/currency/active_record.rb +265 -0
- data/lib/currency/config.rb +91 -0
- data/lib/currency/core_extensions.rb +41 -0
- data/lib/currency/currency/factory.rb +228 -0
- data/lib/currency/currency.rb +175 -0
- data/lib/currency/currency_version.rb +6 -0
- data/lib/currency/exception.rb +119 -0
- data/lib/currency/exchange/rate/deriver.rb +157 -0
- data/lib/currency/exchange/rate/source/base.rb +166 -0
- data/lib/currency/exchange/rate/source/failover.rb +63 -0
- data/lib/currency/exchange/rate/source/federal_reserve.rb +160 -0
- data/lib/currency/exchange/rate/source/historical/rate.rb +184 -0
- data/lib/currency/exchange/rate/source/historical/rate_loader.rb +186 -0
- data/lib/currency/exchange/rate/source/historical/writer.rb +220 -0
- data/lib/currency/exchange/rate/source/historical.rb +79 -0
- data/lib/currency/exchange/rate/source/new_york_fed.rb +127 -0
- data/lib/currency/exchange/rate/source/provider.rb +120 -0
- data/lib/currency/exchange/rate/source/test.rb +50 -0
- data/lib/currency/exchange/rate/source/the_financials.rb +191 -0
- data/lib/currency/exchange/rate/source/timed_cache.rb +198 -0
- data/lib/currency/exchange/rate/source/xe.rb +165 -0
- data/lib/currency/exchange/rate/source.rb +89 -0
- data/lib/currency/exchange/rate.rb +214 -0
- data/lib/currency/exchange/time_quantitizer.rb +111 -0
- data/lib/currency/exchange.rb +50 -0
- data/lib/currency/formatter.rb +290 -0
- data/lib/currency/macro.rb +321 -0
- data/lib/currency/money.rb +295 -0
- data/lib/currency/money_helper.rb +13 -0
- data/lib/currency/parser.rb +151 -0
- data/lib/currency.rb +143 -0
- data/test/string_test.rb +54 -0
- data/test/test_base.rb +44 -0
- metadata +90 -0
@@ -0,0 +1,290 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
require 'rss/rss' # Time#xmlschema
|
5
|
+
|
6
|
+
|
7
|
+
# This class formats a Money value as a String.
|
8
|
+
# Each Currency has a default Formatter.
|
9
|
+
class Currency::Formatter
|
10
|
+
# The underlying object for Currency::Formatter#format.
|
11
|
+
# This object is cloned and initialized with strings created
|
12
|
+
# from Formatter#format.
|
13
|
+
# It handles the Formatter#format string interpolation.
|
14
|
+
class Template
|
15
|
+
@@empty_hash = { }
|
16
|
+
@@empty_hash.freeze
|
17
|
+
|
18
|
+
# The template string.
|
19
|
+
attr_accessor :template
|
20
|
+
|
21
|
+
# The Currency::Money object being formatted.
|
22
|
+
attr_accessor :money
|
23
|
+
# The Currency::Currency object being formatted.
|
24
|
+
attr_accessor :currency
|
25
|
+
|
26
|
+
# The sign: '-' or nil.
|
27
|
+
attr_accessor :sign
|
28
|
+
# The whole part of the value, with thousands_separator or nil.
|
29
|
+
attr_accessor :whole
|
30
|
+
# The fraction part of the value, with decimal_separator or nil.
|
31
|
+
attr_accessor :fraction
|
32
|
+
# The currency symbol or nil.
|
33
|
+
attr_accessor :symbol
|
34
|
+
# The currency code or nil.
|
35
|
+
attr_accessor :code
|
36
|
+
|
37
|
+
# The time or nil.
|
38
|
+
attr_accessor :time
|
39
|
+
|
40
|
+
def initialize(opts = @@empty_hash)
|
41
|
+
@template =
|
42
|
+
@template_proc =
|
43
|
+
nil
|
44
|
+
|
45
|
+
opts.each_pair{ | k, v | self.send("#{k}=", v) }
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
# Sets the template string and uncaches the template_proc.
|
50
|
+
def template=(x)
|
51
|
+
if @template != x
|
52
|
+
@template_proc = nil
|
53
|
+
end
|
54
|
+
@template = x
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# Defines a the self._format template procedure using
|
59
|
+
# the template as a string to be interpolated.
|
60
|
+
def template_proc(template = @template)
|
61
|
+
return @template_proc if @template_proc
|
62
|
+
@template_proc = template || ''
|
63
|
+
# @template_proc = @template_proc.gsub(/[\\"']/) { | x | "\\" + x }
|
64
|
+
@template_proc = "def self._format; \"#{@template_proc}\"; end"
|
65
|
+
self.instance_eval @template_proc
|
66
|
+
@template_proc
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Formats the current state using the template.
|
71
|
+
def format
|
72
|
+
template_proc
|
73
|
+
_format
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# Defaults to ','
|
79
|
+
attr_accessor :thousands_separator
|
80
|
+
|
81
|
+
# Defaults to '.'
|
82
|
+
attr_accessor :decimal_separator
|
83
|
+
|
84
|
+
# If true, insert _thousands_separator_ between each 3 digits in the whole value.
|
85
|
+
attr_accessor :thousands
|
86
|
+
|
87
|
+
# If true, append _decimal_separator_ and decimal digits after whole value.
|
88
|
+
attr_accessor :cents
|
89
|
+
|
90
|
+
# If true, prefix value with currency symbol.
|
91
|
+
attr_accessor :symbol
|
92
|
+
|
93
|
+
# If true, append currency code.
|
94
|
+
attr_accessor :code
|
95
|
+
|
96
|
+
# If true, append the time.
|
97
|
+
attr_accessor :time
|
98
|
+
|
99
|
+
# The number of fractional digits in the time.
|
100
|
+
# Defaults to 4.
|
101
|
+
attr_accessor :time_fractional_digits
|
102
|
+
|
103
|
+
# If true, use html formatting.
|
104
|
+
#
|
105
|
+
# Currency::Money(12.45, :EUR).to_s(:html => true; :code => true)
|
106
|
+
# => "€12.45 <span class=\"currency_code\">EUR</span>"
|
107
|
+
attr_accessor :html
|
108
|
+
|
109
|
+
# A template string used to format a money value.
|
110
|
+
# Defaults to:
|
111
|
+
#
|
112
|
+
# '#{code}#{code && " "}#{symbol}#{sign}#{whole}#{fraction}#{time && " "}#{time}'
|
113
|
+
attr_accessor :template
|
114
|
+
|
115
|
+
|
116
|
+
# If passed true, formats for an input field (i.e.: as a number).
|
117
|
+
def as_input_value=(x)
|
118
|
+
if x
|
119
|
+
self.thousands_separator = ''
|
120
|
+
self.decimal_separator = '.'
|
121
|
+
self.thousands = false
|
122
|
+
self.cents = true
|
123
|
+
self.symbol = false
|
124
|
+
self.code = false
|
125
|
+
self.html = false
|
126
|
+
self.time = false
|
127
|
+
self.time_fractional_digits = nil
|
128
|
+
end
|
129
|
+
x
|
130
|
+
end
|
131
|
+
|
132
|
+
|
133
|
+
@@default = nil
|
134
|
+
# Get the default Formatter.
|
135
|
+
def self.default
|
136
|
+
@@default || self.new
|
137
|
+
end
|
138
|
+
|
139
|
+
|
140
|
+
# Set the default Formatter.
|
141
|
+
def self.default=(x)
|
142
|
+
@@default = x
|
143
|
+
end
|
144
|
+
|
145
|
+
|
146
|
+
def initialize(opt = { })
|
147
|
+
@thousands_separator = ','
|
148
|
+
@decimal_separator = '.'
|
149
|
+
@thousands = true
|
150
|
+
@cents = true
|
151
|
+
@symbol = true
|
152
|
+
@code = false
|
153
|
+
@html = false
|
154
|
+
@time = false
|
155
|
+
@time_fractional_digits = 4
|
156
|
+
@template = '#{code}#{code && " "}#{symbol}#{sign}#{whole}#{fraction}#{time && " "}#{time}'
|
157
|
+
@template_object = nil
|
158
|
+
|
159
|
+
opt.each_pair{ | k, v | self.send("#{k}=", v) }
|
160
|
+
end
|
161
|
+
|
162
|
+
|
163
|
+
def currency=(x) # :nodoc:
|
164
|
+
# DO NOTHING!
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
# Sets the template and the Template#template.
|
169
|
+
def template=(x)
|
170
|
+
if @template_object
|
171
|
+
@template_object.template = x
|
172
|
+
end
|
173
|
+
@template = x
|
174
|
+
end
|
175
|
+
|
176
|
+
|
177
|
+
# Returns the Template object.
|
178
|
+
def template_object
|
179
|
+
return @template_object if @template_object
|
180
|
+
|
181
|
+
@template_object = Template.new
|
182
|
+
@template_object.template = @template if @template
|
183
|
+
# $stderr.puts "template.template = #{@template_object.template.inspect}"
|
184
|
+
@template_object.template_proc # pre-cache before clone.
|
185
|
+
|
186
|
+
@template_object
|
187
|
+
end
|
188
|
+
|
189
|
+
|
190
|
+
def _format(m, currency = nil, time = nil) # :nodoc:
|
191
|
+
# Get currency.
|
192
|
+
currency ||= m.currency
|
193
|
+
|
194
|
+
# Get time.
|
195
|
+
time ||= m.time
|
196
|
+
|
197
|
+
# Setup template
|
198
|
+
tmpl = self.template_object.clone
|
199
|
+
# $stderr.puts "template.template = #{tmpl.template.inspect}"
|
200
|
+
tmpl.money = m
|
201
|
+
tmpl.currency = currency
|
202
|
+
|
203
|
+
# Get scaled integer representation for this Currency.
|
204
|
+
# $stderr.puts "m.currency = #{m.currency}, currency => #{currency}"
|
205
|
+
x = m.Money_rep(currency)
|
206
|
+
|
207
|
+
# Remove sign.
|
208
|
+
x = - x if ( neg = x < 0 )
|
209
|
+
tmpl.sign = neg ? '-' : nil
|
210
|
+
|
211
|
+
# Convert to String.
|
212
|
+
x = x.to_s
|
213
|
+
|
214
|
+
# Keep prefixing "0" until filled to scale.
|
215
|
+
while ( x.length <= currency.scale_exp )
|
216
|
+
x = "0" + x
|
217
|
+
end
|
218
|
+
|
219
|
+
# Insert decimal place.
|
220
|
+
whole = x[0 .. currency.format_left]
|
221
|
+
fraction = x[currency.format_right .. -1]
|
222
|
+
|
223
|
+
# Do thousands.
|
224
|
+
x = whole
|
225
|
+
if @thousands && (@thousands_separator && ! @thousands_separator.empty?)
|
226
|
+
x.reverse!
|
227
|
+
x.gsub!(/(\d\d\d)/) {|y| y + @thousands_separator}
|
228
|
+
x.sub!(/#{@thousands_separator}$/,'')
|
229
|
+
x.reverse!
|
230
|
+
end
|
231
|
+
|
232
|
+
# Put whole and fractional parts.
|
233
|
+
tmpl.whole = x
|
234
|
+
tmpl.fraction = @cents && @decimal_separator ? @decimal_separator + fraction : nil
|
235
|
+
|
236
|
+
|
237
|
+
# Add symbol?
|
238
|
+
tmpl.symbol = @symbol ? ((@html && currency.symbol_html) || currency.symbol) : nil
|
239
|
+
|
240
|
+
|
241
|
+
# Add currency code.
|
242
|
+
tmpl.code = @code ? _format_Currency(currency) : nil
|
243
|
+
|
244
|
+
# Add time.
|
245
|
+
tmpl.time = @time && time ? _format_Time(time) : nil
|
246
|
+
|
247
|
+
# Ask template to format the components.
|
248
|
+
tmpl.format
|
249
|
+
end
|
250
|
+
|
251
|
+
|
252
|
+
def _format_Currency(c) # :nodoc:
|
253
|
+
x = ''
|
254
|
+
x << '<span class="currency_code">' if @html
|
255
|
+
x << c.code.to_s
|
256
|
+
x << '</span>' if @html
|
257
|
+
x
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
def _format_Time(t) # :nodoc:
|
262
|
+
x = ''
|
263
|
+
x << t.getutc.xmlschema(@time_fractional_digits) if t
|
264
|
+
x
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
@@empty_hash = { }
|
269
|
+
@@empty_hash.freeze
|
270
|
+
|
271
|
+
# Format a Money object as a String.
|
272
|
+
#
|
273
|
+
# m = Money.new("1234567.89")
|
274
|
+
# m.to_s(:code => true, :symbol => false)
|
275
|
+
# => "1,234,567.89 USD"
|
276
|
+
#
|
277
|
+
def format(m, opt = @@empty_hash)
|
278
|
+
fmt = self
|
279
|
+
|
280
|
+
unless opt.empty?
|
281
|
+
fmt = fmt.clone
|
282
|
+
opt.each_pair{ | k, v | fmt.send("#{k}=", v) }
|
283
|
+
end
|
284
|
+
|
285
|
+
# $stderr.puts "format(opt = #{opt.inspect})"
|
286
|
+
fmt._format(m, opt[:currency]) # Allow override of current currency.
|
287
|
+
end
|
288
|
+
|
289
|
+
end # class
|
290
|
+
|
@@ -0,0 +1,321 @@
|
|
1
|
+
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
|
+
# See LICENSE.txt for details.
|
3
|
+
|
4
|
+
class Currency::Money
|
5
|
+
@@money_attributes = { }
|
6
|
+
|
7
|
+
# Called by money macro when a money attribute
|
8
|
+
# is created.
|
9
|
+
def self.register_money_attribute(attr_opts)
|
10
|
+
(@@money_attributes[attr_opts[:class]] ||= { })[attr_opts[:attr_name]] = attr_opts
|
11
|
+
end
|
12
|
+
|
13
|
+
# Returns an array of option hashes for all the money attributes of
|
14
|
+
# this class.
|
15
|
+
#
|
16
|
+
# Superclass attributes are not included.
|
17
|
+
def self.money_attributes_for_class(cls)
|
18
|
+
(@@money_atttributes[cls] || { }).values
|
19
|
+
end
|
20
|
+
|
21
|
+
# Iterates through all known money attributes in all classes.
|
22
|
+
#
|
23
|
+
# each_money_attribute { | money_opts |
|
24
|
+
# ...
|
25
|
+
# }
|
26
|
+
def self.each_money_attribute(&blk)
|
27
|
+
@@money_attributes.each do | cls, hash |
|
28
|
+
hash.each do | attr_name, attr_opts |
|
29
|
+
yield attr_opts
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end # class
|
35
|
+
|
36
|
+
|
37
|
+
module Currency::Macro
|
38
|
+
def self.append_features(base) # :nodoc:
|
39
|
+
# $stderr.puts " Currency::ActiveRecord#append_features(#{base})"
|
40
|
+
super
|
41
|
+
base.extend(ClassMethods)
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
# == Macro Suppport
|
47
|
+
#
|
48
|
+
# Support for Money attributes.
|
49
|
+
#
|
50
|
+
# require 'currency'
|
51
|
+
# require 'currency/macro'
|
52
|
+
#
|
53
|
+
# class SomeClass
|
54
|
+
# include ::Currency::Macro
|
55
|
+
# attr_accessor :amount
|
56
|
+
# attr_money :amount_money, :value => :amount, :currency_fixed => :USD, :rep => :float
|
57
|
+
# end
|
58
|
+
#
|
59
|
+
# x = SomeClass.new
|
60
|
+
# x.amount = 123.45
|
61
|
+
# x.amount
|
62
|
+
# # => 123.45
|
63
|
+
# x.amount_money
|
64
|
+
# # => $123.45 USD
|
65
|
+
# x.amount_money = x.amount_money + "12.45"
|
66
|
+
# # => $135.90 USD
|
67
|
+
# x.amount
|
68
|
+
# # => 135.9
|
69
|
+
# x.amount = 45.951
|
70
|
+
# x.amount_money
|
71
|
+
# # => $45.95 USD
|
72
|
+
# x.amount
|
73
|
+
# # => 45.951
|
74
|
+
#
|
75
|
+
module ClassMethods
|
76
|
+
|
77
|
+
# Defines a Money object attribute that is bound
|
78
|
+
# to other attributes.
|
79
|
+
#
|
80
|
+
# Options:
|
81
|
+
#
|
82
|
+
# :value => undef
|
83
|
+
#
|
84
|
+
# Defines the value attribute to use for storing the money value.
|
85
|
+
# Defaults to the attribute name.
|
86
|
+
#
|
87
|
+
# If this attribute is different from the attribute name,
|
88
|
+
# the money object will intercept #{value}=(x) to flush
|
89
|
+
# any cached Money object.
|
90
|
+
#
|
91
|
+
# :readonly => false
|
92
|
+
#
|
93
|
+
# If true, the underlying attribute is readonly. Thus the Money object
|
94
|
+
# cannot be cached. This is useful for computed money values.
|
95
|
+
#
|
96
|
+
# :rep => :float
|
97
|
+
#
|
98
|
+
# This option specifies how the value attribute stores Money values.
|
99
|
+
# if :rep is :rep, then the value is stored as a scaled integer as
|
100
|
+
# defined by the Currency.
|
101
|
+
# If :rep is :float, or :integer the corresponding #to_f or #to_i
|
102
|
+
# method is used.
|
103
|
+
# Defaults to :float.
|
104
|
+
#
|
105
|
+
# :currency => undef
|
106
|
+
#
|
107
|
+
# Defines the attribute used to store and
|
108
|
+
# retrieve the Money's Currency 3-letter ISO code.
|
109
|
+
#
|
110
|
+
# :currency_fixed => currency_code (e.g.: :USD)
|
111
|
+
#
|
112
|
+
# Defines the Currency to use for storing a normalized Money
|
113
|
+
# value.
|
114
|
+
#
|
115
|
+
# All Money values will be converted to this Currency before
|
116
|
+
# storing. This allows SQL summary operations,
|
117
|
+
# like SUM(), MAX(), AVG(), etc., to produce meaningful results,
|
118
|
+
# regardless of the initial currency specified. If this
|
119
|
+
# option is used, subsequent reads will be in the specified
|
120
|
+
# normalization :currency_fixed.
|
121
|
+
#
|
122
|
+
# :currency_preferred => undef
|
123
|
+
#
|
124
|
+
# Defines the name of attribute used to store and
|
125
|
+
# retrieve the Money's Currency ISO code. This option can be used
|
126
|
+
# with normalized Money values to retrieve the Money value
|
127
|
+
# in its original Currency, while
|
128
|
+
# allowing SQL summary operations on the normalized Money values
|
129
|
+
# to still be valid.
|
130
|
+
#
|
131
|
+
# :currency_update => undef
|
132
|
+
#
|
133
|
+
# If true, the currency attribute is updated upon setting the
|
134
|
+
# money attribute.
|
135
|
+
#
|
136
|
+
# :time => undef
|
137
|
+
#
|
138
|
+
# Defines the attribute used to
|
139
|
+
# retrieve the Money's time. If this option is used, each
|
140
|
+
# Money value will use this attribute during historical Currency
|
141
|
+
# conversions.
|
142
|
+
#
|
143
|
+
# Money values can share a time value with other attributes
|
144
|
+
# (e.g. a created_on column in ActiveRecord::Base).
|
145
|
+
#
|
146
|
+
# If this option is true, the money time attribute will be named
|
147
|
+
# "#{attr_name}_time" and :time_update will be true.
|
148
|
+
#
|
149
|
+
# :time_update => undef
|
150
|
+
#
|
151
|
+
# If true, the Money time value is updated upon setting the
|
152
|
+
# money attribute.
|
153
|
+
#
|
154
|
+
def attr_money(attr_name, *opts)
|
155
|
+
opts = Hash[*opts]
|
156
|
+
|
157
|
+
attr_name = attr_name.to_s
|
158
|
+
opts[:class] = self
|
159
|
+
opts[:name] = attr_name.intern
|
160
|
+
::Currency::Money.register_money_attribute(opts)
|
161
|
+
|
162
|
+
value = opts[:value] || opts[:name]
|
163
|
+
opts[:value] = value
|
164
|
+
write_value = opts[:write_value] ||= "self.#{value} = "
|
165
|
+
|
166
|
+
# Intercept value setter?
|
167
|
+
if ! opts[:readonly] && value.to_s != attr_name.to_s
|
168
|
+
alias_accessor = <<-"end_eval"
|
169
|
+
alias :before_money_#{value}= :#{value}=
|
170
|
+
|
171
|
+
def #{value}=(__value)
|
172
|
+
@#{attr_name} = nil # uncache
|
173
|
+
self.before_money_#{value} = __value
|
174
|
+
end
|
175
|
+
|
176
|
+
end_eval
|
177
|
+
end
|
178
|
+
|
179
|
+
# How to convert between numeric representation and Money.
|
180
|
+
rep = opts[:rep] ||= :float
|
181
|
+
to_rep = opts[:to_rep]
|
182
|
+
from_rep = opts[:from_rep]
|
183
|
+
if rep == :rep
|
184
|
+
to_rep = 'rep'
|
185
|
+
from_rep = '::Currency::Money.new_rep'
|
186
|
+
else
|
187
|
+
case rep
|
188
|
+
when :float
|
189
|
+
to_rep = 'to_f'
|
190
|
+
when :integer
|
191
|
+
to_rep = 'to_i'
|
192
|
+
else
|
193
|
+
raise ::Currency::Exception::InvalidMoneyValue, "Cannot use value representation: #{rep.inspect}"
|
194
|
+
end
|
195
|
+
from_rep = '::Currency::Money.new'
|
196
|
+
end
|
197
|
+
to_rep = to_rep.to_s
|
198
|
+
from_rep = from_rep.to_s
|
199
|
+
|
200
|
+
# Money time values.
|
201
|
+
time = opts[:time]
|
202
|
+
write_time = ''
|
203
|
+
if time
|
204
|
+
if time == true
|
205
|
+
time = "#{attr_name}_time"
|
206
|
+
opts[:time_update] = true
|
207
|
+
end
|
208
|
+
read_time = "self.#{time}"
|
209
|
+
end
|
210
|
+
opts[:time] = time
|
211
|
+
if opts[:time_update]
|
212
|
+
write_time = "self.#{time} = #{attr_name}_money && #{attr_name}_money.time"
|
213
|
+
end
|
214
|
+
time ||= 'nil'
|
215
|
+
read_time ||= time
|
216
|
+
|
217
|
+
currency_fixed = opts[:currency_fixed]
|
218
|
+
currency_fixed &&= ":#{currency_fixed}"
|
219
|
+
|
220
|
+
currency = opts[:currency]
|
221
|
+
if currency == true
|
222
|
+
currency = currency.to_s
|
223
|
+
currency = "self.#{attr_name}_currency"
|
224
|
+
end
|
225
|
+
if currency
|
226
|
+
read_currency = "self.#{currency}"
|
227
|
+
if opts[:currency_update]
|
228
|
+
write_currency = "self.#{currency} = #{attr_name}_money.nil? ? nil : #{attr_name}_money.currency.code"
|
229
|
+
else
|
230
|
+
convert_currency = "#{attr_name}_money = #{attr_name}_money.convert(#{read_currency}, #{read_time})"
|
231
|
+
end
|
232
|
+
end
|
233
|
+
opts[:currency] = currency
|
234
|
+
write_currency ||= ''
|
235
|
+
convert_currency ||= ''
|
236
|
+
|
237
|
+
currency_preferred = opts[:currency_preferred]
|
238
|
+
if currency_preferred
|
239
|
+
currency_preferred = currency_preferred.to_s
|
240
|
+
read_preferred_currency = "@#{attr_name} = @#{attr_name}.convert(#{currency_preferred}, #{read_time})"
|
241
|
+
write_preferred_currency = "self.#{currency_preferred} = @#{attr_name}_money.currency.code"
|
242
|
+
end
|
243
|
+
|
244
|
+
currency ||= currency_fixed
|
245
|
+
read_currency ||= currency
|
246
|
+
|
247
|
+
alias_accessor ||= ''
|
248
|
+
|
249
|
+
validate ||= ''
|
250
|
+
|
251
|
+
if opts[:readonly]
|
252
|
+
eval_opts = [ (opts[:module_eval] = x = <<-"end_eval"), __FILE__, __LINE__ ]
|
253
|
+
#{validate}
|
254
|
+
|
255
|
+
def #{attr_name}
|
256
|
+
#{attr_name}_rep = #{value}
|
257
|
+
if #{attr_name}_rep != nil
|
258
|
+
#{attr_name} = #{from_rep}(#{attr_name}_rep, #{read_currency} || #{currency}, #{read_time} || #{time})
|
259
|
+
#{read_preferred_currency}
|
260
|
+
else
|
261
|
+
#{attr_name} = nil
|
262
|
+
end
|
263
|
+
#{attr_name}
|
264
|
+
end
|
265
|
+
|
266
|
+
end_eval
|
267
|
+
else
|
268
|
+
eval_opts = [ (opts[:module_eval] = x = <<-"end_eval"), __FILE__, __LINE__ ]
|
269
|
+
#{validate}
|
270
|
+
|
271
|
+
#{alias_accessor}
|
272
|
+
|
273
|
+
def #{attr_name}
|
274
|
+
unless @#{attr_name}
|
275
|
+
#{attr_name}_rep = #{value}
|
276
|
+
if #{attr_name}_rep != nil
|
277
|
+
@#{attr_name} = #{from_rep}(#{attr_name}_rep, #{read_currency} || #{currency}, #{read_time} || #{time})
|
278
|
+
#{read_preferred_currency}
|
279
|
+
end
|
280
|
+
end
|
281
|
+
@#{attr_name}
|
282
|
+
end
|
283
|
+
|
284
|
+
|
285
|
+
def #{attr_name}=(value)
|
286
|
+
if value == nil
|
287
|
+
#{attr_name}_money = nil
|
288
|
+
elsif value.kind_of?(Integer) || value.kind_of?(Float) || value.kind_of?(String)
|
289
|
+
#{attr_name}_money = ::Currency.Money(value, #{read_currency}, #{read_time})
|
290
|
+
#{write_preferred_currency}
|
291
|
+
elsif value.kind_of?(::Currency::Money)
|
292
|
+
#{attr_name}_money = value
|
293
|
+
#{write_preferred_currency}
|
294
|
+
#{convert_currency}
|
295
|
+
else
|
296
|
+
raise ::Currency::Exception::InvalidMoneyValue, value
|
297
|
+
end
|
298
|
+
|
299
|
+
@#{attr_name} = #{attr_name}_money
|
300
|
+
#{write_value}(#{attr_name}_money.nil? ? nil : #{attr_name}_money.#{to_rep})
|
301
|
+
#{write_currency}
|
302
|
+
#{write_time}
|
303
|
+
|
304
|
+
value
|
305
|
+
end
|
306
|
+
|
307
|
+
end_eval
|
308
|
+
end
|
309
|
+
|
310
|
+
# $stderr.puts " CODE = #{x}"
|
311
|
+
module_eval(*eval_opts)
|
312
|
+
end
|
313
|
+
end # module
|
314
|
+
end # module
|
315
|
+
|
316
|
+
|
317
|
+
# Use include ::Currency::Macro
|
318
|
+
#::Object.class_eval do
|
319
|
+
# include Currency::Macro
|
320
|
+
#end
|
321
|
+
|