Skip to content

Commit

Permalink
Added base functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
bguban committed Sep 21, 2021
1 parent 96be7a6 commit 8765a87
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 29 deletions.
2 changes: 2 additions & 0 deletions lib/iex/api/config/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Client
ca_file
ca_path
endpoint
sse_endpoint
open_timeout
proxy
publishable_token
Expand All @@ -24,6 +25,7 @@ def reset!
self.ca_file = defined?(OpenSSL) ? OpenSSL::X509::DEFAULT_CERT_FILE : nil
self.ca_path = defined?(OpenSSL) ? OpenSSL::X509::DEFAULT_CERT_DIR : nil
self.endpoint = 'https://cloud.iexapis.com/v1'
self.sse_endpoint = 'https://cloud-sse.iexapis.com/v1'
self.publishable_token = ENV['IEX_API_PUBLISHABLE_TOKEN']
self.secret_token = ENV['IEX_API_SECRET_TOKEN']
self.user_agent = "IEX Ruby Client/#{IEX::VERSION}"
Expand Down
19 changes: 17 additions & 2 deletions lib/iex/cloud/request.rb
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
module IEX
module Cloud
module Request
STREAM_EVENT_DELIMITER = "\r\n\r\n".freeze

def get(path, options = {})
request(:get, path, options)
end

def get_stream(path, options = {})
buffer = ""
event_parser = Proc.new do |chunk|
events = (buffer + chunk).lines(STREAM_EVENT_DELIMITER)
buffer = events.last.end_with?(STREAM_EVENT_DELIMITER) ? '' : events.delete_at(-1)
events.each do |event|
yield JSON.parse(event.gsub(/\Adata: /, ''))
end
end

request(:get, path, { endpoint: sse_endpoint, request: { on_data: event_parser } }.merge(options))
end

def post(path, options = {})
request(:post, path, options)
end
Expand All @@ -20,16 +35,16 @@ def delete(path, options = {})
private

def request(method, path, options)
path = [endpoint, path].join('/')
path = [options.delete(:endpoint) || endpoint, path].join('/')
response = connection.send(method) do |request|
request.options.merge!(options.delete(:request)) if options.key?(:request)
case method
when :get, :delete
request.url(path, options)
when :post, :put
request.path = path
request.body = options.to_json unless options.empty?
end
request.options.merge!(options.delete(:request)) if options.key?(:request)
end
response.body
end
Expand Down
13 changes: 13 additions & 0 deletions lib/iex/endpoints/quote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,19 @@ def quote(symbol, options = {})
rescue Faraday::ResourceNotFound => e
raise IEX::Errors::SymbolNotFoundError.new(symbol, e.response[:body])
end

# @param symbols - a list of symbols
# @param options[:interval] sets intervals such as 1Second, 5Second, or 1Minute
def stream_quote(symbols, options = {})
options[:symbols] = Array(symbols).join(',')
interval = options.delete(:interval)

get_stream("stocksUS#{interval}", { token: secret_token }.merge(options)) do |payload|
payload.each do |quote|
yield IEX::Resources::Quote.new(quote)
end
end
end
end
end
end
61 changes: 61 additions & 0 deletions spec/fixtures/iex/stream_quote/spy.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

73 changes: 46 additions & 27 deletions spec/iex/endpoints/quote_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,58 @@

describe IEX::Resources::Quote do
include_context 'client'
context 'known symbol', vcr: { cassette_name: 'quote/msft' } do
subject do
client.quote('MSFT')
end
it 'retrieves a quote' do
expect(subject.symbol).to eq 'MSFT'
expect(subject.company_name).to eq 'Microsoft Corp.'
expect(subject.market_cap).to eq 915_754_985_600
end
it 'coerces numbers' do
expect(subject.latest_price).to eq 119.36
expect(subject.change).to eq(-0.61)
expect(subject.week_52_high).to eq 120.82
expect(subject.week_52_low).to eq 87.73
expect(subject.change_percent).to eq(-0.00508)
expect(subject.change_percent_s).to eq '-0.51%'
expect(subject.extended_change_percent).to eq(-0.00008)
expect(subject.extended_change_percent_s).to eq '-0.01%'

describe '#quote' do
context 'known symbol', vcr: { cassette_name: 'quote/msft' } do
subject do
client.quote('MSFT')
end
it 'retrieves a quote' do
expect(subject.symbol).to eq 'MSFT'
expect(subject.company_name).to eq 'Microsoft Corp.'
expect(subject.market_cap).to eq 915_754_985_600
end
it 'coerces numbers' do
expect(subject.latest_price).to eq 119.36
expect(subject.change).to eq(-0.61)
expect(subject.week_52_high).to eq 120.82
expect(subject.week_52_low).to eq 87.73
expect(subject.change_percent).to eq(-0.00508)
expect(subject.change_percent_s).to eq '-0.51%'
expect(subject.extended_change_percent).to eq(-0.00008)
expect(subject.extended_change_percent_s).to eq '-0.01%'
end
it 'coerces times' do
expect(subject.latest_update).to eq 1_554_408_000_193
expect(subject.latest_update_t).to eq Time.at(1_554_408_000)
expect(subject.iex_last_updated).to eq 1_554_407_999_529
expect(subject.iex_last_updated_t).to eq Time.at(1_554_407_999)
end
end
it 'coerces times' do
expect(subject.latest_update).to eq 1_554_408_000_193
expect(subject.latest_update_t).to eq Time.at(1_554_408_000)
expect(subject.iex_last_updated).to eq 1_554_407_999_529
expect(subject.iex_last_updated_t).to eq Time.at(1_554_407_999)

context 'invalid symbol', vcr: { cassette_name: 'quote/invalid' } do
subject do
client.quote('INVALID')
end
it 'fails with SymbolNotFoundError' do
expect { subject }.to raise_error IEX::Errors::SymbolNotFoundError, 'Symbol INVALID Not Found'
end
end
end

context 'invalid symbol', vcr: { cassette_name: 'quote/invalid' } do
describe '#stream_quote' do
subject do
client.quote('INVALID')
quotes = []
client.stream_quote('SPY', interval: '5Second') do |quote|
quotes << quote
end

quotes.first
end
it 'fails with SymbolNotFoundError' do
expect { subject }.to raise_error IEX::Errors::SymbolNotFoundError, 'Symbol INVALID Not Found'

it 'retrieves a quote', vcr: { cassette_name: 'stream_quote/spy' } do
expect(subject.symbol).to eq('SPY')
expect(subject.close).to eq(433.63)
end
end
end

0 comments on commit 8765a87

Please # to comment.