cleanconscience-currency 0.7.0.11

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.
Files changed (55) hide show
  1. data/COPYING.txt +339 -0
  2. data/ChangeLog +8 -0
  3. data/LICENSE.txt +65 -0
  4. data/Manifest.txt +57 -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 +304 -0
  13. data/lib/currency/config.rb +93 -0
  14. data/lib/currency/core_extensions.rb +33 -0
  15. data/lib/currency/currency.rb +172 -0
  16. data/lib/currency/currency/factory.rb +131 -0
  17. data/lib/currency/exception.rb +119 -0
  18. data/lib/currency/exchange.rb +48 -0
  19. data/lib/currency/exchange/rate.rb +214 -0
  20. data/lib/currency/exchange/rate/deriver.rb +157 -0
  21. data/lib/currency/exchange/rate/source.rb +89 -0
  22. data/lib/currency/exchange/rate/source/base.rb +166 -0
  23. data/lib/currency/exchange/rate/source/failover.rb +63 -0
  24. data/lib/currency/exchange/rate/source/federal_reserve.rb +151 -0
  25. data/lib/currency/exchange/rate/source/historical.rb +79 -0
  26. data/lib/currency/exchange/rate/source/historical/rate.rb +185 -0
  27. data/lib/currency/exchange/rate/source/historical/rate_loader.rb +186 -0
  28. data/lib/currency/exchange/rate/source/historical/writer.rb +220 -0
  29. data/lib/currency/exchange/rate/source/new_york_fed.rb +127 -0
  30. data/lib/currency/exchange/rate/source/provider.rb +117 -0
  31. data/lib/currency/exchange/rate/source/test.rb +50 -0
  32. data/lib/currency/exchange/rate/source/the_financials.rb +191 -0
  33. data/lib/currency/exchange/rate/source/timed_cache.rb +198 -0
  34. data/lib/currency/exchange/rate/source/xe.rb +152 -0
  35. data/lib/currency/exchange/time_quantitizer.rb +111 -0
  36. data/lib/currency/formatter.rb +308 -0
  37. data/lib/currency/macro.rb +321 -0
  38. data/lib/currency/money.rb +293 -0
  39. data/lib/currency/money_helper.rb +13 -0
  40. data/lib/currency/parser.rb +196 -0
  41. data/spec/ar_simple_spec.rb +80 -0
  42. data/spec/ar_spec_helper.rb +164 -0
  43. data/spec/config_spec.rb +70 -0
  44. data/spec/federal_reserve_spec.rb +71 -0
  45. data/spec/formatter_spec.rb +72 -0
  46. data/spec/historical_writer_spec.rb +121 -0
  47. data/spec/macro_spec.rb +109 -0
  48. data/spec/money_spec.rb +367 -0
  49. data/spec/new_york_fed_spec.rb +73 -0
  50. data/spec/parser_spec.rb +105 -0
  51. data/spec/spec_helper.rb +25 -0
  52. data/spec/time_quantitizer_spec.rb +115 -0
  53. data/spec/timed_cache_spec.rb +95 -0
  54. data/spec/xe_spec.rb +50 -0
  55. metadata +116 -0
@@ -0,0 +1,80 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # Copyright (C) 2008 Asa Wilson <acvwilson(at)gmail.com>
3
+ # Copyright (C) 2009 David Palm <dvdplm(at)gmail.com>
4
+ # See LICENSE.txt for details.
5
+
6
+ require File.dirname(__FILE__) + '/ar_spec_helper'
7
+
8
+ class Dog < ActiveRecord::Base
9
+ attr_money :price, :currency_column => true, :allow_nil => true
10
+ end
11
+
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
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
42
+
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
78
+
79
+ end
80
+ end
@@ -0,0 +1,164 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # Copyright (C) 2008 Asa Wilson <acvwilson(at)gmail.com>
3
+ # See LICENSE.txt for details.
4
+
5
+ require File.dirname(__FILE__) + '/spec_helper'
6
+
7
+ require 'active_record'
8
+ require 'active_record/migration'
9
+ require File.dirname(__FILE__) + '/../lib/currency/active_record'
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
+
47
+ AR_M = ActiveRecord::Migration
48
+ AR_B = ActiveRecord::Base
49
+
50
+ def ar_setup
51
+ AR_B.establish_connection(database_spec)
52
+
53
+ # Subclasses can override this.
54
+ @currency_test_migration ||= nil
55
+ @currency_test ||= nil
56
+
57
+ # schema_down
58
+
59
+ schema_up
60
+
61
+ end
62
+
63
+ # DB Connection info
64
+ def database_spec
65
+ # TODO: Get from ../config/database.yml:test
66
+ # Create test database on:
67
+
68
+ # MYSQL:
69
+ #
70
+ # sudo mysqladmin create test;
71
+ # sudo mysql
72
+ # grant all on test.* to test@localhost identified by 'test';
73
+ # flush privileges;
74
+
75
+ # POSTGRES:
76
+ #
77
+ # CREATE USER test PASSWORD 'test';
78
+ # CREATE DATABASE test WITH OWNER = test;
79
+ #
80
+
81
+ # @database_spec = {
82
+ # :adapter => ENV['TEST_DB_ADAPTER'] || 'mysql',
83
+ # :host => ENV['TEST_DB_HOST'] || 'localhost',
84
+ # :username => ENV['TEST_DB_USER'] || 'test',
85
+ # :password => ENV['TEST_DB_PASS'] || 'test',
86
+ # :database => ENV['TEST_DB_TEST'] || 'test'
87
+ # }
88
+
89
+ @database_spec = {
90
+ :adapter => ENV['TEST_DB_ADAPTER'] || 'mysql',
91
+ :host => ENV['TEST_DB_HOST'] || 'localhost',
92
+ :username => ENV['TEST_DB_USER'] || 'root',
93
+ :password => ENV['TEST_DB_PASS'] || '',
94
+ :database => ENV['TEST_DB_TEST'] || 'currency_gem_test'
95
+ }
96
+
97
+ end
98
+
99
+ # Run AR migrations UP
100
+ def schema_up
101
+ return unless @currency_test_migration
102
+ begin
103
+ @currency_test_migration.migrate(:up)
104
+ rescue Object =>e
105
+ $stderr.puts "Warning: #{e}"
106
+ end
107
+ end
108
+
109
+
110
+ # Run AR migrations DOWN
111
+ def schema_down
112
+ return unless @currency_test_migration
113
+ begin
114
+ @currency_test_migration.migrate(:down)
115
+ rescue Object => e
116
+ $stderr.puts "Warning: #{e}"
117
+ end
118
+ end
119
+
120
+ # Scaffold: insert stuff into DB so we can test AR integration
121
+ def insert_records
122
+ delete_records
123
+
124
+ @currency_test.reset_column_information
125
+
126
+ @usd = @currency_test.new(:name => '#1: USD', :amount => Currency::Money.new("12.34", :USD))
127
+ @usd.save
128
+
129
+ @cad = @currency_test.new(:name => '#2: CAD', :amount => Currency::Money.new("56.78", :CAD))
130
+ @cad.save
131
+ end
132
+
133
+ def delete_records
134
+ @currency_test.destroy_all
135
+ end
136
+
137
+ ##################################################
138
+
139
+ # TODO: need this?
140
+ def assert_equal_money(a,b)
141
+ a.should_not be_nil
142
+ b.should_not be_nil
143
+ # Make sure a and b are not the same object.
144
+ b.object_id.should_not == a.object_id
145
+ b.id.should == a.id
146
+ a.amount.should_not == nil
147
+ a.amount.should be_kind_of(Currency::Money)
148
+ b.amount.should_not == nil
149
+ b.amount.should be_kind_of(Currency::Money)
150
+ # Make sure that what gets stored in the database comes back out
151
+ # when converted back to the original currency.
152
+ b.amount.rep.should == a.amount.convert(b.amount.currency).rep
153
+ end
154
+
155
+ # TODO: need this?
156
+ def assert_equal_currency(a,b)
157
+ assert_equal_money a, b
158
+
159
+ b.amount.rep.should == a.amount.rep
160
+ b.amount.currency.should == a.amount.currency
161
+ b.amount.currency.code.should == a.amount.currency.code
162
+
163
+ end
164
+ =end
@@ -0,0 +1,70 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Currency::Config do
4
+
5
+ it "should truncate" do
6
+ Currency::Config.configure do | c |
7
+ c.float_ref_filter = Proc.new { | x | x }
8
+
9
+ m = Currency::Money.new(1.999999999)
10
+ m.should be_kind_of(Currency::Money)
11
+ m.rep.should == 1999999
12
+ end
13
+ end
14
+
15
+ it "should round" do
16
+ Currency::Config.configure do | c |
17
+ c.float_ref_filter = Proc.new { | x | x.round }
18
+
19
+ m = Currency::Money.new(1.99999999)
20
+ m.should be_kind_of(Currency::Money)
21
+ m.rep.should == 2000000
22
+ end
23
+
24
+ end
25
+
26
+ describe "the scale expression is configurable" do
27
+ before(:all) do
28
+ @config = Currency::Config.new
29
+ end
30
+
31
+ before(:each) do
32
+ Currency::Config.current = nil
33
+ Currency::Config.send(:class_variable_set, "@@default", nil)
34
+ end
35
+
36
+ it "should have a scale_exp setter" do
37
+ Currency::Config.current.should respond_to(:scale_exp=)
38
+ end
39
+
40
+ it "has a 'scale' reader" do
41
+ Currency::Config.current.should respond_to(:scale)
42
+ end
43
+
44
+ it "uses the scale reader from the config when creating new Money object" do
45
+ Currency::Config.should_receive(:current).and_return(@config)
46
+ @config.should_receive(:scale).and_return(100)
47
+ 10.money
48
+ end
49
+
50
+ it "can be configured using a block" do
51
+ Currency::Config.configure do |config|
52
+ config.scale_exp = 6
53
+ end
54
+
55
+ 10.money.currency.scale_exp.should == 6
56
+
57
+ Currency::Config.configure do |config|
58
+ config.scale_exp = 4
59
+ end
60
+ 10.money.currency.scale_exp.should == 4
61
+ end
62
+
63
+ it "can be configured using straight setters" do
64
+ 10.money(:USD).currency.scale_exp.should == 2
65
+ Currency::Config.current.scale_exp = 6
66
+ 10.money(:USD).currency.scale_exp.should == 6
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,71 @@
1
+ # Copyright (C) 2006-2007 Kurt Stephens <ruby-currency(at)umleta.com>
2
+ # See LICENSE.txt for details.
3
+
4
+ require File.dirname(__FILE__) + '/spec_helper'
5
+ require File.dirname(__FILE__) + '/../lib/currency/exchange/rate/source/federal_reserve'
6
+
7
+ # Uncomment to avoid hitting the FED for every testrun
8
+ Currency::Exchange::Rate::Source::FederalReserve.class_eval do
9
+ def get_page_content
10
+ %Q{
11
+
12
+ SPOT EXCHANGE RATE - DISNEYLAND
13
+
14
+ ------------------------------
15
+ 14-Nov-08 1.1
16
+ }
17
+ end
18
+ end
19
+
20
+ include Currency
21
+ describe "FederalReserve" do
22
+ def available?
23
+ unless @available
24
+ @available = @source.available?
25
+ STDERR.puts "Warning: FederalReserve unavailable on Saturday and Sunday, skipping tests." unless @available
26
+ end
27
+ @available
28
+ end
29
+
30
+ # Called by the before(:all) in spec_helper
31
+ # Overriding here to force FederalReserve Exchange.
32
+ # TODO: when refactoring the whole spec to test only specific FedralReserve Stuff, make sure this one goes away
33
+ def get_rate_source(source = nil)
34
+ @source ||= Exchange::Rate::Source::FederalReserve.new(:verbose => false)
35
+ @deriver ||= Exchange::Rate::Deriver.new(:source => @source, :verbose => @source.verbose)
36
+ end
37
+
38
+ def get_rates
39
+ @rates ||= @source.raw_rates
40
+ end
41
+
42
+ before(:all) do
43
+ get_rate_source
44
+ get_rates
45
+ end
46
+
47
+ before(:each) do
48
+ get_rate_source
49
+ end
50
+
51
+ it "can retrieve rates from the FED" do
52
+ @rates.should_not be_nil
53
+ end
54
+
55
+ it "can convert from USD to CAD" do
56
+ usd = Money.new(123.45, :USD)
57
+
58
+ cad = usd.convert(:CAD)
59
+ cad.should_not be_nil
60
+ cad.to_f.should be_kind_of(Numeric)
61
+ end
62
+
63
+ it "can do conversions from AUD to USD to JPY" do
64
+ aud = Money.new(123.45, :AUD)
65
+ usd = aud.convert(:USD)
66
+ jpy = usd.convert(:JPY)
67
+ jpy.should_not be_nil
68
+ jpy.to_f.should be_kind_of(Numeric)
69
+ end
70
+
71
+ end
@@ -0,0 +1,72 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe Currency::Formatter do
4
+ before(:each) do
5
+ @time = nil
6
+ @money = Currency::Money.new_rep(1234567890000, :USD, @time)
7
+
8
+ end
9
+
10
+ it "can convert to string" do
11
+ @money.should be_kind_of(Currency::Money)
12
+ @money.currency.should == Currency::Currency.default
13
+ @money.currency.code.should == :USD
14
+ @money.to_s.should == "$1,234,567.890000"
15
+ @money.time.should == @time
16
+ end
17
+
18
+
19
+ it "handles thousands options" do
20
+ @money.to_s(:thousands => false).should == "$1234567.890000"
21
+ @money.to_s(:thousands => true).should == "$1,234,567.890000"
22
+ end
23
+
24
+
25
+ it "handles cents options" do
26
+ @money.to_s(:cents => false).should == "$1,234,567"
27
+ @money.to_s(:cents => true).should == "$1,234,567.890000"
28
+ end
29
+
30
+
31
+ it "handles symbol options" do
32
+ @money.to_s(:symbol => false).should == "1,234,567.890000"
33
+ @money.to_s(:symbol => true).should == "$1,234,567.890000"
34
+ end
35
+
36
+
37
+ it "handles code options" do
38
+ @money.to_s(:code => false).should == "$1,234,567.890000"
39
+ @money.to_s(:code => true).should == "USD $1,234,567.890000"
40
+ end
41
+
42
+
43
+ it "handles html and more" do
44
+ m = ::Currency::Money(12.45, :USD)
45
+ money_string = m.to_s(:html => true, :code => true)
46
+ money_string.should == "<span class=\"currency_code\">USD</span> $12.450000"
47
+
48
+
49
+ m = ::Currency::Money(12.45, :EUR)
50
+ money_string = m.to_s(:html => true, :code => true)
51
+ money_string.should == "<span class=\"currency_code\">EUR</span> &#8364;12.450000"
52
+
53
+ m = ::Currency::Money(12345.45, :EUR)
54
+ money_string = m.to_s(:html => true, :code => true, :thousands_separator => '_')
55
+ money_string.should == "<span class=\"currency_code\">EUR</span> &#8364;12_345.450000"
56
+ end
57
+
58
+
59
+ it "handles time options" do
60
+ time = Time.new
61
+ m = Currency::Money.new_rep(1234567890000, :USD, time)
62
+ m.to_s(:time => false).should == "$1,234,567.890000"
63
+ m.to_s(:time => true).should == "$1,234,567.890000 #{time.getutc.xmlschema(4)}"
64
+ end
65
+
66
+ it "handles decimal options" do
67
+ @money = Currency::Money.new_rep(1234567890000, :USD, @time)
68
+ @money.to_s(:decimals => 2).should == "$1,234,567.89"
69
+ @money.to_s(:decimals => 3).should == "$1,234,567.890"
70
+ @money.to_s(:decimals => 4).should == "$1,234,567.8900"
71
+ end
72
+ end