ccy_convertor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ ZTYwZTU1NWIzNTZkOTE3N2EwMjdiYjllOTQ3ZjQzM2IzZWE1NmQxZA==
5
+ data.tar.gz: !binary |-
6
+ ZWYyN2JmMjU3M2QxMTM4ZTRmZWU3OTNkMDBlNDg0OTkxMTM0MTVhMw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ NGJhMjAzYWJiMWQzYTcxM2ZlZDA4NDI0MjZkZDVmOTRmNzYxN2U3N2EzMTM4
10
+ ODdiOTEzMTUzZTdiYjk1NWZhNTRhNTEyYTk0ZjI5ZTg3OWQ4ZmM0MmYyNDc0
11
+ NDY0YTBkYjBjZmE1ZTkzOTBhMjEwODM1Y2FkOTU4NGE4Y2M0MmI=
12
+ data.tar.gz: !binary |-
13
+ MjRkODRkN2Q0NjFiMDYxNDRmMDE3MDZiNzg0ZTQwZmQ4MDY4ZTA3ZDY5NGEx
14
+ OWYyYWIxN2JkYWFiNzNjNThkZTVmNTk0OGQ2OGEzZWNjOGM3MGYwYWJmNjMz
15
+ NTgzMmFmMDNmNzk4NGI5ODEzYjljODczZjBmMzY4M2I2ZWI4Mzc=
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Rohan Pujari
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,166 @@
1
+ # CcyConvertor
2
+
3
+ CcyConvertor provides live currency rate for various currencies and allows to convert money from one currency to other. Currently it supports 3 rate provider. New rate provider can be easily plugged in
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ ```ruby
10
+ gem 'ccy_convertor'
11
+ ```
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install ccy_convertor
20
+
21
+ ## Usage
22
+
23
+ Once gem is installed you can find out exchange rate between currency as follows
24
+ ```ruby
25
+ CcyConvertor.rate(from_ccy: 'USD', to_ccy: 'NZD') # will use default rate provider to get rate
26
+ ```
27
+ Note: Default rate provider is CcyConvertor::YahooFinance. You can change default rate provider. Check [configuration section](#configuration)
28
+
29
+ Rate provider can also be provided as a parameter. Rate provider is a class which provides rate by using rest_api
30
+ ```ruby
31
+ CcyConvertor.rate(from_ccy: 'USD', to_ccy: 'NZD', rate_provider: CcyConvertor::OpenExchangeRate)
32
+ CcyConvertor.rate(from_ccy: 'USD', to_ccy: 'NZD', rate_provider: CcyConvertor::JSONRates)
33
+ ```
34
+ You can also directly use rate provider class as follows.
35
+ ```ruby
36
+ CcyConvertor::OpenExchangeRate.rate('USD', 'INR') # will return USD/INR rate
37
+ ```
38
+ Note: CcyConvertor::OpenExchangeRate and CcyConvertor::JSONRate requires api_key. You can register at respective websites to get a api key
39
+
40
+ #### Rate Providers
41
+ | Rate provider class name | rest api source | Api key required |
42
+ |---|---|---|
43
+ | CcyConvertor::YahooFinance | 'yahoo.finance.xchange' table yql | no |
44
+ | CcyConvertor::OpenExchangeRate | www.openexchangerates.org | yes |
45
+ | CcyConvertor::JSONRate | www.jsonrates.com | yes |
46
+
47
+ Api key can be provided individually to this classes as
48
+
49
+ ```ruby
50
+ CcyConvertor::OpenExchangeRate.api_key = 'XXXXXXXXX'
51
+ CcyConvertor::OpenExchangeRate.api_key = 'XXXXXXXXX'
52
+ ```
53
+
54
+ Also check [configuration section](#configuration) to know other ways to provide api_key to rate provider classes
55
+
56
+ You can convert money from one currency to another in following ways
57
+ Below code will use rate provided from www.openexchangerates.org
58
+ ```ruby
59
+ CcyConvertor::OpenExchangeRate.convert(from_ccy: 'USD', to_ccy: 'NZD', amount: 10)
60
+ 10.usd.to_nzd(rate_provider: Ccyconvertor::OpenExchangeRate)
61
+ ```
62
+
63
+ Below code will use default rate provider. Default rate provider is configurable . Check [configuration section](#configuration)
64
+ ```ruby
65
+ CcyConvertor.convert(from_ccy: 'USD', to_ccy: 'NZD', amount: 10)
66
+ 10.usd.to_nzd
67
+ ```
68
+ You can also get all the rates of currency with respect to particular base currency
69
+ ```ruby
70
+ Ccyconvertor::OpenExchangeRate.rate_matrix
71
+ ```
72
+ Above method will return hash with currency code as key and rate as value. All rates would be with respect to USD. OpenExchangeRate do not allow us to specify other base currency and USD is always the base currency.
73
+
74
+ For Ccyconvertor::JSONRate we can specify the base currency
75
+ ```ruby
76
+ Ccyconvertor::OpenExchangeRate.rate_matrix('NZD')
77
+ ```
78
+ All rates returned would be with respect to NZD. If no parameter is given then base currency is USD by default
79
+ Note: Ccyconvertor::YahooFinance do not support rate_matrix method
80
+
81
+ ## Configuration
82
+
83
+ You can configure following parameters
84
+
85
+ 1. default_rate-provider: Default rate provider is the rate provider which is used when no rate provider is species. Rate provider is a api service that this gem uses to provide rate. By default default rate provider is CcyConvertor::YahooFinance. Check rate providers details [here](#rate-providers)
86
+
87
+ 2. api_keys: CcyConvertor::OpenExchangeRate and CcyConvertor::JSONRate provider requires api_key. You can register at there respective sites to get the api_key
88
+
89
+ 3. cache_duration: specifies the time for which the response would be cached. By default this time is zero seconds i.e no caching is done by default. If cache_duration is 60 seconds and if you want a exchange rate of USD/INR multiple times in your application, request to rate provider would be made only once in 60 seconds and after 60 seconds next request would be made.
90
+ ActiveSupport::Cache is used for caching
91
+
92
+ 4. roud_up_rate: This takes fixnum which tells number of decimal places to which the rate would be rounded to.
93
+
94
+ 5. roud_up_amount: This takes fixnum which tells number of decimal places to which the rate would be rounded to.
95
+
96
+ Sample configuration:
97
+ ```ruby
98
+ CcyConvertor.configure do |config|
99
+ config.round_up_rate = 4
100
+ config.round_up_amount = 4
101
+ config.default_rate_provider = CcyConvertor::JSONRate
102
+ config.api_keys = {
103
+ open_exchange_rate: 'XXXXXXXXX',
104
+ json_rate: 'XXXXXX'
105
+ }
106
+ config.cache_duration = {
107
+ open_exchange_rate: 20,
108
+ yahoo_finance: 30,
109
+ json_rate: 20
110
+ }
111
+ end
112
+ ```
113
+ If you are using rails, above code can be pasted in config/initializers/ccy_convertor.rb
114
+
115
+ Note: api_keys and cache_duration expects hash. Hash key is name of the class without module name in a underscore format
116
+
117
+ ## Adding new rate provider
118
+
119
+ Its simple to add a new rate provider. You can plug in any rate provider which provides rest api.
120
+
121
+ ##### Steps for adding rate provider that support api call to get all rate in single api call:
122
+
123
+ 1. Make a class with appropriate name inherit it from CccyConvertor::RateProvider
124
+ 2. Add following class methods
125
+ ```ruby
126
+ rest_url_for_rate_matrix(base_ccy=nil)
127
+ ```
128
+ Above method should return rest api url to get rates of alll currencies.
129
+ ```ruby
130
+ rate_matrix(base_ccy=nil)
131
+ ```
132
+ Above method should return rates in hash format as
133
+ ```ruby
134
+ {
135
+ 'currency_code1' => rate with respect to base_ccy,
136
+ 'currency_code2' => rate with respect to base_ccy
137
+ }
138
+ ```
139
+ Note: currency_code should be in upper case
140
+ You can call ``` rate_matrix_response(base_ccy) ``` method inside ```rate_matrix(base_ccy)``` method to get response from url returned by ```rest_url_for_rate_matrix(base_ccy=nil)``` method
141
+ Once you get response from rate_matrix_response method you can convert it to response format as mentioned above
142
+
143
+ ##### Steps for adding rate provider that does not support api call to get all rate in single api call:
144
+
145
+ 1. Make a class with appropriate name inherit it from CccyConvertor::RateProvider
146
+ 2. Add following class methods
147
+ ```ruby
148
+ rest_url_for_rate(from_ccy, to_ccy)
149
+ ```
150
+ Above method should return url for geting exchange rate between from_ccy and to_ccy
151
+ ```ruby
152
+ rate(from_ccy, to_ccy)
153
+ ```
154
+ Above method should return exchange rate(Numeric type) between from_ccy and to_ccy. You can call ```rate_response(from_ccy, to_ccy)``` inside ```rate(from_ccy, to_ccy)``` to get response from url returned by ```rest_url_for_rate(from_ccy, to_ccy)```
155
+
156
+ Now you can directly use new rate provider added by you as an existing rate provider present in the gem. You can also use all the cofiguration present for th rate provider. If rate provider added by you require api_key, you can provide it as metioned in configurtion section.
157
+ If you want to use api_key inside you rate provider class, you can use class method api_key to access it.
158
+ Check rate providers inside lib/rate_providers for more information
159
+
160
+ ## Contributing
161
+
162
+ 1. Fork it ( https://github.com/rohanpujaris/ccy_convertor/fork )
163
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
164
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
165
+ 4. Push to the branch (`git push origin my-new-feature`)
166
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'ccy_convertor/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "ccy_convertor"
8
+ spec.version = CcyConvertor::VERSION
9
+ spec.authors = ["Rohan Pujari"]
10
+ spec.email = ["rohanpujaris@gmail.com"]
11
+ spec.summary = %q{CcyConvertor provides live currency rate for various currencies and allows to convert money from one currency to other}
12
+ spec.description = %q{CcyConvertor provides live currency rate for various currencies and allows to convert money from one currency to other. Currently it supports 3 rate provider. New rate provider can be easily plugged in}
13
+ spec.homepage = "https://github.com/rohanpujaris/ccy_convertor"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.6"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.add_runtime_dependency "activesupport", ">= 3.0"
25
+ spec.add_runtime_dependency "httparty"
26
+ end
@@ -0,0 +1,39 @@
1
+ require 'active_support/core_ext/string/inflections'
2
+ require 'active_support/cache.rb'
3
+ require 'httparty'
4
+ require 'digest/sha1'
5
+
6
+ require 'ccy_convertor/version'
7
+ require 'ccy_convertor/configuration'
8
+ require 'ccy_convertor/constant'
9
+ require 'ccy_convertor/extension'
10
+ require 'ccy_convertor/money'
11
+ require 'ccy_convertor/exception'
12
+ require 'ccy_convertor/rate_cache'
13
+ require 'ccy_convertor/process_and_validate_option'
14
+ require 'ccy_convertor/rate_providers/rate_provider'
15
+ require 'ccy_convertor/rate_providers/yahoo_finance'
16
+ require 'ccy_convertor/rate_providers/open_exchange_rate'
17
+ require 'ccy_convertor/rate_providers/json_rate'
18
+
19
+ module CcyConvertor
20
+ class << self
21
+ def rate(options)
22
+ RateProvider.process_options!(options)
23
+ RateProvider.validate_presence_of_hash_keys!(options, [:from_ccy, :to_ccy])
24
+ rate = rate_provider(options).rate(options[:to_ccy], options[:from_ccy])
25
+ return rate if CcyConvertor.configuration.round_up_rate.nil?
26
+ rate.to_f.round(CcyConvertor.configuration.round_up_rate)
27
+ end
28
+
29
+ def convert(options)
30
+ amount = rate_provider(options).convert(options)
31
+ return amount if CcyConvertor.configuration.round_up_amount.nil?
32
+ amount.to_f.round(CcyConvertor.configuration.round_up_amount)
33
+ end
34
+
35
+ def rate_provider(options)
36
+ options[:rate_provider] || CcyConvertor.configuration.default_rate_provider
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ module CcyConvertor
2
+ class << self
3
+ attr_accessor :configuration
4
+
5
+ def configuration
6
+ @configuration ||= Configuration.new
7
+ end
8
+
9
+ def configure
10
+ yield(configuration) if block_given?
11
+ end
12
+ end
13
+
14
+ class Configuration
15
+ attr_accessor :round_up_rate, :round_up_amount, :api_keys, :default_rate_provider, :cache_duration
16
+
17
+ def default_rate_provider
18
+ @default_rate_provider || CcyConvertor::YahooFinance
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,187 @@
1
+ module CcyConvertor
2
+ module Constant
3
+ CCY_CODE_AND_NAME = {
4
+ 'AED' => 'United Arab Emirates dirham',
5
+ 'AFN' => 'Afghani',
6
+ 'ALL' => 'Lek',
7
+ 'AMD' => 'Armenian Dram',
8
+ 'ANG' => 'Netherlands Antillian Guilder',
9
+ 'AOA' => 'Kwanza',
10
+ 'ARS' => 'Argentine Peso',
11
+ 'AUD' => 'Australian Dollar',
12
+ 'AWG' => 'Aruban Guilder',
13
+ 'AZN' => 'Azerbaijanian Manat',
14
+ 'BAM' => 'Convertible Marks',
15
+ 'BBD' => 'Barbados Dollar',
16
+ 'BDT' => 'Bangladeshi Taka',
17
+ 'BGN' => 'Bulgarian Lev',
18
+ 'BHD' => 'Bahraini Dinar',
19
+ 'BIF' => 'Burundian Franc',
20
+ 'BMD' => 'Bermudian Dollar (customarily known as Bermuda Dollar)',
21
+ 'BND' => 'Brunei Dollar',
22
+ 'BOB' => 'Boliviano',
23
+ 'BOV' => 'Bolivian Mvdol (Funds code)',
24
+ 'BRL' => 'Brazilian Real',
25
+ 'BSD' => 'Bahamian Dollar',
26
+ 'BTN' => 'Ngultrum',
27
+ 'BWP' => 'Pula',
28
+ 'BYR' => 'Belarussian Ruble',
29
+ 'BZD' => 'Belize Dollar',
30
+ 'CAD' => 'Canadian Dollar',
31
+ 'CDF' => 'Franc Congolais',
32
+ 'CHE' => 'WIR Euro (complementary currency)',
33
+ 'CHF' => 'Swiss Franc',
34
+ 'CHW' => 'WIR Franc (complementary currency)',
35
+ 'CLF' => 'Unidades de formento (Funds code)',
36
+ 'CLP' => 'Chilean Peso',
37
+ 'CNY' => 'Yuan Renminbi',
38
+ 'COP' => 'Colombian Peso',
39
+ 'COU' => 'Unidad de Valor Real',
40
+ 'CRC' => 'Costa Rican Colon',
41
+ 'CUP' => 'Cuban Peso',
42
+ 'CVE' => 'Cape Verde Escudo',
43
+ 'CYP' => 'Cyprus Pound',
44
+ 'CZK' => 'Czech Koruna',
45
+ 'DJF' => 'Djibouti Franc',
46
+ 'DKK' => 'Danish Krone',
47
+ 'DOP' => 'Dominican Peso',
48
+ 'DZD' => 'Algerian Dinar',
49
+ 'EEK' => 'Kroon',
50
+ 'EGP' => 'Egyptian Pound',
51
+ 'ERN' => 'Nakfa',
52
+ 'ETB' => 'Ethiopian Birr',
53
+ 'EUR' => 'Euro',
54
+ 'FJD' => 'Fiji Dollar',
55
+ 'FKP' => 'Falkland Islands Pound',
56
+ 'GBP' => 'Pound Sterling',
57
+ 'GEL' => 'Lari',
58
+ 'GHS' => 'Cedi',
59
+ 'GIP' => 'Gibraltar pound',
60
+ 'GMD' => 'Dalasi',
61
+ 'GNF' => 'Guinea Franc',
62
+ 'GTQ' => 'Quetzal',
63
+ 'GYD' => 'Guyana Dollar',
64
+ 'HKD' => 'Hong Kong Dollar',
65
+ 'HNL' => 'Lempira',
66
+ 'HRK' => 'Croatian Kuna',
67
+ 'HTG' => 'Haiti Gourde',
68
+ 'HUF' => 'Forint',
69
+ 'IDR' => 'Rupiah',
70
+ 'ILS' => 'New Israeli Shekel',
71
+ 'INR' => 'Indian Rupee',
72
+ 'IQD' => 'Iraqi Dinar',
73
+ 'IRR' => 'Iranian Rial',
74
+ 'ISK' => 'Iceland Krona',
75
+ 'JMD' => 'Jamaican Dollar',
76
+ 'JOD' => 'Jordanian Dinar',
77
+ 'JPY' => 'Japanese yen',
78
+ 'KES' => 'Kenyan Shilling',
79
+ 'KGS' => 'Som',
80
+ 'KHR' => 'Riel',
81
+ 'KMF' => 'Comoro Franc',
82
+ 'KPW' => 'North Korean Won',
83
+ 'KRW' => 'South Korean Won',
84
+ 'KWD' => 'Kuwaiti Dinar',
85
+ 'KYD' => 'Cayman Islands Dollar',
86
+ 'KZT' => 'Tenge',
87
+ 'LAK' => 'Kip',
88
+ 'LBP' => 'Lebanese Pound',
89
+ 'LKR' => 'Sri Lanka Rupee',
90
+ 'LRD' => 'Liberian Dollar',
91
+ 'LSL' => 'Loti',
92
+ 'LTL' => 'Lithuanian Litas',
93
+ 'LVL' => 'Latvian Lats',
94
+ 'LYD' => 'Libyan Dinar',
95
+ 'MAD' => 'Moroccan Dirham',
96
+ 'MDL' => 'Moldovan Leu',
97
+ 'MGA' => 'Malagasy Ariary',
98
+ 'MKD' => 'Denar',
99
+ 'MMK' => 'Kyat',
100
+ 'MNT' => 'Tugrik',
101
+ 'MOP' => 'Pataca',
102
+ 'MRO' => 'Ouguiya',
103
+ 'MTL' => 'Maltese Lira',
104
+ 'MUR' => 'Mauritius Rupee',
105
+ 'MVR' => 'Rufiyaa',
106
+ 'MWK' => 'Kwacha',
107
+ 'MXN' => 'Mexican Peso',
108
+ 'MXV' => 'Mexican Unidad de Inversion (UDI) (Funds code)',
109
+ 'MYR' => 'Malaysian Ringgit',
110
+ 'MZN' => 'Metical',
111
+ 'NAD' => 'Namibian Dollar',
112
+ 'NGN' => 'Naira',
113
+ 'NIO' => 'Cordoba Oro',
114
+ 'NOK' => 'Norwegian Krone',
115
+ 'NPR' => 'Nepalese Rupee',
116
+ 'NZD' => 'New Zealand Dollar',
117
+ 'OMR' => 'Rial Omani',
118
+ 'PAB' => 'Balboa',
119
+ 'PEN' => 'Nuevo Sol',
120
+ 'PGK' => 'Kina',
121
+ 'PHP' => 'Philippine Peso',
122
+ 'PKR' => 'Pakistan Rupee',
123
+ 'PLN' => 'Zloty',
124
+ 'PYG' => 'Guarani',
125
+ 'QAR' => 'Qatari Rial',
126
+ 'RON' => 'Romanian New Leu',
127
+ 'RSD' => 'Serbian Dinar',
128
+ 'RUB' => 'Russian Ruble',
129
+ 'RWF' => 'Rwanda Franc',
130
+ 'SAR' => 'Saudi Riyal',
131
+ 'SBD' => 'Solomon Islands Dollar',
132
+ 'SCR' => 'Seychelles Rupee',
133
+ 'SDG' => 'Sudanese Pound',
134
+ 'SEK' => 'Swedish Krona',
135
+ 'SGD' => 'Singapore Dollar',
136
+ 'SHP' => 'Saint Helena Pound',
137
+ 'SKK' => 'Slovak Koruna',
138
+ 'SLL' => 'Leone',
139
+ 'SOS' => 'Somali Shilling',
140
+ 'SRD' => 'Surinam Dollar',
141
+ 'STD' => 'Dobra',
142
+ 'SYP' => 'Syrian Pound',
143
+ 'SZL' => 'Lilangeni',
144
+ 'THB' => 'Baht',
145
+ 'TJS' => 'Somoni',
146
+ 'TMM' => 'Manat',
147
+ 'TND' => 'Tunisian Dinar',
148
+ 'TOP' => 'Pa\'anga',
149
+ 'TRY' => 'New Turkish Lira',
150
+ 'TTD' => 'Trinidad and Tobago Dollar',
151
+ 'TWD' => 'New Taiwan Dollar',
152
+ 'TZS' => 'Tanzanian Shilling',
153
+ 'UAH' => 'Hryvnia',
154
+ 'UGX' => 'Uganda Shilling',
155
+ 'USD' => 'US Dollar',
156
+ 'USN' => '',
157
+ 'USS' => '',
158
+ 'UYU' => 'Peso Uruguayo',
159
+ 'UZS' => 'Uzbekistan Som',
160
+ 'VEB' => 'Venezuelan bolivar',
161
+ 'VND' => 'Vietnamese dong',
162
+ 'VUV' => 'Vatu',
163
+ 'WST' => 'Samoan Tala',
164
+ 'XAF' => 'CFA Franc BEAC',
165
+ 'XAG' => 'Silver (one Troy ounce)',
166
+ 'XAU' => 'Gold (one Troy ounce)',
167
+ 'XBA' => 'European Composite Unit (EURCO) (Bonds market unit)',
168
+ 'XBB' => 'European Monetary Unit (E.M.U.-6) (Bonds market unit)',
169
+ 'XBC' => 'European Unit of Account 9 (E.U.A.-9) (Bonds market unit)',
170
+ 'XBD' => 'European Unit of Account 17 (E.U.A.-17) (Bonds market unit)',
171
+ 'XCD' => 'East Caribbean Dollar',
172
+ 'XDR' => 'Special Drawing Rights',
173
+ 'XFO' => 'Gold franc (special settlement currency)',
174
+ 'XFU' => 'UIC franc (special settlement currency)',
175
+ 'XOF' => 'CFA Franc BCEAO',
176
+ 'XPD' => 'Palladium (one Troy ounce)',
177
+ 'XPF' => 'CFP franc',
178
+ 'XPT' => 'Platinum (one Troy ounce)',
179
+ 'XTS' => 'Code reserved for testing purposes',
180
+ 'XXX' => 'No currency',
181
+ 'YER' => 'Yemeni Rial',
182
+ 'ZAR' => 'South African Rand',
183
+ 'ZMK' => 'Kwacha',
184
+ 'ZWD' => 'Zimbabwe Dollar'
185
+ }
186
+ end
187
+ end
@@ -0,0 +1,9 @@
1
+ module CcyConvertor
2
+ class NoApiKeyPresent < StandardError; end
3
+
4
+ class InvalidAmount < StandardError; end
5
+
6
+ class InvalidCurrencyCode < StandardError; end
7
+
8
+ class CurrencyNotSupported < StandardError; end
9
+ end
@@ -0,0 +1,5 @@
1
+ class Numeric
2
+ CcyConvertor::Constant::CCY_CODE_AND_NAME.each do |code, name|
3
+ define_method(code.downcase) { CcyConvertor::Money.new(code, self) }
4
+ end
5
+ end
@@ -0,0 +1,21 @@
1
+ module CcyConvertor
2
+ class Money
3
+ attr_accessor :code, :name, :amount
4
+
5
+ def initialize(code, amount)
6
+ @code = code
7
+ @amount = amount
8
+ end
9
+
10
+ def name
11
+ CcyConvertor::Constant::CCY_CODE_AND_NAME[code]
12
+ end
13
+
14
+ CcyConvertor::Constant::CCY_CODE_AND_NAME.each do |code, name|
15
+ define_method("to_#{code.downcase}") do |options = {}|
16
+ options.merge!(money: self, to_ccy: code)
17
+ CcyConvertor.convert(options)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
1
+ module CcyConvertor
2
+ module ProcessAndValidateOption
3
+ def process_options!(options)
4
+ unless options[:money].nil?
5
+ options.merge!(from_ccy: options[:money].code, amount: options[:money].amount)
6
+ end
7
+ end
8
+
9
+ def validate_options!(options)
10
+ validate_presence_of_hash_keys!(options, [:from_ccy, :to_ccy, :amount])
11
+ validate_amount!(options[:amount])
12
+ validate_currency_codes!([options[:from_ccy], options[:to_ccy]])
13
+ end
14
+
15
+ def validate_presence_of_hash_keys!(options, keys)
16
+ options_not_provided = keys - options.keys
17
+ if options_not_provided.count != 0
18
+ raise ArgumentError,
19
+ "argument hash should have #{options_not_provided.join(', ')} #{options_not_provided.count > 1 ? 'keys' : 'key'}"
20
+ end
21
+ end
22
+
23
+ def validate_amount!(amount)
24
+ unless amount.is_a?(Numeric)
25
+ raise CcyConvertor::InvalidAmount, 'options[:amount] must be a number'
26
+ end
27
+ end
28
+
29
+ def validate_currency_codes!(currency_codes)
30
+ currency_codes.each do |code|
31
+ unless CcyConvertor::Constant::CCY_CODE_AND_NAME[code]
32
+ raise CcyConvertor::InvalidCurrencyCode, "Currency code '#{code}' doesn't exists"
33
+ end
34
+ end
35
+ end
36
+
37
+ def validate_currency_support!(currencies, rate_matrix)
38
+ currencies.each do |ccy|
39
+ if rate_matrix[ccy].nil?
40
+ raise CcyConvertor::CurrencyNotSupported, "Currency '#{ccy}' is not supported by OpenExchangeRate"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,28 @@
1
+ module CcyConvertor
2
+ module RateCache
3
+ attr_writer :cache_duration
4
+
5
+ def cache
6
+ @cache ||= {}
7
+ @cache[rate_provider_name] ||= ActiveSupport::Cache::MemoryStore.new(expires_in: cache_duration)
8
+ end
9
+
10
+ def cache_duration
11
+ @cache_duration ||= if cache_duration_nil?
12
+ 0
13
+ else
14
+ CcyConvertor.configuration.cache_duration[rate_provider_name]
15
+ end
16
+ end
17
+
18
+ def cache_duration_nil?
19
+ @cache_duration.nil? &&
20
+ (CcyConvertor.configuration.cache_duration.nil? ||
21
+ CcyConvertor.configuration.cache_duration[rate_provider_name].nil?)
22
+ end
23
+
24
+ def cache_key(request_url)
25
+ Digest::SHA2.hexdigest request_url
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+ module CcyConvertor
2
+ class JSONRate < CcyConvertor::RateProvider
3
+ class << self
4
+ def rest_url_for_rate_matrix(base_ccy)
5
+ "http://jsonrates.com/get/?apiKey=#{api_key}&base=#{base_ccy || 'USD'}"
6
+ end
7
+
8
+ def rate_matrix(base_ccy = nil)
9
+ JSON.parse(rate_matrix_response(base_ccy))['rates']
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module CcyConvertor
2
+ class OpenExchangeRate < CcyConvertor::RateProvider
3
+ class << self
4
+ def rest_url_for_rate_matrix(base_ccy = nil)
5
+ "https://openexchangerates.org/api/latest.json?app_id=#{api_key}"
6
+ end
7
+
8
+ def rate_matrix
9
+ rate_matrix_response['rates']
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,58 @@
1
+ module CcyConvertor
2
+ class RateProvider
3
+ extend CcyConvertor::RateCache
4
+ extend CcyConvertor::ProcessAndValidateOption
5
+
6
+ class << self
7
+ attr_writer :api_key
8
+
9
+ def api_key
10
+ if api_key_nil?
11
+ raise CcyConvertor::NoApiKeyPresent, "api_key not set for #{name}"
12
+ end
13
+ @api_key ||= CcyConvertor.configuration.api_keys[rate_provider_name]
14
+ end
15
+
16
+ def api_key_nil?
17
+ @api_key.nil? &&
18
+ (CcyConvertor.configuration.api_keys.nil? ||
19
+ CcyConvertor.configuration.api_keys[rate_provider_name].nil?)
20
+ end
21
+
22
+ def rate_provider_name
23
+ self.name.demodulize.underscore.to_sym
24
+ end
25
+
26
+ def response_hash(request_url)
27
+ cache_key = cache_key(request_url)
28
+ return cache.read(cache_key) if cache.exist?(cache_key)
29
+ response = HTTParty.get(request_url).parsed_response
30
+ puts cache.write(cache_key, response, expires_in: cache_duration)
31
+ response
32
+ end
33
+
34
+ def rate_matrix_response(base_ccy = nil)
35
+ response_hash(rest_url_for_rate_matrix(base_ccy))
36
+ end
37
+
38
+ def rate_response(from_ccy, to_ccy)
39
+ response_hash(rest_url_for_rate(from_ccy, to_ccy))
40
+ end
41
+
42
+ def rate_from_rate_matrix(from_ccy, to_ccy)
43
+ rate_matrix = rate_matrix()
44
+ validate_currency_support!([from_ccy, to_ccy], rate_matrix)
45
+ rate_matrix[from_ccy].to_f / rate_matrix[to_ccy].to_f
46
+ end
47
+ alias :rate :rate_from_rate_matrix
48
+
49
+ def convert(options)
50
+ process_options!(options)
51
+ validate_options!(options)
52
+ converted_rate = options[:amount] * rate(options[:to_ccy], options[:from_ccy])
53
+ return converted_rate if CcyConvertor.configuration.round_up_amount.nil?
54
+ converted_rate.round(CcyConvertor.configuration.round_up_amount)
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ module CcyConvertor
2
+ class YahooFinance < CcyConvertor::RateProvider
3
+ class << self
4
+ def rest_url_for_rate(from_ccy, to_ccy)
5
+ 'https://query.yahooapis.com/v1/public/yql?q='\
6
+ "select%20%20Rate%20from%20yahoo.finance.xchange%20where%20pair%20in%20(%22#{to_ccy}#{from_ccy}%22)"\
7
+ '&format=json&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys'
8
+ end
9
+
10
+ def rate(from_ccy, to_ccy)
11
+ rate = rate_response(from_ccy, to_ccy)['query']['results']['rate']['Rate']
12
+ if rate.nil? || rate == 'N/A'
13
+ raise CcyConvertor::CurrencyNotSupported, "No rates available for #{from_ccy}/#{to_ccy}"
14
+ end
15
+ rate.to_f
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ module CcyConvertor
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,122 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ccy_convertor
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Rohan Pujari
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-05-21 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.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
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: activesupport
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :runtime
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: httparty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ! '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: CcyConvertor provides live currency rate for various currencies and allows
70
+ to convert money from one currency to other. Currently it supports 3 rate provider.
71
+ New rate provider can be easily plugged in
72
+ email:
73
+ - rohanpujaris@gmail.com
74
+ executables: []
75
+ extensions: []
76
+ extra_rdoc_files: []
77
+ files:
78
+ - .gitignore
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - ccy_convertor.gemspec
84
+ - lib/ccy_convertor.rb
85
+ - lib/ccy_convertor/configuration.rb
86
+ - lib/ccy_convertor/constant.rb
87
+ - lib/ccy_convertor/exception.rb
88
+ - lib/ccy_convertor/extension.rb
89
+ - lib/ccy_convertor/money.rb
90
+ - lib/ccy_convertor/process_and_validate_option.rb
91
+ - lib/ccy_convertor/rate_cache.rb
92
+ - lib/ccy_convertor/rate_providers/json_rate.rb
93
+ - lib/ccy_convertor/rate_providers/open_exchange_rate.rb
94
+ - lib/ccy_convertor/rate_providers/rate_provider.rb
95
+ - lib/ccy_convertor/rate_providers/yahoo_finance.rb
96
+ - lib/ccy_convertor/version.rb
97
+ homepage: https://github.com/rohanpujaris/ccy_convertor
98
+ licenses:
99
+ - MIT
100
+ metadata: {}
101
+ post_install_message:
102
+ rdoc_options: []
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ! '>='
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ requirements: []
116
+ rubyforge_project:
117
+ rubygems_version: 2.2.2
118
+ signing_key:
119
+ specification_version: 4
120
+ summary: CcyConvertor provides live currency rate for various currencies and allows
121
+ to convert money from one currency to other
122
+ test_files: []