Fix sections order and generate multiple reports

Outputs all reports as HTML in the same given folder.
This commit is contained in:
Matt Baer 2016-03-07 15:41:20 -05:00
parent 0e4c211104
commit 38a2c39509
3 changed files with 90 additions and 95 deletions

View File

@ -18,9 +18,9 @@ type (
Report struct { Report struct {
Num int Num int
Month string Month string
Year int `json:"year"` Year int `json:"year"`
Summary string `json:"summary"` Summary string `json:"summary"`
Sections []Section Sections []Section `json:"sections"`
} }
// Section represents an area of life to report on. This contains a // 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 var err error
r := Report{} 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 // Determine report number and month from filename in the format
// NNN-month.json // NNN-month.json
baseName := path.Base(f.Name()) baseName := path.Base(f.Name())
@ -58,53 +64,5 @@ func ParseReport(f *os.File) (*Report, error) {
r.Month = "First" 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 return &r, nil
} }

View File

@ -3,8 +3,10 @@ package main
import ( import (
"fmt" "fmt"
"html/template" "html/template"
"io/ioutil"
"os" "os"
"path" "path"
"strings"
report "github.com/thebaer/life-report" report "github.com/thebaer/life-report"
) )
@ -18,23 +20,49 @@ func main() {
} }
dir := os.Args[1] dir := os.Args[1]
f, err := os.Open(path.Join(dir, "template.json")) files, err := ioutil.ReadDir(dir)
if err != nil { if err != nil {
fmt.Fprintf(os.Stdout, "Unable to open file: %v\n", err) fmt.Print("Unable to read directory: %v\n", err)
return return
} }
r, err := report.ParseReport(f)
if err != nil {
fmt.Fprintf(os.Stdout, "Unable to parse report: %v\n", err)
return
}
f.Close()
t, err := template.ParseFiles("../report.tmpl") t, err := template.ParseFiles("../report.tmpl")
if err != nil { if err != nil {
fmt.Fprintf(os.Stdout, "Unable to parse template: %v\n", err) fmt.Printf("Unable to parse template: %v\n", err)
return return
} }
t.Execute(os.Stdout, r)
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()
}
} }

View File

@ -1,36 +1,45 @@
{ {
"year": 2016, "year": 2016,
"health": { "sections": [
"title": "health / diet", {
"details": [ "title": "health / diet",
] "details": [
}, ]
"money": { },
"summary": [ {
] "title": "money",
}, "summary": [
"travels": { ]
"details": [ },
] {
}, "title": "travels",
"studies": { "details": [
"details": [ ]
] },
}, {
"music": { "title": "studies",
"details": [ "details": [
] ]
}, },
"books": { {
"details": [ "title": "music",
] "details": [
}, ]
"distractions": { },
"details": [ {
] "title": "books",
}, "details": [
"projects": { ]
"details": [ },
] {
} "title": "distractions",
"details": [
]
},
{
"title": "work / projects",
"details": [
]
}
]
} }