From 35c5c70b250415673a28598bc4c7fd5e6ea921d6 Mon Sep 17 00:00:00 2001 From: Elara Musayelyan Date: Tue, 22 Aug 2023 17:34:26 -0700 Subject: [PATCH] Remove abbreviations to make decoded reports easier to read --- convert.go | 154 +++++++++++++++++++++++++++++++++++++++++++++++++ taf.go | 34 ++++++----- taf_test.go | 12 ++-- types.go | 92 ++++++++++++++--------------- units/units.go | 79 ++++++++----------------- 5 files changed, 250 insertions(+), 121 deletions(-) create mode 100644 convert.go diff --git a/convert.go b/convert.go new file mode 100644 index 0000000..1f26639 --- /dev/null +++ b/convert.go @@ -0,0 +1,154 @@ +package taf + +func convertSkyConditionType(s string) SkyConditionType { + switch s { + case "FEW": + return Few + case "SCT": + return Scattered + case "BKN": + return Broken + case "OVC": + return Overcast + case "VV": + return VerticalVisibility + case "SKC": + return SkyClear + default: + return "" + } +} + +func convertCloudType(s string) CloudType { + switch s { + case "CB": + return CumuloNimbus + case "TCU": + return ToweringCumulus + default: + return "" + } +} + +func convertModifier(s string) Modifier { + switch s { + case "+": + return Heavy + case "-": + return Light + default: + return "" + } +} + +func convertDescriptor(s string) Descriptor { + switch s { + case "MI": + return Shallow + case "BC": + return Patches + case "DC": + return LowDrifting + case "BL": + return Blowing + case "SH": + return Showers + case "TS": + return Thunderstorm + case "FZ": + return Freezing + case "PR": + return Partial + default: + return "" + } +} + +func convertPrecipitation(s string) Precipitation { + switch s { + case "DZ": + return Drizzle + case "RA": + return Rain + case "SN": + return Snow + case "SG": + return SnowGrains + case "IC": + return IceCrystals + case "PL": + return IcePellets + case "GR": + return Hail + case "GS": + return SmallHail + case "UP": + return Unknown + default: + return "" + } +} + +func convertObscuration(s string) Obscuration { + switch s { + case "BR": + return Mist + case "FG": + return Fog + case "FU": + return Smoke + case "DU": + return Dust + case "SA": + return Sand + case "HZ": + return Haze + case "PY": + return Spray + case "VA": + return VolcanicAsh + default: + return "" + } +} + +func convertPhenomenon(s string) Phenomenon { + switch s { + case "PO": + return Whirls + case "SQ": + return Squalls + case "FC": + return FunnelCloud + case "SS": + return Sandstorm + case "DS": + return Duststorm + default: + return "" + } +} + +func convertTemperatureType(s string) TemperatureType { + switch s { + case "TX": + return High + case "TN": + return Low + default: + return "" + } +} + +func convertChangeType(s string) ChangeType { + switch s { + case "FM": + return From + case "BECMG": + return Becoming + case "TEMPO": + return Temporary + default: + return "" + } +} diff --git a/taf.go b/taf.go index 6b5462f..24f8d6d 100644 --- a/taf.go +++ b/taf.go @@ -94,17 +94,17 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { setField(out, "Valid", vp) case item.Weather != nil: appendField(out, "Weather", Weather{ - Modifier: Modifier(item.Weather.Modifier), - Descriptor: Descriptor(item.Weather.Descriptor), - Precipitation: Precipitation(item.Weather.Precipitation), - Obscuration: Obscuration(item.Weather.Obscuration), - Phenomenon: Phenomenon(item.Weather.Other), + Modifier: convertModifier(item.Weather.Modifier), + Descriptor: convertDescriptor(item.Weather.Descriptor), + Precipitation: convertPrecipitation(item.Weather.Precipitation), + Obscuration: convertObscuration(item.Weather.Obscuration), + Phenomenon: convertPhenomenon(item.Weather.Other), }) case item.Vicinity != nil: appendField(out, "Weather", Weather{ Vicinity: true, - Descriptor: Descriptor(item.Vicinity.Descriptor), - Precipitation: Precipitation(item.Vicinity.Precipitation), + Descriptor: convertDescriptor(item.Vicinity.Descriptor), + Precipitation: convertPrecipitation(item.Vicinity.Precipitation), }) case item.SkyCondition != nil: var altitude int @@ -117,8 +117,8 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { appendField(out, "SkyCondition", SkyCondition{ Altitude: altitude * 100, // Scale factor for altitude is 100 - Type: SkyConditionType(item.SkyCondition.Type), - CloudType: CloudType(item.SkyCondition.CloudType), + Type: convertSkyConditionType(item.SkyCondition.Type), + CloudType: convertCloudType(item.SkyCondition.CloudType), }) case item.Temperature != nil: vt, err := parseValidTime(item.Temperature.Time) @@ -132,7 +132,7 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { } appendField(out, "Temperature", Temperature{ - Type: TemperatureType(item.Temperature.Type), + Type: convertTemperatureType(item.Temperature.Type), Time: vt, Value: val, }) @@ -173,7 +173,11 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { item.Visibility.Unit = "M" } - unit := units.Distance(item.Visibility.Unit) + unit, ok := units.ParseDistance(item.Visibility.Unit) + if !ok { + return nil, participle.Errorf(item.Visibility.Pos, "visibility: invalid unit %q", item.Visibility.Unit) + } + val, _ := ratNum.Float64() if opts.DistanceUnit != "" { @@ -234,7 +238,11 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { } } - unit := units.Speed(item.WindSpeed.Unit) + unit, ok := units.ParseSpeed(item.WindSpeed.Unit) + if !ok { + return nil, participle.Errorf(item.WindSpeed.Pos, "wind: invalid unit %q", item.Visibility.Unit) + } + if opts.SpeedUnit != "" { speed = unit.Convert(opts.SpeedUnit, speed) if gusts != 0 { @@ -260,7 +268,7 @@ func ParseWithOptions(r io.Reader, opts Options) (*Forecast, error) { } case item.Change != nil: ch := &Change{ - Type: ChangeType(item.Change.Type), + Type: convertChangeType(item.Change.Type), } // FM changes don't have a valid pair, they only come with a single time string diff --git a/taf_test.go b/taf_test.go index 762fbcc..7feb462 100644 --- a/taf_test.go +++ b/taf_test.go @@ -28,7 +28,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ @@ -60,7 +60,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ @@ -84,7 +84,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ @@ -108,7 +108,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ @@ -132,7 +132,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ @@ -156,7 +156,7 @@ func TestKLAX(t *testing.T) { Visibility: Visibility{ Plus: true, Value: 6, - Unit: units.StatuteMiles, + Unit: units.Miles, }, Wind: Wind{ Direction: Direction{ diff --git a/types.go b/types.go index 6d46a12..6db7284 100644 --- a/types.go +++ b/types.go @@ -60,19 +60,19 @@ type Visibility struct { type SkyConditionType string const ( - Few SkyConditionType = "FEW" - Scattered SkyConditionType = "SCT" - Broken SkyConditionType = "BKN" - Overcast SkyConditionType = "OVC" - VerticalVisibility SkyConditionType = "VV" - SkyClear SkyConditionType = "SKC" + Few SkyConditionType = "Few" + Scattered SkyConditionType = "Scattered" + Broken SkyConditionType = "Broken" + Overcast SkyConditionType = "Overcast" + VerticalVisibility SkyConditionType = "VerticalVisibility" + SkyClear SkyConditionType = "SkyClear" ) type CloudType string const ( - CumuloNimbus CloudType = "CB" - ToweringCumulus CloudType = "TCU" + CumuloNimbus CloudType = "CumuloNumbus" + ToweringCumulus CloudType = "ToweringCumulus" ) type SkyCondition struct { @@ -97,58 +97,58 @@ type Direction struct { type Modifier string const ( - Heavy Modifier = "+" - Light Modifier = "-" + Heavy Modifier = "Heavy" + Light Modifier = "Light" ) type Descriptor string const ( - Shallow Descriptor = "MI" - Patches Descriptor = "BC" - LowDrifting Descriptor = "DC" - Blowing Descriptor = "BL" - Showers Descriptor = "SH" - Thunderstorm Descriptor = "TS" - Freezing Descriptor = "FZ" - Partial Descriptor = "PR" + Shallow Descriptor = "Shallow" + Patches Descriptor = "Patches" + LowDrifting Descriptor = "LowDrifting" + Blowing Descriptor = "Blowing" + Showers Descriptor = "Showers" + Thunderstorm Descriptor = "Thunderstorm" + Freezing Descriptor = "Freezing" + Partial Descriptor = "Partial" ) type Precipitation string const ( - Drizzle Precipitation = "DZ" - Rain Precipitation = "RA" - Snow Precipitation = "SN" - SnowGrains Precipitation = "SG" - IceCrystals Precipitation = "IC" - IcePellets Precipitation = "PL" - Hail Precipitation = "GR" - SmallHail Precipitation = "GS" - Unknown Precipitation = "UP" + Drizzle Precipitation = "Drizzle" + Rain Precipitation = "Rain" + Snow Precipitation = "Snow" + SnowGrains Precipitation = "SnowGrains" + IceCrystals Precipitation = "IceCrystals" + IcePellets Precipitation = "IcePellets" + Hail Precipitation = "Hail" + SmallHail Precipitation = "SmallHail" + Unknown Precipitation = "Unknown" ) type Obscuration string const ( - Mist Obscuration = "BR" - Fog Obscuration = "FG" - Smoke Obscuration = "FU" - Dust Obscuration = "DU" - Sand Obscuration = "SA" - Haze Obscuration = "HZ" - Spray Obscuration = "PY" - VolcanicAsh Obscuration = "VA" + Mist Obscuration = "Mist" + Fog Obscuration = "Fog" + Smoke Obscuration = "Smoke" + Dust Obscuration = "Dust" + Sand Obscuration = "Sand" + Haze Obscuration = "Haze" + Spray Obscuration = "Spray" + VolcanicAsh Obscuration = "VolcanicAsh" ) type Phenomenon string const ( - Whirls Phenomenon = "PO" - Squalls Phenomenon = "SQ" - FunnelCloud Phenomenon = "FC" - SandStorm Phenomenon = "SS" - DustStorm Phenomenon = "DS" + Whirls Phenomenon = "Whirls" + Squalls Phenomenon = "Squalls" + FunnelCloud Phenomenon = "FunnelCloud" + Sandstorm Phenomenon = "Sandstorm" + Duststorm Phenomenon = "Duststorm" ) type Weather struct { @@ -163,8 +163,8 @@ type Weather struct { type TemperatureType string const ( - High TemperatureType = "TX" - Low TemperatureType = "TN" + High TemperatureType = "High" + Low TemperatureType = "Low" ) type Temperature struct { @@ -176,13 +176,13 @@ type Temperature struct { type ChangeType string const ( - From ChangeType = "FM" - Becoming ChangeType = "BECMG" - Temporary ChangeType = "TEMPO" + From ChangeType = "From" + Becoming ChangeType = "Becoming" + Temporary ChangeType = "Temporary" ) type Flag string const ( - CeilingAndVisibilityOK Flag = "CAVOK" + CeilingAndVisibilityOK Flag = "CeilingAndVisibilityOK" ) diff --git a/units/units.go b/units/units.go index 52c0d86..bcd6754 100644 --- a/units/units.go +++ b/units/units.go @@ -9,25 +9,11 @@ type Speed string // Speed units const ( - MetersPerSecond Speed = "MPS" - KilometersPerHour Speed = "KMH" - Knots Speed = "KT" + MetersPerSecond Speed = "MetersPerSecond" + KilometersPerHour Speed = "KilometersPerHour" + Knots Speed = "Knots" ) -var speedNames = map[Speed]string{ - MetersPerSecond: "m/s", - KilometersPerHour: "kph", - Knots: "kts", -} - -func (su Speed) String() string { - name, ok := speedNames[su] - if !ok { - return "" - } - return name -} - // Convert converts a value from one unit to another func (sf Speed) Convert(st Speed, val int) int { switch { @@ -52,18 +38,16 @@ func (sf Speed) Convert(st Speed, val int) int { // mps, m/s, kmh, kph, kt, and kts. // This function is case-insensitive. func ParseSpeed(s string) (Speed, bool) { - if _, ok := speedNames[Speed(s)]; ok { - return Speed(s), true + switch strings.ToLower(s) { + case "m/s", "mps", "meterspersecond", "meters per second": + return MetersPerSecond, true + case "kmh", "kph", "km/h", "kilometersperhour", "kilometers per hour": + return KilometersPerHour, true + case "kt", "kts", "knot", "knots": + return Knots, true + default: + return "", false } - - for su, name := range speedNames { - if strings.EqualFold(s, name) || - strings.EqualFold(s, string(su)) { - return su, true - } - } - - return "", false } // Distance represents a unit of distance @@ -71,29 +55,16 @@ type Distance string // Distance units const ( - StatuteMiles Distance = "SM" - Meters Distance = "M" + Miles Distance = "Miles" + Meters Distance = "Meters" ) -var distanceNames = map[Distance]string{ - StatuteMiles: "mi", - Meters: "m", -} - -func (du Distance) String() string { - name, ok := distanceNames[du] - if !ok { - return "" - } - return name -} - // Convert converts a value from one unit to another func (df Distance) Convert(dt Distance, val float64) float64 { switch { - case df == StatuteMiles && dt == Meters: + case df == Miles && dt == Meters: return val * 1609 - case df == Meters && dt == StatuteMiles: + case df == Meters && dt == Miles: return val / 1609 default: return val @@ -103,16 +74,12 @@ func (df Distance) Convert(dt Distance, val float64) float64 { // ParseDistance parses a speed value. Valid inputs include: // sm, mi, and m. This function is case-insensitive. func ParseDistance(s string) (Distance, bool) { - if _, ok := distanceNames[Distance(s)]; ok { - return Distance(s), true + switch strings.ToLower(s) { + case "sm", "mi", "mile", "miles": + return Miles, true + case "m", "meter", "meters": + return Meters, true + default: + return "", false } - - for d, name := range distanceNames { - if strings.EqualFold(s, name) || - strings.EqualFold(s, string(d)) { - return d, true - } - } - - return "", false }