puppy_money 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +38 -0
- data/Rakefile +6 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/puppy_money/currencies.rb +7 -0
- data/lib/puppy_money/currency_data.rb +1118 -0
- data/lib/puppy_money/money.rb +89 -0
- data/lib/puppy_money/rate_api.rb +22 -0
- data/lib/puppy_money/version.rb +3 -0
- data/lib/puppy_money.rb +5 -0
- data/puppy_money.gemspec +34 -0
- metadata +159 -0
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'active_support/core_ext/object/try'
|
2
|
+
require_relative 'currencies'
|
3
|
+
require_relative 'rate_api'
|
4
|
+
|
5
|
+
class Money
|
6
|
+
attr_reader :amount, :currency, :manual_currencies
|
7
|
+
|
8
|
+
# use optional_rates for manual currency conversion
|
9
|
+
def initialize amount, currency, manual_currencies={}
|
10
|
+
validate_amount amount
|
11
|
+
validate_currency currency.try(:upcase)
|
12
|
+
|
13
|
+
# validate manual currency unless it is a non_standard currency (e.g. bitcoin)
|
14
|
+
manual_currencies.each do |name, info|
|
15
|
+
validate_currency name.to_s.upcase unless info[:non_standard]
|
16
|
+
end
|
17
|
+
|
18
|
+
@amount = amount.round(2)
|
19
|
+
@currency = currency.try(:upcase)
|
20
|
+
@manual_currencies = manual_currencies
|
21
|
+
end
|
22
|
+
|
23
|
+
def inspect
|
24
|
+
"#{@amount} #{@currency}"
|
25
|
+
end
|
26
|
+
|
27
|
+
def convert_to transfer_currency, non_standard=false
|
28
|
+
transfer_currency = transfer_currency.try(:upcase)
|
29
|
+
# validate the transfer currency unless:
|
30
|
+
## 1. user explicitly specifies that it is a non-standard currency (e.g. bitcoin)
|
31
|
+
validate_currency transfer_currency unless non_standard
|
32
|
+
# use real-time exchange rates if:
|
33
|
+
## 1. user has not provided exchange rates manually
|
34
|
+
## 2 given transfer currency is not supported
|
35
|
+
if @manual_currencies.empty? && RateApi.fetch_symbols(@currency).include?(transfer_currency)
|
36
|
+
transfer_rate = RateApi.fetch_transfer_rate(@currency, transfer_currency)
|
37
|
+
Money.new(@amount * transfer_rate, transfer_currency)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# money object arithmetic and comparison
|
42
|
+
[:+, :-, :*, :/, :==, :>, :>=, :<, :<=, :<=>].each do |operation|
|
43
|
+
define_method(operation) do |other|
|
44
|
+
if [:+, :-, :*, :/].include? operation
|
45
|
+
if @currency == other.currency
|
46
|
+
Money.new(@amount.public_send(operation, other.amount), @currency)
|
47
|
+
else
|
48
|
+
[
|
49
|
+
Money.new(@amount.public_send(operation, other.conversion_amount(@currency)), @currency),
|
50
|
+
Money.new(self.conversion_amount(other.currency).public_send(operation, other.amount), other.currency)
|
51
|
+
]
|
52
|
+
end
|
53
|
+
else
|
54
|
+
if @currency == other.currency
|
55
|
+
@amount.public_send(operation, other.amount)
|
56
|
+
else
|
57
|
+
@amount.public_send(operation, other.conversion_amount(@currency))
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def conversion_amount transfer_currency
|
64
|
+
convert_to(transfer_currency).amount
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def validate_amount amount
|
70
|
+
# ensure that the amount is a numeric value
|
71
|
+
raise ArgumentError, "Amount must be a number" unless amount.is_a? Numeric
|
72
|
+
end
|
73
|
+
|
74
|
+
def validate_currency currency, manual_rates=false
|
75
|
+
if manual_rates
|
76
|
+
currency.map do |c|
|
77
|
+
# raise an error if manual rate is not recognized
|
78
|
+
raise ArgumentError, currency_error(currency) unless Currencies.abbreviations.include? c.to_s.upcase
|
79
|
+
end
|
80
|
+
else
|
81
|
+
# raise an error if base rate is not recognized
|
82
|
+
raise ArgumentError, currency_error(currency) unless Currencies.abbreviations.include?(currency)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def currency_error(currency)
|
87
|
+
" `#{currency}` is an invalid (currency abbreviation must be a recognized 3 character string)"
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'httparty'
|
2
|
+
|
3
|
+
module RateApi
|
4
|
+
# needs refactoring!!!
|
5
|
+
|
6
|
+
# get complete rate info
|
7
|
+
def self.rate_request base_currency
|
8
|
+
HTTParty.get "http://api.fixer.io/latest?base=#{base_currency}"
|
9
|
+
end
|
10
|
+
|
11
|
+
# get rate symbol abbreviations
|
12
|
+
def self.fetch_symbols base_currency
|
13
|
+
rate_info = self.rate_request base_currency
|
14
|
+
rate_info['rates'].keys << rate_info['base']
|
15
|
+
end
|
16
|
+
|
17
|
+
# return a transfer rate
|
18
|
+
def self.fetch_transfer_rate base_currency, transfer_currency
|
19
|
+
xrates = self.rate_request base_currency
|
20
|
+
xrates['rates'][transfer_currency]
|
21
|
+
end
|
22
|
+
end
|
data/lib/puppy_money.rb
ADDED
data/puppy_money.gemspec
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'puppy_money/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "puppy_money"
|
8
|
+
spec.version = PuppyMoney::VERSION
|
9
|
+
spec.authors = ["Dan Kreiger"]
|
10
|
+
spec.email = ["dan@dankreiger.com"]
|
11
|
+
|
12
|
+
spec.summary = %q{Easy currency conversion}
|
13
|
+
spec.description = %q{Convert currencies using live exchange rates.}
|
14
|
+
spec.homepage = "https://github.com/dankreiger/puppy_money"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.bindir = "exe"
|
21
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
|
24
|
+
# development
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.14"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
28
|
+
spec.add_development_dependency "pry", "~> 0.10"
|
29
|
+
spec.add_development_dependency "irbtools", "~> 2.1"
|
30
|
+
|
31
|
+
# runtime
|
32
|
+
spec.add_runtime_dependency "activesupport", "~> 5.0"
|
33
|
+
spec.add_runtime_dependency "httparty", "~> 0.14"
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: puppy_money
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Dan Kreiger
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.14'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.14'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0.10'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0.10'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: irbtools
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '2.1'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.1'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: activesupport
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '5.0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '5.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: httparty
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0.14'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0.14'
|
111
|
+
description: Convert currencies using live exchange rates.
|
112
|
+
email:
|
113
|
+
- dan@dankreiger.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".gitignore"
|
119
|
+
- ".rspec"
|
120
|
+
- ".travis.yml"
|
121
|
+
- CODE_OF_CONDUCT.md
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- bin/console
|
127
|
+
- bin/setup
|
128
|
+
- lib/puppy_money.rb
|
129
|
+
- lib/puppy_money/currencies.rb
|
130
|
+
- lib/puppy_money/currency_data.rb
|
131
|
+
- lib/puppy_money/money.rb
|
132
|
+
- lib/puppy_money/rate_api.rb
|
133
|
+
- lib/puppy_money/version.rb
|
134
|
+
- puppy_money.gemspec
|
135
|
+
homepage: https://github.com/dankreiger/puppy_money
|
136
|
+
licenses:
|
137
|
+
- MIT
|
138
|
+
metadata: {}
|
139
|
+
post_install_message:
|
140
|
+
rdoc_options: []
|
141
|
+
require_paths:
|
142
|
+
- lib
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
requirements:
|
145
|
+
- - ">="
|
146
|
+
- !ruby/object:Gem::Version
|
147
|
+
version: '0'
|
148
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
153
|
+
requirements: []
|
154
|
+
rubyforge_project:
|
155
|
+
rubygems_version: 2.6.11
|
156
|
+
signing_key:
|
157
|
+
specification_version: 4
|
158
|
+
summary: Easy currency conversion
|
159
|
+
test_files: []
|