acvwilson-currency 0.6.4 → 0.7
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/currency.gemspec +1 -1
- data/lib/currency/active_record.rb +68 -62
- data/lib/currency.rb +1 -1
- data/spec/ar_simple_spec.rb +70 -13
- data/spec/ar_spec_helper.rb +38 -1
- metadata +2 -2
- data/spec/ar_column_spec.rb +0 -56
data/currency.gemspec
CHANGED
@@ -145,27 +145,29 @@ module Currency::ActiveRecord
|
|
145
145
|
column = opts[:column] || opts[:attr_name]
|
146
146
|
opts[:column] = column
|
147
147
|
|
148
|
+
# TODO: rewrite with define_method (dvd, 15-03-2009)
|
148
149
|
if column.to_s != attr_name.to_s
|
149
150
|
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
|
151
|
+
alias :before_money_#{column}=, :#{column}=
|
156
152
|
|
153
|
+
def #{column}=(__value)
|
154
|
+
@{attr_name} = nil # uncache
|
155
|
+
before_money#{column} = __value
|
156
|
+
end
|
157
157
|
end_eval
|
158
|
-
end
|
159
158
|
|
159
|
+
end
|
160
|
+
alias_accessor ||= ''
|
161
|
+
|
160
162
|
currency = opts[:currency]
|
161
163
|
|
162
164
|
currency_column = opts[:currency_column]
|
163
165
|
if currency_column && ! currency_column.kind_of?(String)
|
164
|
-
currency_column = currency_column.to_s
|
165
166
|
currency_column = "#{column}_currency"
|
166
167
|
end
|
168
|
+
|
167
169
|
if currency_column
|
168
|
-
read_currency = "read_attribute(:#{currency_column
|
170
|
+
read_currency = "read_attribute(:#{currency_column})"
|
169
171
|
write_currency = "write_attribute(:#{currency_column}, #{attr_name}_money.nil? ? nil : #{attr_name}_money.currency.code.to_s)"
|
170
172
|
end
|
171
173
|
opts[:currency_column] = currency_column
|
@@ -187,6 +189,7 @@ end_eval
|
|
187
189
|
read_time = "self.#{time}"
|
188
190
|
end
|
189
191
|
opts[:time] = time
|
192
|
+
|
190
193
|
if opts[:time_update]
|
191
194
|
write_time = "self.#{time} = #{attr_name}_money && #{attr_name}_money.time"
|
192
195
|
end
|
@@ -201,63 +204,66 @@ end_eval
|
|
201
204
|
|
202
205
|
validate_allow_nil = opts[:allow_nil] ? ', :allow_nil => true' : ''
|
203
206
|
validate = "# Validation\n"
|
204
|
-
validate << "\nvalidates_numericality_of :#{attr_name}#{validate_allow_nil}\n"
|
207
|
+
validate << "\nvalidates_numericality_of :#{attr_name} #{validate_allow_nil}\n"
|
205
208
|
validate << "\nvalidates_format_of :#{currency_column}, :with => /^[A-Z][A-Z][A-Z]$/#{validate_allow_nil}\n" if currency_column
|
206
|
-
|
207
|
-
#
|
208
|
-
#
|
209
|
-
#
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
#{
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
end
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
209
|
+
|
210
|
+
# =================================================================================================
|
211
|
+
# = Define the currency_column setter, so that the Money object changes when the currency changes =
|
212
|
+
# =================================================================================================
|
213
|
+
if currency_column
|
214
|
+
currency_column_setter = %Q{
|
215
|
+
def #{currency_column}=(currency_code)
|
216
|
+
@#{attr_name} = nil
|
217
|
+
write_attribute(:#{currency_column}, currency_code)
|
218
|
+
end
|
219
|
+
}
|
220
|
+
class_eval currency_column_setter, __FILE__, __LINE__
|
221
|
+
end
|
222
|
+
|
223
|
+
class_eval (opts[:module_eval] = x = <<-"end_eval"), __FILE__, __LINE__
|
224
|
+
#{validate}
|
225
|
+
|
226
|
+
#{alias_accessor}
|
227
|
+
|
228
|
+
# Getter
|
229
|
+
def #{attr_name}
|
230
|
+
unless @#{attr_name}
|
231
|
+
rep = read_attribute(:#{column})
|
232
|
+
unless rep.nil?
|
233
|
+
@#{attr_name} = ::Currency::Money.new_rep(rep, #{read_currency} || #{currency}, #{read_time} || #{time})
|
234
|
+
#{read_preferred_currency}
|
235
|
+
end
|
236
|
+
end
|
237
|
+
@#{attr_name}
|
238
|
+
end
|
239
|
+
|
240
|
+
# Setter
|
241
|
+
def #{attr_name}=(value)
|
242
|
+
if value.nil? || value.to_s.strip == ''
|
243
|
+
#{attr_name}_money = nil
|
244
|
+
elsif value.kind_of?(Integer) || value.kind_of?(String) || value.kind_of?(Float)
|
245
|
+
#{attr_name}_money = ::Currency::Money(value, #{read_currency})
|
246
|
+
#{write_preferred_currency}
|
247
|
+
elsif value.kind_of?(::Currency::Money)
|
248
|
+
#{attr_name}_money = value
|
249
|
+
#{write_preferred_currency}
|
250
|
+
#{write_currency ? write_currency : "#{attr_name}_money = #{attr_name}_money.convert(#{currency})"}
|
251
|
+
else
|
252
|
+
raise ::Currency::Exception::InvalidMoneyValue, value
|
253
|
+
end
|
254
|
+
|
255
|
+
@#{attr_name} = #{attr_name}_money # TODO: Really needed? Isn't the write_attribute enough? (answer: no, because the getter method does an "if @#{attr_name}" to check if it's set)
|
250
256
|
|
251
|
-
|
252
|
-
|
257
|
+
write_attribute(:#{column}, #{attr_name}_money.nil? ? nil : #{attr_name}_money.rep)
|
258
|
+
#{write_time}
|
253
259
|
|
254
|
-
|
255
|
-
end
|
256
|
-
|
257
|
-
def #{attr_name}_before_type_cast
|
258
|
-
#{attr_name}.to_f if #{attr_name}
|
259
|
-
end
|
260
|
+
value
|
261
|
+
end
|
260
262
|
|
263
|
+
def #{attr_name}_before_type_cast
|
264
|
+
#{attr_name}.to_f if #{attr_name}
|
265
|
+
end
|
266
|
+
|
261
267
|
end_eval
|
262
268
|
=begin
|
263
269
|
Replaced the _before_type_cast because it's buggy and weird:
|
data/lib/currency.rb
CHANGED
@@ -130,7 +130,7 @@ require 'currency/exception'
|
|
130
130
|
require 'currency/money'
|
131
131
|
require 'currency/currency'
|
132
132
|
require 'currency/currency/factory'
|
133
|
-
require 'currency/money'
|
133
|
+
require 'currency/money' # TODO: Why require this twice? (dvd, 15-03-2009)
|
134
134
|
require 'currency/parser'
|
135
135
|
require 'currency/formatter' # require this one before the parser and enjoy the weird bugs!
|
136
136
|
require 'currency/exchange'
|
data/spec/ar_simple_spec.rb
CHANGED
@@ -1,23 +1,80 @@
|
|
1
1
|
# Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
|
2
2
|
# Copyright (C) 2008 Asa Wilson <acvwilson(at)gmail.com>
|
3
|
+
# Copyright (C) 2009 David Palm <dvdplm(at)gmail.com>
|
3
4
|
# See LICENSE.txt for details.
|
4
5
|
|
5
6
|
require File.dirname(__FILE__) + '/ar_spec_helper'
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
insert_records
|
8
|
+
class Dog < ActiveRecord::Base
|
9
|
+
attr_money :price, :currency_column => true, :allow_nil => true
|
10
|
+
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
describe "extending ActiveRecord" do
|
13
|
+
describe "attr_money" do
|
14
|
+
before do
|
15
|
+
Dog.connection.execute("INSERT INTO dogs VALUES(null, 'fido', 1500, 'USD')") # NOTE: by-passing AR here to achieve clean slate (dvd, 15-03-2009)
|
16
|
+
@dog = Dog.first
|
17
|
+
end
|
15
18
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
describe "retrieving money values" do
|
20
|
+
it "sets up the Money object at first read" do
|
21
|
+
pending
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns the ivar on subsequent reads" do
|
25
|
+
pending
|
26
|
+
end
|
27
|
+
|
28
|
+
it "does not setup a Money object if the db column does not contain an integer to use for money rep" do
|
29
|
+
pending
|
30
|
+
end
|
31
|
+
|
32
|
+
it "casts the currency to the preferred one, if a preferred currency was set" do
|
33
|
+
pending
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "currency column" do
|
38
|
+
before do
|
39
|
+
Dog.connection.execute("INSERT INTO dogs VALUES(null, 'fido', 1500, 'USD')") # NOTE: by-passing AR here to achieve clean slate (dvd, 15-03-2009)
|
40
|
+
@dog = Dog.first
|
41
|
+
end
|
19
42
|
|
20
|
-
|
21
|
-
|
22
|
-
|
43
|
+
it "changes the currency when the value on the currency column changes" do
|
44
|
+
@dog.price.currency.code.should == :USD
|
45
|
+
@dog.update_attributes(:price_currency => 'EUR')
|
46
|
+
@dog.price.currency.code.should == :EUR
|
47
|
+
end
|
48
|
+
|
49
|
+
it "does NOT convert to the new currency when the currency column changes" do
|
50
|
+
@dog.price.rep.should == 1500
|
51
|
+
@dog.update_attributes(:price_currency => :EUR)
|
52
|
+
@dog.price.rep.should == 1500
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "saving" do
|
57
|
+
it "saves the price with the default currency when set to 10.money" do
|
58
|
+
@dog.price = 10.money
|
59
|
+
@dog.price.should == Currency::Money("10")
|
60
|
+
end
|
61
|
+
|
62
|
+
it "saves the price with the currency of the Money object" do
|
63
|
+
@dog.price = 10.money(:EUR)
|
64
|
+
@dog.price.should == Currency::Money("10", "EUR")
|
65
|
+
end
|
66
|
+
|
67
|
+
it "can change just the currency" do
|
68
|
+
@dog.price_currency = 'CAD'
|
69
|
+
@dog.save
|
70
|
+
@dog.price.should == Currency::Money("15", "CAD")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "can save changes using update_attributes" do
|
74
|
+
@dog.update_attributes(:price => 5, :price_currency => 'CAD')
|
75
|
+
@dog.price.should == 5.money('CAD')
|
76
|
+
end
|
77
|
+
end
|
23
78
|
|
79
|
+
end
|
80
|
+
end
|
data/spec/ar_spec_helper.rb
CHANGED
@@ -8,6 +8,42 @@ require 'active_record'
|
|
8
8
|
require 'active_record/migration'
|
9
9
|
require File.dirname(__FILE__) + '/../lib/currency/active_record'
|
10
10
|
|
11
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/db/database.yml'))
|
12
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
13
|
+
# ActiveRecord::Base.establish_connection(config['mysql_debug'])
|
14
|
+
ActiveRecord::Base.establish_connection(config['sqlite3mem'])
|
15
|
+
|
16
|
+
ActiveRecord::Migration.verbose = false
|
17
|
+
load(File.dirname(__FILE__) + "/db/schema.rb")
|
18
|
+
|
19
|
+
# ============================================
|
20
|
+
# = Load some currency symbols (171 records) =
|
21
|
+
# ============================================
|
22
|
+
currency_codes = IO.read(File.dirname(__FILE__) + '/db/currency_codes.sql')
|
23
|
+
currency_codes.each_line do |sql_insert|
|
24
|
+
ActiveRecord::Base.connection.execute(sql_insert)
|
25
|
+
end
|
26
|
+
|
27
|
+
# ================================
|
28
|
+
# = Load some rates (84 records) =
|
29
|
+
# ================================
|
30
|
+
rates = IO.read(File.dirname(__FILE__) + '/db/currency_historical_rates.sql')
|
31
|
+
rates.each_line do |sql_insert|
|
32
|
+
ActiveRecord::Base.connection.execute(sql_insert)
|
33
|
+
end
|
34
|
+
|
35
|
+
AR_M = ActiveRecord::Migration
|
36
|
+
AR_B = ActiveRecord::Base
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
=begin
|
41
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
42
|
+
|
43
|
+
require 'active_record'
|
44
|
+
require 'active_record/migration'
|
45
|
+
require File.dirname(__FILE__) + '/../lib/currency/active_record'
|
46
|
+
|
11
47
|
AR_M = ActiveRecord::Migration
|
12
48
|
AR_B = ActiveRecord::Base
|
13
49
|
|
@@ -124,4 +160,5 @@ def assert_equal_currency(a,b)
|
|
124
160
|
b.amount.currency.should == a.amount.currency
|
125
161
|
b.amount.currency.code.should == a.amount.currency.code
|
126
162
|
|
127
|
-
end
|
163
|
+
end
|
164
|
+
=end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acvwilson-currency
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: "0.7"
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Asa Wilson
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2009-
|
13
|
+
date: 2009-03-15 11:25:57.897576 -07:00
|
14
14
|
default_executable:
|
15
15
|
dependencies: []
|
16
16
|
|
data/spec/ar_column_spec.rb
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/ar_spec_helper'
|
2
|
-
|
3
|
-
##################################################
|
4
|
-
# Basic CurrenyTest AR::B class
|
5
|
-
#
|
6
|
-
|
7
|
-
# TODO: Move elsewhere, combine with other AR tests
|
8
|
-
|
9
|
-
TABLE_NAME = 'currency_column_test'
|
10
|
-
|
11
|
-
class CurrencyColumnTestMigration < AR_M
|
12
|
-
def self.up
|
13
|
-
create_table TABLE_NAME.intern do |t|
|
14
|
-
t.column :name, :string
|
15
|
-
t.column :amount, :integer # Money
|
16
|
-
t.column :amount_currency, :string, :size => 3 # Money.currency.code
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.down
|
21
|
-
drop_table TABLE_NAME.intern
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class CurrencyColumnTest < AR_B
|
26
|
-
set_table_name TABLE_NAME
|
27
|
-
attr_money :amount, :currency_column => true
|
28
|
-
end
|
29
|
-
|
30
|
-
##################################################
|
31
|
-
|
32
|
-
describe "ActiveRecord macros" do
|
33
|
-
before(:all) do
|
34
|
-
AR_B.establish_connection(database_spec)
|
35
|
-
@currency_test_migration ||= CurrencyColumnTestMigration
|
36
|
-
@currency_test ||= CurrencyColumnTest
|
37
|
-
schema_down
|
38
|
-
schema_up
|
39
|
-
end
|
40
|
-
|
41
|
-
after(:all) do
|
42
|
-
schema_down
|
43
|
-
end
|
44
|
-
|
45
|
-
it "can store and retrieve money values from a DB and automagically transfomr them to Money" do
|
46
|
-
insert_records
|
47
|
-
|
48
|
-
usd = @currency_test.find(@usd.id)
|
49
|
-
usd.should == @usd
|
50
|
-
usd.object_id.should_not == @usd.object_id # not same object
|
51
|
-
|
52
|
-
cad = @currency_test.find(@cad.id)
|
53
|
-
cad.should == @cad
|
54
|
-
cad.object_id.should_not == @cad.object_id # not same object
|
55
|
-
end
|
56
|
-
end
|