nbrb_currency 1.0.1 → 2.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b19f134db3e29e87e74d1c58239099587ac8f3bfa3563a407f8ad4b84dce8690
4
+ data.tar.gz: 9c3de588bada21ac5a81179dee21b3983f15625028da3e731e92daa04e51012e
5
+ SHA512:
6
+ metadata.gz: 1fd4d6970ba3c58c1f3f153ccca68d6643172e7a4dfb0fd2c86d5cdb94e8849ef773d8d607e0de89da2c6a7b8be260e477faa5af9105b26c011b50f736f813fd
7
+ data.tar.gz: 1e1ce7921df0a8ecc44cef88438fd1094b4d38ed66d5280e86a5fd70e742559b4105f5a5f5201dfe510029c2975401a97661f1bd4b7157080699b0b4bb213881
data/CHANGELOG.md ADDED
@@ -0,0 +1,59 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [2.0.0] - 2025-12-05
6
+
7
+ ### Breaking Changes
8
+ - Minimum Ruby version now 3.1.0
9
+ - Updated to money gem ~> 6.19
10
+ - Default base currency changed from BYR to BYN (with automatic date-based selection)
11
+
12
+ ### Added
13
+ - Historical rates support with date-based exchange rates
14
+ - Dual currency support: BYR (pre-July 1, 2016) and BYN (post-July 1, 2016)
15
+ - `update_historical_rates(cache, date)` method for fetching historical rates
16
+ - `save_historical_rates(cache, date)` method for saving historical rates
17
+ - Date parameter support in `exchange()` and `exchange_with()` methods
18
+ - SAX parser for efficient XML parsing
19
+ - BigDecimal precision (5 decimal places) for accurate calculations
20
+ - `CurrencyUnavailable` exception for better error handling
21
+ - Export/import rates functionality (YAML, JSON, Ruby Marshal)
22
+ - Thread-safe transaction support via historical rates store
23
+ - Metadata in gemspec (changelog_uri, source_code_uri, bug_tracker_uri)
24
+
25
+ ### Changed
26
+ - Refactored to match eu_central_bank architecture patterns
27
+ - Updated NBRB API URLs to use HTTPS
28
+ - Modernized gemspec to RubyGems 4.0 standards
29
+ - Updated specs to RSpec 3.x standards
30
+ - Converted README from RDoc to Markdown
31
+
32
+ ### Removed
33
+ - Removed obsolete development dependencies (rr, shoulda, monetize)
34
+ - Removed support for Ruby < 3.1.0
35
+
36
+ ## [Unreleased] - 2015-04-07
37
+
38
+ ### Changed
39
+ - Updated for Money 6.x compatibility
40
+ - Fixed Money::Currency::TABLE removal in Money 5.0.0
41
+ - Fixed subunit conversion
42
+ - Updated RSpec should syntax
43
+ - Removed LVL and LTL (disappeared from NBRB XML)
44
+
45
+ ### Added
46
+ - Monetize core extensions support
47
+
48
+ ## [1.0.1] - 2011-11-02
49
+
50
+ ### Fixed
51
+ - Money version bump
52
+ - JPY currency handling workaround
53
+
54
+ ## [1.0.0] - 2011-10-26
55
+
56
+ ### Initial Release
57
+ - Basic exchange rate functionality from NBRB
58
+ - BYR currency support
59
+ - Money gem compatibility
data/README.md ADDED
@@ -0,0 +1,128 @@
1
+ # NBRB Currency
2
+
3
+ Exchange rates from the National Bank of the Republic of Belarus (NBRB). Compatible with the [money](https://github.com/RubyMoney/money) gem.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install nbrb_currency
9
+ ```
10
+
11
+ Or add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem 'nbrb_currency'
15
+ ```
16
+
17
+ ## Usage
18
+
19
+ ```ruby
20
+ require 'nbrb_currency'
21
+
22
+ # Create bank instance
23
+ bank = NbrbCurrency.new
24
+
25
+ # Update rates from NBRB
26
+ bank.update_rates
27
+
28
+ # Exchange money
29
+ money = Money.new(100_00, "USD")
30
+ money.exchange_to("BYN") # => Money.new(250_00, "BYN")
31
+ ```
32
+
33
+ ### Historical Rates
34
+
35
+ The gem supports both BYR (pre-2016) and BYN (post-2016) currencies with automatic date-based selection:
36
+
37
+ ```ruby
38
+ # Fetch historical rates for a specific date
39
+ bank.update_historical_rates(nil, Date.new(2020, 1, 15))
40
+
41
+ # Exchange with historical rates
42
+ bank.exchange(100_00, "USD", "BYN", Date.new(2020, 1, 15))
43
+
44
+ # Pre-redenomination rates (before July 1, 2016)
45
+ bank.exchange(100_00, "USD", "BYR", Date.new(2015, 1, 1))
46
+ ```
47
+
48
+ ### Caching
49
+
50
+ ```ruby
51
+ # Save rates to file
52
+ bank.save_rates('/tmp/nbrb_rates.xml')
53
+
54
+ # Load rates from cache
55
+ bank.update_rates('/tmp/nbrb_rates.xml')
56
+
57
+ # Save historical rates
58
+ bank.save_historical_rates('/tmp/nbrb_historical.xml', Date.new(2020, 1, 1))
59
+ ```
60
+
61
+ ### Export/Import Rates
62
+
63
+ ```ruby
64
+ # Export rates
65
+ yaml_string = bank.export_rates(:yaml)
66
+ json_string = bank.export_rates(:json)
67
+
68
+ # Import rates
69
+ bank.import_rates(:yaml, yaml_string)
70
+ bank.import_rates(:json, json_string)
71
+ ```
72
+
73
+ ## Currency Support
74
+
75
+ Supports major currencies including: USD, EUR, RUB, PLN, UAH, GBP, JPY, CNY, CHF, SEK, NOK, DKK, CAD, AUD, NZD, TRY, KRW, SGD, HKD.
76
+
77
+ Legacy support for BYR (Belarusian Ruble before July 1, 2016 redenomination).
78
+
79
+ ## Currency Detection
80
+
81
+ The gem automatically detects BYR vs BYN based on:
82
+ - **Date**: Before July 1, 2016 → BYR, after → BYN
83
+ - **Rate magnitude**: > 100 → BYR, < 100 → BYN (when date is ambiguous)
84
+
85
+ ## Error Handling
86
+
87
+ ```ruby
88
+ begin
89
+ bank.exchange(100, 'USD', 'XXX')
90
+ rescue CurrencyUnavailable => e
91
+ puts "Currency not supported: #{e.message}"
92
+ end
93
+ ```
94
+
95
+ ## Migrating from 1.x
96
+
97
+ ### Breaking Changes
98
+ - Minimum Ruby version: 2.x → 3.4.7
99
+ - Default currency: BYR → BYN (automatic based on date)
100
+ - API changed from XML to JSON
101
+
102
+ ### Code Changes
103
+ ```ruby
104
+ # v1.x
105
+ bank.get_rate("USD", "BYR")
106
+
107
+ # v2.0
108
+ bank.get_rate("USD", "BYN") # For current rates
109
+ bank.get_rate("USD", "BYR", Date.new(2015, 1, 1)) # For historical pre-2016
110
+ ```
111
+
112
+ ## Requirements
113
+
114
+ - Ruby >= 3.4.7
115
+ - money gem >= 6.19
116
+
117
+ ## License
118
+
119
+ MIT License. See LICENSE file for details.
120
+
121
+ ## Contributing
122
+
123
+ 1. Fork the repository
124
+ 2. Create your feature branch
125
+ 3. Add tests for your changes
126
+ 4. Commit your changes
127
+ 5. Push to the branch
128
+ 6. Create a Pull Request
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Money
4
+ module RatesStore
5
+ class NbrbHistoricalStore < Money::RatesStore::Memory
6
+ INDEX_DATE_SEPARATOR = '_AT_'
7
+
8
+ def add_rate(currency_iso_from, currency_iso_to, rate, date = nil)
9
+ transaction { rates[rate_key_for(currency_iso_from, currency_iso_to, date)] = rate }
10
+ end
11
+
12
+ def get_rate(currency_iso_from, currency_iso_to, date = nil)
13
+ transaction { rates[rate_key_for(currency_iso_from, currency_iso_to, date)] }
14
+ end
15
+
16
+ def each_rate(&)
17
+ enum = Enumerator.new do |yielder|
18
+ rates.each do |key, rate|
19
+ iso_from, iso_to = key.split(Memory::INDEX_KEY_SEPARATOR)
20
+ iso_to, date = iso_to.split(INDEX_DATE_SEPARATOR)
21
+ date = Date.parse(date) if date
22
+ yielder.yield iso_from, iso_to, rate, date
23
+ end
24
+ end
25
+
26
+ block_given? ? enum.each(&) : enum
27
+ end
28
+
29
+ private
30
+
31
+ def rate_key_for(currency_iso_from, currency_iso_to, date = nil)
32
+ key = [currency_iso_from, currency_iso_to].join(Memory::INDEX_KEY_SEPARATOR)
33
+ key = [key, date.to_s].join(INDEX_DATE_SEPARATOR) if date
34
+ key.upcase
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ class NbrbCurrency
4
+ class RatesDocument
5
+ attr_reader :rates, :updated_at
6
+
7
+ def initialize(json_data)
8
+ @rates = {}
9
+ @updated_at = nil
10
+ parse(json_data)
11
+ end
12
+
13
+ private
14
+
15
+ def parse(json_data)
16
+ data = JSON.parse(json_data)
17
+
18
+ data.each { |rate_data| add_rate_entry(rate_data) }
19
+
20
+ raise 'No rates parsed' if @rates.empty? || @updated_at.nil?
21
+ end
22
+
23
+ def add_rate_entry(rate_data)
24
+ date = Date.parse(rate_data['Date'])
25
+ @updated_at ||= date
26
+ @rates[date] ||= []
27
+
28
+ currency = rate_data['Cur_Abbreviation']
29
+ rate = rate_data['Cur_OfficialRate'].to_s
30
+ scale = rate_data['Cur_Scale'].to_s
31
+
32
+ @rates[date] << [currency, rate, scale]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NbrbCurrencyVersion
4
+ VERSION = '2.0.0'
5
+ end
data/lib/nbrb_currency.rb CHANGED
@@ -1,55 +1,238 @@
1
- require 'rubygems'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'open-uri'
3
- require 'nokogiri'
4
+ require 'json'
4
5
  require 'money'
5
6
 
6
- class InvalidCache < StandardError ; end
7
+ require_relative 'nbrb_currency/version'
8
+ require_relative 'money/rates_store/nbrb_historical_store'
9
+
10
+ class InvalidCache < StandardError; end
11
+ class CurrencyUnavailable < StandardError; end
12
+
13
+ class NbrbCurrency < Money::Bank::VariableExchange # rubocop:disable Metrics/ClassLength
14
+ include NbrbCurrencyVersion
15
+
16
+ attr_accessor :last_updated, :rates_updated_at, :historical_last_updated, :historical_rates_updated_at
17
+
18
+ SERIALIZER_DATE_SEPARATOR = '_AT_'
19
+ DECIMAL_PRECISION = 5
20
+ NBRB_RATES_URL = 'https://api.nbrb.by/exrates/rates?periodicity=0'
21
+ NBRB_HISTORICAL_URL = 'https://api.nbrb.by/exrates/rates?ondate=%s&periodicity=0'
7
22
 
8
- class NbrbCurrency < Money::Bank::VariableExchange
23
+ # BYN redenomination date: July 1, 2016 (10000:1)
24
+ REDENOMINATION_DATE = Date.new(2016, 7, 1)
25
+ # Threshold to detect BYR vs BYN (BYR rates are typically > 1000, BYN < 100)
26
+ BYR_THRESHOLD = 100
9
27
 
10
- NBRB_RATES_URL = 'http://nbrb.by/Services/XmlExRates.aspx'
11
- CURRENCIES = %w(AUD BGN UAH DKK USD EUR PLN JPY IRR ISK CAD CNY KWD LVL LTL MDL NOK RUB SGD KGS KZT TRY GBP CZK SEK CHF)
28
+ CURRENCIES = %w(USD EUR RUB PLN UAH GBP JPY CNY CHF SEK NOK DKK CAD AUD NZD TRY KRW SGD HKD).freeze
29
+ LEGACY_CURRENCIES = %w(BYR).freeze
30
+
31
+ def initialize(store = Money::RatesStore::NbrbHistoricalStore.new, &)
32
+ super
33
+ end
34
+
35
+ def update_rates(cache = nil)
36
+ update_parsed_rates(doc(cache, NBRB_RATES_URL))
37
+ end
12
38
 
13
- def update_rates(cache=nil)
14
- exchange_rates(cache).each do |exchange_rate|
15
- rate = exchange_rate.xpath("Rate").text
16
- currency = exchange_rate.xpath("CharCode").text
17
- scale = exchange_rate.xpath("Scale").text
18
- next if currency == "XDR"
19
- add_rate(currency, "BYR", (BigDecimal.new(rate) / BigDecimal.new(scale)).to_f)
39
+ def update_historical_rates(cache = nil, date = nil)
40
+ url = date ? (NBRB_HISTORICAL_URL % date.strftime('%Y-%m-%d')) : NBRB_RATES_URL
41
+ update_parsed_historical_rates(doc(cache, url))
42
+ end
43
+
44
+ def save_rates(cache, url = NBRB_RATES_URL)
45
+ raise InvalidCache unless cache
46
+
47
+ File.open(cache, 'w') do |file|
48
+ URI.parse(url).open { |io| io.each_line { |line| file.puts line } }
20
49
  end
21
- add_rate("BYR", "BYR", 1)
22
50
  end
23
51
 
24
- def save_rates(cache)
25
- raise InvalidCache if !cache
26
- File.open(cache, "w") do |file|
27
- io = open(NBRB_RATES_URL) ;
28
- io.each_line {|line| file.puts line}
52
+ def save_historical_rates(cache, date = nil)
53
+ url = date ? (NBRB_HISTORICAL_URL % date.strftime('%Y-%m-%d')) : NBRB_RATES_URL
54
+ save_rates(cache, url)
55
+ end
56
+
57
+ def exchange(cents, from_currency, to_currency, date = nil)
58
+ exchange_with(Money.new(cents, from_currency), to_currency, date)
59
+ end
60
+
61
+ def exchange_with(from, to_currency, date = nil)
62
+ base_currency = base_currency_for_date(date)
63
+ rate = get_rate(from.currency, to_currency,
64
+ date) || calculate_cross_rate(from.currency, to_currency, base_currency, date)
65
+
66
+ calculate_exchange(from, to_currency, rate)
67
+ end
68
+
69
+ def get_rate(from, to, date = nil)
70
+ return 1 if from == to
71
+
72
+ check_currency_available(from, date)
73
+ check_currency_available(to, date)
74
+
75
+ date = date[:date] if date.is_a?(Hash)
76
+
77
+ store.get_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, date)
78
+ end
79
+
80
+ def set_rate(from, to, rate, date = nil)
81
+ date = date[:date] if date.is_a?(Hash)
82
+ store.add_rate(::Money::Currency.wrap(from).iso_code, ::Money::Currency.wrap(to).iso_code, rate, date)
83
+ end
84
+
85
+ def rates
86
+ store.each_rate.with_object({}) do |(from, to, rate, date), hash|
87
+ key = [from, to].join(SERIALIZER_SEPARATOR)
88
+ key = [key, date.to_s].join(SERIALIZER_DATE_SEPARATOR) if date
89
+ hash[key] = rate
29
90
  end
30
91
  end
31
92
 
32
- def exchange(cents, from_currency, to_currency)
33
- exchange_with(Money.new(cents, from_currency), to_currency)
93
+ def export_rates(format, file = nil, _opts = {})
94
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include? format
95
+
96
+ store.transaction do
97
+ s = case format
98
+ when :json
99
+ JSON.dump(rates)
100
+ when :ruby
101
+ Marshal.dump(rates)
102
+ when :yaml
103
+ YAML.dump(rates)
104
+ end
105
+
106
+ File.write(file, s) unless file.nil?
107
+ s
108
+ end
34
109
  end
35
110
 
36
- def exchange_with(from, to_currency)
37
- rate = get_rate(from.currency, to_currency)
38
- unless rate
39
- from_base_rate = get_rate(from.currency, "BYR")
40
- to_base_rate = get_rate(to_currency, "BYR")
41
- rate = (BigDecimal.new(from_base_rate, 8) / BigDecimal.new(to_base_rate, 8)).to_f
42
- raise "Rate #{from.currency} - #{to_currency} unknown!" unless rate
111
+ def import_rates(format, data, _opts = {})
112
+ raise Money::Bank::UnknownRateFormat unless RATE_FORMATS.include? format
113
+
114
+ store.transaction do
115
+ parsed_data = parse_import_data(format, data)
116
+
117
+ parsed_data.each do |key, rate|
118
+ from, to = key.split(SERIALIZER_SEPARATOR)
119
+ to, date = to.split(SERIALIZER_DATE_SEPARATOR)
120
+ store.add_rate from, to, BigDecimal(rate, DECIMAL_PRECISION), date
121
+ end
43
122
  end
44
- Money.new(((Money::Currency.wrap(to_currency).subunit_to_unit.to_f / from.currency.subunit_to_unit.to_f) * from.cents * rate).round, to_currency)
123
+
124
+ self
125
+ end
126
+
127
+ def check_currency_available(currency, date = nil)
128
+ currency_string = currency.to_s
129
+ base = base_currency_for_date(date)
130
+ return true if currency_string == base
131
+ return true if CURRENCIES.include?(currency_string)
132
+ return true if LEGACY_CURRENCIES.include?(currency_string)
133
+
134
+ raise CurrencyUnavailable, "No rates available for #{currency_string}"
45
135
  end
46
136
 
47
137
  protected
48
138
 
49
- def exchange_rates(cache=nil)
50
- rates_source = !!cache ? cache : NBRB_RATES_URL
51
- doc = Nokogiri::XML(open(rates_source))
52
- doc.xpath('DailyExRates//Currency')
139
+ def base_currency_for_date(date)
140
+ (date && date < REDENOMINATION_DATE) ? 'BYR' : 'BYN'
141
+ end
142
+
143
+ def detect_base_currency_from_rate(usd_rate)
144
+ (usd_rate.to_f > BYR_THRESHOLD) ? 'BYR' : 'BYN'
145
+ end
146
+
147
+ def doc(cache, url = NBRB_RATES_URL)
148
+ json_data = cache ? File.read(cache) : URI.parse(url).open.read
149
+ ::NbrbCurrency::RatesDocument.new(json_data)
53
150
  end
54
151
 
152
+ def update_parsed_rates(rates_document)
153
+ store.transaction do
154
+ copy_rates_with_document_date(rates_document, false)
155
+ end
156
+ @rates_updated_at = rates_document.updated_at
157
+ @last_updated = Time.now
158
+ end
159
+
160
+ def copy_rates_with_document_date(rates_document, with_date)
161
+ rates_document.rates.each do |date, rates|
162
+ usd_rate = rates.find { |curr, _, _| curr == 'USD' }
163
+ base = usd_rate ? detect_base_currency_from_rate(usd_rate[1]) : base_currency_for_date(date)
164
+
165
+ rates.each { |currency, rate, scale| process_currency_rate(currency, rate, scale, base, with_date ? date : nil) }
166
+ set_rate(base, base, 1, with_date ? date : nil)
167
+ end
168
+ end
169
+
170
+ def update_parsed_historical_rates(rates_document)
171
+ store.transaction do
172
+ copy_rates_with_document_date(rates_document, true)
173
+ end
174
+ @historical_rates_updated_at = rates_document.updated_at
175
+ @historical_last_updated = Time.now
176
+ end
177
+
178
+ private
179
+
180
+ def parse_import_data(format, data)
181
+ case format
182
+ when :json
183
+ JSON.parse(data)
184
+ when :ruby
185
+ Marshal.load(data) # rubocop:disable Security/MarshalLoad
186
+ when :yaml
187
+ if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0')
188
+ YAML.safe_load(data, permitted_classes: [BigDecimal])
189
+ else
190
+ YAML.safe_load(data, [BigDecimal], [], true)
191
+ end
192
+ end
193
+ end
194
+
195
+ def process_currency_rate(currency, rate, scale, base, date)
196
+ return if currency == 'XDR'
197
+ return unless currency_recognized?(currency)
198
+
199
+ adjusted_rate = BigDecimal(rate, DECIMAL_PRECISION) / BigDecimal(scale, DECIMAL_PRECISION)
200
+ set_rate(currency, base, adjusted_rate, date)
201
+ end
202
+
203
+ def currency_recognized?(currency)
204
+ Money::Currency.wrap(currency)
205
+ true
206
+ rescue Money::Currency::UnknownCurrency
207
+ false
208
+ end
209
+
210
+ def calculate_cross_rate(from_currency, to_currency, base_currency, date)
211
+ from_base_rate = nil
212
+ to_base_rate = nil
213
+
214
+ store.transaction do
215
+ from_base_rate = get_rate(from_currency.to_s, base_currency, date)
216
+ to_base_rate = get_rate(to_currency, base_currency, date)
217
+ end
218
+
219
+ unless from_base_rate && to_base_rate
220
+ message = "No conversion rate known for '#{from_currency.iso_code}' -> '#{to_currency}'"
221
+ message << " on #{date}" if date
222
+ raise Money::Bank::UnknownRate, message
223
+ end
224
+
225
+ from_base_rate / to_base_rate
226
+ end
227
+
228
+ def calculate_exchange(from, to_currency, rate)
229
+ to_currency_money = Money::Currency.wrap(to_currency).subunit_to_unit
230
+ from_currency_money = from.currency.subunit_to_unit
231
+ decimal_money = BigDecimal(to_currency_money,
232
+ DECIMAL_PRECISION) / BigDecimal(from_currency_money, DECIMAL_PRECISION)
233
+ money = (decimal_money * from.cents * rate).round
234
+ Money.new(money, to_currency)
235
+ end
55
236
  end
237
+
238
+ require_relative 'nbrb_currency/rates_document'
metadata CHANGED
@@ -1,115 +1,82 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nbrb_currency
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
5
- prerelease:
4
+ version: 2.0.0
6
5
  platform: ruby
7
6
  authors:
8
- - Aleks Grebennik
9
- autorequire:
7
+ - Alexander Grebennik
10
8
  bindir: bin
11
9
  cert_chain: []
12
- date: 2011-11-02 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
13
11
  dependencies:
14
12
  - !ruby/object:Gem::Dependency
15
- name: nokogiri
16
- requirement: &13578880 !ruby/object:Gem::Requirement
17
- none: false
13
+ name: bigdecimal
14
+ requirement: !ruby/object:Gem::Requirement
18
15
  requirements:
19
- - - ! '>='
16
+ - - ">="
20
17
  - !ruby/object:Gem::Version
21
18
  version: '0'
22
19
  type: :runtime
23
20
  prerelease: false
24
- version_requirements: *13578880
25
- - !ruby/object:Gem::Dependency
26
- name: money
27
- requirement: &13577320 !ruby/object:Gem::Requirement
28
- none: false
21
+ version_requirements: !ruby/object:Gem::Requirement
29
22
  requirements:
30
- - - ~>
23
+ - - ">="
31
24
  - !ruby/object:Gem::Version
32
- version: 4.0.1
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: *13577320
36
- - !ruby/object:Gem::Dependency
37
- name: rspec
38
- requirement: &13576480 !ruby/object:Gem::Requirement
39
- none: false
40
- requirements:
41
- - - ! '>='
42
- - !ruby/object:Gem::Version
43
- version: 2.0.0
44
- type: :development
45
- prerelease: false
46
- version_requirements: *13576480
25
+ version: '0'
47
26
  - !ruby/object:Gem::Dependency
48
- name: rr
49
- requirement: &13565740 !ruby/object:Gem::Requirement
50
- none: false
27
+ name: money
28
+ requirement: !ruby/object:Gem::Requirement
51
29
  requirements:
52
- - - ! '>='
30
+ - - ">="
53
31
  - !ruby/object:Gem::Version
54
- version: '0'
55
- type: :development
32
+ version: '6.19'
33
+ type: :runtime
56
34
  prerelease: false
57
- version_requirements: *13565740
58
- - !ruby/object:Gem::Dependency
59
- name: shoulda
60
- requirement: &13564440 !ruby/object:Gem::Requirement
61
- none: false
35
+ version_requirements: !ruby/object:Gem::Requirement
62
36
  requirements:
63
- - - ! '>='
37
+ - - ">="
64
38
  - !ruby/object:Gem::Version
65
- version: '0'
66
- type: :development
67
- prerelease: false
68
- version_requirements: *13564440
39
+ version: '6.19'
69
40
  description: This gem reads exchange rates from the National Bank of the Republic
70
41
  of Belarus website. It uses it to calculates exchange rates. It is compatible with
71
42
  the money gem
72
43
  email:
73
- - aleks.grebennik@gmail.com
44
+ - sl.bug.sl@gmail.com
74
45
  executables: []
75
46
  extensions: []
76
47
  extra_rdoc_files: []
77
48
  files:
78
- - .gitignore
79
- - Gemfile
49
+ - CHANGELOG.md
80
50
  - LICENSE
81
- - README.rdoc
82
- - Rakefile
51
+ - README.md
52
+ - lib/money/rates_store/nbrb_historical_store.rb
83
53
  - lib/nbrb_currency.rb
84
- - nbrb_currency.gemspec
85
- - spec/exchange_rates.xml
86
- - spec/exchange_rates.yml
87
- - spec/nbrb_currency_spec.rb
88
- - spec/spec_helper.rb
89
- - spec/tmp/.gitkeep
90
- homepage: http://github.com/slbug/nbrb_currency
91
- licenses: []
92
- post_install_message:
54
+ - lib/nbrb_currency/rates_document.rb
55
+ - lib/nbrb_currency/version.rb
56
+ homepage: https://github.com/slbug/nbrb_currency
57
+ licenses:
58
+ - MIT
59
+ metadata:
60
+ changelog_uri: https://github.com/slbug/nbrb_currency/blob/main/CHANGELOG.md
61
+ source_code_uri: https://github.com/slbug/nbrb_currency
62
+ bug_tracker_uri: https://github.com/slbug/nbrb_currency/issues
63
+ rubygems_mfa_required: 'true'
93
64
  rdoc_options: []
94
65
  require_paths:
95
66
  - lib
96
67
  required_ruby_version: !ruby/object:Gem::Requirement
97
- none: false
98
68
  requirements:
99
- - - ! '>='
69
+ - - ">="
100
70
  - !ruby/object:Gem::Version
101
- version: '0'
71
+ version: 3.4.7
102
72
  required_rubygems_version: !ruby/object:Gem::Requirement
103
- none: false
104
73
  requirements:
105
- - - ! '>='
74
+ - - ">="
106
75
  - !ruby/object:Gem::Version
107
- version: 1.3.6
76
+ version: '0'
108
77
  requirements: []
109
- rubyforge_project:
110
- rubygems_version: 1.8.11
111
- signing_key:
112
- specification_version: 3
78
+ rubygems_version: 3.7.2
79
+ specification_version: 4
113
80
  summary: Calculates exchange rates based on rates from National Bank of the Republic
114
81
  of Belarus. Money gem compatible.
115
82
  test_files: []
data/.gitignore DELETED
@@ -1,4 +0,0 @@
1
- *.gem
2
- .bundle
3
- Gemfile.lock
4
- pkg/*
data/Gemfile DELETED
@@ -1,3 +0,0 @@
1
- source "http://rubygems.org"
2
-
3
- gemspec
data/README.rdoc DELETED
@@ -1,31 +0,0 @@
1
- = nbrb_currency
2
-
3
- == Introduction
4
-
5
- This gem downloads the exchange rates from the National Bank of the Republic of Belarus. You can calculate exchange rates with it. It is compatible with the money gem.
6
-
7
- == Installation
8
-
9
- $ gem install nbrb_currency
10
-
11
- == Dependencies
12
-
13
- * nokogiri
14
- * money
15
-
16
- == Usage
17
-
18
- Check documentation for https://github.com/RubyMoney/eu_central_bank, it's almost the same
19
-
20
- == Note on Patches/Pull Requests
21
-
22
- * Fork the project.
23
- * Make your feature addition or bug fix.
24
- * Add tests for it. This is important so I don't break it in a
25
- future version unintentionally.
26
- * Commit, do not mess with rakefile, version, or history.
27
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
28
-
29
- == Copyright
30
-
31
- Copyright (c) 2010 RubyMoney. See LICENSE for details.
data/Rakefile DELETED
@@ -1,11 +0,0 @@
1
- require "bundler/gem_tasks"
2
-
3
- begin
4
- require 'rspec/core/rake_task'
5
- RSpec::Core::RakeTask.new
6
- rescue LoadError
7
- task(:spec){abort "`gem install rspec` to run specs"}
8
- end
9
-
10
- task :default => :spec
11
-
@@ -1,27 +0,0 @@
1
- # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
-
4
- Gem::Specification.new do |s|
5
- s.name = "nbrb_currency"
6
- s.version = "1.0.1"
7
- s.platform = Gem::Platform::RUBY
8
- s.authors = ["Aleks Grebennik"]
9
- s.email = ["aleks.grebennik@gmail.com"]
10
- s.homepage = "http://github.com/slbug/nbrb_currency"
11
- s.summary = %q{Calculates exchange rates based on rates from National Bank of the Republic of Belarus. Money gem compatible.}
12
- s.description = %q{This gem reads exchange rates from the National Bank of the Republic of Belarus website. It uses it to calculates exchange rates. It is compatible with the money gem}
13
-
14
- s.required_rubygems_version = ">= 1.3.6"
15
-
16
- s.add_dependency "nokogiri"
17
- s.add_dependency "money", "~> 4.0.1"
18
-
19
- s.add_development_dependency "rspec", ">= 2.0.0"
20
- s.add_development_dependency "rr"
21
- s.add_development_dependency "shoulda"
22
-
23
- s.files = `git ls-files`.split("\n")
24
- s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
26
- s.require_paths = ["lib"]
27
- end
@@ -1,192 +0,0 @@
1
- <?xml version="1.0" encoding="windows-1251"?>
2
- <DailyExRates Date="10/26/2011">
3
- <Currency Id="170">
4
- <NumCode>036</NumCode>
5
- <CharCode>AUD</CharCode>
6
- <Scale>1</Scale>
7
- <Name>������������� ������</Name>
8
- <Rate>8920.87</Rate>
9
- </Currency>
10
- <Currency Id="191">
11
- <NumCode>975</NumCode>
12
- <CharCode>BGN</CharCode>
13
- <Scale>1</Scale>
14
- <Name>������c��� ���</Name>
15
- <Rate>6059.74</Rate>
16
- </Currency>
17
- <Currency Id="224">
18
- <NumCode>980</NumCode>
19
- <CharCode>UAH</CharCode>
20
- <Scale>1</Scale>
21
- <Name>������</Name>
22
- <Rate>1064.87</Rate>
23
- </Currency>
24
- <Currency Id="36">
25
- <NumCode>208</NumCode>
26
- <CharCode>DKK</CharCode>
27
- <Scale>1</Scale>
28
- <Name>������� �����</Name>
29
- <Rate>1592.06</Rate>
30
- </Currency>
31
- <Currency Id="145">
32
- <NumCode>840</NumCode>
33
- <CharCode>USD</CharCode>
34
- <Scale>1</Scale>
35
- <Name>������ ���</Name>
36
- <Rate>8520</Rate>
37
- </Currency>
38
- <Currency Id="19">
39
- <NumCode>978</NumCode>
40
- <CharCode>EUR</CharCode>
41
- <Scale>1</Scale>
42
- <Name>����</Name>
43
- <Rate>11860</Rate>
44
- </Currency>
45
- <Currency Id="166">
46
- <NumCode>960</NumCode>
47
- <CharCode>XDR</CharCode>
48
- <Scale>1</Scale>
49
- <Name>������� ��� (SDR) �� ���</Name>
50
- <Rate>13467.99</Rate>
51
- </Currency>
52
- <Currency Id="219">
53
- <NumCode>985</NumCode>
54
- <CharCode>PLN</CharCode>
55
- <Scale>1</Scale>
56
- <Name>������</Name>
57
- <Rate>2714.33</Rate>
58
- </Currency>
59
- <Currency Id="67">
60
- <NumCode>392</NumCode>
61
- <CharCode>JPY</CharCode>
62
- <Scale>10</Scale>
63
- <Name>����</Name>
64
- <Rate>1119.43</Rate>
65
- </Currency>
66
- <Currency Id="264">
67
- <NumCode>364</NumCode>
68
- <CharCode>IRR</CharCode>
69
- <Scale>1000</Scale>
70
- <Name>�������� ����</Name>
71
- <Rate>794.63</Rate>
72
- </Currency>
73
- <Currency Id="58">
74
- <NumCode>352</NumCode>
75
- <CharCode>ISK</CharCode>
76
- <Scale>1</Scale>
77
- <Name>���������� �����</Name>
78
- <Rate>74.54</Rate>
79
- </Currency>
80
- <Currency Id="23">
81
- <NumCode>124</NumCode>
82
- <CharCode>CAD</CharCode>
83
- <Scale>1</Scale>
84
- <Name>��������� ������</Name>
85
- <Rate>8494.94</Rate>
86
- </Currency>
87
- <Currency Id="254">
88
- <NumCode>156</NumCode>
89
- <CharCode>CNY</CharCode>
90
- <Scale>1</Scale>
91
- <Name>��������� ����</Name>
92
- <Rate>1339.46</Rate>
93
- </Currency>
94
- <Currency Id="72">
95
- <NumCode>414</NumCode>
96
- <CharCode>KWD</CharCode>
97
- <Scale>1</Scale>
98
- <Name>���������� �����</Name>
99
- <Rate>30996.47</Rate>
100
- </Currency>
101
- <Currency Id="176">
102
- <NumCode>428</NumCode>
103
- <CharCode>LVL</CharCode>
104
- <Scale>1</Scale>
105
- <Name>���������� ���</Name>
106
- <Rate>16836.28</Rate>
107
- </Currency>
108
- <Currency Id="177">
109
- <NumCode>440</NumCode>
110
- <CharCode>LTL</CharCode>
111
- <Scale>1</Scale>
112
- <Name>��������� ���</Name>
113
- <Rate>3432.51</Rate>
114
- </Currency>
115
- <Currency Id="178">
116
- <NumCode>498</NumCode>
117
- <CharCode>MDL</CharCode>
118
- <Scale>1</Scale>
119
- <Name>���������� ���</Name>
120
- <Rate>730.39</Rate>
121
- </Currency>
122
- <Currency Id="101">
123
- <NumCode>578</NumCode>
124
- <CharCode>NOK</CharCode>
125
- <Scale>1</Scale>
126
- <Name>���������� �����</Name>
127
- <Rate>1544.71</Rate>
128
- </Currency>
129
- <Currency Id="190">
130
- <NumCode>643</NumCode>
131
- <CharCode>RUB</CharCode>
132
- <Scale>1</Scale>
133
- <Name>���������� �����</Name>
134
- <Rate>279</Rate>
135
- </Currency>
136
- <Currency Id="119">
137
- <NumCode>702</NumCode>
138
- <CharCode>SGD</CharCode>
139
- <Scale>1</Scale>
140
- <Name>��������c��� ������</Name>
141
- <Rate>6743.71</Rate>
142
- </Currency>
143
- <Currency Id="223">
144
- <NumCode>417</NumCode>
145
- <CharCode>KGS</CharCode>
146
- <Scale>1</Scale>
147
- <Name>���</Name>
148
- <Rate>187.97</Rate>
149
- </Currency>
150
- <Currency Id="222">
151
- <NumCode>398</NumCode>
152
- <CharCode>KZT</CharCode>
153
- <Scale>1</Scale>
154
- <Name>�����</Name>
155
- <Rate>57.58</Rate>
156
- </Currency>
157
- <Currency Id="256">
158
- <NumCode>949</NumCode>
159
- <CharCode>TRY</CharCode>
160
- <Scale>1</Scale>
161
- <Name>�������� ����</Name>
162
- <Rate>4714.74</Rate>
163
- </Currency>
164
- <Currency Id="143">
165
- <NumCode>826</NumCode>
166
- <CharCode>GBP</CharCode>
167
- <Scale>1</Scale>
168
- <Name>���� ����������</Name>
169
- <Rate>13618.37</Rate>
170
- </Currency>
171
- <Currency Id="171">
172
- <NumCode>203</NumCode>
173
- <CharCode>CZK</CharCode>
174
- <Scale>1</Scale>
175
- <Name>������� �����</Name>
176
- <Rate>475.9</Rate>
177
- </Currency>
178
- <Currency Id="129">
179
- <NumCode>752</NumCode>
180
- <CharCode>SEK</CharCode>
181
- <Scale>1</Scale>
182
- <Name>�������� �����</Name>
183
- <Rate>1300.6</Rate>
184
- </Currency>
185
- <Currency Id="130">
186
- <NumCode>756</NumCode>
187
- <CharCode>CHF</CharCode>
188
- <Scale>1</Scale>
189
- <Name>����������� �����</Name>
190
- <Rate>9684.57</Rate>
191
- </Currency>
192
- </DailyExRates>
@@ -1,28 +0,0 @@
1
- currencies:
2
- AUD: 8920.87
3
- BGN: 6059.74
4
- UAH: 1064.87
5
- DKK: 1592.06
6
- USD: 8520
7
- EUR: 11860
8
- PLN: 2714.33
9
- JPY: 111.943
10
- IRR: 0.79463
11
- ISK: 74.54
12
- CAD: 8494.94
13
- CNY: 1339.46
14
- KWD: 30996.47
15
- LVL: 16836.28
16
- LTL: 3432.51
17
- MDL: 730.39
18
- NOK: 1544.71
19
- RUB: 279
20
- SGD: 6743.71
21
- KGS: 187.97
22
- KZT: 57.58
23
- TRY: 4714.74
24
- GBP: 13618.37
25
- CZK: 475.9
26
- SEK: 1300.6
27
- CHF: 9684.57
28
-
@@ -1,79 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
- require 'yaml'
3
-
4
- describe "NbrbCurrency" do
5
- before(:each) do
6
- @bank = NbrbCurrency.new
7
- @cache_path = File.expand_path(File.dirname(__FILE__) + '/exchange_rates.xml')
8
- @yml_cache_path = File.expand_path(File.dirname(__FILE__) + '/exchange_rates.yml')
9
- @tmp_cache_path = File.expand_path(File.dirname(__FILE__) + '/tmp/exchange_rates.xml')
10
- @exchange_rates = YAML.load_file(@yml_cache_path)
11
- end
12
-
13
- after(:each) do
14
- if File.exists? @tmp_cache_path
15
- File.delete @tmp_cache_path
16
- end
17
- end
18
-
19
- it "should save the xml file from nbrb given a file path" do
20
- @bank.save_rates(@tmp_cache_path)
21
- File.exists?(@tmp_cache_path).should == true
22
- end
23
-
24
- it "should raise an error if an invalid path is given to save_rates" do
25
- lambda { @bank.save_rates(nil) }.should raise_exception
26
- end
27
-
28
- it "should update itself with exchange rates from nbrb website" do
29
- stub(OpenURI::OpenRead).open(NbrbCurrency::NBRB_RATES_URL) {@cache_path}
30
- @bank.update_rates
31
- NbrbCurrency::CURRENCIES.each do |currency|
32
- @bank.get_rate(currency, "BYR").should > 0
33
- end
34
- end
35
-
36
- it "should update itself with exchange rates from cache" do
37
- @bank.update_rates(@cache_path)
38
- NbrbCurrency::CURRENCIES.each do |currency|
39
- @bank.get_rate(currency, "BYR").should > 0
40
- end
41
- end
42
-
43
- it "should return the correct exchange rates using exchange" do
44
- @bank.update_rates(@cache_path)
45
- NbrbCurrency::CURRENCIES.reject{|c| %w{JPY KWD}.include?(c) }.each do |currency|
46
- @bank.exchange(100, currency, "BYR").cents.should == (@exchange_rates["currencies"][currency].to_f * 100).round
47
- end
48
- subunit = Money::Currency.wrap("KWD").subunit_to_unit.to_f
49
- @bank.exchange(1000, "KWD", "BYR").cents.should == ((subunit / 1000) * @exchange_rates["currencies"]['KWD'].to_f * 100).round
50
- subunit = Money::Currency.wrap("JPY").subunit_to_unit.to_f
51
- @bank.exchange(100, "JPY", "BYR").cents.should == ((subunit * 100) * @exchange_rates["currencies"]['JPY'].to_f * 100).round
52
- end
53
-
54
- it "should return the correct exchange rates using exchange_with" do
55
- @bank.update_rates(@cache_path)
56
- NbrbCurrency::CURRENCIES.reject{|c| %w{JPY KWD}.include?(c) }.each do |currency|
57
- @bank.exchange_with(Money.new(100, currency), "BYR").cents.should == (@exchange_rates["currencies"][currency].to_f * 100).round
58
- @bank.exchange_with(1.to_money(currency), "BYR").cents.should == (@exchange_rates["currencies"][currency].to_f * 100).round
59
- end
60
- @bank.exchange_with(5000.to_money('JPY'), 'BYR').cents.should == 55971500 # 559715 BYR
61
- end
62
-
63
- # in response to #4
64
- it "should exchange btc" do
65
- Money::Currency::TABLE[:btc] = {
66
- :priority => 1,
67
- :iso_code => "BTC",
68
- :name => "Bitcoin",
69
- :symbol => "BTC",
70
- :subunit => "Cent",
71
- :subunit_to_unit => 1000,
72
- :separator => ".",
73
- :delimiter => ","
74
- }
75
- @bank.add_rate("USD", "BTC", 1 / 13.7603)
76
- @bank.add_rate("BTC", "USD", 13.7603)
77
- @bank.exchange(100, "BTC", "USD").cents.should == 138
78
- end
79
- end
data/spec/spec_helper.rb DELETED
@@ -1,7 +0,0 @@
1
- require 'nbrb_currency'
2
- require 'shoulda'
3
- require 'rr'
4
-
5
- RSpec.configure do |config|
6
- config.mock_with :rr
7
- end
data/spec/tmp/.gitkeep DELETED
File without changes