More tweaking of graceful panic/recover

master
Michael Dvorkin 11 years ago
parent 7accc918cb
commit 8f55a6acf7
  1. 29
      layout.go
  2. 9
      yahoo_market.go
  3. 47
      yahoo_quotes.go

@ -53,26 +53,24 @@ func (self *Layout) Market(market *Market) string {
return err
}
buffer := new(bytes.Buffer)
markup := `{{.Dow.name}}: {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}}, {{.Sp500.name}}: {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}}, {{.Nasdaq.name}}: {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}
{{.Advances.name}}: {{.Advances.nyse}} ({{.Advances.nysep}}) on NYSE and {{.Advances.nasdaq}} ({{.Advances.nasdaqp}}) on Nasdaq. {{.Declines.name}}: {{.Declines.nyse}} ({{.Declines.nysep}}) on NYSE and {{.Declines.nasdaq}} ({{.Declines.nasdaqp}}) on Nasdaq {{if .IsClosed}}<right>U.S. markets closed</right>{{end}}
New highs: {{.Highs.nyse}} on NYSE and {{.Highs.nasdaq}} on Nasdaq. New lows: {{.Lows.nyse}} on NYSE and {{.Lows.nasdaq}} on Nasdaq.`
template, err := template.New(`market`).Parse(markup)
if err != nil {
panic(err)
}
buffer := new(bytes.Buffer)
highlight(market.Dow, market.Sp500, market.Nasdaq)
if err := template.Execute(buffer, market); err != nil {
panic(err)
}
template,_ := template.New(`market`).Parse(markup)
template.Execute(buffer, market)
return buffer.String()
}
//-----------------------------------------------------------------------------
func (self *Layout) Quotes(quotes *Quotes) string {
if ok, err := quotes.Ok(); !ok {
return err
}
vars := struct {
Now string
Header string
@ -83,6 +81,7 @@ func (self *Layout) Quotes(quotes *Quotes) string {
self.prettify(quotes),
}
buffer := new(bytes.Buffer)
markup := `<right><white>{{.Now}}</></right>
@ -90,17 +89,9 @@ func (self *Layout) Quotes(quotes *Quotes) string {
{{.Header}}
{{range.Stocks}}{{if .Advancing}}<green>{{end}}{{.Ticker}}{{.LastTrade}}{{.Change}}{{.ChangePct}}{{.Open}}{{.Low}}{{.High}}{{.Low52}}{{.High52}}{{.Volume}}{{.AvgVolume}}{{.PeRatio}}{{.Dividend}}{{.Yield}}{{.MarketCap}}</>
{{end}}`
//markup += fmt.Sprintf("[%v]", quotes.profile.Grouped)
template, err := template.New(`quotes`).Parse(markup)
if err != nil {
panic(err)
}
buffer := new(bytes.Buffer)
err = template.Execute(buffer, vars)
if err != nil {
panic(err)
}
template,_ := template.New(`quotes`).Parse(markup)
template.Execute(buffer, vars)
return buffer.String()
}

@ -1,6 +1,7 @@
// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//-----------------------------------------------------------------------------
package mop
@ -13,7 +14,7 @@ import (
`strings`
)
const url = `http://finance.yahoo.com/marketupdate/overview`
const market_url = `http://finance.yahoo.com/marketupdate/overview`
type Market struct {
IsClosed bool
@ -67,14 +68,14 @@ func (self *Market) Initialize() *Market {
//-----------------------------------------------------------------------------
func (self *Market) Fetch() (this *Market) {
this = self // <-- This ensures we return correct self in case of panic attack.
this = self // <-- This ensures we return correct self after recover() from panic() attack.
defer func() {
if err := recover(); err != nil {
self.errors = fmt.Sprintf("Error fetching market data...\n%s", err)
}
}()
response, err := http.Get(url)
response, err := http.Get(market_url)
if err != nil {
panic(err)
}
@ -124,7 +125,7 @@ func (self *Market) trim(body []byte) []byte {
func (self *Market) extract(snippet []byte) *Market {
matches := self.regex.FindAllStringSubmatch(string(snippet), -1)
if len(matches) < 1 || len(matches[0]) < 37 {
panic(`Unable to parse ` + url)
panic(`Unable to parse ` + market_url)
}
self.Dow[`name`] = matches[0][1]

@ -1,6 +1,7 @@
// Copyright (c) 2013 by Michael Dvorkin. All Rights Reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
//-----------------------------------------------------------------------------
package mop
@ -35,7 +36,7 @@ import (
// j3: market cap rt
// j1: market cap
const yahoo_quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1`
const quotes_url = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=,l1c6k2oghjkva2r2rdyj3j1`
type Stock struct {
Ticker string
@ -62,48 +63,53 @@ type Quotes struct {
market *Market
profile *Profile
stocks []Stock
errors string
}
//-----------------------------------------------------------------------------
func (self *Quotes) Initialize(market *Market, profile *Profile) *Quotes {
self.market = market
self.profile = profile
self.errors = ``
return self
}
// Fetch the latest stock quotes and parse raw fetched data into array of
// []Stock structs.
func (self *Quotes) Fetch() *Quotes {
if self.Ready() {
// Format the URL and send the request.
url := fmt.Sprintf(yahoo_quotes_url, self.profile.ListOfTickers())
//-----------------------------------------------------------------------------
func (self *Quotes) Fetch() (this *Quotes) {
this = self // <-- This ensures we return correct self after recover() from panic() attack.
if self.is_ready() {
defer func() {
if err := recover(); err != nil {
self.errors = fmt.Sprintf("\n\n\n\nError fetching stock quotes...\n%s", err)
}
}()
url := fmt.Sprintf(quotes_url, self.profile.ListOfTickers())
response, err := http.Get(url)
if err != nil {
panic(err)
}
// Fetch response and get its body.
defer response.Body.Close()
body, err := ioutil.ReadAll(response.Body)
if err != nil {
panic(err)
}
self.parse(self.sanitize(body))
self.parse(sanitize(body))
}
return self
}
// Return true if we haven't fetched the quotes yet *or* the stock market is
// still open and we might want to grab the latest quotes. In both cases we
// make sure the list of requested tickers is not empty.
func (self *Quotes) Ready() bool {
return (self.stocks == nil || !self.market.IsClosed) && len(self.profile.Tickers) > 0
//-----------------------------------------------------------------------------
func (self *Quotes) Ok() (bool, string) {
return self.errors == ``, self.errors
}
//-----------------------------------------------------------------------------
func (self *Quotes) Format() string {
return new(Layout).Initialize().Quotes(self)
@ -125,6 +131,17 @@ func (self *Quotes) RemoveTickers(tickers []string) (removed int, err error) {
return
}
// "Private" methods.
// Return true if we haven't fetched the quotes yet *or* the stock market is
// still open and we might want to grab the latest quotes. In both cases we
// make sure the list of requested tickers is not empty.
//-----------------------------------------------------------------------------
func (self *Quotes) is_ready() bool {
return (self.stocks == nil || !self.market.IsClosed) && len(self.profile.Tickers) > 0
}
//-----------------------------------------------------------------------------
func (self *Quotes) parse(body []byte) *Quotes {
lines := bytes.Split(body, []byte{'\n'})
@ -155,7 +172,9 @@ func (self *Quotes) parse(body []byte) *Quotes {
return self
}
// Utility methods.
//-----------------------------------------------------------------------------
func (self *Quotes) sanitize(body []byte) []byte {
func sanitize(body []byte) []byte {
return bytes.Replace(bytes.TrimSpace(body), []byte{'"'}, []byte{}, -1)
}

Loading…
Cancel
Save