metar-parser 1.2.1 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/metar/data/base.rb +15 -0
- data/lib/metar/data/density_altitude.rb +15 -0
- data/lib/metar/data/direction.rb +9 -0
- data/lib/metar/data/distance.rb +27 -0
- data/lib/metar/data/lightning.rb +61 -0
- data/lib/metar/data/observer.rb +24 -0
- data/lib/metar/data/pressure.rb +23 -0
- data/lib/metar/data/remark.rb +98 -0
- data/lib/metar/data/runway_visible_range.rb +85 -0
- data/lib/metar/data/sky_condition.rb +61 -0
- data/lib/metar/data/speed.rb +22 -0
- data/lib/metar/data/station_code.rb +7 -0
- data/lib/metar/data/temperature.rb +21 -0
- data/lib/metar/data/temperature_and_dew_point.rb +18 -0
- data/lib/metar/data/time.rb +54 -0
- data/lib/metar/data/variable_wind.rb +25 -0
- data/lib/metar/data/vertical_visibility.rb +26 -0
- data/lib/metar/data/visibility.rb +71 -0
- data/lib/metar/data/visibility_remark.rb +8 -0
- data/lib/metar/data/weather_phenomenon.rb +86 -0
- data/lib/metar/data/wind.rb +82 -0
- data/lib/metar/data.rb +22 -636
- data/lib/metar/i18n.rb +6 -0
- data/lib/metar/parser.rb +165 -120
- data/lib/metar/report.rb +1 -1
- data/lib/metar/version.rb +2 -2
- data/lib/metar.rb +7 -6
- data/locales/de.yml +1 -0
- data/locales/en.yml +1 -0
- data/locales/it.yml +2 -1
- data/locales/pt-BR.yml +1 -0
- data/spec/data/density_altitude_spec.rb +12 -0
- data/spec/{distance_spec.rb → data/distance_spec.rb} +1 -1
- data/spec/data/lightning_spec.rb +49 -0
- data/spec/data/pressure_spec.rb +22 -0
- data/spec/data/remark_spec.rb +99 -0
- data/spec/data/runway_visible_range_spec.rb +92 -0
- data/spec/{sky_condition_spec.rb → data/sky_condition_spec.rb} +10 -6
- data/spec/data/speed_spec.rb +45 -0
- data/spec/data/temperature_spec.rb +36 -0
- data/spec/{variable_wind_spec.rb → data/variable_wind_spec.rb} +6 -6
- data/spec/{vertical_visibility_spec.rb → data/vertical_visibility_spec.rb} +2 -2
- data/spec/{data_spec.rb → data/visibility_remark_spec.rb} +1 -11
- data/spec/{visibility_spec.rb → data/visibility_spec.rb} +9 -7
- data/spec/{weather_phenomenon_spec.rb → data/weather_phenomenon_spec.rb} +7 -3
- data/spec/{wind_spec.rb → data/wind_spec.rb} +10 -7
- data/spec/parser_spec.rb +107 -13
- data/spec/report_spec.rb +12 -1
- data/spec/spec_helper.rb +1 -1
- data/spec/station_spec.rb +2 -1
- metadata +56 -31
- data/spec/pressure_spec.rb +0 -22
- data/spec/remark_spec.rb +0 -147
- data/spec/runway_visible_range_spec.rb +0 -81
- data/spec/speed_spec.rb +0 -45
- data/spec/temperature_spec.rb +0 -36
data/lib/metar/parser.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "m9t"
|
2
|
+
|
3
|
+
require "metar/data"
|
2
4
|
|
3
5
|
# References:
|
4
6
|
# WMO = World Meteorological Organization Manual on Codes Volume I.1
|
@@ -26,11 +28,22 @@ module Metar
|
|
26
28
|
thread_attributes[:compliance] = compliance
|
27
29
|
end
|
28
30
|
|
29
|
-
attr_reader :raw
|
30
|
-
attr_reader :
|
31
|
-
|
32
|
-
|
33
|
-
|
31
|
+
attr_reader :raw
|
32
|
+
attr_reader :metar
|
33
|
+
attr_reader :observer
|
34
|
+
attr_reader :wind
|
35
|
+
attr_reader :variable_wind
|
36
|
+
attr_reader :visibility
|
37
|
+
attr_reader :minimum_visibility
|
38
|
+
attr_reader :runway_visible_range
|
39
|
+
attr_reader :present_weather
|
40
|
+
attr_reader :sky_conditions
|
41
|
+
attr_reader :vertical_visibility
|
42
|
+
attr_reader :temperature_and_dew_point
|
43
|
+
attr_reader :sea_level_pressure
|
44
|
+
attr_reader :recent_weather
|
45
|
+
attr_reader :unparsed
|
46
|
+
attr_reader :remarks
|
34
47
|
|
35
48
|
def initialize(raw)
|
36
49
|
@raw = raw
|
@@ -38,39 +51,101 @@ module Metar
|
|
38
51
|
analyze
|
39
52
|
end
|
40
53
|
|
54
|
+
def station_code
|
55
|
+
@station_code.value
|
56
|
+
end
|
57
|
+
|
41
58
|
def time
|
42
|
-
|
59
|
+
@time.value
|
60
|
+
end
|
61
|
+
|
62
|
+
def cavok?
|
63
|
+
@cavok
|
64
|
+
end
|
65
|
+
|
66
|
+
def temperature
|
67
|
+
return nil if @temperature_and_dew_point.nil?
|
68
|
+
@temperature_and_dew_point.temperature
|
69
|
+
end
|
70
|
+
|
71
|
+
def dew_point
|
72
|
+
return nil if @temperature_and_dew_point.nil?
|
73
|
+
@temperature_and_dew_point.dew_point
|
74
|
+
end
|
75
|
+
|
76
|
+
def raw_attributes
|
77
|
+
attr = {
|
78
|
+
metar: metar,
|
79
|
+
datetime: @time.raw,
|
80
|
+
station_code: station_code,
|
81
|
+
}
|
82
|
+
%i(
|
83
|
+
minimum_visibility
|
84
|
+
observer
|
85
|
+
sea_level_pressure
|
86
|
+
temperature_and_dew_point
|
87
|
+
visibility variable_wind vertical_visibility
|
88
|
+
wind
|
89
|
+
).each do |key|
|
90
|
+
attr = add_raw_if_present(attr, key)
|
91
|
+
end
|
92
|
+
%i(
|
93
|
+
present_weather
|
94
|
+
recent_weather remarks runway_visible_range
|
95
|
+
sky_conditions
|
96
|
+
).each do |key|
|
97
|
+
attr = add_raw_if_not_empty(attr, key)
|
98
|
+
end
|
99
|
+
attr[:cavok] = "CAVOK" if cavok?
|
100
|
+
attr
|
43
101
|
end
|
44
102
|
|
45
103
|
private
|
46
104
|
|
105
|
+
def add_raw_if_present(hash, attribute)
|
106
|
+
value = send(attribute)
|
107
|
+
return hash if value.nil?
|
108
|
+
return hash if value.raw.nil?
|
109
|
+
hash[attribute] = value.raw
|
110
|
+
hash
|
111
|
+
end
|
112
|
+
|
113
|
+
def add_raw_if_not_empty(hash, attribute)
|
114
|
+
values = send(attribute)
|
115
|
+
raws = values.map(&:raw).compact
|
116
|
+
return hash if raws.size == 0
|
117
|
+
hash[attribute] = raws.join(" ")
|
118
|
+
hash
|
119
|
+
end
|
120
|
+
|
47
121
|
def analyze
|
48
122
|
@chunks = @metar.split(' ')
|
49
123
|
|
50
124
|
@station_code = nil
|
51
|
-
@
|
125
|
+
@time = nil
|
126
|
+
@observer = nil
|
52
127
|
@wind = nil
|
53
128
|
@variable_wind = nil
|
129
|
+
@cavok = nil
|
54
130
|
@visibility = nil
|
55
131
|
@minimum_visibility = nil
|
56
132
|
@runway_visible_range = []
|
57
133
|
@present_weather = []
|
58
134
|
@sky_conditions = []
|
59
135
|
@vertical_visibility = nil
|
60
|
-
@
|
61
|
-
@dew_point = nil
|
136
|
+
@temperature_and_dew_point = nil
|
62
137
|
@sea_level_pressure = nil
|
63
138
|
@recent_weather = []
|
64
139
|
@unparsed = []
|
65
140
|
@remarks = []
|
66
141
|
|
67
|
-
|
142
|
+
seek_station_code
|
68
143
|
seek_datetime
|
69
|
-
|
144
|
+
seek_observer
|
70
145
|
seek_wind
|
71
146
|
seek_variable_wind
|
72
|
-
|
73
|
-
if
|
147
|
+
seek_cavok
|
148
|
+
if !cavok?
|
74
149
|
seek_visibility
|
75
150
|
seek_minimum_visibility
|
76
151
|
seek_runway_visible_range
|
@@ -85,92 +160,64 @@ module Metar
|
|
85
160
|
seek_remarks
|
86
161
|
end
|
87
162
|
|
88
|
-
def
|
89
|
-
|
90
|
-
|
91
|
-
else
|
163
|
+
def seek_station_code
|
164
|
+
@station_code = Metar::Data::StationCode.parse(@chunks[0])
|
165
|
+
if @station_code.nil?
|
92
166
|
raise ParseError.new("Expecting location, found '#{ @chunks[0] }' in #{@metar}")
|
93
167
|
end
|
168
|
+
@chunks.shift
|
169
|
+
@station_code
|
94
170
|
end
|
95
171
|
|
96
172
|
def seek_datetime
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
104
|
-
if @chunks[0] =~ date_matcher
|
105
|
-
@day, @hour, @minute = $1.to_i, $2.to_i, $3.to_i
|
106
|
-
found = true
|
107
|
-
else
|
108
|
-
if not strict?
|
109
|
-
if @chunks[0] =~ /^(\d{1,2})(\d{2})Z$/
|
110
|
-
# The day is missing, use today's date
|
111
|
-
@day = Time.now.day
|
112
|
-
@hour, @minute = $1.to_i, $2.to_i, $3.to_i
|
113
|
-
found = true
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
if found
|
118
|
-
@chunks.shift
|
119
|
-
else
|
120
|
-
raise ParseError.new("Expecting datetime, found '#{@chunks[0]}' in #{@metar}")
|
173
|
+
datetime = @chunks.shift
|
174
|
+
@time = Metar::Data::Time.parse(
|
175
|
+
datetime, year: raw.time.year, month: raw.time.month, strict: strict?
|
176
|
+
)
|
177
|
+
if !@time
|
178
|
+
raise ParseError.new("Expecting datetime, found '#{datetime}' in #{@metar}")
|
121
179
|
end
|
180
|
+
@time
|
122
181
|
end
|
123
182
|
|
124
|
-
def
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
@observer = :auto
|
129
|
-
when @chunks[0] == 'COR' # WMO specified code word for correction
|
130
|
-
@chunks.shift
|
131
|
-
@observer = :corrected
|
132
|
-
when @chunks[0] =~ /CC[A-Z]/ # Canadian correction
|
133
|
-
# Canada uses CCA for first correction, CCB for second, etc...
|
134
|
-
@chunks.shift
|
135
|
-
@observer = :corrected
|
136
|
-
when @chunks[0] == 'RTD' # Delayed observation, no comments on observer
|
137
|
-
@chunks.shift
|
138
|
-
else
|
139
|
-
nil
|
140
|
-
end
|
183
|
+
def seek_observer
|
184
|
+
@observer = Metar::Data::Observer.parse(@chunks[0])
|
185
|
+
@chunks.shift if @observer.raw
|
186
|
+
@observer
|
141
187
|
end
|
142
188
|
|
143
189
|
def seek_wind
|
144
|
-
wind = Wind.parse(@chunks[0])
|
145
|
-
if wind
|
146
|
-
|
147
|
-
@wind = wind
|
148
|
-
end
|
190
|
+
@wind = Metar::Data::Wind.parse(@chunks[0])
|
191
|
+
@chunks.shift if @wind
|
192
|
+
@wind
|
149
193
|
end
|
150
194
|
|
151
195
|
def seek_variable_wind
|
152
|
-
variable_wind = VariableWind.parse(@chunks[0])
|
153
|
-
if variable_wind
|
154
|
-
|
155
|
-
@variable_wind = variable_wind
|
156
|
-
end
|
196
|
+
@variable_wind = Metar::Data::VariableWind.parse(@chunks[0])
|
197
|
+
@chunks.shift if @variable_wind
|
198
|
+
@variable_wind
|
157
199
|
end
|
158
200
|
|
159
201
|
def seek_cavok
|
160
202
|
if @chunks[0] == 'CAVOK'
|
203
|
+
@visibility = Metar::Data::Visibility.new(
|
204
|
+
nil,
|
205
|
+
distance: M9t::Distance.kilometers(10), comparator: :more_than
|
206
|
+
)
|
207
|
+
@present_weather << Metar::Data::WeatherPhenomenon.new(
|
208
|
+
nil, phenomenon: "No significant weather"
|
209
|
+
)
|
210
|
+
@sky_conditions << Metar::Data::SkyCondition.new(nil) # = 'clear skies'
|
161
211
|
@chunks.shift
|
162
|
-
@
|
163
|
-
@present_weather << Metar::WeatherPhenomenon.new('No significant weather')
|
164
|
-
@sky_conditions << SkyCondition.new # = 'clear skies'
|
165
|
-
return true
|
212
|
+
@cavok = true
|
166
213
|
else
|
167
|
-
|
214
|
+
@cavok = false
|
168
215
|
end
|
169
216
|
end
|
170
217
|
|
171
218
|
# 15.10, 15.6.1
|
172
219
|
def seek_visibility
|
173
|
-
if
|
220
|
+
if observer.value == :auto # WMO 15.4
|
174
221
|
if @chunks[0] == '////'
|
175
222
|
@chunks.shift # Simply dispose of it
|
176
223
|
return
|
@@ -178,50 +225,52 @@ module Metar
|
|
178
225
|
end
|
179
226
|
|
180
227
|
if @chunks[0] == '1' or @chunks[0] == '2'
|
181
|
-
visibility = Visibility.parse(@chunks[0] + ' ' + @chunks[1])
|
182
|
-
if visibility
|
228
|
+
@visibility = Metar::Data::Visibility.parse(@chunks[0] + ' ' + @chunks[1])
|
229
|
+
if @visibility
|
183
230
|
@chunks.shift
|
184
231
|
@chunks.shift
|
185
|
-
@visibility = visibility
|
186
232
|
end
|
187
233
|
else
|
188
|
-
visibility = Visibility.parse(@chunks[0])
|
189
|
-
if visibility
|
234
|
+
@visibility = Metar::Data::Visibility.parse(@chunks[0])
|
235
|
+
if @visibility
|
190
236
|
@chunks.shift
|
191
|
-
@visibility = visibility
|
192
237
|
end
|
193
238
|
end
|
239
|
+
@visibility
|
194
240
|
end
|
195
241
|
|
196
242
|
# Optional after visibility: 15.6.2
|
197
243
|
def seek_minimum_visibility
|
198
|
-
minimum_visibility = Visibility.parse(@chunks[0])
|
199
|
-
if minimum_visibility
|
200
|
-
|
201
|
-
@minimum_visibility = minimum_visibility
|
202
|
-
end
|
244
|
+
@minimum_visibility = Metar::Data::Visibility.parse(@chunks[0])
|
245
|
+
@chunks.shift if @minimum_visibility
|
246
|
+
@minimum_visibility
|
203
247
|
end
|
204
248
|
|
205
249
|
def seek_runway_visible_range
|
206
250
|
loop do
|
207
|
-
|
208
|
-
break if
|
251
|
+
rvr = Metar::Data::RunwayVisibleRange.parse(@chunks[0])
|
252
|
+
break if rvr.nil?
|
209
253
|
@chunks.shift
|
210
|
-
@runway_visible_range <<
|
254
|
+
@runway_visible_range << rvr
|
211
255
|
end
|
256
|
+
@runway_visible_range
|
212
257
|
end
|
213
258
|
|
214
259
|
def seek_present_weather
|
215
|
-
if
|
260
|
+
if observer.value == :auto
|
216
261
|
if @chunks[0] == '//' # WMO 15.4
|
217
|
-
@
|
218
|
-
|
262
|
+
@present_weather << Metar::Data::WeatherPhenomenon.new(
|
263
|
+
nil, phenomenon: "not observed"
|
264
|
+
)
|
265
|
+
@chunks.shift
|
219
266
|
return
|
220
267
|
end
|
221
268
|
end
|
222
269
|
|
223
270
|
loop do
|
224
|
-
|
271
|
+
break if @chunks.size == 0
|
272
|
+
break if @chunks[0].start_with?("RE")
|
273
|
+
wtp = Metar::Data::WeatherPhenomenon.parse(@chunks[0])
|
225
274
|
break if wtp.nil?
|
226
275
|
@chunks.shift
|
227
276
|
@present_weather << wtp
|
@@ -230,7 +279,7 @@ module Metar
|
|
230
279
|
|
231
280
|
# Repeatable: 15.9.1.3
|
232
281
|
def seek_sky_conditions
|
233
|
-
if
|
282
|
+
if observer.value == :auto # WMO 15.4
|
234
283
|
if @chunks[0] == '///' or @chunks[0] == '//////'
|
235
284
|
@chunks.shift # Simply dispose of it
|
236
285
|
return
|
@@ -238,7 +287,7 @@ module Metar
|
|
238
287
|
end
|
239
288
|
|
240
289
|
loop do
|
241
|
-
sky_condition = SkyCondition.parse(@chunks[0])
|
290
|
+
sky_condition = Metar::Data::SkyCondition.parse(@chunks[0])
|
242
291
|
break if sky_condition.nil?
|
243
292
|
@chunks.shift
|
244
293
|
@sky_conditions << sky_condition
|
@@ -246,40 +295,36 @@ module Metar
|
|
246
295
|
end
|
247
296
|
|
248
297
|
def seek_vertical_visibility
|
249
|
-
vertical_visibility = VerticalVisibility.parse(@chunks[0])
|
250
|
-
if vertical_visibility
|
251
|
-
|
252
|
-
@vertical_visibility = vertical_visibility
|
253
|
-
end
|
298
|
+
@vertical_visibility = Metar::Data::VerticalVisibility.parse(@chunks[0])
|
299
|
+
@chunks.shift if vertical_visibility
|
300
|
+
@vertical_visibility
|
254
301
|
end
|
255
302
|
|
256
303
|
def seek_temperature_dew_point
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
304
|
+
@temperature_and_dew_point = Metar::Data::TemperatureAndDewPoint.parse(
|
305
|
+
@chunks[0]
|
306
|
+
)
|
307
|
+
|
308
|
+
@chunks.shift if @temperature_and_dew_point
|
309
|
+
@temperature_and_dew_point
|
263
310
|
end
|
264
311
|
|
265
312
|
def seek_sea_level_pressure
|
266
|
-
sea_level_pressure = Pressure.parse(@chunks[0])
|
267
|
-
if sea_level_pressure
|
268
|
-
|
269
|
-
@sea_level_pressure = sea_level_pressure
|
270
|
-
end
|
313
|
+
@sea_level_pressure = Metar::Data::Pressure.parse(@chunks[0])
|
314
|
+
@chunks.shift if @sea_level_pressure
|
315
|
+
@sea_level_pressure
|
271
316
|
end
|
272
317
|
|
273
318
|
def seek_recent_weather
|
274
319
|
loop do
|
275
320
|
return if @chunks.size == 0
|
276
|
-
|
277
|
-
|
278
|
-
recent_weather = Metar::WeatherPhenomenon.parse(m.post_match)
|
321
|
+
break if !@chunks[0].start_with?("RE")
|
322
|
+
recent_weather = Metar::Data::WeatherPhenomenon.parse(@chunks[0])
|
279
323
|
break if recent_weather.nil?
|
280
324
|
@chunks.shift
|
281
325
|
@recent_weather << recent_weather
|
282
326
|
end
|
327
|
+
@recent_weather
|
283
328
|
end
|
284
329
|
|
285
330
|
def seek_to_remarks
|
@@ -297,13 +342,13 @@ module Metar
|
|
297
342
|
# WMO: 15.15
|
298
343
|
def seek_remarks
|
299
344
|
return if @chunks.size == 0
|
300
|
-
raise 'seek_remarks
|
345
|
+
raise 'seek_remarks called without remark' if @chunks[0] != 'RMK'
|
301
346
|
|
302
347
|
@chunks.shift # Drop 'RMK'
|
303
348
|
@remarks = []
|
304
349
|
loop do
|
305
350
|
break if @chunks.size == 0
|
306
|
-
r = Metar::Remark.parse(@chunks[0])
|
351
|
+
r = Metar::Data::Remark.parse(@chunks[0])
|
307
352
|
if r
|
308
353
|
if r.is_a?(Array)
|
309
354
|
@remarks += r
|
@@ -315,17 +360,17 @@ module Metar
|
|
315
360
|
end
|
316
361
|
if @chunks[0] == 'VIS' and @chunks.size >= 3 and @chunks[1] == 'MIN'
|
317
362
|
@chunks.shift(2)
|
318
|
-
r = Metar::VisibilityRemark.parse(@chunks[0])
|
363
|
+
r = Metar::Data::VisibilityRemark.parse(@chunks[0])
|
319
364
|
@remarks << r
|
320
365
|
end
|
321
|
-
if @chunks[0] == 'DENSITY'
|
366
|
+
if @chunks[0] == 'DENSITY' && @chunks.size >= 3 && @chunks[1] == 'ALT'
|
322
367
|
@chunks.shift(2)
|
323
|
-
r = Metar::DensityAltitude.parse(@chunks[0])
|
368
|
+
r = Metar::Data::DensityAltitude.parse(@chunks[0])
|
324
369
|
@remarks << r
|
325
370
|
end
|
326
371
|
case
|
327
372
|
when @chunks[0] =~ /^LTG(|CG|IC|CC|CA)$/
|
328
|
-
r = Metar::Lightning.parse_chunks(@chunks)
|
373
|
+
r = Metar::Data::Lightning.parse_chunks(@chunks)
|
329
374
|
@remarks << r
|
330
375
|
else
|
331
376
|
@remarks << @chunks.shift
|
data/lib/metar/report.rb
CHANGED
data/lib/metar/version.rb
CHANGED
data/lib/metar.rb
CHANGED
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "metar/i18n"
|
2
|
+
require "metar/raw"
|
3
|
+
require "metar/station"
|
4
|
+
require "metar/parser"
|
5
|
+
require "metar/report"
|
6
|
+
require "metar/version"
|
6
7
|
|
7
8
|
module Metar
|
8
|
-
|
9
9
|
# Base class for all Metar exceptions
|
10
10
|
class MetarError < StandardError
|
11
11
|
end
|
@@ -14,5 +14,6 @@ module Metar
|
|
14
14
|
class ParseError < MetarError
|
15
15
|
end
|
16
16
|
|
17
|
+
autoload :Data, "metar/data"
|
17
18
|
end
|
18
19
|
|
data/locales/de.yml
CHANGED
data/locales/en.yml
CHANGED
data/locales/it.yml
CHANGED
data/locales/pt-BR.yml
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require "spec_helper"
|
3
|
+
|
4
|
+
RSpec.describe Metar::Data::DensityAltitude do
|
5
|
+
describe ".parse" do
|
6
|
+
subject { described_class.parse("50FT") }
|
7
|
+
|
8
|
+
it "interprets the value as feet" do
|
9
|
+
expect(subject.height.to_feet).to eq(50)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Metar::Data::Lightning do
|
4
|
+
context '.parse_chunks' do
|
5
|
+
[
|
6
|
+
['direction', 'LTG SE', [:default, nil, ['SE']]],
|
7
|
+
['distance direction', 'LTG DSNT SE', [:default, 16093.44, ['SE']]],
|
8
|
+
['distance direction and direction', 'LTG DSNT NE AND W', [:default, 16093.44, ['NE', 'W']]],
|
9
|
+
['distance direction-direction', 'LTG DSNT SE-SW', [:default, 16093.44, ['SE', 'SW']]],
|
10
|
+
['distance all quandrants', 'LTG DSNT ALQDS', [:default, 16093.44, ['N', 'E', 'S', 'W']]],
|
11
|
+
].each do |docstring, section, expected|
|
12
|
+
example docstring do
|
13
|
+
chunks = section.split(' ')
|
14
|
+
r = described_class.parse_chunks(chunks)
|
15
|
+
|
16
|
+
expect(r).to be_a(described_class)
|
17
|
+
expect(r.type).to eq(expected[0])
|
18
|
+
if expected[1]
|
19
|
+
expect(r.distance.value).to eq(expected[1])
|
20
|
+
else
|
21
|
+
expect(r.distance).to be_nil
|
22
|
+
end
|
23
|
+
expect(r.directions).to eq(expected[2])
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'removes parsed chunks' do
|
28
|
+
chunks = ['LTG', 'DSNT', 'SE', 'FOO']
|
29
|
+
|
30
|
+
r = described_class.parse_chunks(chunks)
|
31
|
+
|
32
|
+
expect(chunks).to eq(['FOO'])
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'fails if the first chunk is not LTGnnn' do
|
36
|
+
expect do
|
37
|
+
described_class.parse_chunks(['FOO'])
|
38
|
+
end.to raise_error(RuntimeError, /not lightning/)
|
39
|
+
end
|
40
|
+
|
41
|
+
it "doesn't not fail if all chunks are parsed" do
|
42
|
+
chunks = ['LTG', 'DSNT', 'SE']
|
43
|
+
|
44
|
+
r = described_class.parse_chunks(chunks)
|
45
|
+
|
46
|
+
expect(chunks).to eq([])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Metar::Data::Pressure do
|
4
|
+
context '.parse' do
|
5
|
+
it 'interprets the Q prefix as hectopascals' do
|
6
|
+
expect(described_class.parse('Q1300').value).to be_within(0.01).of(1.3)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'interprets the A prefix as inches of mercury' do
|
10
|
+
expect(described_class.parse('A1234').value).to be_within(0.01).of(0.42)
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'require 4 digits' do
|
14
|
+
expect(described_class.parse('Q12345')).to be_nil
|
15
|
+
expect(described_class.parse('A123')).to be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns nil for nil' do
|
19
|
+
expect(described_class.parse(nil)).to be_nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|