meplato-money 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+
3
+ require 'singleton'
4
+ require 'thread'
5
+ require 'open-uri'
6
+ require 'rubygems' if RUBY_VERSION <= '1.9'
7
+ if defined?(Yajl)
8
+ require 'yajl/json_gem'
9
+ else
10
+ require 'json'
11
+ end
12
+
13
+ module Money
14
+ class MeplatoBank
15
+ include Singleton
16
+
17
+ def initialize
18
+ @rates = {}
19
+ @mutex = Mutex.new
20
+ load_rates
21
+ end
22
+
23
+ def add_rate(source, target, rate)
24
+ @mutex.synchronize do
25
+ add_rate_synchronized(source, target, rate)
26
+ end
27
+ end
28
+
29
+ def get_rate(source, target)
30
+ @mutex.synchronize do
31
+ @rates["#{source}_#{target}".upcase]
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def add_rate_synchronized(source, target, rate)
38
+ @rates["#{source}_#{target}".upcase] = rate
39
+ end
40
+
41
+ def load_rates
42
+ latest = JSON.parse(open("http://services.meplato.com/rates/latest?format=json").read)
43
+ @mutex.synchronize do
44
+ latest.each do |r|
45
+ add_rate_synchronized(r['source'], r['target'], r['rate'])
46
+ add_rate_synchronized(r['target'], r['source'], 1.0 / r['rate'])
47
+ end
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,138 @@
1
+ # encoding: utf-8
2
+
3
+ require 'money/currencies'
4
+ require 'money/formats'
5
+
6
+ module Money
7
+
8
+ class UnknownCurrency < StandardError; end
9
+ class UnknownRate < StandardError; end
10
+
11
+ # Money::Money is the central place for working with
12
+ # monetary values. You can create a new +Money+ instance
13
+ # by one of these methods:
14
+ #
15
+ # Initializing with amount and currency:
16
+ #
17
+ # m = Money::Money.new(1.99, "EUR")
18
+ #
19
+ # Initializing with amount only.
20
+ # The +default_currency+ will then be used:
21
+ #
22
+ # m = Money::Money.new(1.99)
23
+ #
24
+ class Money
25
+ include Comparable
26
+
27
+ attr_reader :amount, :currency, :bank
28
+
29
+ class << self
30
+ attr_accessor :default_bank
31
+ attr_accessor :default_currency
32
+ attr_accessor :default_locale
33
+
34
+ def same_currency?(source, target)
35
+ source.upcase == target.upcase
36
+ end
37
+ end
38
+
39
+ self.default_bank = MeplatoBank.instance
40
+ self.default_currency = "USD"
41
+ self.default_locale = "en"
42
+
43
+ def initialize(amount, currency = Money.default_currency, bank = Money.default_bank)
44
+ @amount, @currency, @bank = amount, currency || Money.default_currency, bank || Money.default_bank
45
+ raise UnknownCurrency unless CURRENCIES[@currency]
46
+ end
47
+
48
+ def positive?
49
+ @amount && @amount > 0
50
+ end
51
+
52
+ def negative?
53
+ @amount && @amount < 0
54
+ end
55
+
56
+ def zero?
57
+ @amount && @amount == 0
58
+ end
59
+
60
+ def nan?
61
+ @amount.nil?
62
+ end
63
+
64
+ def ==(other)
65
+ self.amount == other.amount && Money.same_currency?(self.currency, other.currency)
66
+ end
67
+
68
+ def <=>(other)
69
+ if Money.same_currency?(@currency, other.currency)
70
+ @amount <=> other.amount
71
+ else
72
+ @amount <=> other.exchange_to(@currency).amount
73
+ end
74
+ end
75
+
76
+ def +(other)
77
+ if Money.same_currency?(@currency, other.currency)
78
+ Money.new(@amount + other.amount, @currency)
79
+ else
80
+ Money.new(@amount + other.exchange_to(@currency).amount, @currency)
81
+ end
82
+ end
83
+
84
+ def -(other)
85
+ if Money.same_currency?(@currency, other.currency)
86
+ Money.new(@amount - other.amount, @currency)
87
+ else
88
+ Money.new(@amount - other.exchange_to(@currency).amount, @currency)
89
+ end
90
+ end
91
+
92
+ def exchange_to(target)
93
+ unless Money.same_currency?(@currency, target)
94
+ rate = self.bank.get_rate(@currency, target)
95
+ if !rate
96
+ raise UnknownRate, "No conversion from #{@currency} to #{target}"
97
+ end
98
+ Money.new(@amount * rate, target)
99
+ else
100
+ self
101
+ end
102
+ end
103
+
104
+ def as_euro
105
+ self.exchange_to("EUR")
106
+ end
107
+
108
+ def format(options = {})
109
+ defaults = {
110
+ :locale => self.class.default_locale,
111
+ :bank => @bank,
112
+ :currency => @currency
113
+ }
114
+ MoneyFormatter.new(self, defaults.merge(options)).to_s
115
+ end
116
+
117
+ def to_s(options = {})
118
+ self.format(options)
119
+ end
120
+
121
+ def self.parse(value, currency, options = {})
122
+ return Money.new(0, currency, options) if value.nil?
123
+ opts = {
124
+ :locale => default_locale,
125
+ :bank => default_bank,
126
+ :currency => currency || default_currency
127
+ }.merge(options)
128
+ format = FORMATS[opts[:locale]]
129
+ # TODO there's a special case e.g. "($12,345,678.90)" that has to be converted to -12345678.90
130
+ s = value.gsub(/[^0-9\-#{format[:decimal_sep]}]/, '')
131
+ s.gsub!(format[:decimal_sep], '.')
132
+ Money.new(s.to_f, opts[:currency], opts)
133
+ end
134
+
135
+ private
136
+
137
+ end
138
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+
3
+ require 'money/currencies'
4
+ require 'money/formats'
5
+
6
+ module Money
7
+ # Money::MoneyFormatter persues locale-specific
8
+ # formatting of a +Money+ instance.
9
+ #
10
+ # m = Money::Money.new(100, "EUR")
11
+ # puts MoneyFormatter.new(m, :locale => "de-DE")
12
+ #
13
+ # or as a shortcut:
14
+ #
15
+ # m = Money::Money.new(100, "EUR")
16
+ # puts m.format(:locale => "de-DE")
17
+ #
18
+ class MoneyFormatter
19
+
20
+ attr_reader :money, :locale, :bank
21
+
22
+ def initialize(money, options = {})
23
+ @money = money
24
+ @locale = options[:locale] || Money.default_locale
25
+ @locale.gsub!(/_/, '-')
26
+ @bank = options[:bank] || Money.default_bank
27
+ @format = FORMATS[@locale]
28
+ @currency_symbol = CURRENCIES[@money.currency][:symbol]
29
+ end
30
+
31
+ def to_s
32
+ unless @money.nan?
33
+ pattern = @money.positive? || @money.zero? ? @format[:pos_pattern] : @format[:neg_pattern]
34
+ precision = CURRENCIES[@money.currency][:decimal_digits] # @format[:decimal_digits]
35
+ # divisor = 10 ** precision
36
+ #if @money.amount.round(2) == 1.77
37
+ # puts ""
38
+ # puts "Money = #{@money.amount} #{@money.currency}"
39
+ # puts " Prec: #{precision}"
40
+ # puts " Divi: #{divisor}"
41
+ #end
42
+ number = number_with_precision(
43
+ @money.amount.to_f.abs, # / divisor,
44
+ precision,
45
+ @format[:decimal_sep],
46
+ @format[:group_sep])
47
+ pattern.gsub("n", number).gsub("$", @currency_symbol)
48
+ end
49
+ end
50
+
51
+ private
52
+
53
+ # Shamelessly stolen from actionpack
54
+ def number_with_precision(number, precision, separator, delimiter)
55
+ begin
56
+ rounded_number = (Float(number) * (10 ** precision)).round.to_f / 10 ** precision
57
+ number = "%01.#{precision}f" % rounded_number
58
+ parts = number.to_s.split('.')
59
+ parts[0].gsub!(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1#{delimiter}")
60
+ parts.join(separator)
61
+ rescue
62
+ number
63
+ end
64
+ end
65
+
66
+ end
67
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: meplato-money
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Oliver Eilhard
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-10-12 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: &70300784862420 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '1.0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: *70300784862420
25
+ - !ruby/object:Gem::Dependency
26
+ name: rdoc
27
+ requirement: &70300784861960 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.5'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *70300784861960
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70300784861500 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0.8'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *70300784861500
47
+ description: Working with monetary values as well as performing currency exchange.
48
+ email:
49
+ - oliver.eilhard@gmail.com
50
+ executables: []
51
+ extensions: []
52
+ extra_rdoc_files:
53
+ - CHANGELOG.md
54
+ - LICENSE
55
+ - README.md
56
+ files:
57
+ - lib/money.rb
58
+ - lib/money/core_ext.rb
59
+ - lib/money/core_ext/string_ext.rb
60
+ - lib/money/core_ext/try.rb
61
+ - lib/money/currencies.rb
62
+ - lib/money/fixed_bank.rb
63
+ - lib/money/formats.rb
64
+ - lib/money/meplato_bank.rb
65
+ - lib/money/money.rb
66
+ - lib/money/money_formatter.rb
67
+ - CHANGELOG.md
68
+ - LICENSE
69
+ - README.md
70
+ homepage: http://github.com/meplato/money
71
+ licenses: []
72
+ post_install_message:
73
+ rdoc_options:
74
+ - --charset=UTF-8
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: 1.3.6
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.10
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Working with monetary values as well as performing currency exchange.
95
+ test_files: []