diff --git a/cmd/mop.go b/cmd/mop.go
index 7726410..53442df 100644
--- a/cmd/mop.go
+++ b/cmd/mop.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.
Command Description
@@ -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)
diff --git a/column_editor.go b/column_editor.go
index dfef0d5..699bcde 100644
--- a/column_editor.go
+++ b/column_editor.go
@@ -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()
diff --git a/layout.go b/layout.go
index fff1b80..d6ff386 100644
--- a/layout.go
+++ b/layout.go
@@ -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 := `{{.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}}
-{{.London.name}}> {{.London.change}} ({{.London.percent}}) at {{.London.latest}} {{.Frankfurt.name}}> {{.Frankfurt.change}} ({{.Frankfurt.percent}}) at {{.Frankfurt.latest}} {{.Paris.name}}> {{.Paris.change}} ({{.Paris.percent}}) at {{.Paris.latest}} {{if .IsClosed}}U.S. markets closed{{end}}
-{{.Tokyo.name}}> {{.Tokyo.change}} ({{.Tokyo.percent}}) at {{.Tokyo.latest}} {{.HongKong.name}}> {{.HongKong.change}} ({{.HongKong.percent}}) at {{.HongKong.latest}} {{.Shanghai.name}}> {{.Shanghai.change}} ({{.Shanghai.percent}}) at {{.Shanghai.latest}}`
+ markup := `Dow> {{.Dow.change}} ({{.Dow.percent}}) at {{.Dow.latest}} S&P 500> {{.Sp500.change}} ({{.Sp500.percent}}) at {{.Sp500.latest}} NASDAQ> {{.Nasdaq.change}} ({{.Nasdaq.percent}}) at {{.Nasdaq.latest}}
+Tokyo> {{.Tokyo.change}} ({{.Tokyo.percent}}) at {{.Tokyo.latest}} HK> {{.HongKong.change}} ({{.HongKong.percent}}) at {{.HongKong.latest}} London> {{.London.change}} ({{.London.percent}}) at {{.London.latest}} Frankfurt> {{.Frankfurt.change}} ({{.Frankfurt.percent}}) at {{.Frankfurt.latest}} {{if .IsClosed}}U.S. markets closed{{end}}
+10-Year Yield> {{.Yield.latest}}% ({{.Yield.change}}) Euro> ${{.Euro.latest}} ({{.Euro.change}}%) Yen> ¥{{.Yen.latest}} ({{.Yen.change}}%) Oil> ${{.Oil.latest}} ({{.Oil.change}}%) 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
}
diff --git a/line_editor.go b/line_editor.go
index d2d1779..03cab55 100644
--- a/line_editor.go
+++ b/line_editor.go
@@ -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
diff --git a/markup.go b/markup.go
index 6675c13..fae6b1e 100644
--- a/markup.go
+++ b/markup.go
@@ -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
diff --git a/sorter.go b/sorter.go
index 87057b9..f02e178 100644
--- a/sorter.go
+++ b/sorter.go
@@ -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
diff --git a/yahoo_quotes.go b/yahoo_quotes.go
index 7dd6e8e..a20fcb0 100644
--- a/yahoo_quotes.go
+++ b/yahoo_quotes.go
@@ -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