From @zacsketches on November 13, 2018 0:39
An ais Report
contains the fields necessary to conduct data science. However, the current implementation of Parse
which converts string data present in public data sources into numeric data relies on several brittle practices.
Parse
should use the reflect package to iterate over the fields of a Report
instead of a hardcoded list of requiredFields
that exists in the current version. From this iteration it should check the Headers
of the passed record to ensure the record has the minimally viable set of headers necessary. Alternatively, it could parse every field that it can identify in the Headers
and return a Report
with those fields set.
Additionally, if each field in a Report
was an interface instead of a fundamental type then Parse
could call an interface method to parse that field. For example, this interface could take the design
type Parsable interface{
Parse(s string) (interface{}, error)
}
type IntField int
// Parse wraps strconv.Atoi for integer fields in an ais Report
func (f IntField) Parse(s string) (int, error) {
i, err := strconv.Atoi(s)
if err != nil {
return 0, err
}
return i, nil
}
type Report struct {
MMSI IntField
IMO IntField
. . .
Lat FloatField
}
This design would eliminate the second hardcoded list in the existing function that calls the specific ParseFOO
function depending on the field name. The resulting Parse
pseudocode would look more like this.
nameParse := make(map[string]Parsable
rep := Report{}
s := reflect.ValueOf(&rep).Elem()
typeOfRep := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
name := fmt.Sprintf(typeOfRep.Field(i).Name)
nameParse[name] = f.MethodByName("Parse")
}
for i , str := range record {
header := headers[i]
var v interface{}
v, ok := nameParse[header]
if !ok {
continue
}
rep.header = v(str)
}
return header
There are most definitely some syntax errors here that will need to get worked out, but this method is much more robust against changes in an AIS report and flexible to user input.
Copied from original issue: FATHOM5/Seattle_Reasonable_Track2#26