diff --git a/meta/generate/main.go b/meta/generate/main.go index 852cb0b37..23984269b 100644 --- a/meta/generate/main.go +++ b/meta/generate/main.go @@ -34,6 +34,7 @@ func main() { "installedRecorders": {"InstalledRecorder"}, "installedSensors": {"InstalledSensor"}, "marks": {"Mark"}, + "methods": {"Method"}, "monuments": {"Monument"}, "mounts": {"Mount"}, "networks": {"Network"}, @@ -60,6 +61,7 @@ func main() { "classes": {"Class", []string{"station"}}, "darts": {"Dart", []string{"station"}}, "marks": {"Mark", []string{"code"}}, + "methods": {"Method", []string{"domain", "name"}}, "monuments": {"Monument", []string{"mark"}}, "mounts": {"Mount", []string{"code"}}, "networks": {"Network", []string{"code"}}, diff --git a/meta/method.go b/meta/method.go new file mode 100644 index 000000000..d21597867 --- /dev/null +++ b/meta/method.go @@ -0,0 +1,98 @@ +package meta + +import ( + "sort" + "strings" +) + +const ( + methodDomain int = iota + methodName + methodDescription + methodReference + methodLast +) + +var methodHeaders Header = map[string]int{ + "Domain": methodDomain, + "Method": methodName, + "Description": methodDescription, + "Reference": methodReference, +} + +type Method struct { + Domain string + Name string + Description string + Reference string +} + +type MethodList []Method + +func (m MethodList) Len() int { return len(m) } +func (m MethodList) Swap(i, j int) { m[i], m[j] = m[j], m[i] } +func (m MethodList) Less(i, j int) bool { + switch { + case m[i].Domain < m[j].Domain: + return true + case m[i].Domain < m[j].Domain: + return false + case m[i].Name < m[j].Name: + return true + default: + return false + } +} + +func (m MethodList) encode() [][]string { + var data [][]string + + data = append(data, methodHeaders.Columns()) + + for _, row := range m { + data = append(data, []string{ + row.Domain, + row.Name, + row.Description, + row.Reference, + }) + } + + return data +} + +func (m *MethodList) decode(data [][]string) error { + if !(len(data) > 1) { + return nil + } + + var methods []Method + + fields := methodHeaders.Fields(data[0]) + for _, row := range data[1:] { + d := fields.Remap(row) + + methods = append(methods, Method{ + Domain: strings.TrimSpace(d[methodDomain]), + Name: strings.TrimSpace(d[methodName]), + Description: strings.TrimSpace(d[methodDescription]), + Reference: strings.TrimSpace(d[methodReference]), + }) + } + + *m = MethodList(methods) + + return nil +} + +func LoadMethods(path string) ([]Method, error) { + var m []Method + + if err := LoadList(path, (*MethodList)(&m)); err != nil { + return nil, err + } + + sort.Sort(MethodList(m)) + + return m, nil +} diff --git a/meta/methods_test.go b/meta/methods_test.go new file mode 100644 index 000000000..c11e28b4d --- /dev/null +++ b/meta/methods_test.go @@ -0,0 +1,22 @@ +package meta + +import ( + "testing" +) + +func TestMethodList(t *testing.T) { + t.Run("check methods", testListFunc("testdata/methods.csv", &MethodList{ + Method{ + Domain: "envirosensor", + Name: "max", + Description: "The maximum value of the observation over the output interval", + Reference: "https://help.campbellsci.com/crbasic/cr1000x/Content/Instructions/maximum.htm", + }, + Method{ + Domain: "manualcollect", + Name: "accumulation-chamber", + Description: "An upside down bucket-shaped collection device is placed on the ground surface. A sensor in the chamber measures the concentration of gas coming from the ground beneath the chamber", + Reference: "https://www.geonet.org.nz/volcano/how", + }, + })) +} diff --git a/meta/set.go b/meta/set.go index 582c569b4..665879b2f 100644 --- a/meta/set.go +++ b/meta/set.go @@ -52,6 +52,7 @@ const ( VisibilityFile = "environment/visibility.csv" CitationsFile = "references/citations.csv" + MethodsFile = "references/methods.csv" ) // SetPathMap is used to manipulate the filepath inside the Set. @@ -105,6 +106,7 @@ type Set struct { visibilities VisibilityList citations CitationList + methods MethodList } func (s *Set) files() map[string]List { @@ -152,6 +154,7 @@ func (s *Set) files() map[string]List { VisibilityFile: &s.visibilities, CitationsFile: &s.citations, + MethodsFile: &s.methods, } } diff --git a/meta/set_auto.go b/meta/set_auto.go index d185e3899..b795acdbd 100644 --- a/meta/set_auto.go +++ b/meta/set_auto.go @@ -125,6 +125,11 @@ func (s Set) Marks() []Mark { return s.marks } +// Methods is a helper function to return a slice of Method values. +func (s Set) Methods() []Method { + return s.methods +} + // Monuments is a helper function to return a slice of Monument values. func (s Set) Monuments() []Monument { return s.monuments @@ -266,6 +271,20 @@ func (s Set) Mark(code string) (Mark, bool) { return Mark{}, false } +// Method is a helper function to return a Method value and true if one exists. +func (s Set) Method(domain, name string) (Method, bool) { + for _, v := range s.methods { + if domain != v.Domain { + continue + } + if name != v.Name { + continue + } + return v, true + } + return Method{}, false +} + // Monument is a helper function to return a Monument value and true if one exists. func (s Set) Monument(mark string) (Monument, bool) { for _, v := range s.monuments { diff --git a/meta/testdata/methods.csv b/meta/testdata/methods.csv new file mode 100644 index 000000000..83d3cccd8 --- /dev/null +++ b/meta/testdata/methods.csv @@ -0,0 +1,3 @@ +Domain,Method,Description,Reference +envirosensor,max,The maximum value of the observation over the output interval,https://help.campbellsci.com/crbasic/cr1000x/Content/Instructions/maximum.htm +manualcollect,accumulation-chamber,An upside down bucket-shaped collection device is placed on the ground surface. A sensor in the chamber measures the concentration of gas coming from the ground beneath the chamber,https://www.geonet.org.nz/volcano/how diff --git a/tests/methods_test.go b/tests/methods_test.go new file mode 100644 index 000000000..3675bdbe1 --- /dev/null +++ b/tests/methods_test.go @@ -0,0 +1,38 @@ +package delta_test + +import ( + "testing" + + "github.com/GeoNet/delta" + "github.com/GeoNet/delta/meta" +) + +var methodChecks = map[string]func(*meta.Set) func(t *testing.T){ + "check for duplicate methods": func(set *meta.Set) func(t *testing.T) { + return func(t *testing.T) { + methods := make(map[meta.Method]interface{}) + for _, c := range set.Methods() { + key := meta.Method{ + Domain: c.Domain, + Name: c.Name, + } + if _, ok := methods[key]; ok { + t.Errorf("method %s/%s is duplicated", c.Domain, c.Name) + } + methods[key] = true + } + } + }, +} + +func TestMethods(t *testing.T) { + + set, err := delta.New() + if err != nil { + t.Fatal(err) + } + + for k, v := range methodChecks { + t.Run(k, v(set)) + } +}