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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52251c871972f9221490d20f9d21d5b0169d7a3c7bdda891cf5451d31a4ea39b
4
- data.tar.gz: 8a710025b3460c4fe7e2d7734e138a12d1b8d97ab0c815a4c7135ca9c326f9af
3
+ metadata.gz: 3a734585f1c78f69aa036254c97cf008d815185c61df21ceb1acf9c670ccbca8
4
+ data.tar.gz: befcfc665db447c41dfc9d484f5bb3ff50d3d7b05891030846585acfd4d80dc7
5
5
  SHA512:
6
- metadata.gz: 736d3472c878639b025c625aef6eef9ed14060a7a2a334beb2bc92037c7525aa9a2b3a363d3a35c4101a34fb4462d8a8788a85867a71d3e24f785501cf739c7b
7
- data.tar.gz: 75fa77f2a4e15285c7a9892491ed54967af80b1674c6d433b61b277dcf5e0ca451b85a35db47ba4b41111470f6ced2b45ae84163ad1aabb8afd2a44ad0038867
6
+ metadata.gz: f77fe3509fc9bdd96f154fce1b6ed592679d3e9fe2712bf0af5cedc6dce3f1298bc06b63f4684f69bb608e622f7ac2753ac7dcc727e877d75410b8bfe26af741
7
+ data.tar.gz: 9341ff720130bb1bd26d33142873b9eeca003277691e6165952be2a972c699e0ec92faf31403a6938595601e52ca52f6444dc915582948cb5c8bb5b7ae81f4df
@@ -0,0 +1,3 @@
1
+ # These are supported funding model platforms
2
+
3
+ liberapay: sebasjimenezv
@@ -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
@@ -8,10 +8,8 @@
8
8
  /spec/reports/
9
9
  /tmp/
10
10
 
11
- # CodeClimate Coverage Reporter
12
- codeclimate-coverage-reporter.sh
13
-
14
11
  .DS_Store
15
12
  */**/.DS_Store
16
13
 
17
14
  /.byebug_history
15
+ /node_modules/
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
- - '**/Rakefile'
6
- - '**/config.ru'
6
+ - "**/Rakefile"
7
+ - "**/config.ru"
7
8
  Exclude:
8
9
  - bloomberg_currency.gemspec
9
- - 'db/**/*'
10
- - 'config/**/*'
11
- - 'script/**/*'
12
- - 'spec/**/*'
10
+ - "db/**/*"
11
+ - "config/**/*"
12
+ - "script/**/*"
13
+ - "spec/**/*"
14
+ - "bin/**/*"
13
15
  - !ruby/regexp /old_and_unused\.rb$/
14
16
 
15
- Metrics/LineLength:
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
- - 'Gemfile'
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
- Style/FileName:
23
+ Naming/FileName:
24
24
  Exclude:
25
- - 'Gemfile'
25
+ - "Gemfile"
data/.ruby_version CHANGED
@@ -1 +1 @@
1
- 2.6.5
1
+ 3.3.0
data/.simplecov CHANGED
@@ -1,4 +1,6 @@
1
1
  SimpleCov.start do
2
2
  add_filter '/spec/'
3
3
  add_group "lib", "lib"
4
- end
4
+
5
+ minimum_coverage 95.5
6
+ end
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # Bloomberg Currency
2
2
 
3
- [![Build Status](https://travis-ci.org/sebasjimenez10/bloomberg_currency.svg?branch=master)](https://travis-ci.org/sebasjimenez10/bloomberg_currency) [![Code Climate](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency/badges/gpa.svg)](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency) [![Test Coverage](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency/badges/coverage.svg)](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency/coverage) [![Issue Count](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency/badges/issue_count.svg)](https://codeclimate.com/github/sebasjimenez10/bloomberg_currency)
3
+ [![Build Status](https://github.com/sebasjimenez10/bloomberg_currency/actions/workflows/ci.yml/badge.svg)](https://github.com/sebasjimenez10/bloomberg_currency/actions/workflows/ci.yml)
4
+ [![Gem Version](https://badge.fury.io/rb/bloomberg_currency.svg)](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
- $ bundle
18
+ ```
19
+ $ bundle
20
+ ```
18
21
 
19
22
  Or install it yourself as:
20
23
 
21
- $ gem install bloomberg_currency
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
- *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.
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
- The gem usability has been improved in version 1.0.0. Now you only need to create an instance of the class `BC::Quote`, passing the two currencies you'd like to get information about, like this:
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', 'EUR')
31
- => #<BC::Quote:0x00007fd5858f1620 @price=0.8303, @datetime="", @detail=#<BC::QuoteDetail:0x00007fd583330238 @open=0.8307, @day_range=0.8299..0.8307, @previous_close=0.8306, @last_52_weeks_range=0.8098..0.94, @ytd_return=1.43>, @available=true>
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:0x00007fd583330238 @open=0.8307, @day_range=0.8299..0.8307, @previous_close=0.8306, @last_52_weeks_range=0.8098..0.94, @ytd_return=1.43>
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
- Then the quote object offers a few accessor methods:
55
+ The `BC::Quote` quote object offers the following accessor methods:
37
56
 
38
- - `price`: Returns a float price
39
- - `datetime`: Returns the date time when the price was captured
40
- - `detail`: Returns an object of the class BC::QuoteDetail which encapsulate the details of the quote. Will be explained later on.
41
- - `available?`: Return true or false if the exchange is available or not.
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
- The `BC::QuoteDetail` class offers the following methods:
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
- - `open`: Returns the value in which the currency opened.
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 EUR exchange:
78
+ Getting information about the USD and COP exchange:
58
79
 
59
80
  ```
60
- quote = BC::Quote.new('USD', 'EUR')
61
- quote.price
62
- => 0.8147
63
-
64
- quote.datetime
65
- => #<DateTime: 2018-01-16T14:35:00-05:00 ((2458135j,70500s,0n),-18000s,2299161j)>
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:0x007faadd9fb868 @open=0.8154, @day_range=0.8143..0.8199, @previous_close=0.8154, @last_52_weeks_range=0.8133..0.9529, @ytd_return=-1.91>
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
@@ -4,5 +4,4 @@ IFS=$'\n\t'
4
4
  set -vx
5
5
 
6
6
  bundle install
7
-
8
- # Do any other automated setup that you need to do here
7
+ npm install
@@ -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 = ['sebasjimenezv@gmail.com']
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 = 'exe'
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
- spec.add_development_dependency 'bundler', '~> 1.13'
37
- spec.add_development_dependency 'rake', '>= 12.3.3'
38
- spec.add_development_dependency 'rspec', '~> 3.0'
39
- spec.add_development_dependency 'simplecov', '~> 0.11'
40
- spec.add_development_dependency 'rubocop', '~> 0.49.0'
41
- spec.add_development_dependency 'codeclimate-test-reporter', '~> 1.0', '>= 1.0.0'
42
- spec.add_development_dependency 'pry-byebug', '~> 3.5.1'
43
- spec.add_development_dependency 'vcr', '~> 6.0.0'
44
- spec.add_development_dependency 'webmock', '~> 3.5.0'
45
-
46
- spec.add_runtime_dependency 'nokogiri', '~> 1.6', '>= 1.6.8'
47
- spec.add_runtime_dependency 'faraday', '~> 0.9.2'
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
@@ -2,8 +2,9 @@
2
2
 
3
3
  module BC
4
4
  module API
5
- class Host
6
- URL = 'https://www.bloomberg.com/quote/'.freeze
5
+ module Errors
6
+ class SiteLoadError < StandardError
7
+ end
7
8
  end
8
9
  end
9
10
  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
- class << self
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
- def parse(document)
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
- def parse_quote(document)
37
- price_container = document.xpath("//section[contains(@class, 'quotePageSnapshot')]")
38
- detailed_quote_container = document.xpath("//div[contains(@class, 'details__')]")
39
- price_element = price_container.xpath("//span[starts-with(@class, 'priceText__')]")
40
- price_datetime_element = price_container.xpath("//div[contains(@class, 'time__')]")
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
- open: open_price,
57
- day_range: range_one_day,
58
- previous_close: previous_close,
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
- def extract_value_from_detail(container, section)
65
- container
66
- .xpath("//section[contains(@class, '#{section}')]")
67
- .children[1].text
68
- end
52
+ private
69
53
 
70
- def extract_values_for_range(container, section)
71
- container
72
- .xpath("//section[contains(@class, '#{section}')]")
73
- .children[1]
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
- def calculate_datetime(datetime_str)
81
- if datetime_str.index(':')
82
- ::DateTime.strptime(datetime_str, 'As of %H:%M %p %z %m/%d/%Y')
83
- else
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,7 +1,4 @@
1
1
  module BC
2
2
  module API
3
- USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_1) '\
4
- 'AppleWebKit/537.36 (KHTML, like Gecko) '\
5
- 'Chrome/88.0.4324.150 Safari/537.36'.freeze
6
3
  end
7
4
  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
- # Quote Information Class
29
+ # Represents a currency quote
5
30
  class Quote
6
- attr_accessor :price, :datetime, :detail, :available
31
+ attr_reader :name, :detail, :price, :delta, :delta_percent, :last_updated_at
7
32
 
8
- def initialize(currency_one, currency_two)
9
- result = BC::API::Site.quote(currency_one, currency_two)
33
+ def initialize(currency_one:, currency_two:)
34
+ quote_data = BC::API::Site.new(currency_one, currency_two).quote
10
35
 
11
- @price = result[:price]
12
- @datetime = result[:datetime]
13
- @detail = result[:detail]
14
- @available = result[:available]
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
- def available?
18
- available
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
- # Quote Details Class
39
+ # Represents a currency quote detail
5
40
  class QuoteDetail
6
- attr_accessor :open, :day_range, :previous_close, :last_52_weeks_range, :ytd_return
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
- @open = process_float(attributes[:open])
10
- @day_range = process_range(attributes[:day_range])
11
- @previous_close = process_float(attributes[:previous_close])
12
- @last_52_weeks_range = process_range(attributes[:range_52_wks])
13
- @ytd_return = process_float(attributes[:ytd_return])
14
- end
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module BC
4
- VERSION = '1.1.1'.freeze
4
+ VERSION = '2.0.0'.freeze
5
5
  end
@@ -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/host'
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
@@ -0,0 +1,12 @@
1
+ {
2
+ "name": "bloomberg_currency_helper",
3
+ "version": "1.0.0",
4
+ "main": "bin/fetch.js",
5
+ "scripts": {
6
+ "fetch": "node bin/fetch.js"
7
+ },
8
+ "dependencies": {
9
+ "playwright": "^1.44.0",
10
+ "playwright-extra": "^4.3.1"
11
+ }
12
+ }
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: 1.1.1
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sebastian Jimenez Velez
8
- autorequire:
9
- bindir: exe
8
+ bindir: bin
10
9
  cert_chain: []
11
- date: 2021-02-18 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
- name: bundler
13
+ name: bigdecimal
15
14
  requirement: !ruby/object:Gem::Requirement
16
15
  requirements:
17
- - - "~>"
16
+ - - ">="
18
17
  - !ruby/object:Gem::Version
19
- version: '1.13'
20
- type: :development
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: '1.13'
25
+ version: '0'
27
26
  - !ruby/object:Gem::Dependency
28
- name: rake
27
+ name: faraday
29
28
  requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
- - - ">="
30
+ - - "~>"
32
31
  - !ruby/object:Gem::Version
33
- version: 12.3.3
34
- type: :development
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: 12.3.3
39
+ version: '2.13'
41
40
  - !ruby/object:Gem::Dependency
42
- name: rspec
41
+ name: nokogiri
43
42
  requirement: !ruby/object:Gem::Requirement
44
43
  requirements:
45
44
  - - "~>"
46
45
  - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
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: '3.0'
53
+ version: '1.18'
55
54
  - !ruby/object:Gem::Dependency
56
- name: simplecov
55
+ name: bundler
57
56
  requirement: !ruby/object:Gem::Requirement
58
57
  requirements:
59
58
  - - "~>"
60
59
  - !ruby/object:Gem::Version
61
- version: '0.11'
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: '0.11'
67
+ version: '2.6'
69
68
  - !ruby/object:Gem::Dependency
70
- name: rubocop
69
+ name: rake
71
70
  requirement: !ruby/object:Gem::Requirement
72
71
  requirements:
73
72
  - - "~>"
74
73
  - !ruby/object:Gem::Version
75
- version: 0.49.0
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: 0.49.0
81
+ version: '13.2'
83
82
  - !ruby/object:Gem::Dependency
84
- name: codeclimate-test-reporter
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: '1.0'
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: '1.0'
95
+ version: '3.13'
103
96
  - !ruby/object:Gem::Dependency
104
- name: pry-byebug
97
+ name: simplecov
105
98
  requirement: !ruby/object:Gem::Requirement
106
99
  requirements:
107
100
  - - "~>"
108
101
  - !ruby/object:Gem::Version
109
- version: 3.5.1
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: 3.5.1
109
+ version: 0.13.0
117
110
  - !ruby/object:Gem::Dependency
118
- name: vcr
111
+ name: rubocop
119
112
  requirement: !ruby/object:Gem::Requirement
120
113
  requirements:
121
114
  - - "~>"
122
115
  - !ruby/object:Gem::Version
123
- version: 6.0.0
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: 6.0.0
123
+ version: '1.75'
131
124
  - !ruby/object:Gem::Dependency
132
- name: webmock
125
+ name: rubocop-rake
133
126
  requirement: !ruby/object:Gem::Requirement
134
127
  requirements:
135
128
  - - "~>"
136
129
  - !ruby/object:Gem::Version
137
- version: 3.5.0
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: 3.5.0
137
+ version: 0.7.1
145
138
  - !ruby/object:Gem::Dependency
146
- name: nokogiri
139
+ name: rubocop-rspec
147
140
  requirement: !ruby/object:Gem::Requirement
148
141
  requirements:
149
142
  - - "~>"
150
143
  - !ruby/object:Gem::Version
151
- version: '1.6'
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: '1.6'
162
- - - ">="
163
- - !ruby/object:Gem::Version
164
- version: 1.6.8
151
+ version: 3.6.0
165
152
  - !ruby/object:Gem::Dependency
166
- name: faraday
153
+ name: pry-byebug
167
154
  requirement: !ruby/object:Gem::Requirement
168
155
  requirements:
169
156
  - - "~>"
170
157
  - !ruby/object:Gem::Version
171
- version: 0.9.2
172
- type: :runtime
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: 0.9.2
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
- - sebasjimenezv@gmail.com
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/host.rb
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.0.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
data/.travis.yml DELETED
@@ -1,6 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.6.5
5
- before_install: gem install bundler -v 1.17.2
6
- before_script: rubocop