diff options
-rw-r--r-- | cmd/mfmt/main.go | 25 | ||||
-rw-r--r-- | lib/mintage/parser.go | 32 | ||||
-rw-r--r-- | lib/mintage/parser_test.go | 44 | ||||
-rw-r--r-- | main.go | 16 | ||||
-rw-r--r-- | template/coins_mintages.templ | 34 |
5 files changed, 90 insertions, 61 deletions
diff --git a/cmd/mfmt/main.go b/cmd/mfmt/main.go index cb9b0cd..263b258 100644 --- a/cmd/mfmt/main.go +++ b/cmd/mfmt/main.go @@ -50,17 +50,20 @@ func mfmt(path string, in io.Reader, out io.Writer) error { } fmt.Fprintf(out, `BEGIN %d`, data.StartYear) - if len(data.Circ) != 0 { - fmt.Fprintln(out, "\n\nBEGIN CIRC") - formatSection(out, data.Circ) - } - if len(data.BU) != 0 { - fmt.Fprintln(out, "\n\nBEGIN BU") - formatSection(out, data.BU) - } - if len(data.Proof) != 0 { - fmt.Fprintln(out, "\n\nBEGIN PROOF") - formatSection(out, data.Proof) + for i, tbl := range data.Tables { + if len(tbl) != 0 { + var section string + switch mintage.CoinType(i) { + case mintage.TypeCirculated: + section = "CIRC" + case mintage.TypeNIFC: + section = "BU" + case mintage.TypeProof: + section = "PROOF" + } + fmt.Fprintf(out, "\n\nBEGIN %s\n", section) + formatSection(out, tbl) + } } fmt.Fprintln(out, "") diff --git a/lib/mintage/parser.go b/lib/mintage/parser.go index 4c5e6f9..fb92e64 100644 --- a/lib/mintage/parser.go +++ b/lib/mintage/parser.go @@ -9,6 +9,15 @@ import ( "unicode" ) +type CoinType int + +const ( + TypeCirculated CoinType = iota + TypeNIFC + TypeProof + coinTypes +) + const ( _ = -iota Unknown // Unknown mintage @@ -33,8 +42,8 @@ type Row struct { } type Set struct { - StartYear int - Circ, BU, Proof []Row + StartYear int + Tables [coinTypes][]Row } func (r Row) Label() string { @@ -46,8 +55,8 @@ func (r Row) Label() string { func Parse(reader io.Reader, file string) (Set, error) { var ( - data Set // Our data struct - slice *[]Row // Where to append mintages + data Set + ctype CoinType = -1 ) scanner := bufio.NewScanner(reader) @@ -77,11 +86,11 @@ func Parse(reader io.Reader, file string) (Set, error) { switch arg { case "CIRC": - slice = &data.Circ + ctype = TypeCirculated case "BU": - slice = &data.BU + ctype = TypeNIFC case "PROOF": - slice = &data.Proof + ctype = TypeProof default: if !isNumeric(arg, false) { return Set{}, SyntaxError{ @@ -113,7 +122,7 @@ func Parse(reader io.Reader, file string) (Set, error) { fallthrough case isNumeric(tokens[0], true), tokens[0] == "?": switch { - case slice == nil: + case ctype == -1: return Set{}, SyntaxError{ expected: "coin type declaration", got: tokens[0], @@ -146,10 +155,11 @@ func Parse(reader io.Reader, file string) (Set, error) { } row := Row{Mintmark: mintmark.s} - if len(*slice) == 0 { + if len(data.Tables[ctype]) == 0 { row.Year = data.StartYear } else { - row.Year = (*slice)[len(*slice)-1].Year + rows := data.Tables[ctype] + row.Year = rows[len(rows)-1].Year if row.Mintmark == "" || mintmark.star { row.Year++ } @@ -162,7 +172,7 @@ func Parse(reader io.Reader, file string) (Set, error) { row.Cols[i] = atoiWithDots(tok) } } - *slice = append(*slice, row) + data.Tables[ctype] = append(data.Tables[ctype], row) default: return Set{}, SyntaxError{ expected: "‘BEGIN’ directive or mintage row", diff --git a/lib/mintage/parser_test.go b/lib/mintage/parser_test.go index dd78c71..3cc8ea3 100644 --- a/lib/mintage/parser_test.go +++ b/lib/mintage/parser_test.go @@ -28,7 +28,7 @@ func TestParserComplete(t *testing.T) { data.StartYear) } - for i, row := range data.Circ { + for i, row := range data.Tables[TypeCirculated] { for j, col := range row.Cols { var n int if i == 1 && j == 1 { @@ -37,12 +37,12 @@ func TestParserComplete(t *testing.T) { n = 1000*i + j + 1000 } if col != n { - t.Fatalf("Expected data.Circ[i][j]=%d; got %d", n, col) + t.Fatalf("Expected data.Tables[TypeCirculated][i][j]=%d; got %d", n, col) } } } - for i, row := range data.BU { + for i, row := range data.Tables[TypeNIFC] { for j, col := range row.Cols { var n int if i == 1 && j == 1 { @@ -51,12 +51,12 @@ func TestParserComplete(t *testing.T) { n = 1000*i + j + 1100 } if col != n { - t.Fatalf("Expected data.BU[i][j]=%d; got %d", n, col) + t.Fatalf("Expected data.Tables[TypeNIFC][i][j]=%d; got %d", n, col) } } } - for i, row := range data.Proof { + for i, row := range data.Tables[TypeProof] { for j, col := range row.Cols { var n int if i == 1 && j == 1 { @@ -65,19 +65,19 @@ func TestParserComplete(t *testing.T) { n = 1000*i + j + 1200 } if col != n { - t.Fatalf("Expected data.Proof[i][j]=%d; got %d", n, col) + t.Fatalf("Expected data.Tables[TypeProof][i][j]=%d; got %d", n, col) } } } - if len(data.Circ) != 2 { - t.Fatalf("Expected len(data.Circ)=2; got %d", len(data.Circ)) + if len(data.Tables[TypeCirculated]) != 2 { + t.Fatalf("Expected len(data.Tables[TypeCirculated])=2; got %d", len(data.Tables[TypeCirculated])) } - if len(data.BU) != 2 { - t.Fatalf("Expected len(data.BU)=2; got %d", len(data.BU)) + if len(data.Tables[TypeNIFC]) != 2 { + t.Fatalf("Expected len(data.Tables[TypeNIFC])=2; got %d", len(data.Tables[TypeNIFC])) } - if len(data.Proof) != 2 { - t.Fatalf("Expected len(data.Proof)=2; got %d", len(data.Proof)) + if len(data.Tables[TypeProof]) != 2 { + t.Fatalf("Expected len(data.Tables[TypeProof])=2; got %d", len(data.Tables[TypeProof])) } } @@ -96,8 +96,8 @@ func TestParserNoProof(t *testing.T) { t.Fatalf(`Expected err=nil; got "%s"`, err) } - if len(data.Proof) != 0 { - t.Fatalf("Expected len(data.Proof)=0; got %d", len(data.Proof)) + if len(data.Tables[TypeProof]) != 0 { + t.Fatalf("Expected len(data.Tables[TypeProof])=0; got %d", len(data.Tables[TypeProof])) } } @@ -114,7 +114,7 @@ func TestParserMintmarks(t *testing.T) { t.Fatalf(`Expected err=nil; got "%s"`, err) } - for i, row := range data.Circ { + for i, row := range data.Tables[TypeCirculated] { for j, col := range row.Cols { var n int if i > 0 && j == 1 { @@ -123,21 +123,21 @@ func TestParserMintmarks(t *testing.T) { n = 1000*i + j + 1000 } if col != n { - t.Fatalf("Expected data.Circ[i][j]=%d; got %d", n, col) + t.Fatalf("Expected data.Tables[TypeCirculated][i][j]=%d; got %d", n, col) } } } for i, y := range [...]int{2020, 2021, 2021} { - if data.Circ[i].Year != y { - t.Fatalf("Expected data.Circ[%d].Year=%d; got %d", - i, y, data.Circ[i].Year) + if data.Tables[TypeCirculated][i].Year != y { + t.Fatalf("Expected data.Tables[TypeCirculated][%d].Year=%d; got %d", + i, y, data.Tables[TypeCirculated][i].Year) } } for i, s := range [...]string{"", "KNM", "MdP"} { - if data.Circ[i].Mintmark != s { - t.Fatalf(`Expected data.Circ[%d].Mintmark="%s"; got "%s"`, - i, s, data.Circ[i].Mintmark) + if data.Tables[TypeCirculated][i].Mintmark != s { + t.Fatalf(`Expected data.Tables[TypeCirculated][%d].Mintmark="%s"; got "%s"`, + i, s, data.Tables[TypeCirculated][i].Mintmark) } } } @@ -111,15 +111,27 @@ func mintageHandler(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { countries := lib.SortedCountries( r.Context().Value("printer").(lib.Printer)) - code := cmp.Or(r.FormValue("c"), countries[0].Code) + code := strings.ToLower(cmp.Or(r.FormValue("code"), countries[0].Code)) + ctype := strings.ToLower(cmp.Or(r.FormValue("type"), "circ")) path := filepath.Join("data", "mintages", code) f, _ := os.Open(path) // TODO: Handle error defer f.Close() set, _ := mintage.Parse(f, path) // TODO: Handle error + var idx mintage.CoinType + switch ctype { + case "circ": + idx = mintage.TypeCirculated + case "nifc": + idx = mintage.TypeNIFC + case "proof": + idx = mintage.TypeProof + } + ctx := context.WithValue(r.Context(), "code", code) - ctx = context.WithValue(ctx, "set", set) + ctx = context.WithValue(ctx, "type", ctype) + ctx = context.WithValue(ctx, "table", set.Tables[idx]) ctx = context.WithValue(ctx, "countries", countries) next.ServeHTTP(w, r.WithContext(ctx)) }) diff --git a/template/coins_mintages.templ b/template/coins_mintages.templ index b6ed2de..47940e1 100644 --- a/template/coins_mintages.templ +++ b/template/coins_mintages.templ @@ -17,7 +17,7 @@ var denoms = [...]float64{ templ CoinsMintages() { {{ code := ctx.Value("code").(string) - set := ctx.Value("set").(mintage.Set) + table := ctx.Value("table").([]mintage.Row) p := ctx.Value("printer").(lib.Printer) }} <header> @@ -45,7 +45,7 @@ templ CoinsMintages() { <div class="grid"> <label for="country-dd"> { p.T("Country") } - <select id="country-dd" name="c"> + <select id="country-dd" name="code"> for _, c := range ctx.Value("countries"). ([]lib.Country) { <option @@ -58,18 +58,9 @@ templ CoinsMintages() { </select> </label> <fieldset> - <label for="compact-circ"> - <input id="compact-circ" type="checkbox" name="circ" checked/> - { p.T("Circulation Coins") } - </label> - <label for="compact-nifc"> - <input id="compact-nifc" type="checkbox" name="nifc"/> - { p.T("NIFC / BU Sets") } - </label> - <label for="compact-proof"> - <input id="compact-proof" type="checkbox" name="proof"/> - { p.T("Proof Coins") } - </label> + @coinTypeRadio("circ", p.T("Circulation Coins")) + @coinTypeRadio("nifc", p.T("NIFC / BU Sets")) + @coinTypeRadio("proof", p.T("Proof Coins")) </fieldset> </div> <button type="submit">{ p.T("Filter") }</button> @@ -83,7 +74,7 @@ templ CoinsMintages() { } </thead> <tbody> - for _, row := range set.Circ { + for _, row := range table { <tr> <th scope="col"> if row.Mintmark != "" { @@ -110,3 +101,16 @@ templ CoinsMintages() { </section> </main> } + +templ coinTypeRadio(short, long string) { + <label for={ "compact-" + short }> + <input + id={ "compact-" + short } + type="radio" + name="type" + value={ short } + checked?={ ctx.Value("type").(string) == short } + /> + { long } + </label> +} |