Outputs all reports as HTML in the same given folder.master
@@ -18,9 +18,9 @@ type ( | |||
Report struct { | |||
Num int | |||
Month string | |||
Year int `json:"year"` | |||
Summary string `json:"summary"` | |||
Sections []Section | |||
Year int `json:"year"` | |||
Summary string `json:"summary"` | |||
Sections []Section `json:"sections"` | |||
} | |||
// Section represents an area of life to report on. This contains a | |||
@@ -42,6 +42,12 @@ func ParseReport(f *os.File) (*Report, error) { | |||
var err error | |||
r := Report{} | |||
// Parse JSON into a Report | |||
jsonParser := json.NewDecoder(f) | |||
if err = jsonParser.Decode(&r); err != nil { | |||
return nil, err | |||
} | |||
// Determine report number and month from filename in the format | |||
// NNN-month.json | |||
baseName := path.Base(f.Name()) | |||
@@ -58,53 +64,5 @@ func ParseReport(f *os.File) (*Report, error) { | |||
r.Month = "First" | |||
} | |||
// Parse JSON into a map | |||
var d map[string]interface{} | |||
jsonParser := json.NewDecoder(f) | |||
if err = jsonParser.Decode(&d); err != nil { | |||
return nil, err | |||
} | |||
// Populate Report struct from the map | |||
for k, v := range d { | |||
// Handle consistent properties here, like year | |||
if k == "year" { | |||
r.Year = int(v.(float64)) | |||
continue | |||
} else if k == "summary" { | |||
r.Summary = v.(string) | |||
continue | |||
} | |||
// All other properties will be the names of sections. The property name | |||
// will be used as the default title for any given section, unless | |||
// overridden by the object's actual `title` property. | |||
s := Section{ | |||
Title: k, | |||
} | |||
m := v.(map[string]interface{}) | |||
if m["title"] != nil { | |||
s.Title = m["title"].(string) | |||
} | |||
// Populate section summary | |||
if m["summary"] != nil { | |||
sums := m["summary"].([]interface{}) | |||
for _, sum := range sums { | |||
s.Summary = append(s.Summary, template.HTML(sum.(string))) | |||
} | |||
} | |||
// Populate section details | |||
if m["details"] != nil { | |||
dets := m["details"].([]interface{}) | |||
for _, det := range dets { | |||
s.Details = append(s.Details, template.HTML(det.(string))) | |||
} | |||
} | |||
r.Sections = append(r.Sections, s) | |||
} | |||
return &r, nil | |||
} |
@@ -3,8 +3,10 @@ package main | |||
import ( | |||
"fmt" | |||
"html/template" | |||
"io/ioutil" | |||
"os" | |||
"path" | |||
"strings" | |||
report "github.com/thebaer/life-report" | |||
) | |||
@@ -18,23 +20,49 @@ func main() { | |||
} | |||
dir := os.Args[1] | |||
f, err := os.Open(path.Join(dir, "template.json")) | |||
files, err := ioutil.ReadDir(dir) | |||
if err != nil { | |||
fmt.Fprintf(os.Stdout, "Unable to open file: %v\n", err) | |||
fmt.Print("Unable to read directory: %v\n", err) | |||
return | |||
} | |||
r, err := report.ParseReport(f) | |||
t, err := template.ParseFiles("../report.tmpl") | |||
if err != nil { | |||
fmt.Fprintf(os.Stdout, "Unable to parse report: %v\n", err) | |||
fmt.Printf("Unable to parse template: %v\n", err) | |||
return | |||
} | |||
f.Close() | |||
t, err := template.ParseFiles("../report.tmpl") | |||
if err != nil { | |||
fmt.Fprintf(os.Stdout, "Unable to parse template: %v\n", err) | |||
return | |||
for _, file := range files { | |||
if file.Name() == "template.json" || !strings.HasSuffix(file.Name(), ".json") { | |||
continue | |||
} | |||
f, err := os.Open(path.Join(dir, file.Name())) | |||
if err != nil { | |||
fmt.Fprintf(os.Stdout, "Unable to open file: %v\n", err) | |||
continue | |||
} | |||
if strings.HasPrefix(file.Name(), ".") { | |||
f.Close() | |||
continue | |||
} | |||
r, err := report.ParseReport(f) | |||
if err != nil { | |||
f.Close() | |||
fmt.Fprintf(os.Stdout, "Unable to parse report %s: %v\n", file.Name(), err) | |||
continue | |||
} | |||
f.Close() | |||
outName := strings.Replace(file.Name(), ".json", ".html", 1) | |||
o, err := os.Create(path.Join(dir, outName)) | |||
if err != nil { | |||
fmt.Fprintf(os.Stdout, "Unable to write report %s: %v\n", outName, err) | |||
continue | |||
} | |||
t.Execute(o, r) | |||
o.Close() | |||
} | |||
t.Execute(os.Stdout, r) | |||
} |
@@ -1,36 +1,45 @@ | |||
{ | |||
"year": 2016, | |||
"health": { | |||
"title": "health / diet", | |||
"details": [ | |||
] | |||
}, | |||
"money": { | |||
"summary": [ | |||
] | |||
}, | |||
"travels": { | |||
"details": [ | |||
] | |||
}, | |||
"studies": { | |||
"details": [ | |||
] | |||
}, | |||
"music": { | |||
"details": [ | |||
] | |||
}, | |||
"books": { | |||
"details": [ | |||
] | |||
}, | |||
"distractions": { | |||
"details": [ | |||
] | |||
}, | |||
"projects": { | |||
"details": [ | |||
] | |||
} | |||
"sections": [ | |||
{ | |||
"title": "health / diet", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "money", | |||
"summary": [ | |||
] | |||
}, | |||
{ | |||
"title": "travels", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "studies", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "music", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "books", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "distractions", | |||
"details": [ | |||
] | |||
}, | |||
{ | |||
"title": "work / projects", | |||
"details": [ | |||
] | |||
} | |||
] | |||
} |