Idiomatic Go

master
Michael Dvorkin 10 years ago
parent 27ebd8dfa4
commit 51b6250fcf
  1. 10
      cmd/mop.go
  2. 16
      column_editor.go
  3. 36
      layout.go
  4. 14
      line_editor.go
  5. 7
      markup.go
  6. 10
      sorter.go
  7. 21
      yahoo_quotes.go

@ -10,7 +10,7 @@ import (
`time`
)
const help = `Mop v0.1.0 -- Copyright (c) 2013 Michael Dvorkin. All Rights Reserved.
const help = `Mop v0.2.0 -- Copyright (c) 2013-15 Michael Dvorkin. All Rights Reserved.
NO WARRANTIES OF ANY KIND WHATSOEVER. SEE THE LICENSE FILE FOR DETAILS.
<u>Command</u> <u>Description </u>
@ -46,8 +46,8 @@ func mainLoop(screen *mop.Screen, profile *mop.Profile) {
}
}()
market := new(mop.Market).Initialize()
quotes := new(mop.Quotes).Initialize(market, profile)
market := mop.NewMarket()
quotes := mop.NewQuotes(market, profile)
screen.Draw(market, quotes)
loop:
@ -60,10 +60,10 @@ loop:
if event.Key == termbox.KeyEsc || event.Ch == 'q' || event.Ch == 'Q' {
break loop
} else if event.Ch == '+' || event.Ch == '-' {
lineEditor = new(mop.LineEditor).Initialize(screen, quotes)
lineEditor = mop.NewLineEditor(screen, quotes)
lineEditor.Prompt(event.Ch)
} else if event.Ch == 'o' || event.Ch == 'O' {
columnEditor = new(mop.ColumnEditor).Initialize(screen, quotes)
columnEditor = mop.NewColumnEditor(screen, quotes)
} else if event.Ch == 'g' || event.Ch == 'G' {
if profile.Regroup() == nil {
screen.Draw(quotes)

@ -16,13 +16,15 @@ type ColumnEditor struct {
profile *Profile // Pointer to Profile where we save newly selected sort order.
}
// Initialize sets internal variables and highlights current column name
// (as stored in Profile).
func (editor *ColumnEditor) Initialize(screen *Screen, quotes *Quotes) *ColumnEditor {
editor.screen = screen
editor.quotes = quotes
editor.layout = screen.layout
editor.profile = quotes.profile
// Returns new initialized ColumnEditor struct. As part of initialization it
// highlights current column name (as stored in Profile).
func NewColumnEditor(screen *Screen, quotes *Quotes) *ColumnEditor {
editor := &ColumnEditor{
screen: screen,
quotes: quotes,
layout: screen.layout,
profile: quotes.profile,
}
editor.selectCurrentColumn()

@ -33,9 +33,9 @@ type Layout struct {
quotesTemplate *template.Template // Pointer to template to format the list of stock quotes.
}
// Initialize assigns the default values that stay unchanged for the life of
// allocated Layout struct.
func (layout *Layout) Initialize() *Layout {
// Creates the layout and assigns the default values that stay unchanged.
func NewLayout() *Layout {
layout := &Layout{}
layout.columns = []Column{
{ -7, `Ticker`, `Ticker`, nil },
{ 10, `LastTrade`, `Last`, currency },
@ -67,8 +67,9 @@ func (layout *Layout) Market(market *Market) string {
return err // then simply return the error string.
}
highlight(market.Dow, market.Sp500, market.Nasdaq, market.London, market.Frankfurt,
market.Paris, market.Tokyo, market.HongKong, market.Shanghai)
highlight(market.Dow, market.Sp500, market.Nasdaq,
market.Tokyo, market.HongKong, market.London, market.Frankfurt,
market.Yield, market.Oil, market.Euro, market.Gold)
buffer := new(bytes.Buffer)
layout.marketTemplate.Execute(buffer, market)
@ -152,7 +153,7 @@ func (layout *Layout) prettify(quotes *Quotes) []Stock {
profile := quotes.profile
if layout.sorter == nil { // Initialize sorter on first invocation.
layout.sorter = new(Sorter).Initialize(profile)
layout.sorter = NewSorter(profile)
}
layout.sorter.SortByCurrentColumn(pretty)
//
@ -183,9 +184,9 @@ func (layout *Layout) pad(str string, width int) string {
//-----------------------------------------------------------------------------
func buildMarketTemplate() *template.Template {
markup := `<yellow>{{.Dow.name}}</> {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}} <yellow>{{.Sp500.name}}</> {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}} <yellow>{{.Nasdaq.name}}</> {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}
<yellow>{{.London.name}}</> {{.London.change}} ({{.London.percent}}) at {{.London.latest}} <yellow>{{.Frankfurt.name}}</> {{.Frankfurt.change}} ({{.Frankfurt.percent}}) at {{.Frankfurt.latest}} <yellow>{{.Paris.name}}</> {{.Paris.change}} ({{.Paris.percent}}) at {{.Paris.latest}} {{if .IsClosed}}<right>U.S. markets closed</right>{{end}}
<yellow>{{.Tokyo.name}}</> {{.Tokyo.change}} ({{.Tokyo.percent}}) at {{.Tokyo.latest}} <yellow>{{.HongKong.name}}</> {{.HongKong.change}} ({{.HongKong.percent}}) at {{.HongKong.latest}} <yellow>{{.Shanghai.name}}</> {{.Shanghai.change}} ({{.Shanghai.percent}}) at {{.Shanghai.latest}}`
markup := `<yellow>Dow</> {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}} <yellow>S&P 500</> {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}} <yellow>NASDAQ</> {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}
<yellow>Tokyo</> {{.Tokyo.change}} ({{.Tokyo.percent}}) at {{.Tokyo.latest}} <yellow>HK</> {{.HongKong.change}} ({{.HongKong.percent}}) at {{.HongKong.latest}} <yellow>London</> {{.London.change}} ({{.London.percent}}) at {{.London.latest}} <yellow>Frankfurt</> {{.Frankfurt.change}} ({{.Frankfurt.percent}}) at {{.Frankfurt.latest}} {{if .IsClosed}}<right>U.S. markets closed</right>{{end}}
<yellow>10-Year Yield</> {{.Yield.latest}}% ({{.Yield.change}}) <yellow>Euro</> ${{.Euro.latest}} ({{.Euro.change}}%) <yellow>Yen</> ¥{{.Yen.latest}} ({{.Yen.change}}%) <yellow>Oil</> ${{.Oil.latest}} ({{.Oil.change}}%) <yellow>Gold</> ${{.Gold.latest}} ({{.Gold.change}}%)`
return template.Must(template.New(`market`).Parse(markup))
}
@ -267,7 +268,8 @@ func last(str string) string {
if len(str) >= 6 && str[0:6] == `N/A - ` {
return str[6:]
}
return str
return percent(str)
}
//-----------------------------------------------------------------------------
@ -282,11 +284,23 @@ func currency(str string) string {
return `$` + str
}
// Returns percent value truncated at 2 decimal points.
//-----------------------------------------------------------------------------
func percent(str string) string {
if str == `N/A` {
return `-`
}
return str + `%`
split := strings.Split(str, ".")
if len(split) == 2 {
digits := len(split[1])
if digits > 2 {
digits = 2
}
str = split[0] + "." + split[1][0:digits]
}
if str[len(str)-1] != '%' {
str += `%`
}
return str
}

@ -24,13 +24,13 @@ type LineEditor struct {
regex *regexp.Regexp // Regex to split comma-delimited input string.
}
// Initialize sets internal pointers and compiles the regular expression.
func (editor *LineEditor) Initialize(screen *Screen, quotes *Quotes) *LineEditor {
editor.screen = screen
editor.quotes = quotes
editor.regex = regexp.MustCompile(`[,\s]+`)
return editor
// Returns new initialized LineEditor struct.
func NewLineEditor(screen *Screen, quotes *Quotes) *LineEditor {
return &LineEditor{
screen: screen,
quotes: quotes,
regex: regexp.MustCompile(`[,\s]+`),
}
}
// Prompt displays a prompt in response to '+' or '-' commands. Unknown commands

@ -31,9 +31,10 @@ type Markup struct {
regex *regexp.Regexp // Regex to identify the supported tag names.
}
// Initialize creates tags to Termbox translation hash and sets default
// colors and string alignment.
func (markup *Markup) Initialize() *Markup {
// Creates markup to define tag to Termbox translation rules and store default
// colors and column alignments.
func NewMarkup() *Markup {
markup := &Markup{}
markup.Foreground = termbox.ColorDefault
markup.Background = termbox.ColorDefault
markup.RightAligned = false

@ -85,11 +85,11 @@ func (list byDividendDesc) Less(i, j int) bool { return list.sortable[j].Divi
func (list byYieldDesc) Less(i, j int) bool { return list.sortable[j].Yield < list.sortable[i].Yield }
func (list byMarketCapDesc) Less(i, j int) bool { return m(list.sortable[j].MarketCap) < m(list.sortable[i].MarketCap) }
// Initialize simply saves the pointer to Profile for later use.
func (sorter *Sorter) Initialize(profile *Profile) *Sorter {
sorter.profile = profile
return sorter
// Returns new Sorter struct.
func NewSorter(profile *Profile) *Sorter {
return &Sorter{
profile: profile,
}
}
// SortByCurrentColumn builds a list of sort interface based on current sort

@ -15,11 +15,7 @@ import (
// See http://www.gummy-stuff.org/Yahoo-stocks.htm
//
// Also http://query.yahooapis.com/v1/public/yql
// ?q=select%20*%20from%20yahoo.finance.quotes%20where%20symbol%20in(%22ALU%22,%22AAPL%22)
// &env=http%3A%2F%2Fstockstables.org%2Falltables.env&format=json'
//const quotesURL = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1c6k2oghjkva2r2rdyj3j1`
// const quotesURL = `http://download.finance.yahoo.com/d/quotes.csv?s=%s&f=sl1c6k2oghjkva2r2rdyj3j1`
// c2: realtime change vs c1: change
// k2: realtime change vs p2: change
//
@ -57,14 +53,13 @@ type Quotes struct {
errors string // Error string if any.
}
// Initialize sets the initial values for the Quotes struct. It returns "self"
// so that the next function call could be chained.
func (quotes *Quotes) Initialize(market *Market, profile *Profile) *Quotes {
quotes.market = market
quotes.profile = profile
quotes.errors = ``
return quotes
// Sets the initial values and returns new Quotes struct.
func NewQuotes(market *Market, profile *Profile) *Quotes {
return &Quotes{
market: market,
profile: profile,
errors: ``,
}
}
// Fetch the latest stock quotes and parse raw fetched data into array of

Loading…
Cancel
Save