meplato-money 0.1.3

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.
@@ -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: []