From: James Edward Gray II Date: 2005-08-10T00:52:52+09:00 Subject: Re: [SOLUTION] Stock Portfolios (#41) On Aug 5, 2005, at 11:30 AM, Ruby Quiz wrote: > This week's Ruby Quiz is to build this simple tool. Here's the code used to create the quiz: #!/usr/local/bin/ruby require "yaml" require "soap/rpc/driver" server = SOAP::RPC::Driver.new( "http://services.xmethods.com/soap", "urn:xmethods-delayed-quotes" ) server.add_method( "getQuote", "symbol" ) Struct.new("Shares", :symbol, :shares, :price, :date) file_name = File.join(ENV["HOME"], ".portfolio.yaml") portfolio = if File.exist? file_name File.open(file_name) { |file| YAML.load(file) } else Hash.new end if portfolio.empty? or not ARGV.empty? and ARGV.first == "-p" loop do print "Buy (symbol shares/dollars): " line = $stdin.gets.strip break if line.empty? ticker, amount = line.split price = server.getQuote(ticker) if price <= 0 puts "Unable to fetch a price for that ticker symbol." next end if amount =~ /^\$(\d+)$/ dollars = Integer($1) shares = (dollars / price).to_i elsif amount =~ /^[1-9]\d*$/ shares = Integer(amount) else puts "Unknown amount format." next end if shares.zero? puts "You can't purchase any shares for that amount." next else date = Time.now.strftime("%m/%d/%y %H:%M") buy = Struct::Shares.new(ticker, shares, price, date) portfolio[buy.symbol] = buy puts "You purchased #{buy.shares} shares of # {buy.symbol} " + "for $#{"%.2f" % (buy.shares * price)}." end end File.open(file_name, "w") { |file| YAML.dump(portfolio, file) } end output = [%w{Symbol Shares Buy\ Price Buy\ Date Current\ Price Gain/ Loss}] portfolio.each do |ticker, details| current = server.getQuote(ticker) output << [ ticker, details.shares, details.price, details.date, current, details.shares * current - details.shares * details.price ] end widths = Array.new(output.first.size, 0) output.each do |row| row.each_index do |index| width = if row[index].is_a? Float ("%.2f" % row[index]).length + 1 else row[index].to_s.length end widths[index] = width if width > widths[index] end end border = "+-" + widths.map { |width| "-" * width }.join("-+-") + "-+" template = ("| " + output.last.map do |column| case column when Float "$%#{widths.shift - 1}.2f" when Integer "%#{widths.shift}d" else "%#{widths.shift}s" end end.join(" | ") + " |").sub(/\A\| %/, "| %-") puts border puts template.gsub(/ \| \$?%(\d+)(?:\.\d+)?[sdf]/, " | %\\1s") % output.first output[1..-1].sort.each do |row| puts border puts template % row end puts border __END__ James Edward Gray II