Use reflection when formatting column data

master
Michael Dvorkin 11 years ago
parent 1152285520
commit 7b75a6387d
  1. 80
      layout.go
  2. 11
      yahoo_quotes.go

@ -7,6 +7,7 @@ package mop
import ( import (
`bytes` `bytes`
`fmt` `fmt`
`reflect`
`regexp` `regexp`
`strings` `strings`
`text/template` `text/template`
@ -16,8 +17,10 @@ import (
const TotalColumns = 15 const TotalColumns = 15
type Column struct { type Column struct {
width int width int
title string name string
title string
formatter func(string)string
} }
type Layout struct { type Layout struct {
@ -30,21 +33,21 @@ type Layout struct {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Layout) Initialize() *Layout { func (self *Layout) Initialize() *Layout {
self.columns = []Column{ self.columns = []Column{
{ -7, `Ticker` }, { -7, `Ticker`, `Ticker`, nil },
{ 10, `Last` }, { 10, `LastTrade`, `Last`, currency },
{ 10, `Change` }, { 10, `Change`, `Change`, currency },
{ 10, `Change%` }, { 10, `ChangePct`, `Change%`, last },
{ 10, `Open` }, { 10, `Open`, `Open`, currency },
{ 10, `Low` }, { 10, `Low`, `Low`, currency },
{ 10, `High` }, { 10, `High`, `High`, currency },
{ 10, `52w Low` }, { 10, `Low52`, `52w Low`, currency },
{ 10, `52w High` }, { 10, `High52`, `52w High`, currency },
{ 11, `Volume` }, { 11, `Volume`, `Volume`, nil },
{ 11, `AvgVolume` }, { 11, `AvgVolume`, `AvgVolume`, nil },
{ 9, `P/E` }, { 9, `PeRatio`, `P/E`, blank },
{ 9, `Dividend` }, { 9, `Dividend`, `Dividend`, blank_currency },
{ 9, `Yield` }, { 9, `Yield`, `Yield`, percent },
{ 11, `MktCap` }, { 11, `MarketCap`, `MktCap`, currency },
} }
self.regex = regexp.MustCompile(`(\.\d+)[MB]?$`) self.regex = regexp.MustCompile(`(\.\d+)[MB]?$`)
self.market_template = build_market_template() self.market_template = build_market_template()
@ -107,24 +110,27 @@ func (self *Layout) Header(profile *Profile) string {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Layout) prettify(quotes *Quotes) []Stock { func (self *Layout) prettify(quotes *Quotes) []Stock {
pretty := make([]Stock, len(quotes.stocks)) pretty := make([]Stock, len(quotes.stocks))
//
for i, q := range quotes.stocks { // Iterate over the list of stocks and properly format all its columns.
pretty[i].Ticker = self.pad(q.Ticker, 0) //
pretty[i].LastTrade = self.pad(currency(q.LastTrade), 1) for i, stock := range quotes.stocks {
pretty[i].Change = self.pad(currency(q.Change), 2) pretty[i].Advancing = stock.Advancing
pretty[i].ChangePct = self.pad(last(q.ChangePct), 3) //
pretty[i].Open = self.pad(currency(q.Open), 4) // Iterate over the list of stock columns. For each column name:
pretty[i].Low = self.pad(currency(q.Low), 5) // - Get current column value.
pretty[i].High = self.pad(currency(q.High), 6) // - If the column has the formatter method then call it.
pretty[i].Low52 = self.pad(currency(q.Low52), 7) // - Set the column value padding it to the given width.
pretty[i].High52 = self.pad(currency(q.High52), 8) //
pretty[i].Volume = self.pad(q.Volume, 9) for _,column := range self.columns {
pretty[i].AvgVolume = self.pad(q.AvgVolume, 10) // ex. value = stock.Change
pretty[i].PeRatio = self.pad(blank(q.PeRatioX), 11) value := reflect.ValueOf(&stock).Elem().FieldByName(column.name).String()
pretty[i].Dividend = self.pad(blank_currency(q.Dividend), 12) if column.formatter != nil {
pretty[i].Yield = self.pad(percent(q.Yield), 13) // ex. value = currency(value)
pretty[i].MarketCap = self.pad(currency(q.MarketCapX), 14) value = column.formatter(value)
pretty[i].Advancing = q.Advancing }
// ex. pretty[i].Change = self.pad(value, 10)
reflect.ValueOf(&pretty[i]).Elem().FieldByName(column.name).SetString(self.pad(value, column.width))
}
} }
profile := quotes.profile profile := quotes.profile
@ -141,7 +147,7 @@ func (self *Layout) prettify(quotes *Quotes) []Stock {
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
func (self *Layout) pad(str string, col int) string { func (self *Layout) pad(str string, width int) string {
match := self.regex.FindStringSubmatch(str) match := self.regex.FindStringSubmatch(str)
if len(match) > 0 { if len(match) > 0 {
switch len(match[1]) { switch len(match[1]) {
@ -152,7 +158,7 @@ func (self *Layout) pad(str string, col int) string {
} }
} }
return fmt.Sprintf(`%*s`, self.columns[col].width, str) return fmt.Sprintf(`%*s`, width, str)
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------

@ -161,7 +161,16 @@ func (self *Quotes) parse(body []byte) *Quotes {
self.stocks[i].Yield = string(columns[14]) self.stocks[i].Yield = string(columns[14])
self.stocks[i].MarketCap = string(columns[15]) self.stocks[i].MarketCap = string(columns[15])
self.stocks[i].MarketCapX = string(columns[16]) self.stocks[i].MarketCapX = string(columns[16])
self.stocks[i].Advancing = self.stocks[i].Change[0:1] != `-` //
// Try realtime and revert to last known if realtime is not available.
//
if self.stocks[i].PeRatio == `N/A` && self.stocks[i].PeRatioX != `N/A` {
self.stocks[i].PeRatio = self.stocks[i].PeRatioX
}
if self.stocks[i].MarketCap == `N/A` && self.stocks[i].MarketCapX != `N/A` {
self.stocks[i].MarketCap = self.stocks[i].MarketCapX
}
self.stocks[i].Advancing = (self.stocks[i].Change[0:1] != `-`)
} }
return self return self

Loading…
Cancel
Save