sevenwire-money 2.0.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/MIT-LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ Copyright (c) 2005 Tobias Lutke
2
+ Copyright (c) 2008 Phusion
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ "Software"), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,97 @@
1
+ = Introduction
2
+
3
+ This library aids one in handling money and different currencies. Features:
4
+
5
+ - Provides a Money class which encapsulates all information about an certain
6
+ amount of money, such as its value and its currency.
7
+ - Represents monetary values as integers, in cents. This avoids floating point
8
+ rounding errors.
9
+ - Provides APIs for exchanging money from one currency to another.
10
+ - Has the ability to parse a money string into a Money object.
11
+
12
+ Resources:
13
+
14
+ - Website: http://money.rubyforge.org
15
+ - RDoc API: http://money.rubyforge.org
16
+ - Git repository: http://github.com/FooBarWidget/money/tree/master
17
+
18
+ == Download
19
+
20
+ Install stable releases with the following command:
21
+
22
+ gem install money
23
+
24
+ The development version (hosted on Github) can be installed with:
25
+
26
+ gem sources -a http://gems.github.com
27
+ gem install FooBarWidget-money
28
+
29
+ == Usage
30
+
31
+ === Synopsis
32
+
33
+ require 'money'
34
+
35
+ # 10.00 USD
36
+ money = Money.new(1000, "USD")
37
+ money.cents # => 1000
38
+ money.currency # => "USD"
39
+
40
+ Money.new(1000, "USD") == Money.new(1000, "USD") # => true
41
+ Money.new(1000, "USD") == Money.new(100, "USD") # => false
42
+ Money.new(1000, "USD") == Money.new(1000, "EUR") # => false
43
+
44
+ === Currency Exchange
45
+
46
+ Exchanging money is performed through an exchange bank object. The default
47
+ exchange bank object requires one to manually specify the exchange rate. Here's
48
+ an example of how it works:
49
+
50
+ Money.add_rate("USD", "CAD", 1.24515)
51
+ Money.add_rate("CAD", "USD", 0.803115)
52
+
53
+ Money.us_dollar(100).exchange_to("CAD") # => Money.new(124, "CAD")
54
+ Money.ca_dollar(100).exchange_to("USD") # => Money.new(80, "USD")
55
+
56
+ Comparison and arithmetic operations work as expected:
57
+
58
+ Money.new(1000, "USD") <=> Money.new(900, "USD") # => 1; 9.00 USD is smaller
59
+ Money.new(1000, "EUR") + Money.new(10, "EUR") == Money.new(1010, "EUR")
60
+
61
+ Money.add_rate("USD", "EUR", 0.5)
62
+ Money.new(1000, "EUR") + Money.new(1000, "USD") == Money.new(1500, "EUR")
63
+
64
+ There is nothing stopping you from creating bank objects which scrapes
65
+ www.xe.com for the current rates or just returns <tt>rand(2)</tt>:
66
+
67
+ Money.default_bank = ExchangeBankWhichScrapesXeDotCom.new
68
+
69
+ === Ruby on Rails
70
+
71
+ Use the +compose_of+ helper to let Active Record deal with embedding the money
72
+ object in your models. The following example requires a +cents+ and a +currency+
73
+ field.
74
+
75
+ class ProductUnit < ActiveRecord::Base
76
+ belongs_to :product
77
+ composed_of :price, :class_name => "Money", :mapping => [%w(cents cents), %w(currency currency)]
78
+
79
+ private
80
+ validate :cents_not_zero
81
+
82
+ def cents_not_zero
83
+ errors.add("cents", "cannot be zero or less") unless cents > 0
84
+ end
85
+
86
+ validates_presence_of :sku, :currency
87
+ validates_uniqueness_of :sku
88
+ end
89
+
90
+ === Default Currency
91
+
92
+ By default Money defaults to USD as its currency. This can be overwritten using
93
+
94
+ Money.default_currency = "CAD"
95
+
96
+ If you use Rails, then environment.rb is a very good place to put this.
97
+
data/Rakefile ADDED
@@ -0,0 +1,18 @@
1
+ desc "Build a gem"
2
+ task :gem do
3
+ sh "gem build money.gemspec"
4
+ end
5
+
6
+ task "Generate RDoc documentation"
7
+ task :rdoc do
8
+ sh "hanna README.rdoc lib -U"
9
+ end
10
+
11
+ task :upload => :rdoc do
12
+ sh "scp -r doc/* rubyforge.org:/var/www/gforge-projects/money/"
13
+ end
14
+
15
+ desc "Run unit tests"
16
+ task :test do
17
+ sh "spec -f s -c test/*_spec.rb"
18
+ end
data/lib/money.rb ADDED
@@ -0,0 +1,25 @@
1
+ # Copyright (c) 2005 Tobias Luetke
2
+ # Copyright (c) 2008 Phusion
3
+ #
4
+ # Permission is hereby granted, free of charge, to any person obtaining
5
+ # a copy of this software and associated documentation files (the
6
+ # "Software"), to deal in the Software without restriction, including
7
+ # without limitation the rights to use, copy, modify, merge, publish,
8
+ # distribute, sublicense, and/or sell copies of the Software, and to
9
+ # permit persons to whom the Software is furnished to do so, subject to
10
+ # the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be
13
+ # included in all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+
23
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__))
24
+ require 'money/money'
25
+ require 'money/core_extensions'
@@ -0,0 +1,38 @@
1
+ class Numeric
2
+ # Converts this numeric to a Money object in the default currency. It
3
+ # multiplies the numeric value by 100 and treats that as cents.
4
+ #
5
+ # 100.to_money => #<Money @cents=10000>
6
+ # 100.37.to_money => #<Money @cents=10037>
7
+ def to_money
8
+ Money.new(self * 100)
9
+ end
10
+ end
11
+
12
+ class String
13
+ # Parses the current string and converts it to a Money object.
14
+ # Excess characters will be discarded.
15
+ #
16
+ # '100'.to_money # => #<Money @cents=10000>
17
+ # '100.37'.to_money # => #<Money @cents=10037>
18
+ # '100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
19
+ # 'USD 100'.to_money # => #<Money @cents=10000, @currency="USD">
20
+ # '$100 USD'.to_money # => #<Money @cents=10000, @currency="USD">
21
+ def to_money
22
+ # Get the currency.
23
+ matches = scan /([A-Z]{2,3})/
24
+ currency = matches[0] ? matches[0][0] : Money.default_currency
25
+
26
+ # Get the cents amount
27
+ sans_spaces = gsub(/\s+/, '')
28
+ matches = sans_spaces.scan /(\-?\d+(?:[\.,]\d+)?)/
29
+ cents = if matches[0]
30
+ value = matches[0][0].gsub(/,/, '.')
31
+ value.to_f * 100
32
+ else
33
+ 0
34
+ end
35
+
36
+ Money.new(cents, currency)
37
+ end
38
+ end
@@ -0,0 +1,4 @@
1
+ class Money
2
+ class UnknownRate < StandardError
3
+ end
4
+ end
@@ -0,0 +1,201 @@
1
+ require 'money/variable_exchange_bank'
2
+
3
+ # Represents an amount of money in a certain currency.
4
+ class Money
5
+ include Comparable
6
+
7
+ attr_reader :cents, :currency, :bank
8
+
9
+ class << self
10
+ # Each Money object is associated to a bank object, which is responsible
11
+ # for currency exchange. This property allows one to specify the default
12
+ # bank object.
13
+ #
14
+ # bank1 = MyBank.new
15
+ # bank2 = MyOtherBank.new
16
+ #
17
+ # Money.default_bank = bank1
18
+ # money1 = Money.new(10)
19
+ # money1.bank # => bank1
20
+ #
21
+ # Money.default_bank = bank2
22
+ # money2 = Money.new(10)
23
+ # money2.bank # => bank2
24
+ # money1.bank # => bank1
25
+ #
26
+ # The default value for this property is an instance if VariableExchangeBank.
27
+ # It allows one to specify custom exchange rates:
28
+ #
29
+ # Money.default_bank.add_rate("USD", "CAD", 1.24515)
30
+ # Money.default_bank.add_rate("CAD", "USD", 0.803115)
31
+ # Money.us_dollar(100).exchange_to("CAD") # => Money.ca_dollar(124)
32
+ # Money.ca_dollar(100).exchange_to("USD") # => Money.us_dollar(80)
33
+ attr_accessor :default_bank
34
+
35
+ # The default currency, which is used when <tt>Money.new</tt> is called
36
+ # without an explicit currency argument. The default value is "USD".
37
+ attr_accessor :default_currency
38
+ end
39
+
40
+ self.default_bank = VariableExchangeBank.instance
41
+ self.default_currency = "USD"
42
+
43
+
44
+ # Create a new money object with value 0.
45
+ def self.empty(currency = default_currency)
46
+ Money.new(0, currency)
47
+ end
48
+
49
+ # Creates a new Money object of the given value, using the Canadian dollar currency.
50
+ def self.ca_dollar(cents)
51
+ Money.new(cents, "CAD")
52
+ end
53
+
54
+ # Creates a new Money object of the given value, using the American dollar currency.
55
+ def self.us_dollar(cents)
56
+ Money.new(cents, "USD")
57
+ end
58
+
59
+ # Creates a new Money object of the given value, using the Euro currency.
60
+ def self.euro(cents)
61
+ Money.new(cents, "EUR")
62
+ end
63
+
64
+ def self.add_rate(from_currency, to_currency, rate)
65
+ Money.default_bank.add_rate(from_currency, to_currency, rate)
66
+ end
67
+
68
+
69
+ # Creates a new money object.
70
+ # Money.new(100)
71
+ #
72
+ # Alternativly you can use the convinience methods like
73
+ # Money.ca_dollar and Money.us_dollar
74
+ def initialize(cents, currency = Money.default_currency, bank = Money.default_bank)
75
+ @cents = cents.round
76
+ @currency = currency
77
+ @bank = bank
78
+ end
79
+
80
+ # Do two money objects equal? Only works if both objects are of the same currency
81
+ def ==(other_money)
82
+ cents == other_money.cents && bank.same_currency?(currency, other_money.currency)
83
+ end
84
+
85
+ def <=>(other_money)
86
+ if bank.same_currency?(currency, other_money.currency)
87
+ cents <=> other_money.cents
88
+ else
89
+ cents <=> other_money.exchange_to(currency).cents
90
+ end
91
+ end
92
+
93
+ def +(other_money)
94
+ if currency == other_money.currency
95
+ Money.new(cents + other_money.cents, other_money.currency)
96
+ else
97
+ Money.new(cents + other_money.exchange_to(currency).cents,currency)
98
+ end
99
+ end
100
+
101
+ def -(other_money)
102
+ if currency == other_money.currency
103
+ Money.new(cents - other_money.cents, other_money.currency)
104
+ else
105
+ Money.new(cents - other_money.exchange_to(currency).cents, currency)
106
+ end
107
+ end
108
+
109
+ # get the cents value of the object
110
+ def cents
111
+ @cents
112
+ end
113
+
114
+ # multiply money by fixnum
115
+ def *(fixnum)
116
+ Money.new(cents * fixnum, currency)
117
+ end
118
+
119
+ # divide money by fixnum
120
+ def /(fixnum)
121
+ Money.new(cents / fixnum, currency)
122
+ end
123
+
124
+ # Test if the money amount is zero
125
+ def zero?
126
+ cents == 0
127
+ end
128
+
129
+
130
+ # Format the price according to several rules
131
+ # Currently supported are :with_currency, :no_cents and :html
132
+ #
133
+ # with_currency:
134
+ #
135
+ # Money.ca_dollar(0).format => "free"
136
+ # Money.ca_dollar(100).format => "$1.00"
137
+ # Money.ca_dollar(100).format(:with_currency) => "$1.00 CAD"
138
+ # Money.us_dollar(85).format(:with_currency) => "$0.85 USD"
139
+ #
140
+ # no_cents:
141
+ #
142
+ # Money.ca_dollar(100).format(:no_cents) => "$1"
143
+ # Money.ca_dollar(599).format(:no_cents) => "$5"
144
+ #
145
+ # Money.ca_dollar(570).format(:no_cents, :with_currency) => "$5 CAD"
146
+ # Money.ca_dollar(39000).format(:no_cents) => "$390"
147
+ #
148
+ # html:
149
+ #
150
+ # Money.ca_dollar(570).format(:html, :with_currency) => "$5.70 <span class=\"currency\">CAD</span>"
151
+ def format(*rules)
152
+ rules = rules.flatten
153
+
154
+ if rules.include?(:no_cents)
155
+ formatted = sprintf("$%d", cents.to_f / 100 )
156
+ else
157
+ formatted = sprintf("$%.2f", cents.to_f / 100 )
158
+ end
159
+
160
+ if rules.include?(:with_currency)
161
+ formatted << " "
162
+ formatted << '<span class="currency">' if rules.include?(:html)
163
+ formatted << currency
164
+ formatted << '</span>' if rules.include?(:html)
165
+ end
166
+ formatted
167
+ end
168
+
169
+ # Money.ca_dollar(100).to_s => "1.00"
170
+ def to_s
171
+ sprintf("%.2f", cents / 100.00)
172
+ end
173
+
174
+ # Recieve the amount of this money object in another currency.
175
+ def exchange_to(other_currency)
176
+ Money.new(@bank.exchange(self.cents, currency, other_currency), other_currency)
177
+ end
178
+
179
+ # Recieve a money object with the same amount as the current Money object
180
+ # in american dollar
181
+ def as_us_dollar
182
+ exchange_to("USD")
183
+ end
184
+
185
+ # Recieve a money object with the same amount as the current Money object
186
+ # in canadian dollar
187
+ def as_ca_dollar
188
+ exchange_to("CAD")
189
+ end
190
+
191
+ # Recieve a money object with the same amount as the current Money object
192
+ # in euro
193
+ def as_euro
194
+ exchange_to("EUR")
195
+ end
196
+
197
+ # Conversation to self
198
+ def to_money
199
+ self
200
+ end
201
+ end
@@ -0,0 +1,72 @@
1
+ require 'thread'
2
+ require 'money/errors'
3
+
4
+ # Class for aiding in exchanging money between different currencies.
5
+ # By default, the Money class uses an object of this class (accessible through
6
+ # Money#bank) for performing currency exchanges.
7
+ #
8
+ # By default, VariableExchangeBank has no knowledge about conversion rates.
9
+ # One must manually specify them with +add_rate+, after which one can perform
10
+ # exchanges with +exchange+. For example:
11
+ #
12
+ # bank = Money::VariableExchangeBank.new
13
+ # bank.add_rate("USD", "CAD", 1.24515)
14
+ # bank.add_rate("CAD", "USD", 0.803115)
15
+ #
16
+ # # Exchange 100 CAD to USD:
17
+ # bank.exchange(100_00, "CAD", "USD") # => 124
18
+ # # Exchange 100 USD to CAD:
19
+ # bank.exchange(100_00, "USD", "CAD") # => 80
20
+ class Money
21
+ class VariableExchangeBank
22
+ # Returns the singleton instance of VariableExchangeBank.
23
+ #
24
+ # By default, <tt>Money.default_bank</tt> returns the same object.
25
+ def self.instance
26
+ @@singleton
27
+ end
28
+
29
+ def initialize
30
+ @rates = {}
31
+ @mutex = Mutex.new
32
+ end
33
+
34
+ # Registers a conversion rate. +from+ and +to+ are both currency names.
35
+ def add_rate(from, to, rate)
36
+ @mutex.synchronize do
37
+ @rates["#{from}_TO_#{to}".upcase] = rate
38
+ end
39
+ end
40
+
41
+ # Gets the rate for exchanging the currency named +from+ to the currency
42
+ # named +to+. Returns nil if the rate is unknown.
43
+ def get_rate(from, to)
44
+ @mutex.synchronize do
45
+ @rates["#{from}_TO_#{to}".upcase]
46
+ end
47
+ end
48
+
49
+ # Given two currency names, checks whether they're both the same currency.
50
+ #
51
+ # bank = VariableExchangeBank.new
52
+ # bank.same_currency?("usd", "USD") # => true
53
+ # bank.same_currency?("usd", "EUR") # => false
54
+ def same_currency?(currency1, currency2)
55
+ currency1.upcase == currency2.upcase
56
+ end
57
+
58
+ # Exchange the given amount of cents in +from_currency+ to +to_currency+.
59
+ # Returns the amount of cents in +to_currency+ as an integer, rounded down.
60
+ #
61
+ # If the conversion rate is unknown, then Money::UnknownRate will be raised.
62
+ def exchange(cents, from_currency, to_currency)
63
+ rate = get_rate(from_currency, to_currency)
64
+ if !rate
65
+ raise Money::UnknownRate, "No conversion rate known for '#{from_currency}' -> '#{to_currency}'"
66
+ end
67
+ (cents * rate).floor
68
+ end
69
+
70
+ @@singleton = VariableExchangeBank.new
71
+ end
72
+ end
data/money.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "money"
3
+ s.version = "2.0.0"
4
+ s.summary = "Money and currency exchange support library"
5
+ s.email = "hongli@phusion.nl"
6
+ s.homepage = "http://money.rubyforge.org/"
7
+ s.description = "Money and currency exchange support library. Patched by Sevenwire."
8
+ s.has_rdoc = true
9
+ s.rubyforge_project = "money"
10
+ s.authors = ["Tobias Luetke", "Hongli Lai"]
11
+
12
+ s.files = [
13
+ "README.rdoc", "MIT-LICENSE", "money.gemspec", "Rakefile",
14
+ "lib/money.rb",
15
+ "lib/money/core_extensions.rb",
16
+ "lib/money/errors.rb",
17
+ "lib/money/money.rb",
18
+ "lib/money/variable_exchange_bank.rb",
19
+ "test/core_extensions_spec.rb",
20
+ "test/exchange_bank_spec.rb",
21
+ "test/money_spec.rb"
22
+ ]
23
+ end
@@ -0,0 +1,36 @@
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ require 'money/core_extensions'
3
+
4
+ describe "Money core extensions" do
5
+ specify "Numberic#to_money works" do
6
+ money = 1234.to_money
7
+ money.cents.should == 1234_00
8
+ money.currency.should == Money.default_currency
9
+
10
+ money = 100.37.to_money
11
+ money.cents.should == 100_37
12
+ money.currency.should == Money.default_currency
13
+ end
14
+
15
+ specify "String#to_money works" do
16
+ "100".to_money.should == Money.new(100_00)
17
+ "100.37".to_money.should == Money.new(100_37)
18
+ "100,37".to_money.should == Money.new(100_37)
19
+ "100 000".to_money.should == Money.new(100_000_00)
20
+
21
+ "100 USD".to_money.should == Money.new(100_00, "USD")
22
+ "-100 USD".to_money.should == Money.new(-100_00, "USD")
23
+ "100 EUR".to_money.should == Money.new(100_00, "EUR")
24
+ "100.37 EUR".to_money.should == Money.new(100_37, "EUR")
25
+ "100,37 EUR".to_money.should == Money.new(100_37, "EUR")
26
+
27
+ "USD 100".to_money.should == Money.new(100_00, "USD")
28
+ "EUR 100".to_money.should == Money.new(100_00, "EUR")
29
+ "EUR 100.37".to_money.should == Money.new(100_37, "EUR")
30
+ "CAD -100.37".to_money.should == Money.new(-100_37, "CAD")
31
+ "EUR 100,37".to_money.should == Money.new(100_37, "EUR")
32
+ "EUR -100,37".to_money.should == Money.new(-100_37, "EUR")
33
+
34
+ "$100 USD".to_money.should == Money.new(100_00, "USD")
35
+ end
36
+ end
@@ -0,0 +1,45 @@
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ require 'money/variable_exchange_bank'
3
+
4
+ describe Money::VariableExchangeBank do
5
+ before :each do
6
+ @bank = Money::VariableExchangeBank.new
7
+ end
8
+
9
+ it "returns the previously specified conversion rate" do
10
+ @bank.add_rate("USD", "EUR", 0.788332676)
11
+ @bank.add_rate("EUR", "YEN", 122.631477)
12
+ @bank.get_rate("USD", "EUR").should == 0.788332676
13
+ @bank.get_rate("EUR", "YEN").should == 122.631477
14
+ end
15
+
16
+ it "treats currency names case-insensitively" do
17
+ @bank.add_rate("usd", "eur", 1)
18
+ @bank.get_rate("USD", "EUR").should == 1
19
+ @bank.same_currency?("USD", "usd").should be_true
20
+ @bank.same_currency?("EUR", "usd").should be_false
21
+ end
22
+
23
+ it "returns nil if the conversion rate is unknown" do
24
+ @bank.get_rate("American Pesos", "EUR").should be_nil
25
+ end
26
+
27
+ it "exchanges money from one currency to another according to the specified conversion rates" do
28
+ @bank.add_rate("USD", "EUR", 0.5)
29
+ @bank.add_rate("EUR", "YEN", 10)
30
+ @bank.exchange(10_00, "USD", "EUR").should == 5_00
31
+ @bank.exchange(500_00, "EUR", "YEN").should == 5000_00
32
+ end
33
+
34
+ it "rounds the exchanged result down" do
35
+ @bank.add_rate("USD", "EUR", 0.788332676)
36
+ @bank.add_rate("EUR", "YEN", 122.631477)
37
+ @bank.exchange(10_00, "USD", "EUR").should == 788
38
+ @bank.exchange(500_00, "EUR", "YEN").should == 6131573
39
+ end
40
+
41
+ it "raises Money::UnknownRate upon conversion if the conversion rate is unknown" do
42
+ block = lambda { @bank.exchange(10, "USD", "EUR") }
43
+ block.should raise_error(Money::UnknownRate)
44
+ end
45
+ end
@@ -0,0 +1,124 @@
1
+ $LOAD_PATH << File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ require 'money/money'
3
+
4
+ describe Money do
5
+ it "is associated to the singleton instance of VariableExchangeBank by default" do
6
+ Money.new(0).bank.object_id.should == Money::VariableExchangeBank.instance.object_id
7
+ end
8
+
9
+ specify "#cents returns the amount of cents passed to the constructor" do
10
+ Money.new(200_00, "USD").cents.should == 200_00
11
+ end
12
+
13
+ it "rounds the given cents to an integer" do
14
+ Money.new(1.00, "USD").cents.should == 1
15
+ Money.new(1.01, "USD").cents.should == 1
16
+ Money.new(1.50, "USD").cents.should == 2
17
+ end
18
+
19
+ specify "#currency returns the currency passed to the constructor" do
20
+ Money.new(200_00, "USD").currency.should == "USD"
21
+ end
22
+
23
+ specify "#zero? returns whether the amount is 0" do
24
+ Money.new(0, "USD").should be_zero
25
+ Money.new(0, "EUR").should be_zero
26
+ Money.new(1, "USD").should_not be_zero
27
+ Money.new(10, "YEN").should_not be_zero
28
+ Money.new(-1, "EUR").should_not be_zero
29
+ end
30
+
31
+ specify "#exchange_to exchanges the amount via its exchange bank" do
32
+ money = Money.new(100_00, "USD")
33
+ money.bank.should_receive(:exchange).with(100_00, "USD", "EUR").and_return(200_00)
34
+ money.exchange_to("EUR")
35
+ end
36
+
37
+ specify "#exchange_to exchanges the amount properly" do
38
+ money = Money.new(100_00, "USD")
39
+ money.bank.should_receive(:exchange).with(100_00, "USD", "EUR").and_return(200_00)
40
+ money.exchange_to("EUR").should == Money.new(200_00, "EUR")
41
+ end
42
+
43
+ specify "#== returns true if and only if their amount and currency are equal" do
44
+ Money.new(1_00, "USD").should == Money.new(1_00, "USD")
45
+ Money.new(1_00, "USD").should_not == Money.new(1_00, "EUR")
46
+ Money.new(1_00, "USD").should_not == Money.new(2_00, "USD")
47
+ Money.new(1_00, "USD").should_not == Money.new(99_00, "EUR")
48
+ end
49
+
50
+ specify "#* multiplies the money's amount by the multiplier while retaining the currency" do
51
+ (Money.new(1_00, "USD") * 10).should == Money.new(10_00, "USD")
52
+ end
53
+
54
+ specify "#* divides the money's amount by the divisor while retaining the currency" do
55
+ (Money.new(10_00, "USD") / 10).should == Money.new(1_00, "USD")
56
+ end
57
+
58
+ specify "Money.empty creates a new Money object of 0 cents" do
59
+ Money.empty.should == Money.new(0)
60
+ end
61
+
62
+ specify "Money.ca_dollar creates a new Money object of the given value in CAD" do
63
+ Money.ca_dollar(50).should == Money.new(50, "CAD")
64
+ end
65
+
66
+ specify "Money.ca_dollar creates a new Money object of the given value in USD" do
67
+ Money.us_dollar(50).should == Money.new(50, "USD")
68
+ end
69
+
70
+ specify "Money.ca_dollar creates a new Money object of the given value in EUR" do
71
+ Money.euro(50).should == Money.new(50, "EUR")
72
+ end
73
+
74
+ specify "Money.add_rate works" do
75
+ Money.add_rate("EUR", "USD", 10)
76
+ Money.new(10_00, "EUR").exchange_to("USD").should == Money.new(100_00, "USD")
77
+ end
78
+ end
79
+
80
+ describe "Actions involving two Money objects" do
81
+ describe "if the other Money object has the same currency" do
82
+ specify "#<=> compares the two objects' amounts" do
83
+ (Money.new(1_00, "USD") <=> Money.new(1_00, "USD")).should == 0
84
+ (Money.new(1_00, "USD") <=> Money.new(99, "USD")).should > 0
85
+ (Money.new(1_00, "USD") <=> Money.new(2_00, "USD")).should < 0
86
+ end
87
+
88
+ specify "#+ adds the other object's amount to the current object's amount while retaining the currency" do
89
+ (Money.new(10_00, "USD") + Money.new(90, "USD")).should == Money.new(10_90, "USD")
90
+ end
91
+
92
+ specify "#- substracts the other object's amount from the current object's amount while retaining the currency" do
93
+ (Money.new(10_00, "USD") - Money.new(90, "USD")).should == Money.new(9_10, "USD")
94
+ end
95
+ end
96
+
97
+ describe "if the other Money object has a different currency" do
98
+ specify "#<=> compares the two objects' amount after converting the other object's amount to its own currency" do
99
+ target = Money.new(200_00, "EUR")
100
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(300_00, "USD"))
101
+ (Money.new(100_00, "USD") <=> target).should < 0
102
+
103
+ target = Money.new(200_00, "EUR")
104
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(100_00, "USD"))
105
+ (Money.new(100_00, "USD") <=> target).should == 0
106
+
107
+ target = Money.new(200_00, "EUR")
108
+ target.should_receive(:exchange_to).with("USD").and_return(Money.new(99_00, "USD"))
109
+ (Money.new(100_00, "USD") <=> target).should > 0
110
+ end
111
+
112
+ specify "#+ adds the other object's amount, converted to this object's currency, to this object's amount while retaining its currency" do
113
+ other = Money.new(90, "EUR")
114
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
115
+ (Money.new(10_00, "USD") + other).should == Money.new(19_00, "USD")
116
+ end
117
+
118
+ specify "#- substracts the other object's amount, converted to this object's currency, from this object's amount while retaining its currency" do
119
+ other = Money.new(90, "EUR")
120
+ other.should_receive(:exchange_to).with("USD").and_return(Money.new(9_00, "USD"))
121
+ (Money.new(10_00, "USD") - other).should == Money.new(1_00, "USD")
122
+ end
123
+ end
124
+ end
metadata ADDED
@@ -0,0 +1,65 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sevenwire-money
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Tobias Luetke
8
+ - Hongli Lai
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2008-12-22 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies: []
16
+
17
+ description: Money and currency exchange support library. Patched by Sevenwire.
18
+ email: hongli@phusion.nl
19
+ executables: []
20
+
21
+ extensions: []
22
+
23
+ extra_rdoc_files: []
24
+
25
+ files:
26
+ - README.rdoc
27
+ - MIT-LICENSE
28
+ - money.gemspec
29
+ - Rakefile
30
+ - lib/money.rb
31
+ - lib/money/core_extensions.rb
32
+ - lib/money/errors.rb
33
+ - lib/money/money.rb
34
+ - lib/money/variable_exchange_bank.rb
35
+ - test/core_extensions_spec.rb
36
+ - test/exchange_bank_spec.rb
37
+ - test/money_spec.rb
38
+ has_rdoc: true
39
+ homepage: http://money.rubyforge.org/
40
+ post_install_message:
41
+ rdoc_options: []
42
+
43
+ require_paths:
44
+ - lib
45
+ required_ruby_version: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - ">="
48
+ - !ruby/object:Gem::Version
49
+ version: "0"
50
+ version:
51
+ required_rubygems_version: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: "0"
56
+ version:
57
+ requirements: []
58
+
59
+ rubyforge_project: money
60
+ rubygems_version: 1.2.0
61
+ signing_key:
62
+ specification_version: 2
63
+ summary: Money and currency exchange support library
64
+ test_files: []
65
+