coinage 0.2.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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 Chris Lloyd
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,140 @@
1
+ Handle and convert your Money!
2
+
3
+ Think of Coinage as a weedy, overworked guy. Amongst other things, this man enjoys exercising Biro's so that his collection's ink levels, when ordered, form a sine wave. So yeah, he also likes the finer points of money. So does Coinage.
4
+
5
+ Here's what you want to know. Coinage allows for: simple conversion between currencies; reliable monetary arithmetic; multi-national input parsing; easy Rails & Merb money handling.
6
+
7
+ This is _not_ meant as a replacement for "ActiveMerchant":http://www.activemerchant.org/, it _is_, however, meant as a replacement for "Money":http://dist.leetsoft.com/api/money/.
8
+
9
+ *WARNING:* To quote 1998, this software is still very much "under construction". I really wouldn't recommend using it in production until it reaches 1.0.
10
+
11
+
12
+ h2. Install
13
+
14
+ sudo gem install coinage
15
+
16
+
17
+ h2. Usage
18
+
19
+ require 'coinage'
20
+
21
+ a = 5.dollars
22
+
23
+ b = Money.new(5, :aud)
24
+
25
+ a + b
26
+
27
+ Ok, lets work through this example. First off, you have to require Coinage. @a@ is then created as a new @Money@ instance with the value of $5. Whenever new @Money@ instances are created without specifying a currency (like in the second line) the currency defaults to United States Dollars. This can be changed as follows:
28
+
29
+ Money.default_currency = :aud
30
+
31
+ The third line creates a new @Money@ instance but this time in Australian Dollars. Note that @a@ does not necessarily equal @b@ as it is unlikely that the two currencies will ever reach parity.
32
+
33
+ Finally, @a + b@ adds the two variables together. Out of the box this should return a new @Money@ object with value USD$10. It is in US Dollars as any arithmetic operator sets the result's currency to the first operand's currency. The result has a value of 10 dollars because by default, Coinage uses the @Coinage::Exchange::None@ exchange, which always provides an exchange rate of 1. This default will change as the other exchanges become more stable.
34
+
35
+ The default exchange can be changed:
36
+
37
+ Money.default_exchange = Coinage::Exchange::Xurrency.new
38
+
39
+ h3. ActiveRecord
40
+
41
+ For the moment, its not nat pretty integrating Coinage with money, but its quite easy:
42
+
43
+ composed_of :price, :class_name => 'Money', :mapping => %w(price_in_cents currency) do |price|
44
+ price.to_money
45
+ end
46
+
47
+ That creates a virtual property, @value@, which maps to the database columns @price_in_cents@ and @currency@. Coinage stores all values as cents. It also creates a setter method, @value=@ which can accept a string so in your view you can have something like:
48
+
49
+ <%= f.text_field :value %>
50
+
51
+ That will work with mass assignment (read: out of the box) and deal with storing all monetary values. Automagic!
52
+
53
+ h3. Defining Custom Exchanges
54
+
55
+ Say you have MaiSpecialAPI giving you currency rates and you want to use that instead of Xurrency or Yahoo. Just create a new exchange like the one below and put all your code in the @rate@ method.
56
+
57
+ class MaiSpecialExchange
58
+
59
+ include Coinage::Exchange::Base
60
+
61
+ def rate(current, target)
62
+ super(current, target) # Verifies that both currencies are supported by your exchange
63
+
64
+ MaiSpecial.get(current, target)
65
+
66
+ end
67
+
68
+ def supported_currencies
69
+ [ :lolz, :catz ]
70
+ end
71
+
72
+ end
73
+
74
+ Then just set
75
+
76
+ Money.default_exchange = MaiSpecialExchange.new
77
+
78
+ and Wallah! Your all set.
79
+
80
+
81
+ h2. Notes
82
+
83
+ * _Namespaces_: While all of Coinage's internal classes are defined in the @Coinage@ namespace, the @Money@ class is defined in the global namespace.
84
+ * _Class Extension_: @Numeric@ and @String@ are given methods such as @:to_money@ and @:cents@.
85
+ * _Commutativity_: With two Money instances, @a + b != b + a@ if @a@ and @b@ have different currencies. This is because currencies are not quantitative and favors the instance acted upon (@a@) rather than the passed instance (@b@).
86
+ * _Supported Currencies_: Are currently hard coded. Not the friendliest interface to work with, but it should work for the most part.
87
+
88
+
89
+ h2. Plans
90
+
91
+ * _Cache exchange calls_: This will provide a major speed-up. Cache to a few different back-ends (flat file, memcached, db) so that calls only have to be made at a defined frequency, rather than every time a conversion is needed. Rake tasks will also be provided if you want to update this cache externally.
92
+ * _More exchange APIs_: At the moment it only supports the Xurrency API. I plan on adding support for Yahoo and XE Premium (when I get a sample response). It is very easy to add your own API back-ends.
93
+ * _Use libxml-ruby_: By far the fastest XML parser out there, it currently is fairly undocumented. Definitely switch to it for parsing exchange data.
94
+ * _Rails 2.2 Integration_: When 2.2 comes out Coinage will be there supporting the new i18n & L10n features in Rails core.
95
+ * _ActiveRecord & DataMapper support_: Provide a class method which will make it easier to transform ordinary fields into Money objects.
96
+ * _String Parsing_: Be able to parse a wide variety of user input such as: 'AUD$50', '$50 AUD', '€50', '€50,99', '50,000.00' and '50.000,00'.
97
+
98
+
99
+ h2. Authors
100
+
101
+ * "Chris Lloyd":http://chrislloyd.com.au
102
+ * You
103
+
104
+
105
+ h2. Contribute
106
+
107
+ You can checkout the source or fork it yourself from Github.
108
+
109
+ git clone git://github.com/chrislloyd/coinage.git
110
+
111
+ If you submit a successful patch then you'll be given full commit rights to the project.
112
+
113
+
114
+ h2. Bugs
115
+
116
+ Bug tracking is handled by "Ditz":http://ditz.rubyforge.org.
117
+
118
+
119
+ h2. License
120
+
121
+ Copyright (c) 2008 Chris Lloyd.
122
+
123
+ Permission is hereby granted, free of charge, to any person obtaining
124
+ a copy of this software and associated documentation files (the
125
+ 'Software'), to deal in the Software without restriction, including
126
+ without limitation the rights to use, copy, modify, merge, publish,
127
+ distribute, sublicense, and/or sell copies of the Software, and to
128
+ permit persons to whom the Software is furnished to do so, subject to
129
+ the following conditions:
130
+
131
+ The above copyright notice and this permission notice shall be
132
+ included in all copies or substantial portions of the Software.
133
+
134
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
135
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
136
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
137
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
138
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
139
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
140
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,64 @@
1
+ require 'rubygems'
2
+ require 'rake/gempackagetask'
3
+ require 'rubygems/specification'
4
+ require 'spec/rake/spectask'
5
+ require 'date'
6
+
7
+ GEM = "coinage"
8
+ GEM_VERSION = "0.2.0"
9
+ AUTHOR = "Chris Lloyd"
10
+ EMAIL = "christopher.lloyd@gmail.com"
11
+ HOMEPAGE = "http://github.com/chrislloyd/coinage"
12
+ SUMMARY = "Handle and convert your Money!"
13
+
14
+ spec = Gem::Specification.new do |s|
15
+ s.name = GEM
16
+ s.version = GEM_VERSION
17
+ s.platform = Gem::Platform::RUBY
18
+ s.rubyforge_project = GEM
19
+ s.has_rdoc = true
20
+ s.extra_rdoc_files = ['README.textile', 'LICENSE']
21
+ s.summary = SUMMARY
22
+ s.description = s.summary
23
+ s.author = AUTHOR
24
+ s.email = EMAIL
25
+ s.homepage = HOMEPAGE
26
+
27
+ # Uncomment this to add a dependency
28
+ # s.add_dependency "foo"
29
+ s.add_dependency 'hpricot'
30
+
31
+ s.require_path = 'lib'
32
+ s.files = %w(LICENSE README.textile Rakefile) + Dir.glob("{lib,specs}/**/*")
33
+ end
34
+
35
+ Rake::GemPackageTask.new(spec) do |pkg|
36
+ pkg.gem_spec = spec
37
+ end
38
+
39
+ task :default => :spec
40
+ task :specs => :spec
41
+
42
+ desc "Run all examples"
43
+ Spec::Rake::SpecTask.new('spec') do |t|
44
+ t.spec_opts = ['--options', 'spec/spec.opts']
45
+ t.spec_files = FileList['spec/**/**/*.rb']
46
+ t.rcov = true
47
+ t.rcov_opts = ['--exclude',"#{GEM}\\.rb,spec/,rspec-*,rcov-*"]
48
+ end
49
+
50
+ desc "install the gem locally"
51
+ task :install => [:package] do
52
+ sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
53
+ end
54
+
55
+ desc "create a gemspec file"
56
+ task :make_spec do
57
+ File.open("#{GEM}.gemspec", "w") do |file|
58
+ file.puts spec.to_ruby
59
+ end
60
+ end
61
+
62
+ task :bugs do
63
+ sh %{ditz html ; open html/index.html} if PLATFORM == 'universal-darwin9.0'
64
+ end
data/lib/coinage.rb ADDED
@@ -0,0 +1,6 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'coinage/core_ext'
5
+ require 'coinage/exchange'
6
+ require 'coinage/money'
@@ -0,0 +1,4 @@
1
+ require 'coinage/core_ext/array'
2
+ require 'coinage/core_ext/class'
3
+ require 'coinage/core_ext/numeric'
4
+ require 'coinage/core_ext/string'
@@ -0,0 +1,16 @@
1
+ class Array
2
+
3
+ # Extracts options from a set of arguments. Removes and returns the last
4
+ # element in the array if it's a hash, otherwise returns a blank hash.
5
+ #
6
+ # def options(*args)
7
+ # args.extract_options!
8
+ # end
9
+ #
10
+ # options(1, 2) # => {}
11
+ # options(1, 2, :a => :b) # => {:a=>:b}
12
+ def extract_options!
13
+ last.is_a?(::Hash) ? pop : {}
14
+ end
15
+
16
+ end
@@ -0,0 +1,54 @@
1
+ # Extends the class object with class and instance accessors for class attributes,
2
+ # just like the native attr* accessors for instance attributes.
3
+ #
4
+ # class Person
5
+ # cattr_accessor :hair_colors
6
+ # end
7
+ #
8
+ # Person.hair_colors = [:brown, :black, :blonde, :red]
9
+ class Class
10
+ def cattr_reader(*syms)
11
+ syms.flatten.each do |sym|
12
+ next if sym.is_a?(Hash)
13
+ class_eval(<<-EOS, __FILE__, __LINE__)
14
+ unless defined? @@#{sym}
15
+ @@#{sym} = nil
16
+ end
17
+
18
+ def self.#{sym}
19
+ @@#{sym}
20
+ end
21
+
22
+ def #{sym}
23
+ @@#{sym}
24
+ end
25
+ EOS
26
+ end
27
+ end
28
+
29
+ def cattr_writer(*syms)
30
+ options = syms.extract_options!
31
+ syms.flatten.each do |sym|
32
+ class_eval(<<-EOS, __FILE__, __LINE__)
33
+ unless defined? @@#{sym}
34
+ @@#{sym} = nil
35
+ end
36
+
37
+ def self.#{sym}=(obj)
38
+ @@#{sym} = obj
39
+ end
40
+
41
+ #{"
42
+ def #{sym}=(obj)
43
+ @@#{sym} = obj
44
+ end
45
+ " unless options[:instance_writer] == false }
46
+ EOS
47
+ end
48
+ end
49
+
50
+ def cattr_accessor(*syms)
51
+ cattr_reader(*syms)
52
+ cattr_writer(*syms)
53
+ end
54
+ end
@@ -0,0 +1,16 @@
1
+ class Numeric
2
+
3
+ def to_money
4
+ Money.new(self)
5
+ end
6
+
7
+ alias :cents :to_money
8
+ alias :cent :to_money
9
+
10
+ def dollars
11
+ Money.new(self*100)
12
+ end
13
+
14
+ alias :dollar :dollars
15
+
16
+ end
@@ -0,0 +1,7 @@
1
+ class String
2
+
3
+ def to_money
4
+ Money.new(self)
5
+ end
6
+
7
+ end
@@ -0,0 +1,5 @@
1
+ require 'coinage/exchange/base'
2
+ require 'coinage/exchange/none'
3
+ require 'coinage/exchange/variable'
4
+ require 'coinage/exchange/yahoo'
5
+ require 'coinage/exchange/xurrency'
@@ -0,0 +1,23 @@
1
+ module Coinage
2
+ module Exchange
3
+ module Base
4
+
5
+ def rate(current, target)
6
+ validate_currencies(current, target)
7
+ end
8
+
9
+ def supported_currencies
10
+ [:usd, :aud, :sgd]
11
+ end
12
+
13
+ def validate_currency(*currencies)
14
+ currencies.each do |currency|
15
+ raise ArgumentError unless supported_currencies.include?(currency)
16
+ end
17
+ end
18
+
19
+ alias :validate_currencies :validate_currency
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,14 @@
1
+ module Coinage
2
+ module Exchange
3
+ class None
4
+
5
+ include Base
6
+
7
+ def rate(current, target)
8
+ super(current, target)
9
+ 1
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ module Coinage
2
+ module Exchange
3
+ class Variable
4
+
5
+ include Base
6
+
7
+ def rate(current, target)
8
+ validate_currencies(current, target)
9
+ 2*rand
10
+ end
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,30 @@
1
+ require 'rubygems'
2
+ # Would use this, but it only reads in from a file!
3
+ # require 'libxml'
4
+ require 'open-uri'
5
+ require 'hpricot'
6
+
7
+ module Coinage
8
+ module Exchange
9
+ class Xurrency
10
+
11
+ include Base
12
+
13
+ def rate(current, target)
14
+ super(current, target)
15
+ uri = "http://xurrency.com/1/#{current}/#{target}/feed"
16
+
17
+ (Hpricot(open(uri).read)/'dc:value').inner_html
18
+ end
19
+
20
+ # From:
21
+ # http://xurrency.com/currencies
22
+ def supported_currencies
23
+ [ :ars, :aud, :brl, :bgn, :cad, :cny, :cop, :hrk, :czk, :dkk, :eek, :eur, :hkd, :huf, :isk, :inr,
24
+ :jpy, :krw, :lvl, :ltl, :myr, :mxn, :ron, :try, :nzd, :nok, :php, :pln, :gbp, :rub, :sgd, :skk,
25
+ :zar, :lkr, :sek, :chf, :twd, :thb, :usd, :vef ]
26
+ end
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,9 @@
1
+ module Coinage
2
+ module Exchange
3
+ class Yahoo
4
+
5
+ include Base
6
+
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,168 @@
1
+ class Money
2
+
3
+ @@default_currency = :usd
4
+ cattr_accessor :default_currency
5
+
6
+ @@default_exchange = Coinage::Exchange::None.new
7
+ cattr_accessor :default_exchange
8
+
9
+ attr_accessor :cents, :currency
10
+ attr_writer :exchange
11
+
12
+ def initialize(cents=0, currency=self.class.default_currency)
13
+ @currency = currency
14
+
15
+ case cents
16
+ when Float
17
+ @cents = cents_from_float(cents)
18
+ when String
19
+ @cents = cents_from_string(cents)
20
+ else
21
+ @cents = cents.to_i
22
+ end
23
+
24
+ end
25
+
26
+ def zero?
27
+ cents.zero?
28
+ end
29
+
30
+ def to_money
31
+ self
32
+ end
33
+
34
+ def to_i
35
+ cents
36
+ end
37
+
38
+ def to_f
39
+ cents.to_f/100
40
+ end
41
+
42
+ def dollars
43
+ (cents/100).round
44
+ end
45
+
46
+ def round
47
+ (cents.to_f/100).round
48
+ end
49
+
50
+ def exchange
51
+ @exchange || self.class.default_exchange
52
+ end
53
+
54
+ def exchange_to!(target)
55
+ raise ArgumentError, "#{exchange.class} does not support conversions from #{currency.to_s.upcase}" unless exchange.supported_currencies.include?(currency)
56
+ raise ArgumentError, "#{exchange.class} does not support conversions to #{target.to_s.upcase}" unless exchange.supported_currencies.include?(target)
57
+ unless currency == target
58
+ self.cents, self.currency = cents * exchange.rate(currency, target), target
59
+ end
60
+ self
61
+ end
62
+
63
+ def exchange_to(target)
64
+ dup.exchange_to!(target)
65
+ end
66
+
67
+ def *(target)
68
+ case target
69
+ when Numeric
70
+ self.class.new( cents * target, currency )
71
+ when Money
72
+ self.class.new( cents * target.exchange_to(currency).cents, currency )
73
+ else
74
+ raise ArgumentError
75
+ end
76
+ end
77
+
78
+ def /(target)
79
+ case target
80
+ when Numeric
81
+ self.class.new( cents / target, currency )
82
+ when Money
83
+ self.class.new( cents / target.exchange_to(currency).cents, currency )
84
+ else
85
+ raise ArgumentError
86
+ end
87
+ end
88
+
89
+ def +(target)
90
+ case target
91
+ when Numeric
92
+ self.class.new( cents + target, currency )
93
+ when Money
94
+ self.class.new( cents + target.exchange_to(currency).cents, currency )
95
+ else
96
+ raise ArgumentError
97
+ end
98
+ end
99
+
100
+ def -(target)
101
+ case target
102
+ when Numeric
103
+ self.class.new( cents - target, currency )
104
+ when Money
105
+ self.class.new( cents - target.exchange_to(currency).cents, currency )
106
+ else
107
+ raise ArgumentError
108
+ end
109
+ end
110
+
111
+ # Uses == instead of .eql? to perform a type conversion between Float and Fixnum
112
+ def eql?(target)
113
+ case target
114
+ when Numeric
115
+ cents == target
116
+ when Money
117
+ if currency == target.currency
118
+ cents == target.cents
119
+ else
120
+ cents == target.exchange_to(currency).cents
121
+ end
122
+ else
123
+ false
124
+ end
125
+ end
126
+
127
+ alias :== :eql?
128
+ alias :equal? :eql?
129
+
130
+ def method_missing(method, *arguments)
131
+ if new_currency = extract_currency_from_method(method)
132
+ return exchange_to(new_currency)
133
+ else
134
+ super
135
+ end
136
+ end
137
+
138
+ def coerce(other)
139
+ return self, other
140
+ end
141
+
142
+ def to_s
143
+ to_f.to_s
144
+ end
145
+
146
+ # def <=>
147
+
148
+ private
149
+
150
+ def cents_from_float(cents)
151
+ cents.round.to_i
152
+ end
153
+
154
+ def cents_from_string(cents, seperator='.')
155
+ if cents.include?(seperator)
156
+ cents.delete(seperator).to_i
157
+ else
158
+ cents.to_i*100
159
+ end
160
+ end
161
+
162
+ def extract_currency_from_method(method)
163
+ return nil unless method = method.to_s.match(/^to_[[:lower:]]+$/)
164
+ expected_currency = method[0].delete('to_').to_sym
165
+ exchange.supported_currencies.include?(expected_currency) ? expected_currency : nil
166
+ end
167
+
168
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: coinage
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ platform: ruby
6
+ authors:
7
+ - Chris Lloyd
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-09-02 00:00:00 +10:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hpricot
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ version:
25
+ description: Handle and convert your Money!
26
+ email: christopher.lloyd@gmail.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files:
32
+ - README.textile
33
+ - LICENSE
34
+ files:
35
+ - LICENSE
36
+ - README.textile
37
+ - Rakefile
38
+ - lib/coinage
39
+ - lib/coinage/core_ext
40
+ - lib/coinage/core_ext/array.rb
41
+ - lib/coinage/core_ext/class.rb
42
+ - lib/coinage/core_ext/numeric.rb
43
+ - lib/coinage/core_ext/string.rb
44
+ - lib/coinage/core_ext.rb
45
+ - lib/coinage/exchange
46
+ - lib/coinage/exchange/base.rb
47
+ - lib/coinage/exchange/none.rb
48
+ - lib/coinage/exchange/variable.rb
49
+ - lib/coinage/exchange/xurrency.rb
50
+ - lib/coinage/exchange/yahoo.rb
51
+ - lib/coinage/exchange.rb
52
+ - lib/coinage/money.rb
53
+ - lib/coinage.rb
54
+ has_rdoc: true
55
+ homepage: http://github.com/chrislloyd/coinage
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project: coinage
76
+ rubygems_version: 1.2.0
77
+ signing_key:
78
+ specification_version: 2
79
+ summary: Handle and convert your Money!
80
+ test_files: []
81
+