bloomberg_currency 1.1.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 +4 -4
- data/.github/FUNDING.yml +3 -0
- data/.github/dependabot.yml +15 -0
- data/.github/workflows/ci.yml +35 -0
- data/.gitignore +1 -3
- data/.rubocop.yml +9 -7
- data/.rubocop_todo.yml +3 -3
- data/.ruby_version +1 -1
- data/.simplecov +3 -1
- data/README.md +58 -36
- data/bin/fetch.js +28 -0
- data/bin/setup +1 -2
- data/bloomberg_currency.gemspec +17 -18
- data/lib/bloomberg_currency/api/{host.rb → errors/site_load_error.rb} +3 -2
- data/lib/bloomberg_currency/api/parser.rb +43 -0
- data/lib/bloomberg_currency/api/site.rb +50 -76
- data/lib/bloomberg_currency/api/site_loader.rb +18 -0
- data/lib/bloomberg_currency/api.rb +0 -3
- data/lib/bloomberg_currency/quote.rb +49 -10
- data/lib/bloomberg_currency/quote_detail.rb +44 -20
- data/lib/bloomberg_currency/version.rb +1 -1
- data/lib/bloomberg_currency.rb +5 -2
- data/package-lock.json +101 -0
- data/package.json +12 -0
- metadata +56 -64
- data/.travis.yml +0 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3a734585f1c78f69aa036254c97cf008d815185c61df21ceb1acf9c670ccbca8
|
|
4
|
+
data.tar.gz: befcfc665db447c41dfc9d484f5bb3ff50d3d7b05891030846585acfd4d80dc7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f77fe3509fc9bdd96f154fce1b6ed592679d3e9fe2712bf0af5cedc6dce3f1298bc06b63f4684f69bb608e622f7ac2753ac7dcc727e877d75410b8bfe26af741
|
|
7
|
+
data.tar.gz: 9341ff720130bb1bd26d33142873b9eeca003277691e6165952be2a972c699e0ec92faf31403a6938595601e52ca52f6444dc915582948cb5c8bb5b7ae81f4df
|
data/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
- package-ecosystem: bundler
|
|
4
|
+
directory: "/"
|
|
5
|
+
schedule:
|
|
6
|
+
interval: daily
|
|
7
|
+
time: "10:00"
|
|
8
|
+
open-pull-requests-limit: 10
|
|
9
|
+
target-branch: master
|
|
10
|
+
ignore:
|
|
11
|
+
- dependency-name: rubocop
|
|
12
|
+
versions:
|
|
13
|
+
- 1.11.0
|
|
14
|
+
- 1.12.0
|
|
15
|
+
- 1.12.1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [master]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
|
|
16
|
+
- name: Set up Ruby
|
|
17
|
+
uses: ruby/setup-ruby@v1
|
|
18
|
+
with:
|
|
19
|
+
ruby-version: 3.3.0
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: gem install bundler -v 2.6.9
|
|
23
|
+
|
|
24
|
+
- name: Bundle install
|
|
25
|
+
run: bundle _2.6.9_ install --jobs 4 --retry 3
|
|
26
|
+
|
|
27
|
+
- name: Run tests
|
|
28
|
+
run: bundle exec rspec
|
|
29
|
+
|
|
30
|
+
- name: Upload coverage report
|
|
31
|
+
if: always()
|
|
32
|
+
uses: actions/upload-artifact@v4
|
|
33
|
+
with:
|
|
34
|
+
name: coverage-report
|
|
35
|
+
path: coverage/
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
|
@@ -1,18 +1,20 @@
|
|
|
1
1
|
inherit_from: .rubocop_todo.yml
|
|
2
2
|
|
|
3
3
|
AllCops:
|
|
4
|
+
NewCops: enable
|
|
4
5
|
Include:
|
|
5
|
-
-
|
|
6
|
-
-
|
|
6
|
+
- "**/Rakefile"
|
|
7
|
+
- "**/config.ru"
|
|
7
8
|
Exclude:
|
|
8
9
|
- bloomberg_currency.gemspec
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
10
|
+
- "db/**/*"
|
|
11
|
+
- "config/**/*"
|
|
12
|
+
- "script/**/*"
|
|
13
|
+
- "spec/**/*"
|
|
14
|
+
- "bin/**/*"
|
|
13
15
|
- !ruby/regexp /old_and_unused\.rb$/
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
Layout/LineLength:
|
|
16
18
|
Max: 120
|
|
17
19
|
|
|
18
20
|
Metrics/MethodLength:
|
data/.rubocop_todo.yml
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
# Cop supports --auto-correct.
|
|
11
11
|
Layout/EmptyLineAfterMagicComment:
|
|
12
12
|
Exclude:
|
|
13
|
-
-
|
|
13
|
+
- "Gemfile"
|
|
14
14
|
|
|
15
15
|
# Offense count: 1
|
|
16
16
|
# Configuration parameters: CountComments, ExcludedMethods.
|
|
@@ -20,6 +20,6 @@ Metrics/BlockLength:
|
|
|
20
20
|
# Offense count: 1
|
|
21
21
|
# Configuration parameters: ExpectMatchingDefinition, Regex, IgnoreExecutableScripts, AllowedAcronyms.
|
|
22
22
|
# AllowedAcronyms: CLI, DSL, ACL, API, ASCII, CPU, CSS, DNS, EOF, GUID, HTML, HTTP, HTTPS, ID, IP, JSON, LHS, QPS, RAM, RHS, RPC, SLA, SMTP, SQL, SSH, TCP, TLS, TTL, UDP, UI, UID, UUID, URI, URL, UTF8, VM, XML, XMPP, XSRF, XSS
|
|
23
|
-
|
|
23
|
+
Naming/FileName:
|
|
24
24
|
Exclude:
|
|
25
|
-
-
|
|
25
|
+
- "Gemfile"
|
data/.ruby_version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
3.3.0
|
data/.simplecov
CHANGED
data/README.md
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# Bloomberg Currency
|
|
2
2
|
|
|
3
|
-
[](https://github.com/sebasjimenez10/bloomberg_currency/actions/workflows/ci.yml)
|
|
4
|
+
[](https://badge.fury.io/rb/bloomberg_currency)
|
|
4
5
|
|
|
5
6
|
Bloomberg Currency provides an easy-to-use API to pull currency exchange rates from the Bloomberg site. If you would like to test out this gem before including it into your project, feel free to clone it, bundle it and run `bin/console` for an interactive prompt.
|
|
6
7
|
|
|
@@ -14,68 +15,91 @@ gem 'bloomberg_currency'
|
|
|
14
15
|
|
|
15
16
|
And then execute:
|
|
16
17
|
|
|
17
|
-
|
|
18
|
+
```
|
|
19
|
+
$ bundle
|
|
20
|
+
```
|
|
18
21
|
|
|
19
22
|
Or install it yourself as:
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
```
|
|
25
|
+
$ gem install bloomberg_currency
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Lastest changes
|
|
29
|
+
|
|
30
|
+
Version `2.0.0` uses Playwright to spin up a headfull chromium browser to load the page content to bypass robot checks. The browser session lasts about ~3 secs. It is recommended to cache results for at least 1 min to prevent being flagged by Bloombergs site.
|
|
31
|
+
|
|
32
|
+
A `fetch.js` script has been added to `bin`. This script is called from ruby to load the site.
|
|
22
33
|
|
|
23
34
|
## Usage
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
_NOTE_: From version `1.1.2` to `2.0.0` there are mayor breaking changes. Please make sure you read the docs before installing/upgrading to the newest version.
|
|
26
37
|
|
|
27
|
-
|
|
38
|
+
_NOTE_: From version `0.1.0` to `1.0.0` there are mayor breaking changes. Please make sure you read the docs before installing/upgrading to the newest version.
|
|
28
39
|
|
|
29
40
|
```
|
|
30
|
-
quote = BC::Quote.new('USD', '
|
|
31
|
-
=>
|
|
41
|
+
quote = BC::Quote.new(currency_one: 'USD', currency_two: 'COP')
|
|
42
|
+
=>
|
|
43
|
+
#<BC::Quote:0x0000000122256368
|
|
44
|
+
@delta=18.36,
|
|
45
|
+
@delta_percent=0.4462999999523163,
|
|
46
|
+
@detail=#<BC::QuoteDetail:0x0000000122178db0 @day_range=4112.38..4136.93, @fifty_two_week_range=3843.94..4545.83, @high=4136.93, @low=4112.38, @open=4120.68, @previous_close=4113.85, @total_return_ytd=-6.21>,
|
|
47
|
+
@last_updated_at=#<DateTime: 2025-05-28T16:45:27+00:00 ((2460824j,60327s,0n),+0s,2299161j)>,
|
|
48
|
+
@name="USDCOP Spot Exchange Rate - Price of 1 USD in COP",
|
|
49
|
+
@price=4132.21>
|
|
50
|
+
|
|
32
51
|
quote.detail
|
|
33
|
-
=> #<BC::QuoteDetail:
|
|
52
|
+
=> #<BC::QuoteDetail:0x0000000122178db0 @day_range=4112.38..4136.93, @fifty_two_week_range=3843.94..4545.83, @high=4136.93, @low=4112.38, @open=4120.68, @previous_close=4113.85, @total_return_ytd=-6.21>
|
|
34
53
|
```
|
|
35
54
|
|
|
36
|
-
|
|
55
|
+
The `BC::Quote` quote object offers the following accessor methods:
|
|
37
56
|
|
|
38
|
-
- `
|
|
39
|
-
- `
|
|
40
|
-
- `
|
|
41
|
-
- `
|
|
57
|
+
- `name` - The name of the currency or financial instrument.
|
|
58
|
+
- `detail` - Additional details or description about the currency or instrument.
|
|
59
|
+
- `price` - The current price or value.
|
|
60
|
+
- `delta` - The absolute change in price since the last update.
|
|
61
|
+
- `delta_percent` - The percentage change in price since the last update.
|
|
62
|
+
- `last_updated_at` - The timestamp indicating when the data was last updated.
|
|
42
63
|
|
|
64
|
+
The `BC::QuoteDetail` detail object offers the following accessor methods:
|
|
43
65
|
|
|
44
|
-
|
|
66
|
+
- `previous_close` - The previous closing price (Float)
|
|
67
|
+
- `low` - The lowest price of the day (Float)
|
|
68
|
+
- `high` - The highest price of the day (Float)
|
|
69
|
+
- `open` - The opening price (Float)
|
|
70
|
+
- `day_range` - The price range for the day (Range)
|
|
71
|
+
- `fifty_two_week_range` - The 52-week price range (Range)
|
|
72
|
+
- `total_return_ytd` - The total return year-to-date (Float)
|
|
45
73
|
|
|
46
|
-
|
|
47
|
-
- `day_range`: Returns the day range up until the moment the quote is generated.
|
|
48
|
-
- `previous_close`: Returns the value where the exchange closed last day.
|
|
49
|
-
- `last_52_weeks_range`: Returns the range od the last 52 weeks.
|
|
50
|
-
- `ytd_return`: Returns the YTD percentage.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
*NOTE*: When the some of the markets close, the `open` and `day_range` attributes on the Bloomberg site aren't displayed. So those attributes may not be present if the market is closed. But the quote may still be available.
|
|
74
|
+
The rest of the classes are intended for internal use and should not be used outside of the `BC::Quote` implementation.
|
|
54
75
|
|
|
55
76
|
## Examples
|
|
56
77
|
|
|
57
|
-
Getting information about the USD and
|
|
78
|
+
Getting information about the USD and COP exchange:
|
|
58
79
|
|
|
59
80
|
```
|
|
60
|
-
quote = BC::Quote.new('USD', '
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
81
|
+
quote = BC::Quote.new(currency_one: 'USD', currency_two: 'COP')
|
|
82
|
+
=>
|
|
83
|
+
#<BC::Quote:0x0000000122256368
|
|
84
|
+
@delta=18.36,
|
|
85
|
+
@delta_percent=0.4462999999523163,
|
|
86
|
+
@detail=#<BC::QuoteDetail:0x0000000122178db0 @day_range=4112.38..4136.93, @fifty_two_week_range=3843.94..4545.83, @high=4136.93, @low=4112.38, @open=4120.68, @previous_close=4113.85, @total_return_ytd=-6.21>,
|
|
87
|
+
@last_updated_at=#<DateTime: 2025-05-28T16:45:27+00:00 ((2460824j,60327s,0n),+0s,2299161j)>,
|
|
88
|
+
@name="USDCOP Spot Exchange Rate - Price of 1 USD in COP",
|
|
89
|
+
@price=4132.21>
|
|
90
|
+
|
|
91
|
+
# Inspect the quote detail
|
|
66
92
|
|
|
67
93
|
quote.detail
|
|
68
|
-
=> #<BC::QuoteDetail:
|
|
69
|
-
|
|
70
|
-
quote.available?
|
|
71
|
-
=> true
|
|
72
|
-
|
|
94
|
+
=> #<BC::QuoteDetail:0x0000000122178db0 @day_range=4112.38..4136.93, @fifty_two_week_range=3843.94..4545.83, @high=4136.93, @low=4112.38, @open=4120.68, @previous_close=4113.85, @total_return_ytd=-6.21>
|
|
73
95
|
```
|
|
74
96
|
|
|
75
97
|
## Development
|
|
76
98
|
|
|
77
99
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rspec spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
78
100
|
|
|
101
|
+
The setup step will require node in your machine, as it will install npm dependencies. These are required to run Playwright.
|
|
102
|
+
|
|
79
103
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
|
80
104
|
|
|
81
105
|
If you would like to contribute please fork the repository, make your changes and create a PR.
|
|
@@ -86,8 +110,6 @@ To release a new version, update the version number in `version.rb`, and then ru
|
|
|
86
110
|
|
|
87
111
|
Bug reports and pull requests are welcome on GitHub at https://github.com/sebasjimenez10/bloomberg_currency. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
|
88
112
|
|
|
89
|
-
|
|
90
113
|
## License
|
|
91
114
|
|
|
92
115
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
|
93
|
-
|
data/bin/fetch.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { chromium } = require('playwright-extra');
|
|
4
|
+
|
|
5
|
+
const ticker = process.argv[2]
|
|
6
|
+
const url = `https://www.bloomberg.com/quote/${ticker}`;
|
|
7
|
+
|
|
8
|
+
if (!ticker) {
|
|
9
|
+
console.error('Error: No ticker provided. Usage: node bin/fetch.js USDEUR:CUR');
|
|
10
|
+
process.exit(1);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
(async () => {
|
|
14
|
+
const browser = await chromium.launch({ headless: false });
|
|
15
|
+
const page = await browser.newPage();
|
|
16
|
+
|
|
17
|
+
// Load the page (don't wait for network to fully idle)
|
|
18
|
+
// Allow dynamic content
|
|
19
|
+
await page.goto(url);
|
|
20
|
+
await page.waitForTimeout(3000);
|
|
21
|
+
|
|
22
|
+
// Print full page HTML content
|
|
23
|
+
const content = await page.content();
|
|
24
|
+
console.log(content);
|
|
25
|
+
|
|
26
|
+
// Close browser
|
|
27
|
+
await browser.close();
|
|
28
|
+
})();
|
data/bin/setup
CHANGED
data/bloomberg_currency.gemspec
CHANGED
|
@@ -9,40 +9,39 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.name = 'bloomberg_currency'
|
|
10
10
|
spec.version = BC::VERSION
|
|
11
11
|
spec.authors = ['Sebastian Jimenez Velez']
|
|
12
|
-
spec.email = ['
|
|
12
|
+
spec.email = ['sebastian@rocktlab.com']
|
|
13
13
|
|
|
14
14
|
spec.summary = 'Bloomberg Currency helps you pull currency rates data from the Bloomberg website'
|
|
15
15
|
spec.description = 'Provides an easy to use API to get currency rates data from the Bloomberg website'
|
|
16
16
|
spec.homepage = 'https://github.com/sebasjimenez10/bloomberg_currency'
|
|
17
17
|
spec.license = 'MIT'
|
|
18
18
|
|
|
19
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
|
20
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
|
21
19
|
if spec.respond_to?(:metadata)
|
|
22
20
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
|
23
21
|
else
|
|
24
|
-
raise 'RubyGems 2.0 or newer is required to protect against '
|
|
25
|
-
'public gem pushes.'
|
|
22
|
+
raise 'RubyGems 2.0 or newer is required to protect against public gem pushes.'
|
|
26
23
|
end
|
|
27
24
|
|
|
28
25
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
29
26
|
f.match(%r{^(test|spec|features)/})
|
|
30
27
|
end
|
|
31
28
|
|
|
32
|
-
spec.bindir = '
|
|
29
|
+
spec.bindir = 'bin'
|
|
33
30
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
34
31
|
spec.require_paths = ['lib']
|
|
35
32
|
|
|
36
|
-
|
|
37
|
-
spec.
|
|
38
|
-
spec.
|
|
39
|
-
spec.
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
spec.add_development_dependency '
|
|
43
|
-
spec.add_development_dependency '
|
|
44
|
-
spec.add_development_dependency '
|
|
45
|
-
|
|
46
|
-
spec.
|
|
47
|
-
spec.
|
|
33
|
+
# Runtime dependencies
|
|
34
|
+
spec.add_runtime_dependency 'bigdecimal'
|
|
35
|
+
spec.add_runtime_dependency 'faraday', '~> 2.13'
|
|
36
|
+
spec.add_runtime_dependency 'nokogiri', '~> 1.18'
|
|
37
|
+
|
|
38
|
+
# Development dependencies
|
|
39
|
+
spec.add_development_dependency 'bundler', '~> 2.6'
|
|
40
|
+
spec.add_development_dependency 'rake', '~> 13.2'
|
|
41
|
+
spec.add_development_dependency 'rspec', '~> 3.13'
|
|
42
|
+
spec.add_development_dependency 'simplecov', '~> 0.13.0'
|
|
43
|
+
spec.add_development_dependency 'rubocop', '~> 1.75'
|
|
44
|
+
spec.add_development_dependency 'rubocop-rake', '~> 0.7.1'
|
|
45
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 3.6.0'
|
|
46
|
+
spec.add_development_dependency 'pry-byebug', '~> 3.11'
|
|
48
47
|
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BC
|
|
4
|
+
module API
|
|
5
|
+
# Provides methods to parse various data types from strings
|
|
6
|
+
# such as prices, datetimes, and ranges.
|
|
7
|
+
#
|
|
8
|
+
# @example
|
|
9
|
+
# price = BC::API::Parser.parse_price("$1,234.56")
|
|
10
|
+
# puts price # => 1234.56
|
|
11
|
+
# datetime = BC::API::Parser.parse_datetime("2023-10-01T12:00:00.000Z")
|
|
12
|
+
# puts datetime # => #<DateTime: 2023-10-01T12:00:00+00:00 ((2459550j,43200s,0n),+0s,2299161j)>
|
|
13
|
+
# tr_ytd = BC::API::Parser.parse_tr_ytd("5%")
|
|
14
|
+
# puts tr_ytd # => 5.0
|
|
15
|
+
# price_range = BC::API::Parser.parse_price_range(["$1,000.00", "$1,500.00"])
|
|
16
|
+
# puts price_range # => 1000.0..1500.0
|
|
17
|
+
# @see BC::API::Site
|
|
18
|
+
# @see BC::Quote
|
|
19
|
+
# @see BC::QuoteDetail
|
|
20
|
+
class Parser
|
|
21
|
+
class << self
|
|
22
|
+
def parse_price(price_str)
|
|
23
|
+
raw_price_str = price_str.gsub(/[^\d.,\-]/, '')
|
|
24
|
+
raw_price_str.delete(',').to_f
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def parse_datetime(datetime_str)
|
|
28
|
+
::DateTime.strptime(datetime_str, '%Y-%m-%dT%H:%M:%S.%LZ')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def parse_tr_ytd(tr_ytd_str)
|
|
32
|
+
tr_ytd_str.delete("%").tr("–—−", "-").to_f
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def parse_price_range(price_range_arr)
|
|
36
|
+
lower = parse_price(price_range_arr[0])
|
|
37
|
+
upper = parse_price(price_range_arr[1])
|
|
38
|
+
lower..upper
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -1,91 +1,65 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Implements scraping of currency quote data from a site using a provided site loader.
|
|
4
|
+
#
|
|
5
|
+
# @example
|
|
6
|
+
# site = BC::API::Site.new("USD", "EUR")
|
|
7
|
+
# quote = site.quote
|
|
8
|
+
#
|
|
9
|
+
# @attr_reader [Object] site_loader The loader responsible for fetching site data.
|
|
10
|
+
#
|
|
11
|
+
# @!attribute [r] site_loader
|
|
12
|
+
# @return [Object] the site loader used to fetch the site data.
|
|
13
|
+
#
|
|
14
|
+
# @param currency_one [String] The base currency code (e.g., "USD").
|
|
15
|
+
# @param currency_two [String] The quote currency code (e.g., "EUR").
|
|
16
|
+
# @param site_loader [Object] The loader class/module used to fetch the site (default: BC::API::SiteLoader).
|
|
17
|
+
#
|
|
18
|
+
# @method quote
|
|
19
|
+
# Fetches and parses the quote data for the given currency pair.
|
|
20
|
+
# @return [Hash, nil] The parsed quote data as a hash, or nil if not found.
|
|
21
|
+
#
|
|
22
|
+
# @!visibility private
|
|
23
|
+
# @method load_site(site_loader)
|
|
24
|
+
# Loads the site for the currency pair using the provided site loader.
|
|
25
|
+
# @param site_loader [Object] The loader to use for fetching the site.
|
|
26
|
+
# @return [Object] The loaded site document.
|
|
27
|
+
#
|
|
28
|
+
# @method build_quote_hash(document)
|
|
29
|
+
# Extracts and parses the quote JSON from the loaded site document.
|
|
30
|
+
# @param document [Object] The loaded site document.
|
|
31
|
+
# @return [Hash, nil] The parsed quote data as a hash, or nil if not found.
|
|
32
|
+
|
|
3
33
|
module BC
|
|
4
34
|
module API
|
|
5
35
|
# Implements site scrapping
|
|
6
36
|
class Site
|
|
7
|
-
|
|
8
|
-
def quote(currency_one, currency_two)
|
|
9
|
-
process(currency_one, currency_two)
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
private
|
|
13
|
-
|
|
14
|
-
def process(currency_one, currency_two)
|
|
15
|
-
site = load_site(currency_one, currency_two)
|
|
16
|
-
parse(site)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def load_site(currency_one, currency_two)
|
|
20
|
-
url = "#{BC::API::Host::URL}#{currency_one}#{currency_two}:CUR"
|
|
21
|
-
headers = {
|
|
22
|
-
'user-agent' => BC::API::USER_AGENT,
|
|
23
|
-
'referer' => 'https://www.google.com/'
|
|
24
|
-
}
|
|
25
|
-
file = Faraday.get(url, nil, headers)
|
|
26
|
-
|
|
27
|
-
Nokogiri::HTML(file.body)
|
|
28
|
-
end
|
|
37
|
+
JSON_QUOTE_XPATH = "//script[@id='__NEXT_DATA__']"
|
|
29
38
|
|
|
30
|
-
|
|
31
|
-
parse_quote(document)
|
|
32
|
-
rescue
|
|
33
|
-
{ price: nil, datetime: nil, detail: nil, available: false }
|
|
34
|
-
end
|
|
39
|
+
attr_reader :site_loader
|
|
35
40
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
price = price_element.text.strip.tr(',', '').to_f
|
|
42
|
-
datetime = calculate_datetime(price_datetime_element.children.first.text.strip)
|
|
43
|
-
details_hash = quote_details(detailed_quote_container)
|
|
44
|
-
|
|
45
|
-
{ price: price, datetime: datetime, detail: BC::QuoteDetail.new(details_hash), available: true }
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def quote_details(container)
|
|
49
|
-
open_price = extract_value_from_detail(container, 'openprice')
|
|
50
|
-
previous_close = extract_value_from_detail(container, 'previousclosingpriceonetradingdayago')
|
|
51
|
-
total_return_ytd = extract_value_from_detail(container, 'totalreturnytd')
|
|
52
|
-
range_one_day = extract_values_for_range(container, 'rangeoneday')
|
|
53
|
-
range_52_weeks = extract_values_for_range(container, 'range52weeks')
|
|
41
|
+
def initialize(currency_one, currency_two, site_loader = BC::API::SiteLoader)
|
|
42
|
+
@currency_one = currency_one
|
|
43
|
+
@currency_two = currency_two
|
|
44
|
+
@site_loader = site_loader
|
|
45
|
+
end
|
|
54
46
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
range_52_wks: range_52_weeks,
|
|
60
|
-
ytd_return: total_return_ytd
|
|
61
|
-
}
|
|
62
|
-
end
|
|
47
|
+
def quote
|
|
48
|
+
document = load_site(site_loader)
|
|
49
|
+
build_quote_hash(document)
|
|
50
|
+
end
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
container
|
|
66
|
-
.xpath("//section[contains(@class, '#{section}')]")
|
|
67
|
-
.children[1].text
|
|
68
|
-
end
|
|
52
|
+
private
|
|
69
53
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
.children[0]
|
|
75
|
-
.children
|
|
76
|
-
.map(&:text)
|
|
77
|
-
.join('-')
|
|
78
|
-
end
|
|
54
|
+
def load_site(site_loader)
|
|
55
|
+
ticker = "#{@currency_one}#{@currency_two}:CUR"
|
|
56
|
+
site_loader.load_site(ticker)
|
|
57
|
+
end
|
|
79
58
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
::DateTime.strptime(datetime_str, 'As of %m/%d/%Y').to_date
|
|
85
|
-
end
|
|
86
|
-
rescue
|
|
87
|
-
''
|
|
88
|
-
end
|
|
59
|
+
def build_quote_hash(document)
|
|
60
|
+
json_tag = document.xpath(JSON_QUOTE_XPATH)
|
|
61
|
+
json_quote = JSON.parse(json_tag.text.strip).dig("props", "pageProps", "quote")
|
|
62
|
+
json_quote
|
|
89
63
|
end
|
|
90
64
|
end
|
|
91
65
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BC
|
|
4
|
+
module API
|
|
5
|
+
class SiteLoader
|
|
6
|
+
class << self
|
|
7
|
+
SCRIPT_PATH = File.expand_path('../../../../bin/fetch.js', __FILE__)
|
|
8
|
+
|
|
9
|
+
def load_site(ticker)
|
|
10
|
+
output, status = Open3.capture2("node #{SCRIPT_PATH} #{ticker}")
|
|
11
|
+
return Nokogiri::HTML(output) if status.success?
|
|
12
|
+
|
|
13
|
+
raise BC::API::Errors::SiteLoadError, "Failed to fetch ticker #{ticker}: #{output}"
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -1,21 +1,60 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# = BC
|
|
4
|
+
#
|
|
5
|
+
# The BC module provides classes and methods for retrieving and representing currency quotes
|
|
6
|
+
# from Bloomberg. It acts as a namespace for all related classes, including {BC::Quote},
|
|
7
|
+
# {BC::API::Site}, {BC::API::Parser}, and {BC::QuoteDetail}.
|
|
8
|
+
#
|
|
9
|
+
# == Examples
|
|
10
|
+
#
|
|
11
|
+
# quote = BC::Quote.new(currency_one: "USD", currency_two: "COP")
|
|
12
|
+
# puts quote.name # => "US Dollar / Colombian Peso"
|
|
13
|
+
# puts quote.price # => 4000.0
|
|
14
|
+
# puts quote.delta # => 10.5
|
|
15
|
+
# puts quote.delta_percent # => 0.26
|
|
16
|
+
# puts quote.last_updated_at # => 2024-06-10 15:30:00 +0000
|
|
17
|
+
#
|
|
18
|
+
# == See Also
|
|
19
|
+
#
|
|
20
|
+
# * BC::API::Site
|
|
21
|
+
# * BC::API::Parser
|
|
22
|
+
# * BC::QuoteDetail
|
|
23
|
+
#
|
|
24
|
+
# == Errors
|
|
25
|
+
#
|
|
26
|
+
# * BC::API::Errors::SiteLoadError - if the site cannot be loaded
|
|
27
|
+
# * JSON::ParserError - if the JSON cannot be parsed
|
|
3
28
|
module BC
|
|
4
|
-
#
|
|
29
|
+
# Represents a currency quote
|
|
5
30
|
class Quote
|
|
6
|
-
|
|
31
|
+
attr_reader :name, :detail, :price, :delta, :delta_percent, :last_updated_at
|
|
7
32
|
|
|
8
|
-
def initialize(currency_one
|
|
9
|
-
|
|
33
|
+
def initialize(currency_one:, currency_two:)
|
|
34
|
+
quote_data = BC::API::Site.new(currency_one, currency_two).quote
|
|
10
35
|
|
|
11
|
-
@price
|
|
12
|
-
@
|
|
13
|
-
@
|
|
14
|
-
@
|
|
36
|
+
@price = BC::API::Parser.parse_price(quote_data["price"])
|
|
37
|
+
@last_updated_at = BC::API::Parser.parse_datetime(quote_data["lastUpdate"])
|
|
38
|
+
@delta = quote_data["priceChange1Day"]
|
|
39
|
+
@delta_percent = quote_data["percentChange1Day"]
|
|
40
|
+
@name = quote_data["longName"]
|
|
41
|
+
@detail = build_quote_detail(quote_data)
|
|
15
42
|
end
|
|
16
43
|
|
|
17
|
-
|
|
18
|
-
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def build_quote_detail(quote_data)
|
|
47
|
+
args = {
|
|
48
|
+
low: quote_data["lowPrice"],
|
|
49
|
+
high: quote_data["highPrice"],
|
|
50
|
+
open: quote_data["openPrice"],
|
|
51
|
+
prev_close: quote_data["prevClose"],
|
|
52
|
+
day_range: quote_data["dayRange"],
|
|
53
|
+
fifty_two_week_range: quote_data["fiftyTwoWeekRange"],
|
|
54
|
+
total_return_ytd: quote_data["totalReturnYtd"]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
BC::QuoteDetail.new(args)
|
|
19
58
|
end
|
|
20
59
|
end
|
|
21
60
|
end
|
|
@@ -1,29 +1,53 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Represents detailed information for a currency quote.
|
|
4
|
+
#
|
|
5
|
+
# == Example
|
|
6
|
+
#
|
|
7
|
+
# quote_detail = BC::QuoteDetail.new(
|
|
8
|
+
# prev_close: 100.0,
|
|
9
|
+
# low: 95.0,
|
|
10
|
+
# high: 105.0,
|
|
11
|
+
# open: 98.0,
|
|
12
|
+
# day_range: (95.0..105.0),
|
|
13
|
+
# fifty_two_week_range: (90.0..110.0),
|
|
14
|
+
# total_return_ytd: 5.0
|
|
15
|
+
# )
|
|
16
|
+
# puts quote_detail.previous_close # => 100.0
|
|
17
|
+
# puts quote_detail.low # => 95.0
|
|
18
|
+
# puts quote_detail.high # => 105.0
|
|
19
|
+
# puts quote_detail.open # => 98.0
|
|
20
|
+
# puts quote_detail.day_range # => 95.0..105.0
|
|
21
|
+
# puts quote_detail.fifty_two_week_range # => 90.0..110.0
|
|
22
|
+
# puts quote_detail.total_return_ytd # => 5.0
|
|
23
|
+
#
|
|
24
|
+
# == Attributes
|
|
25
|
+
#
|
|
26
|
+
# * +previous_close+ - The previous closing price (Float)
|
|
27
|
+
# * +low+ - The lowest price of the day (Float)
|
|
28
|
+
# * +high+ - The highest price of the day (Float)
|
|
29
|
+
# * +open+ - The opening price (Float)
|
|
30
|
+
# * +day_range+ - The price range for the day (Range)
|
|
31
|
+
# * +fifty_two_week_range+ - The 52-week price range (Range)
|
|
32
|
+
# * +total_return_ytd+ - The total return year-to-date (Float)
|
|
33
|
+
#
|
|
34
|
+
# == See Also
|
|
35
|
+
#
|
|
36
|
+
# * BC::Quote
|
|
37
|
+
# * BC::API::Site
|
|
3
38
|
module BC
|
|
4
|
-
#
|
|
39
|
+
# Represents a currency quote detail
|
|
5
40
|
class QuoteDetail
|
|
6
|
-
|
|
41
|
+
attr_reader :previous_close, :low, :high, :open, :day_range, :fifty_two_week_range, :total_return_ytd
|
|
7
42
|
|
|
8
43
|
def initialize(attributes = {})
|
|
9
|
-
@
|
|
10
|
-
@
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
@
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
private
|
|
17
|
-
|
|
18
|
-
def process_range(range)
|
|
19
|
-
return unless range
|
|
20
|
-
edges = range.tr(',', '').strip.split('-')
|
|
21
|
-
edges[0].to_f..edges[1].to_f
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def process_float(float)
|
|
25
|
-
return unless float
|
|
26
|
-
float.tr(',', '').to_f
|
|
44
|
+
@previous_close = BC::API::Parser.parse_price(attributes[:prev_close])
|
|
45
|
+
@low = attributes[:low]
|
|
46
|
+
@high = attributes[:high]
|
|
47
|
+
@open = BC::API::Parser.parse_price(attributes[:open])
|
|
48
|
+
@day_range = BC::API::Parser.parse_price_range(attributes[:day_range])
|
|
49
|
+
@fifty_two_week_range = BC::API::Parser.parse_price_range(attributes[:fifty_two_week_range])
|
|
50
|
+
@total_return_ytd = BC::API::Parser.parse_tr_ytd(attributes[:total_return_ytd])
|
|
27
51
|
end
|
|
28
52
|
end
|
|
29
53
|
end
|
data/lib/bloomberg_currency.rb
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require 'faraday'
|
|
4
3
|
require 'nokogiri'
|
|
4
|
+
require 'open3'
|
|
5
5
|
require 'bigdecimal'
|
|
6
6
|
require 'date'
|
|
7
|
+
require 'json'
|
|
7
8
|
|
|
8
9
|
require 'bloomberg_currency/version'
|
|
9
10
|
require 'bloomberg_currency/api'
|
|
10
11
|
require 'bloomberg_currency/api/site'
|
|
11
|
-
require 'bloomberg_currency/api/
|
|
12
|
+
require 'bloomberg_currency/api/parser'
|
|
13
|
+
require 'bloomberg_currency/api/site_loader'
|
|
14
|
+
require 'bloomberg_currency/api/errors/site_load_error'
|
|
12
15
|
require 'bloomberg_currency/quote'
|
|
13
16
|
require 'bloomberg_currency/quote_detail'
|
|
14
17
|
|
data/package-lock.json
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "bloomberg_currency_helper",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "bloomberg_currency_helper",
|
|
9
|
+
"version": "1.0.0",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"playwright": "^1.44.0",
|
|
12
|
+
"playwright-extra": "^4.3.1"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"node_modules/debug": {
|
|
16
|
+
"version": "4.4.1",
|
|
17
|
+
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz",
|
|
18
|
+
"integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==",
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"ms": "^2.1.3"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=6.0"
|
|
24
|
+
},
|
|
25
|
+
"peerDependenciesMeta": {
|
|
26
|
+
"supports-color": {
|
|
27
|
+
"optional": true
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"node_modules/fsevents": {
|
|
32
|
+
"version": "2.3.2",
|
|
33
|
+
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
|
34
|
+
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
|
35
|
+
"hasInstallScript": true,
|
|
36
|
+
"optional": true,
|
|
37
|
+
"os": [
|
|
38
|
+
"darwin"
|
|
39
|
+
],
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
"node_modules/ms": {
|
|
45
|
+
"version": "2.1.3",
|
|
46
|
+
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
|
47
|
+
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
|
48
|
+
},
|
|
49
|
+
"node_modules/playwright": {
|
|
50
|
+
"version": "1.52.0",
|
|
51
|
+
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.52.0.tgz",
|
|
52
|
+
"integrity": "sha512-JAwMNMBlxJ2oD1kce4KPtMkDeKGHQstdpFPcPH3maElAXon/QZeTvtsfXmTMRyO9TslfoYOXkSsvao2nE1ilTw==",
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"playwright-core": "1.52.0"
|
|
55
|
+
},
|
|
56
|
+
"bin": {
|
|
57
|
+
"playwright": "cli.js"
|
|
58
|
+
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=18"
|
|
61
|
+
},
|
|
62
|
+
"optionalDependencies": {
|
|
63
|
+
"fsevents": "2.3.2"
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
"node_modules/playwright-core": {
|
|
67
|
+
"version": "1.52.0",
|
|
68
|
+
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.52.0.tgz",
|
|
69
|
+
"integrity": "sha512-l2osTgLXSMeuLZOML9qYODUQoPPnUsKsb5/P6LJ2e6uPKXUdPK5WYhN4z03G+YNbWmGDY4YENauNu4ZKczreHg==",
|
|
70
|
+
"bin": {
|
|
71
|
+
"playwright-core": "cli.js"
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=18"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"node_modules/playwright-extra": {
|
|
78
|
+
"version": "4.3.6",
|
|
79
|
+
"resolved": "https://registry.npmjs.org/playwright-extra/-/playwright-extra-4.3.6.tgz",
|
|
80
|
+
"integrity": "sha512-q2rVtcE8V8K3vPVF1zny4pvwZveHLH8KBuVU2MoE3Jw4OKVoBWsHI9CH9zPydovHHOCDxjGN2Vg+2m644q3ijA==",
|
|
81
|
+
"dependencies": {
|
|
82
|
+
"debug": "^4.3.4"
|
|
83
|
+
},
|
|
84
|
+
"engines": {
|
|
85
|
+
"node": ">=12"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"playwright": "*",
|
|
89
|
+
"playwright-core": "*"
|
|
90
|
+
},
|
|
91
|
+
"peerDependenciesMeta": {
|
|
92
|
+
"playwright": {
|
|
93
|
+
"optional": true
|
|
94
|
+
},
|
|
95
|
+
"playwright-core": {
|
|
96
|
+
"optional": true
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
data/package.json
ADDED
metadata
CHANGED
|
@@ -1,217 +1,210 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: bloomberg_currency
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sebastian Jimenez Velez
|
|
8
|
-
|
|
9
|
-
bindir: exe
|
|
8
|
+
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
|
-
name:
|
|
13
|
+
name: bigdecimal
|
|
15
14
|
requirement: !ruby/object:Gem::Requirement
|
|
16
15
|
requirements:
|
|
17
|
-
- - "
|
|
16
|
+
- - ">="
|
|
18
17
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
20
|
-
type: :
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :runtime
|
|
21
20
|
prerelease: false
|
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
22
|
requirements:
|
|
24
|
-
- - "
|
|
23
|
+
- - ">="
|
|
25
24
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
25
|
+
version: '0'
|
|
27
26
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
27
|
+
name: faraday
|
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
|
30
29
|
requirements:
|
|
31
|
-
- - "
|
|
30
|
+
- - "~>"
|
|
32
31
|
- !ruby/object:Gem::Version
|
|
33
|
-
version:
|
|
34
|
-
type: :
|
|
32
|
+
version: '2.13'
|
|
33
|
+
type: :runtime
|
|
35
34
|
prerelease: false
|
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
36
|
requirements:
|
|
38
|
-
- - "
|
|
37
|
+
- - "~>"
|
|
39
38
|
- !ruby/object:Gem::Version
|
|
40
|
-
version:
|
|
39
|
+
version: '2.13'
|
|
41
40
|
- !ruby/object:Gem::Dependency
|
|
42
|
-
name:
|
|
41
|
+
name: nokogiri
|
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
|
44
43
|
requirements:
|
|
45
44
|
- - "~>"
|
|
46
45
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
48
|
-
type: :
|
|
46
|
+
version: '1.18'
|
|
47
|
+
type: :runtime
|
|
49
48
|
prerelease: false
|
|
50
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
50
|
requirements:
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
53
|
+
version: '1.18'
|
|
55
54
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
55
|
+
name: bundler
|
|
57
56
|
requirement: !ruby/object:Gem::Requirement
|
|
58
57
|
requirements:
|
|
59
58
|
- - "~>"
|
|
60
59
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
60
|
+
version: '2.6'
|
|
62
61
|
type: :development
|
|
63
62
|
prerelease: false
|
|
64
63
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
64
|
requirements:
|
|
66
65
|
- - "~>"
|
|
67
66
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '
|
|
67
|
+
version: '2.6'
|
|
69
68
|
- !ruby/object:Gem::Dependency
|
|
70
|
-
name:
|
|
69
|
+
name: rake
|
|
71
70
|
requirement: !ruby/object:Gem::Requirement
|
|
72
71
|
requirements:
|
|
73
72
|
- - "~>"
|
|
74
73
|
- !ruby/object:Gem::Version
|
|
75
|
-
version:
|
|
74
|
+
version: '13.2'
|
|
76
75
|
type: :development
|
|
77
76
|
prerelease: false
|
|
78
77
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
78
|
requirements:
|
|
80
79
|
- - "~>"
|
|
81
80
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
81
|
+
version: '13.2'
|
|
83
82
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
83
|
+
name: rspec
|
|
85
84
|
requirement: !ruby/object:Gem::Requirement
|
|
86
85
|
requirements:
|
|
87
|
-
- - ">="
|
|
88
|
-
- !ruby/object:Gem::Version
|
|
89
|
-
version: 1.0.0
|
|
90
86
|
- - "~>"
|
|
91
87
|
- !ruby/object:Gem::Version
|
|
92
|
-
version: '
|
|
88
|
+
version: '3.13'
|
|
93
89
|
type: :development
|
|
94
90
|
prerelease: false
|
|
95
91
|
version_requirements: !ruby/object:Gem::Requirement
|
|
96
92
|
requirements:
|
|
97
|
-
- - ">="
|
|
98
|
-
- !ruby/object:Gem::Version
|
|
99
|
-
version: 1.0.0
|
|
100
93
|
- - "~>"
|
|
101
94
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '
|
|
95
|
+
version: '3.13'
|
|
103
96
|
- !ruby/object:Gem::Dependency
|
|
104
|
-
name:
|
|
97
|
+
name: simplecov
|
|
105
98
|
requirement: !ruby/object:Gem::Requirement
|
|
106
99
|
requirements:
|
|
107
100
|
- - "~>"
|
|
108
101
|
- !ruby/object:Gem::Version
|
|
109
|
-
version:
|
|
102
|
+
version: 0.13.0
|
|
110
103
|
type: :development
|
|
111
104
|
prerelease: false
|
|
112
105
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
106
|
requirements:
|
|
114
107
|
- - "~>"
|
|
115
108
|
- !ruby/object:Gem::Version
|
|
116
|
-
version:
|
|
109
|
+
version: 0.13.0
|
|
117
110
|
- !ruby/object:Gem::Dependency
|
|
118
|
-
name:
|
|
111
|
+
name: rubocop
|
|
119
112
|
requirement: !ruby/object:Gem::Requirement
|
|
120
113
|
requirements:
|
|
121
114
|
- - "~>"
|
|
122
115
|
- !ruby/object:Gem::Version
|
|
123
|
-
version:
|
|
116
|
+
version: '1.75'
|
|
124
117
|
type: :development
|
|
125
118
|
prerelease: false
|
|
126
119
|
version_requirements: !ruby/object:Gem::Requirement
|
|
127
120
|
requirements:
|
|
128
121
|
- - "~>"
|
|
129
122
|
- !ruby/object:Gem::Version
|
|
130
|
-
version:
|
|
123
|
+
version: '1.75'
|
|
131
124
|
- !ruby/object:Gem::Dependency
|
|
132
|
-
name:
|
|
125
|
+
name: rubocop-rake
|
|
133
126
|
requirement: !ruby/object:Gem::Requirement
|
|
134
127
|
requirements:
|
|
135
128
|
- - "~>"
|
|
136
129
|
- !ruby/object:Gem::Version
|
|
137
|
-
version:
|
|
130
|
+
version: 0.7.1
|
|
138
131
|
type: :development
|
|
139
132
|
prerelease: false
|
|
140
133
|
version_requirements: !ruby/object:Gem::Requirement
|
|
141
134
|
requirements:
|
|
142
135
|
- - "~>"
|
|
143
136
|
- !ruby/object:Gem::Version
|
|
144
|
-
version:
|
|
137
|
+
version: 0.7.1
|
|
145
138
|
- !ruby/object:Gem::Dependency
|
|
146
|
-
name:
|
|
139
|
+
name: rubocop-rspec
|
|
147
140
|
requirement: !ruby/object:Gem::Requirement
|
|
148
141
|
requirements:
|
|
149
142
|
- - "~>"
|
|
150
143
|
- !ruby/object:Gem::Version
|
|
151
|
-
version:
|
|
152
|
-
|
|
153
|
-
- !ruby/object:Gem::Version
|
|
154
|
-
version: 1.6.8
|
|
155
|
-
type: :runtime
|
|
144
|
+
version: 3.6.0
|
|
145
|
+
type: :development
|
|
156
146
|
prerelease: false
|
|
157
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
158
148
|
requirements:
|
|
159
149
|
- - "~>"
|
|
160
150
|
- !ruby/object:Gem::Version
|
|
161
|
-
version:
|
|
162
|
-
- - ">="
|
|
163
|
-
- !ruby/object:Gem::Version
|
|
164
|
-
version: 1.6.8
|
|
151
|
+
version: 3.6.0
|
|
165
152
|
- !ruby/object:Gem::Dependency
|
|
166
|
-
name:
|
|
153
|
+
name: pry-byebug
|
|
167
154
|
requirement: !ruby/object:Gem::Requirement
|
|
168
155
|
requirements:
|
|
169
156
|
- - "~>"
|
|
170
157
|
- !ruby/object:Gem::Version
|
|
171
|
-
version:
|
|
172
|
-
type: :
|
|
158
|
+
version: '3.11'
|
|
159
|
+
type: :development
|
|
173
160
|
prerelease: false
|
|
174
161
|
version_requirements: !ruby/object:Gem::Requirement
|
|
175
162
|
requirements:
|
|
176
163
|
- - "~>"
|
|
177
164
|
- !ruby/object:Gem::Version
|
|
178
|
-
version:
|
|
165
|
+
version: '3.11'
|
|
179
166
|
description: Provides an easy to use API to get currency rates data from the Bloomberg
|
|
180
167
|
website
|
|
181
168
|
email:
|
|
182
|
-
-
|
|
169
|
+
- sebastian@rocktlab.com
|
|
183
170
|
executables: []
|
|
184
171
|
extensions: []
|
|
185
172
|
extra_rdoc_files: []
|
|
186
173
|
files:
|
|
174
|
+
- ".github/FUNDING.yml"
|
|
175
|
+
- ".github/dependabot.yml"
|
|
176
|
+
- ".github/workflows/ci.yml"
|
|
187
177
|
- ".gitignore"
|
|
188
178
|
- ".rspec"
|
|
189
179
|
- ".rubocop.yml"
|
|
190
180
|
- ".rubocop_todo.yml"
|
|
191
181
|
- ".ruby_version"
|
|
192
182
|
- ".simplecov"
|
|
193
|
-
- ".travis.yml"
|
|
194
183
|
- CODE_OF_CONDUCT.md
|
|
195
184
|
- Gemfile
|
|
196
185
|
- LICENSE.txt
|
|
197
186
|
- README.md
|
|
198
187
|
- Rakefile
|
|
199
188
|
- bin/console
|
|
189
|
+
- bin/fetch.js
|
|
200
190
|
- bin/setup
|
|
201
191
|
- bloomberg_currency.gemspec
|
|
202
192
|
- lib/bloomberg_currency.rb
|
|
203
193
|
- lib/bloomberg_currency/api.rb
|
|
204
|
-
- lib/bloomberg_currency/api/
|
|
194
|
+
- lib/bloomberg_currency/api/errors/site_load_error.rb
|
|
195
|
+
- lib/bloomberg_currency/api/parser.rb
|
|
205
196
|
- lib/bloomberg_currency/api/site.rb
|
|
197
|
+
- lib/bloomberg_currency/api/site_loader.rb
|
|
206
198
|
- lib/bloomberg_currency/quote.rb
|
|
207
199
|
- lib/bloomberg_currency/quote_detail.rb
|
|
208
200
|
- lib/bloomberg_currency/version.rb
|
|
201
|
+
- package-lock.json
|
|
202
|
+
- package.json
|
|
209
203
|
homepage: https://github.com/sebasjimenez10/bloomberg_currency
|
|
210
204
|
licenses:
|
|
211
205
|
- MIT
|
|
212
206
|
metadata:
|
|
213
207
|
allowed_push_host: https://rubygems.org
|
|
214
|
-
post_install_message:
|
|
215
208
|
rdoc_options: []
|
|
216
209
|
require_paths:
|
|
217
210
|
- lib
|
|
@@ -226,8 +219,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
226
219
|
- !ruby/object:Gem::Version
|
|
227
220
|
version: '0'
|
|
228
221
|
requirements: []
|
|
229
|
-
rubygems_version: 3.
|
|
230
|
-
signing_key:
|
|
222
|
+
rubygems_version: 3.6.9
|
|
231
223
|
specification_version: 4
|
|
232
224
|
summary: Bloomberg Currency helps you pull currency rates data from the Bloomberg
|
|
233
225
|
website
|