1

I am using the "stock quote" gem (https://github.com/tyrauber/stock_quote) to retrieve stock prices based on user input tickers. While I have a ticker list that is up-to-date, there are some circumstances where the search yields no results. I have this in my code to get the quote:

@companyname = StockQuote::Stock.quote(@ticker).company
@exchange = StockQuote::Stock.quote(@ticker).exchange
@price = StockQuote::Stock.quote(@ticker).last

And it yields this when @ticker = "AKO-A"

undefined method `attributes' for nil:NilClass
file: stock.rb location: block in parse line: 90

Is there anyway to avoid this nomethoderror by making my code more robust (if error then "blank")? Sorry, I am relatively new to ruby and would appreciate any help to point me in the right direction.

  • I attempted an answer, but checked it, and the problem is with the gem in my opinion. It should not throw the exception that it does throw when it cannot find a stock item. It should either return `nil` or should throw an exception you could identify like `StockQuote::Stock::NotFound`. Still, it is possible to protected yourself – Neil Slater Jul 21 '13 at 07:08

3 Answers3

2

Yeah, the problem was definitely with the gem. It was assuming the symbol was accurate and wasn't properly parsing responses for bad symbols.

Sloppy. Rewrote the classes for cleaner code and greater stability. Added in a response_code instance method, which returns 200 or 404, depending upon the validity of the response. Also, a success? or failure? instance method. And, better spec coverage.

Version bumped, and pushed to rubygems.

tyrauber
  • 21
  • 1
  • 2
  • +1 for customer service! You have also provided a working gem wrapped around a not-really-documented web service, so no need to beat yourself up for missing a failure mode. – Neil Slater Jul 22 '13 at 08:53
0

This is a very common condition with Ruby code, and a common idiom to return nil on a failed search.

However this specific gem is a little flaky when it fails to get a good search result. You can protect yourself against it failing by using a begin ... rescue block.

begin
  stock_quote = StockQuote::Stock.quote(@ticker)
rescue StandardError
  stock_quote = nil
end

if stock_quote
  @companyname = stock_quote.company
  @exchange = stock_quote.exchange
  @price = stock_quote.last
end

This might not be ideal program flow for you, so you may need to adapt this.

Note StandardError is what gets rescued by default, I didn't need to write that. You could also put NoMethodError in your situation, and usually you want to restrict rescuing exceptions to specific parts of code where you know how to recover from the error, and also only to the types of errors where you are confident that your handling code is doing the right thing.

Neil Slater
  • 26,512
  • 6
  • 76
  • 94
  • Thanks Neil for the quick reply - really appreciate it. Unfortunately I am still getting the NoMethodError. Any other ideas? I believe the error is occurring in the gem, such that when it inputs the ticker into the Google Finance search it is unable to find the ticker and yields nil. I am hoping that there is some work around I can do so that I can keep using it because it works in 95% of cases. – Joey French Jul 21 '13 at 07:21
  • @jfrench009: I agree the problem is with the gem. I modified this answer a couple of times, and am now suggesting a completely different approach. Could you take a second look? Looking at the gem code on github, it assumes any successful return from Google must contain valid data, and so it fails when Google correctly returns an empty list of search results. – Neil Slater Jul 21 '13 at 07:25
  • Thank you so much, this looks like it did the trick. Again, I really appreciate the help – Joey French Jul 21 '13 at 07:29
0

Here is an example on how use rescue to get around the nonexistent stock symbol problem

require 'stock_quote'

class StockClass

def self.symbol_check(symbol)
  StockQuote::Stock.quote(symbol).symbol
end

def self.price_by_symbol(symbol)
  StockQuote::Stock.quote(symbol).latest_price
end

def self.write_price_by_symbol(symbol, price)
  filename = "#{symbol}.csv"
  todays_date = Time.now.strftime('%Y-%m-%d')
  File.open(filename, "a") do |file|
    file << "#{todays_date}, #{price}\n"
  end
end

end

def stock_price_selector(*symbol_array)
  symbol_array.each do |stock_name|
    begin
      stock_check = StockClass.symbol_check(stock_name)
    rescue  NoMethodError
      puts "#{stock_name} is a bogus ticker symbol"
    else
      stock_price = StockClass.price_by_symbol(stock_name)
      stock_written = StockClass.write_price_by_symbol(stock_name, stock_price)
    end
  end
end


stock_price_selector('AAPL', 'APPL', 'MSFT', 'GOOG')

This will skip the bogus symbol 'APPL' and work for the legtimate ticker symbols.

Tom Cull
  • 1
  • 1