From: Peter Miller on 8 Apr 2010 20:34 I'm trying to write a script that will take stock ticker symbols from a file, pull the company name and current price and write it back to the file while ignoring comments and blank lines so as to leave the rest of the file intact. I can get the stock prices etc. i'm after using the yahoofinance module http://www.transparentech.com/opensource/yahoofinance like so require 'rubygems' require 'yahoofinance' quote_type = YahooFinance::StandardQuote # Set the symbols for which we want to retrieve quotes. quote_symbols = ['yhoo','goog'] # Get the quotes from Yahoo! Finance. The get_quotes method call # returns a Hash containing one quote object of type "quote_type" for # each symbol in "quote_symbols". If a block is given, it will be # called with the quote object (as in the example below). YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| puts "QUOTING: #{qt.symbol}" puts "#{qt.name}" puts "#{qt.lastTrade}" end I want to create an array of ticker symbols like quote_symbols above, but from a file. here's a test data file i'm using # this is the comment line # that was a blank, below is a stock YHOO GOOG # this comment can be deleted i would like the output to look like # this is the comment line # that was a blank, below is a stock YHOO:Yahoo! Inc.:17.35 GOOG:Google Inc.:567.49 this is the code i'm having trouble with. filename = ARGV[0] File.open(filename, 'r+') do |f| lines = f.readlines # load array of lines lines.each do |line| next if line =~ /^#/ # skip comments next if line.chomp.empty? # skip empty lines $ticker[lines] = line #***the problem puts lines.index(line) end end $ticker.each do |p| puts "#{p}" end *** I'm trying to create the array $ticker that has all my stocks so i can pass it on to the yahoofinance module. The other stumbling block for me is how to keep the results of YHOO -> Yahoo! Inc. and the price 17.35 matched up with YHOO so i can put it back on the same line. Thanks Peter -- Posted via http://www.ruby-forum.com/.
From: Jesús Gabriel y Galán on 9 Apr 2010 04:03 On Fri, Apr 9, 2010 at 2:34 AM, Peter Miller <feurry(a)gmail.com> wrote: > I'm trying to write a script that will take stock ticker symbols from a > file, pull the company name and current price and write it back to the > file while ignoring comments and blank lines so as to leave the rest of > the file intact. > > I can get the stock prices etc. i'm after using the yahoofinance module > http://www.transparentech.com/opensource/yahoofinance > like so > > require 'rubygems' > require 'yahoofinance' > > quote_type = YahooFinance::StandardQuote > > # Set the symbols for which we want to retrieve quotes. > quote_symbols = ['yhoo','goog'] > > # Get the quotes from Yahoo! Finance. The get_quotes method call > # returns a Hash containing one quote object of type "quote_type" for > # each symbol in "quote_symbols". If a block is given, it will be > # called with the quote object (as in the example below). > YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| > puts "QUOTING: #{qt.symbol}" > puts "#{qt.name}" > puts "#{qt.lastTrade}" > end > > I want to create an array of ticker symbols like quote_symbols above, > but from a file. > > here's a test data file i'm using > # this is the comment line > > # that was a blank, below is a stock > YHOO > GOOG # this comment can be deleted > > i would like the output to look like > # this is the comment line > > # that was a blank, below is a stock > YHOO:Yahoo! Inc.:17.35 > GOOG:Google Inc.:567.49 > > this is the code i'm having trouble with. > filename = ARGV[0] > > File.open(filename, 'r+') do |f| > lines = f.readlines # load array of lines > lines.each do |line| > next if line =~ /^#/ # skip comments > next if line.chomp.empty? # skip empty lines > $ticker[lines] = line #***the problem > puts lines.index(line) > end > end If you are just reading the lines you can do: lines = File.readlines(filename) Then: ticker = [] lines.each do |line| next if line =~ /^#/ # skip comments next if line.chomp.empty? # skip empty lines ticker << line end p ticker From your specs I think you are missing also the functionality of removing everything after a #. If a line can contain only a ticker symbol and optional things (after all a ticker symbol is just a word), you can do: ticker = [] lines.each do |line| next if line =~ /^#/ # skip comments next if line.chomp.empty? # skip empty lines ticker << line.split(" ")[0] # or maybe line[/\w+/] end > The other stumbling block for me is how to keep the results of YHOO -> > Yahoo! Inc. and the price 17.35 matched up with YHOO so i can put it > back on the same line. An idea would be to fill a hash with the data retrieved for each symbol: ticker_data = {} YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| puts "QUOTING: #{qt.symbol}" puts "#{qt.name}" puts "#{qt.lastTrade}" ticker_data[qt.symbol] = [qt.name, qt.lastTrade] end and then write to the file the data in ticker_data. I can see additional complexity if you want to keep the file exactly as it is (with the comments) but inserting the retrieved data in place. The easiest would be to just write ticker_data: File.open(filename, "w") do |file| ticker_data.each {|ticker, data| file.puts "#{ticker} #{data.join(" ")}"} end If you want to keep the same order of the symbols: File.open(filename, "w") do |file| ticker.each do |ticker| file.puts "#{ticker} #{ticker_data[ticker].join(" ")}"} end end Although this would remove the comments from the file. Jesus.
From: Peter Miller on 9 Apr 2010 09:57 > ticker = [] > lines.each do |line| > next if line =~ /^#/ # skip comments > next if line.chomp.empty? # skip empty lines > ticker << line > end > ticker << line.split(" ")[0] # or maybe line[/\w+/] Thank you. The ticker << line is really helpful. > An idea would be to fill a hash with the data retrieved for each symbol: > > ticker_data = {} > > YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| > puts "QUOTING: #{qt.symbol}" > puts "#{qt.name}" > puts "#{qt.lastTrade}" > ticker_data[qt.symbol] = [qt.name, qt.lastTrade] > end I didn't realize a hash could point to more than one object. Awesome. > and then write to the file the data in ticker_data. I can see > additional complexity if you want to keep the file exactly as it is > (with the comments) but inserting the retrieved data in place. The > easiest would be to just write ticker_data: this is why i was trying to do $ticker[lines] = line when storing the data. I thought I could point the index of the ticker symbol, which would tell me what line it was on, to my array $ticker. Then i wanted to use that index to write back the ticker data to the same line it came from. i think i need to capture the tickers position in the file at this point ticker << line and then somehow use it when writing the file back. I'm going to work on that, but if there is another approach, or my thinking is flawed, a nudge in the right direction would be nice. The hardest part of learning to code for me is thinking like a computer. Thanks for the help Jesus. -- Posted via http://www.ruby-forum.com/.
From: Jesús Gabriel y Galán on 9 Apr 2010 12:56 On Fri, Apr 9, 2010 at 3:57 PM, Peter Miller <feurry(a)gmail.com> wrote: >> An idea would be to fill a hash with the data retrieved for each symbol: >> >> ticker_data = {} >> >> YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| >> puts "QUOTING: #{qt.symbol}" >> puts "#{qt.name}" >> puts "#{qt.lastTrade}" >> ticker_data[qt.symbol] = [qt.name, qt.lastTrade] >> end > > I didn't realize a hash could point to more than one object. Awesome. As Martin explained, it's just one object. It happens to be an array with many other objects inside, or it could be a struct, for example: Quote = Struct.new(:symbol, :name, :last_trade) YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| ticker_data[qt.symbol] = Quote.new qt.symbol, qt.name, qt.last_trade end or another hash: YahooFinance.get_quotes( quote_type, quote_symbols ) do |qt| ticker_data[qt.symbol] = {:symbol => qt.symbol, :name => qt.name, :last_trade => qt.last_trade} end depends on how you want to use it later. > >> and then write to the file the data in ticker_data. I can see >> additional complexity if you want to keep the file exactly as it is >> (with the comments) but inserting the retrieved data in place. The >> easiest would be to just write ticker_data: > > this is why i was trying to do $ticker[lines] = line when storing the > data. I thought I could point the index of the ticker symbol, which > would tell me what line it was on, to my array $ticker. Then i wanted to > use that index to write back the ticker data to the same line it came > from. The problem is that you can't really insert things "in the middle" of a file. If you write something in the current position of a file (the cursor), it will overwrite what's after, it doesn't push the rest of the file to make space for what you are writing. So, the usual simple way is to read the file, modify it in memory and write it all again. If you want to preserve everything, you could split the file in chunks with the comments, and replace the other lines with the result of your calculation. For that, you will have to keep track of which lines represent ticker data. For example (untested): TickerData = Struct.new :symbol, :file_position, :name, :last_trade lines = File.readlines(filename) tickers = {} lines.each_with_index do |line, i| next if line =~ /^#/ # skip comments next if line.chomp.empty? # skip empty lines symbol = line[/\w+/] tickers[symbol] = TickerData.new symbol, i #store the symbol and the file position end YahooFinance.get_quotes( quote_type, tickers.keys ) do |qt| next unless tickers[qt.symbol] tickers[qt.symbol].name = qt.name tickers[qt.symbol].last_trade = qt.last_trade end Now you have the original lines in an array and a hash with all the data, including to which line it corresponds, you can sub the line with what you want, and then write the file back: tickers.each do |symbol, ticker| lines[ticker.file_position] = "#{ticker.symbol} #{ticker.name} #{ticker.last_trade}\n" end File.open(filename, "w") {|file| file.puts lines.join} I think this should work but I haven't tested it. Jesus.
From: Peter Miller on 9 Apr 2010 18:25 well, I just got home from work and was going to hack away.. but instead i cut n paste and got a working script after a couple minor edits. Thanks so much for such a complete solution. I wasn't expecting that! Here is the working code in full. It handles my file perfectly. require 'rubygems' require 'yahoofinance' quote_type = YahooFinance::StandardQuote filename = ARGV[0] TickerData = Struct.new :symbol, :file_position, :name, :last_trade lines = File.readlines(filename) tickers = {} lines.each_with_index do |line, i| next if line =~ /^#/ # skip comments next if line.chomp.empty? # skip empty lines symbol = line[/\w+/].upcase tickers[symbol] = TickerData.new symbol, i #store the symbol and file position end YahooFinance.get_quotes( quote_type, tickers.keys ) do |qt| next unless tickers[qt.symbol] tickers[qt.symbol].name = qt.name tickers[qt.symbol].last_trade = qt.lastTrade end tickers.each do |symbol, ticker| lines[ticker.file_position] = "#{ticker.symbol} #{ticker.name} #{ticker.last_trade}\n" end File.open(filename, "w") {|file| file.puts lines.join} Off to do some reading on structs Thanks Martin and Jesus -- Posted via http://www.ruby-forum.com/.
|
Next
|
Last
Pages: 1 2 Prev: importing config files Next: Closing and reloading compiled extensions |