Skip to content

Commit

Permalink
Add support for int and bool fields (#5)
Browse files Browse the repository at this point in the history
You can now annotate `string`, `int`, and `bool` fields. Any `bool` field value is `true` if it is equal in lowercase to one of `yes`, `y`, `true`, `t`.
  • Loading branch information
nfx authored Nov 5, 2022
1 parent d29d927 commit 4470783
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 52 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ _ = page.Each2("c", "d", func(c, d string) error {
// c:4 d:6
```

Complex [tables with row and col spans](https://en.wikipedia.org/wiki/List_of_AMD_chipsets#AM4_chipsets) are natively supported as well:
Complex [tables with row and col spans](https://en.wikipedia.org/wiki/List_of_AMD_chipsets#AM4_chipsets) are natively supported as well. You can annotate `string`, `int`, and `bool` fields. Any `bool` field value is `true` if it is equal in lowercase to one of `yes`, `y`, `true`, `t`.

![Wikipedia, AMD AM4 chipsets](doc/colspans-rowspans.png)

Expand All @@ -85,12 +85,12 @@ type AM4 struct {
Model string `header:"Model"`
ReleaseDate string `header:"Release date"`
PCIeSupport string `header:"PCIesupport[a]"`
MultiGpuCrossFire string `header:"Multi-GPU CrossFire"`
MultiGpuSLI string `header:"Multi-GPU SLI"`
MultiGpuCrossFire bool `header:"Multi-GPU CrossFire"`
MultiGpuSLI bool `header:"Multi-GPU SLI"`
USBSupport string `header:"USBsupport[b]"`
SATAPorts string `header:"Storage features SATAports"`
SATAPorts int `header:"Storage features SATAports"`
RAID string `header:"Storage features RAID"`
AMDStoreMI string `header:"Storage features AMD StoreMI"`
AMDStoreMI bool `header:"Storage features AMD StoreMI"`
Overclocking string `header:"Processoroverclocking"`
TDP string `header:"TDP"`
SupportExcavator string `header:"CPU support[14] Excavator"`
Expand Down
10 changes: 5 additions & 5 deletions example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,17 @@ func ExampleNewSliceFromUrl() {
// 3M
}

func ExampleNewSliceFromURL_rowspans() {
func ExampleNewSliceFromURL_rowspansAndColspans() {
type AM4 struct {
Model string `header:"Model"`
ReleaseDate string `header:"Release date"`
PCIeSupport string `header:"PCIesupport[a]"`
MultiGpuCrossFire string `header:"Multi-GPU CrossFire"`
MultiGpuSLI string `header:"Multi-GPU SLI"`
MultiGpuCrossFire bool `header:"Multi-GPU CrossFire"`
MultiGpuSLI bool `header:"Multi-GPU SLI"`
USBSupport string `header:"USBsupport[b]"`
SATAPorts string `header:"Storage features SATAports"`
SATAPorts int `header:"Storage features SATAports"`
RAID string `header:"Storage features RAID"`
AMDStoreMI string `header:"Storage features AMD StoreMI"`
AMDStoreMI bool `header:"Storage features AMD StoreMI"`
Overclocking string `header:"Processoroverclocking"`
TDP string `header:"TDP"`
SupportExcavator string `header:"CPU support[14] Excavator"`
Expand Down
46 changes: 41 additions & 5 deletions slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,16 +60,31 @@ func (f *feeder[T]) headers() ([]string, map[string]int, error) {
if header == "" {
continue
}
if field.Type.Kind() != reflect.String {
return nil, nil, fmt.Errorf("only strings are supported, %s is %v",
field.Name, field.Type.Name())
err := f.isTypeSupported(field)
if err != nil {
return nil, nil, err
}
fields[header] = i
headers = append(headers, header)
}
return headers, fields, nil
}

func (f *feeder[T]) isTypeSupported(field reflect.StructField) error {
k := field.Type.Kind()
if k == reflect.String {
return nil
}
if k == reflect.Int {
return nil
}
if k == reflect.Bool {
return nil
}
return fmt.Errorf("setting field is not supported, %s is %v",
field.Name, field.Type.Name())
}

func (f *feeder[T]) table() (*Table, map[int]int, error) {
headers, fields, err := f.headers()
if err != nil {
Expand Down Expand Up @@ -106,8 +121,29 @@ func (f *feeder[T]) slice() ([]T, error) {
// either corrupt row or something like that
continue
}
// remember, we work only with strings now
item.Field(field).SetString(row[idx])
switch item.Field(field).Kind() {
case reflect.String:
item.Field(field).SetString(row[idx])
case reflect.Bool:
var v bool
lower := strings.ToLower(row[idx])
if lower == "yes" ||
lower == "y" ||
lower == "true" ||
lower == "t" {
v = true
}
item.Field(field).SetBool(v)
case reflect.Int:
var v int64
_, err := fmt.Sscan(row[idx], &v)
if err != nil {
column := table.Header[idx]
return nil, fmt.Errorf("row %d: %s: %w", rowIdx, column, err)
}
item.Field(field).SetInt(v)
default: // noop
}
}
}
return sliceValue.Interface().([]T), nil
Expand Down
74 changes: 37 additions & 37 deletions slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,20 +53,20 @@ func TestNewSliceInvalidTypes(t *testing.T) {
C float32 `header:"c"`
}
_, err := NewSliceFromString[exotic](fixture)
assertEqualError(t, err, "only strings are supported, C is float32")
assertEqualError(t, err, "setting field is not supported, C is float32")
}

func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
type AM4 struct {
Model string `header:"Model"`
ReleaseDate string `header:"Release date"`
PCIeSupport string `header:"PCIesupport[a]"`
MultiGpuCrossFire string `header:"Multi-GPU CrossFire"`
MultiGpuSLI string `header:"Multi-GPU SLI"`
MultiGpuCrossFire bool `header:"Multi-GPU CrossFire"`
MultiGpuSLI bool `header:"Multi-GPU SLI"`
USBSupport string `header:"USBsupport[b]"`
SATAPorts string `header:"Storage features SATAports"`
SATAPorts int `header:"Storage features SATAports"`
RAID string `header:"Storage features RAID"`
AMDStoreMI string `header:"Storage features AMD StoreMI"`
AMDStoreMI bool `header:"Storage features AMD StoreMI"`
Overclocking string `header:"Processoroverclocking"`
TDP string `header:"TDP"`
SupportExcavator string `header:"CPU support[14] Excavator"`
Expand All @@ -83,12 +83,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "A320",
ReleaseDate: "February 2017[15]",
PCIeSupport: "PCIe 2.0 ×4",
MultiGpuCrossFire: "No",
MultiGpuSLI: "No",
MultiGpuCrossFire: false,
MultiGpuSLI: false,
USBSupport: "1, 2, 6",
SATAPorts: "4",
SATAPorts: 4,
RAID: "0,1,10",
AMDStoreMI: "No",
AMDStoreMI: false,
Overclocking: "Limited to pre-Zen CPUs, unless an unsupported third-party motherboard firmware applied",
TDP: "~5 W[16]",
SupportExcavator: "Yes",
Expand All @@ -102,12 +102,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "B350",
ReleaseDate: "February 2017[15]",
PCIeSupport: "PCIe 2.0 ×6",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "No",
MultiGpuCrossFire: true,
MultiGpuSLI: false,
USBSupport: "2, 2, 6",
SATAPorts: "4",
SATAPorts: 4,
RAID: "0,1,10",
AMDStoreMI: "No",
AMDStoreMI: false,
Overclocking: "Yes",
TDP: "~5 W[16]",
SupportExcavator: "Yes",
Expand All @@ -121,12 +121,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "X370",
ReleaseDate: "February 2017[15]",
PCIeSupport: "PCIe 2.0 ×8",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "Yes",
MultiGpuCrossFire: true,
MultiGpuSLI: true,
USBSupport: "2, 6, 6",
SATAPorts: "8",
SATAPorts: 8,
RAID: "0,1,10",
AMDStoreMI: "No",
AMDStoreMI: false,
Overclocking: "Yes",
TDP: "~5 W[16]",
SupportExcavator: "Yes",
Expand All @@ -140,12 +140,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "B450",
ReleaseDate: "March 2018[17]",
PCIeSupport: "PCIe 2.0 ×6",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "No",
MultiGpuCrossFire: true,
MultiGpuSLI: false,
USBSupport: "2, 2, 6",
SATAPorts: "4",
SATAPorts: 4,
RAID: "0,1,10",
AMDStoreMI: "Yes",
AMDStoreMI: true,
Overclocking: "Yes,withPBO",
TDP: "~5 W[16]",
SupportExcavator: "Varies[d]",
Expand All @@ -159,12 +159,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "X470",
ReleaseDate: "March 2018[17]",
PCIeSupport: "PCIe 2.0 ×8",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "Yes",
MultiGpuCrossFire: true,
MultiGpuSLI: true,
USBSupport: "2, 6, 6",
SATAPorts: "8",
SATAPorts: 8,
RAID: "0,1,10",
AMDStoreMI: "Yes",
AMDStoreMI: true,
Overclocking: "Yes,withPBO",
TDP: "~5 W[16]",
SupportExcavator: "Varies[d]",
Expand All @@ -178,12 +178,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "A520",
ReleaseDate: "August 2020[19]",
PCIeSupport: "PCIe 3.0 ×6",
MultiGpuCrossFire: "No",
MultiGpuSLI: "No",
MultiGpuCrossFire: false,
MultiGpuSLI: false,
USBSupport: "1, 2, 6",
SATAPorts: "4",
SATAPorts: 4,
RAID: "0,1,10",
AMDStoreMI: "Yes",
AMDStoreMI: true,
Overclocking: "No, unless an unsupported third-party motherboard firmware applied",
TDP: "~5 W[16]",
SupportExcavator: "Varies[d]",
Expand All @@ -197,12 +197,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "B550[e]",
ReleaseDate: "June 2020[20]",
PCIeSupport: "PCIe 3.0 ×10[21]",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "Varies",
MultiGpuCrossFire: true,
MultiGpuSLI: false,
USBSupport: "2, 2, 6",
SATAPorts: "6",
SATAPorts: 6,
RAID: "0,1,10",
AMDStoreMI: "Yes",
AMDStoreMI: true,
Overclocking: "Yes,withPBO",
TDP: "~5 W[16]",
SupportExcavator: "Varies[d]",
Expand All @@ -216,12 +216,12 @@ func TestVeryCreativeTableWithRowAndColspans(t *testing.T) {
Model: "X570",
ReleaseDate: "July 2019[22]",
PCIeSupport: "PCIe 4.0 ×16",
MultiGpuCrossFire: "Yes",
MultiGpuSLI: "Yes",
MultiGpuCrossFire: true,
MultiGpuSLI: true,
USBSupport: "8, 0, 4",
SATAPorts: "12",
SATAPorts: 12,
RAID: "0,1,10",
AMDStoreMI: "Yes",
AMDStoreMI: true,
Overclocking: "Yes,withPBO",
TDP: "~15 W[23][24][f]",
SupportExcavator: "No[g]",
Expand Down

0 comments on commit 4470783

Please sign in to comment.