metar-parser 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +7 -6
- data/lib/metar/data.rb +34 -29
- data/lib/metar/parser.rb +73 -132
- data/lib/metar/raw.rb +6 -0
- data/lib/metar/report.rb +5 -0
- data/lib/metar/version.rb +1 -1
- data/locales/en.yml +2 -0
- data/locales/it.yml +2 -0
- data/spec/unit/parser_spec.rb +22 -6
- data/spec/unit/report_spec.rb +5 -2
- data/spec/unit/runway_visible_range_spec.rb +2 -1
- data/spec/unit/sky_condition_spec.rb +6 -4
- data/spec/unit/visibility_spec.rb +4 -3
- data/spec/unit/weather_phenomenon_spec.rb +4 -1
- metadata +35 -18
data/README.md
CHANGED
@@ -63,15 +63,10 @@ Use Your Own Raw Data
|
|
63
63
|
---------------------
|
64
64
|
```ruby
|
65
65
|
metar_string = "KHWD 280554Z AUTO 29007KT 10SM OVC008 14/12 A3002 RMK AO2 SLP176 T01390117 10211\n"
|
66
|
-
raw = Metar::Raw.new( metar_string )
|
66
|
+
raw = Metar::Raw::Data.new( metar_string )
|
67
67
|
parser = Metar::Parser.new( raw )
|
68
68
|
```
|
69
69
|
|
70
|
-
Implementation
|
71
|
-
==============
|
72
|
-
|
73
|
-
* Parses METAR strings using a state machine.
|
74
|
-
|
75
70
|
Changelog
|
76
71
|
=========
|
77
72
|
|
@@ -84,6 +79,12 @@ The old functionality has been moved to Metar::Raw::Noaa. The new class,
|
|
84
79
|
Metar::Raw::Data accepts a METAR string as a parameter - allowing the user to
|
85
80
|
parse METAR strings without necessarily contacting the NOAA.
|
86
81
|
|
82
|
+
Contributors
|
83
|
+
============
|
84
|
+
|
85
|
+
* [Joe Yates](https://github.com/joeyates)
|
86
|
+
* [Derek Johnson](https://github.com/EpicDraws)
|
87
|
+
|
87
88
|
Alternative Software
|
88
89
|
====================
|
89
90
|
|
data/lib/metar/data.rb
CHANGED
@@ -193,7 +193,7 @@ module Metar
|
|
193
193
|
new( Distance.new( 10000 ), nil, :more_than )
|
194
194
|
when s =~ /(\d{4})NDV/ # WMO
|
195
195
|
new( Distance.new( $1.to_f ) ) # Assuming meters
|
196
|
-
when (s =~ /^((1|2)\s|)([
|
196
|
+
when (s =~ /^((1|2)\s|)([1357])\/([248]|16)SM$/) # US
|
197
197
|
miles = $1.to_f + $3.to_f / $4.to_f
|
198
198
|
distance = Distance.miles( miles )
|
199
199
|
distance.units = :miles
|
@@ -208,10 +208,10 @@ module Metar
|
|
208
208
|
new( distance, nil, :less_than )
|
209
209
|
when s =~ /^(\d+)KM$/
|
210
210
|
new( Distance.kilometers( $1 ) )
|
211
|
-
when s =~ /^(\d+)$/ #
|
212
|
-
new( Distance.
|
211
|
+
when s =~ /^(\d+)$/ # We assume meters
|
212
|
+
new( Distance.new( $1 ) )
|
213
213
|
when s =~ /^(\d+)(N|NE|E|SE|S|SW|W|NW)$/
|
214
|
-
new( Distance.
|
214
|
+
new( Distance.meters( $1 ), M9t::Direction.compass( $2 ) )
|
215
215
|
else
|
216
216
|
nil
|
217
217
|
end
|
@@ -263,7 +263,7 @@ module Metar
|
|
263
263
|
distance = Distance.send( units, count )
|
264
264
|
visibility = Visibility.new(distance, nil, comparator)
|
265
265
|
new(designator, visibility, nil, tendency)
|
266
|
-
when runway_visible_range =~ /^R(\d+[RLC]?)\/(P|M|)(\d{4})V(P|M|)(\d{4})(N|U|D)?(FT)
|
266
|
+
when runway_visible_range =~ /^R(\d+[RLC]?)\/(P|M|)(\d{4})V(P|M|)(\d{4})(N|U|D)?(FT|)$/
|
267
267
|
designator = $1
|
268
268
|
comparator1 = COMPARATOR[$2]
|
269
269
|
count1 = $3.to_f
|
@@ -316,9 +316,11 @@ module Metar
|
|
316
316
|
class WeatherPhenomenon
|
317
317
|
|
318
318
|
Modifiers = {
|
319
|
-
'+'
|
320
|
-
'-'
|
321
|
-
'VC'
|
319
|
+
'+' => 'heavy',
|
320
|
+
'-' => 'light',
|
321
|
+
'VC' => 'nearby',
|
322
|
+
'-VC' => 'nearby light',
|
323
|
+
'+VC' => 'nearby heavy',
|
322
324
|
}
|
323
325
|
|
324
326
|
Descriptors = {
|
@@ -350,7 +352,6 @@ module Metar
|
|
350
352
|
'SH' => 'shower',
|
351
353
|
'SN' => 'snow',
|
352
354
|
'SG' => 'snow grains',
|
353
|
-
'SNRA' => 'snow and rain',
|
354
355
|
'SQ' => 'squall',
|
355
356
|
'UP' => 'unknown phenomenon', # => AUTO
|
356
357
|
'VA' => 'volcanic ash',
|
@@ -358,28 +359,24 @@ module Metar
|
|
358
359
|
'SS' => 'sand storm',
|
359
360
|
'DS' => 'dust storm',
|
360
361
|
'TS' => 'thunderstorm',
|
361
|
-
'TSGR' => 'thunderstorm and hail',
|
362
|
-
'TSGS' => 'thunderstorm and small hail',
|
363
|
-
'TSRA' => 'thunderstorm and rain',
|
364
|
-
'TSRA' => 'thunderstorm and snow',
|
365
|
-
'TSRA' => 'thunderstorm and unknown phenomenon', # => AUTO
|
366
362
|
}
|
367
363
|
|
368
364
|
# Accepts all standard (and some non-standard) present weather codes
|
369
365
|
def WeatherPhenomenon.parse(s)
|
370
|
-
|
366
|
+
phenomena = Phenomena.keys.join('|')
|
371
367
|
descriptors = Descriptors.keys.join('|')
|
372
|
-
modifiers
|
368
|
+
modifiers = Modifiers.keys.join('|')
|
373
369
|
modifiers.gsub!(/([\+\-])/) { "\\#$1" }
|
374
|
-
rxp = Regexp.new("^(#{ modifiers })?(#{ descriptors })?(
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
370
|
+
rxp = Regexp.new("^(#{ modifiers })?(#{ descriptors })?((?:#{ phenomena }){1,2})$")
|
371
|
+
m = rxp.match(s)
|
372
|
+
return nil if m.nil?
|
373
|
+
|
374
|
+
modifier_code = m[1]
|
375
|
+
descriptor_code = m[2]
|
376
|
+
phenomena_codes = m[3].scan(/../)
|
377
|
+
phenomena_phrase = phenomena_codes.map{ |c| Phenomena[c] }.join(' and ')
|
378
|
+
|
379
|
+
Metar::WeatherPhenomenon.new(phenomena_phrase, Modifiers[modifier_code], Descriptors[descriptor_code])
|
383
380
|
end
|
384
381
|
|
385
382
|
attr_reader :phenomenon, :modifier, :descriptor
|
@@ -399,7 +396,7 @@ module Metar
|
|
399
396
|
CONDITION = {
|
400
397
|
'CB' => 'cumulonimbus',
|
401
398
|
'TCU' => 'towering cumulus',
|
402
|
-
'///' => nil,
|
399
|
+
'///' => nil, # cloud type unknown as observed by automatic system (15.9.1.7)
|
403
400
|
'' => nil
|
404
401
|
}
|
405
402
|
CLEAR_SKIES = [
|
@@ -413,11 +410,19 @@ module Metar
|
|
413
410
|
case
|
414
411
|
when CLEAR_SKIES.include?( sky_condition )
|
415
412
|
new
|
416
|
-
when sky_condition =~ /^(BKN|FEW|OVC|SCT)(\d
|
413
|
+
when sky_condition =~ /^(BKN|FEW|OVC|SCT)(\d+|\/{3})(CB|TCU|\/{3}|)?$/
|
417
414
|
quantity = QUANTITY[ $1 ]
|
418
|
-
height =
|
419
|
-
|
415
|
+
height =
|
416
|
+
if $2 == '///'
|
417
|
+
nil
|
418
|
+
else
|
419
|
+
Distance.new( $2.to_i * 30.48 )
|
420
|
+
end
|
421
|
+
type = CONDITION[ $3 ]
|
420
422
|
new(quantity, height, type)
|
423
|
+
when sky_condition =~ /^(CB|TCU)$/
|
424
|
+
type = CONDITION[ $1 ]
|
425
|
+
new(nil, nil, type)
|
421
426
|
else
|
422
427
|
nil
|
423
428
|
end
|
data/lib/metar/parser.rb
CHANGED
@@ -1,87 +1,8 @@
|
|
1
|
-
require 'aasm'
|
2
1
|
require File.join(File.dirname(__FILE__), 'data')
|
3
2
|
|
4
3
|
module Metar
|
5
4
|
|
6
5
|
class Parser
|
7
|
-
include AASM
|
8
|
-
|
9
|
-
aasm_initial_state :start
|
10
|
-
|
11
|
-
aasm_state :start, :after_enter => :seek_location
|
12
|
-
aasm_state :location, :after_enter => :seek_datetime
|
13
|
-
aasm_state :datetime, :after_enter => [:seek_cor_auto, :seek_wind]
|
14
|
-
aasm_state :wind, :after_enter => :seek_variable_wind
|
15
|
-
aasm_state :variable_wind, :after_enter => :seek_visibility
|
16
|
-
aasm_state :visibility, :after_enter => :seek_runway_visible_range
|
17
|
-
aasm_state :runway_visible_range, :after_enter => :seek_present_weather
|
18
|
-
aasm_state :present_weather, :after_enter => :seek_sky_conditions
|
19
|
-
aasm_state :sky_conditions, :after_enter => :seek_vertical_visibility
|
20
|
-
aasm_state :vertical_visibility, :after_enter => :seek_temperature_dew_point
|
21
|
-
aasm_state :temperature_dew_point, :after_enter => :seek_sea_level_pressure
|
22
|
-
aasm_state :sea_level_pressure, :after_enter => :seek_remarks
|
23
|
-
aasm_state :remarks, :after_enter => :seek_end
|
24
|
-
aasm_state :end
|
25
|
-
|
26
|
-
aasm_event :location do
|
27
|
-
transitions :from => :start, :to => :location
|
28
|
-
end
|
29
|
-
|
30
|
-
aasm_event :datetime do
|
31
|
-
transitions :from => :location, :to => :datetime
|
32
|
-
end
|
33
|
-
|
34
|
-
aasm_event :wind do
|
35
|
-
transitions :from => :datetime, :to => :wind
|
36
|
-
end
|
37
|
-
|
38
|
-
aasm_event :cavok do
|
39
|
-
transitions :from => :variable_wind, :to => :sky_conditions
|
40
|
-
end
|
41
|
-
|
42
|
-
aasm_event :variable_wind do
|
43
|
-
transitions :from => :wind, :to => :variable_wind
|
44
|
-
end
|
45
|
-
|
46
|
-
aasm_event :visibility do
|
47
|
-
transitions :from => [:wind, :variable_wind], :to => :visibility
|
48
|
-
end
|
49
|
-
|
50
|
-
aasm_event :runway_visible_range do
|
51
|
-
transitions :from => [:visibility], :to => :runway_visible_range
|
52
|
-
end
|
53
|
-
|
54
|
-
aasm_event :present_weather do
|
55
|
-
transitions :from => [:runway_visible_range],
|
56
|
-
:to => :present_weather
|
57
|
-
end
|
58
|
-
|
59
|
-
aasm_event :sky_conditions do
|
60
|
-
transitions :from => [:present_weather, :visibility, :sky_conditions],
|
61
|
-
:to => :sky_conditions
|
62
|
-
end
|
63
|
-
|
64
|
-
aasm_event :vertical_visibility do
|
65
|
-
transitions :from => [:present_weather, :visibility, :sky_conditions],
|
66
|
-
:to => :vertical_visibility
|
67
|
-
end
|
68
|
-
|
69
|
-
aasm_event :temperature_dew_point do
|
70
|
-
transitions :from => [:wind, :sky_conditions, :vertical_visibility], :to => :temperature_dew_point
|
71
|
-
end
|
72
|
-
|
73
|
-
aasm_event :sea_level_pressure do
|
74
|
-
transitions :from => :temperature_dew_point, :to => :sea_level_pressure
|
75
|
-
end
|
76
|
-
|
77
|
-
aasm_event :remarks do
|
78
|
-
transitions :from => [:temperature_dew_point, :sea_level_pressure],
|
79
|
-
:to => :remarks
|
80
|
-
end
|
81
|
-
|
82
|
-
aasm_event :done do
|
83
|
-
transitions :from => [:remarks], :to => :end
|
84
|
-
end
|
85
6
|
|
86
7
|
def self.for_cccc(cccc)
|
87
8
|
raw = Metar::Raw::Noaa.new(cccc)
|
@@ -89,8 +10,10 @@ module Metar
|
|
89
10
|
end
|
90
11
|
|
91
12
|
attr_reader :raw, :metar
|
92
|
-
attr_reader :station_code, :observer, :wind, :variable_wind, :visibility,
|
93
|
-
|
13
|
+
attr_reader :station_code, :observer, :wind, :variable_wind, :visibility,
|
14
|
+
:minimum_visibility, :runway_visible_range, :present_weather, :sky_conditions,
|
15
|
+
:vertical_visibility, :temperature, :dew_point, :sea_level_pressure,
|
16
|
+
:recent_weather, :remarks
|
94
17
|
|
95
18
|
def initialize(raw)
|
96
19
|
@raw = raw
|
@@ -112,6 +35,7 @@ module Metar
|
|
112
35
|
@wind = nil
|
113
36
|
@variable_wind = nil
|
114
37
|
@visibility = nil
|
38
|
+
@minimum_visibility = nil
|
115
39
|
@runway_visible_range = []
|
116
40
|
@present_weather = []
|
117
41
|
@sky_conditions = []
|
@@ -119,18 +43,35 @@ module Metar
|
|
119
43
|
@temperature = nil
|
120
44
|
@dew_point = nil
|
121
45
|
@sea_level_pressure = nil
|
46
|
+
@recent_weather = []
|
122
47
|
@remarks = []
|
123
48
|
|
124
|
-
|
49
|
+
seek_location
|
50
|
+
seek_datetime
|
51
|
+
seek_cor_auto
|
52
|
+
seek_wind
|
53
|
+
seek_variable_wind
|
54
|
+
cavok = seek_cavok
|
55
|
+
if not cavok
|
56
|
+
seek_visibility
|
57
|
+
seek_minimum_visibility
|
58
|
+
seek_runway_visible_range
|
59
|
+
seek_present_weather
|
60
|
+
seek_sky_conditions
|
61
|
+
end
|
62
|
+
seek_vertical_visibility
|
63
|
+
seek_temperature_dew_point
|
64
|
+
seek_sea_level_pressure
|
65
|
+
seek_recent_weather
|
66
|
+
seek_remarks
|
125
67
|
end
|
126
68
|
|
127
69
|
def seek_location
|
128
70
|
if @chunks[0] =~ /^[A-Z][A-Z0-9]{3}$/
|
129
71
|
@station_code = @chunks.shift
|
130
72
|
else
|
131
|
-
raise ParseError.new("Expecting location, found '#{ @chunks[0] }'")
|
73
|
+
raise ParseError.new("Expecting location, found '#{ @chunks[0] }' in #{@metar}")
|
132
74
|
end
|
133
|
-
location!
|
134
75
|
end
|
135
76
|
|
136
77
|
def seek_datetime
|
@@ -139,9 +80,8 @@ module Metar
|
|
139
80
|
@chunks.shift
|
140
81
|
@day, @hour, @minute = $1.to_i, $2.to_i, $3.to_i
|
141
82
|
else
|
142
|
-
raise ParseError.new("Expecting datetime, found '#{ @chunks[0] }'")
|
83
|
+
raise ParseError.new("Expecting datetime, found '#{ @chunks[0] }' in #{@metar}")
|
143
84
|
end
|
144
|
-
datetime!
|
145
85
|
end
|
146
86
|
|
147
87
|
def seek_cor_auto
|
@@ -152,6 +92,11 @@ module Metar
|
|
152
92
|
when @chunks[0] == 'COR'
|
153
93
|
@chunks.shift
|
154
94
|
@observer = :corrected
|
95
|
+
when @chunks[0] == 'CCA'
|
96
|
+
@chunks.shift
|
97
|
+
@observer = :corrected
|
98
|
+
when @chunks[0] == 'RTD' # Delayed observation, no comments on observer
|
99
|
+
@chunks.shift
|
155
100
|
else
|
156
101
|
nil
|
157
102
|
end
|
@@ -163,7 +108,6 @@ module Metar
|
|
163
108
|
@chunks.shift
|
164
109
|
@wind = wind
|
165
110
|
end
|
166
|
-
wind!
|
167
111
|
end
|
168
112
|
|
169
113
|
def seek_variable_wind
|
@@ -172,23 +116,25 @@ module Metar
|
|
172
116
|
@chunks.shift
|
173
117
|
@variable_wind = variable_wind
|
174
118
|
end
|
175
|
-
variable_wind!
|
176
119
|
end
|
177
120
|
|
178
|
-
def
|
121
|
+
def seek_cavok
|
179
122
|
if @chunks[0] == 'CAVOK'
|
180
123
|
@chunks.shift
|
181
|
-
@visibility
|
124
|
+
@visibility = Visibility.new(M9t::Distance.kilometers(10), nil, :more_than)
|
182
125
|
@present_weather << Metar::WeatherPhenomenon.new('No significant weather')
|
183
|
-
@sky_conditions
|
184
|
-
|
185
|
-
|
126
|
+
@sky_conditions << SkyCondition.new # = 'clear skies'
|
127
|
+
return true
|
128
|
+
else
|
129
|
+
return false
|
186
130
|
end
|
131
|
+
end
|
187
132
|
|
133
|
+
# 15.10, 15.6.1
|
134
|
+
def seek_visibility
|
188
135
|
if @observer == :auto # WMO 15.4
|
189
136
|
if @chunks[0] == '////'
|
190
137
|
@chunks.shift # Simply dispose of it
|
191
|
-
visibility!
|
192
138
|
return
|
193
139
|
end
|
194
140
|
end
|
@@ -207,29 +153,23 @@ module Metar
|
|
207
153
|
@visibility = visibility
|
208
154
|
end
|
209
155
|
end
|
210
|
-
visibility!
|
211
156
|
end
|
212
157
|
|
213
|
-
|
214
|
-
|
215
|
-
|
158
|
+
# Optional after visibility: 15.6.2
|
159
|
+
def seek_minimum_visibility
|
160
|
+
minimum_visibility = Visibility.parse(@chunks[0])
|
161
|
+
if minimum_visibility
|
216
162
|
@chunks.shift
|
217
|
-
@
|
218
|
-
collect_runway_visible_range
|
163
|
+
@minimum_visibility = minimum_visibility
|
219
164
|
end
|
220
165
|
end
|
221
166
|
|
222
167
|
def seek_runway_visible_range
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
def collect_present_weather
|
228
|
-
wtp = WeatherPhenomenon.parse(@chunks[0])
|
229
|
-
if wtp
|
168
|
+
loop do
|
169
|
+
runway_visible_range = RunwayVisibleRange.parse(@chunks[0])
|
170
|
+
break if runway_visible_range.nil?
|
230
171
|
@chunks.shift
|
231
|
-
@
|
232
|
-
collect_present_weather
|
172
|
+
@runway_visible_range << runway_visible_range
|
233
173
|
end
|
234
174
|
end
|
235
175
|
|
@@ -238,35 +178,33 @@ module Metar
|
|
238
178
|
if @chunks[0] == '//' # WMO 15.4
|
239
179
|
@chunks.shift # Simply dispose of it
|
240
180
|
@present_weather << Metar::WeatherPhenomenon.new('not observed')
|
241
|
-
present_weather!
|
242
181
|
return
|
243
182
|
end
|
244
183
|
end
|
245
184
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
def collect_sky_conditions
|
251
|
-
sky_condition = SkyCondition.parse(@chunks[0])
|
252
|
-
if sky_condition
|
185
|
+
loop do
|
186
|
+
wtp = WeatherPhenomenon.parse(@chunks[0])
|
187
|
+
break if wtp.nil?
|
253
188
|
@chunks.shift
|
254
|
-
@
|
255
|
-
collect_sky_conditions
|
189
|
+
@present_weather << wtp
|
256
190
|
end
|
257
191
|
end
|
258
192
|
|
193
|
+
# Repeatable: 15.9.1.3
|
259
194
|
def seek_sky_conditions
|
260
195
|
if @observer == :auto # WMO 15.4
|
261
196
|
if @chunks[0] == '///' or @chunks[0] == '//////'
|
262
197
|
@chunks.shift # Simply dispose of it
|
263
|
-
sky_conditions!
|
264
198
|
return
|
265
199
|
end
|
266
200
|
end
|
267
201
|
|
268
|
-
|
269
|
-
|
202
|
+
loop do
|
203
|
+
sky_condition = SkyCondition.parse(@chunks[0])
|
204
|
+
break if sky_condition.nil?
|
205
|
+
@chunks.shift
|
206
|
+
@sky_conditions << sky_condition
|
207
|
+
end
|
270
208
|
end
|
271
209
|
|
272
210
|
def seek_vertical_visibility
|
@@ -275,7 +213,6 @@ module Metar
|
|
275
213
|
@chunks.shift
|
276
214
|
@vertical_visibility = vertical_visibility
|
277
215
|
end
|
278
|
-
vertical_visibility!
|
279
216
|
end
|
280
217
|
|
281
218
|
def seek_temperature_dew_point
|
@@ -284,10 +221,7 @@ module Metar
|
|
284
221
|
@chunks.shift
|
285
222
|
@temperature = Metar::Temperature.parse($1)
|
286
223
|
@dew_point = Metar::Temperature.parse($2)
|
287
|
-
else
|
288
|
-
raise ParseError.new("Expecting temperature/dew point, found '#{ @chunks[0] }'")
|
289
224
|
end
|
290
|
-
temperature_dew_point!
|
291
225
|
end
|
292
226
|
|
293
227
|
def seek_sea_level_pressure
|
@@ -296,7 +230,19 @@ module Metar
|
|
296
230
|
@chunks.shift
|
297
231
|
@sea_level_pressure = sea_level_pressure
|
298
232
|
end
|
299
|
-
|
233
|
+
end
|
234
|
+
|
235
|
+
def seek_recent_weather
|
236
|
+
loop do
|
237
|
+
return if @chunks.size == 0
|
238
|
+
m = /^RE/.match(@chunks[0])
|
239
|
+
break if m.nil?
|
240
|
+
recent_weather = Metar::WeatherPhenomenon.parse(m.post_match)
|
241
|
+
if recent_weather
|
242
|
+
@chunks.shift
|
243
|
+
@recent_weather << recent_weather
|
244
|
+
end
|
245
|
+
end
|
300
246
|
end
|
301
247
|
|
302
248
|
def seek_remarks
|
@@ -305,11 +251,6 @@ module Metar
|
|
305
251
|
end
|
306
252
|
@remarks += @chunks.clone
|
307
253
|
@chunks = []
|
308
|
-
remarks!
|
309
|
-
end
|
310
|
-
|
311
|
-
def seek_end
|
312
|
-
done!
|
313
254
|
end
|
314
255
|
|
315
256
|
end
|
data/lib/metar/raw.rb
CHANGED
data/lib/metar/report.rb
CHANGED
@@ -10,6 +10,7 @@ module Metar
|
|
10
10
|
:time,
|
11
11
|
:wind,
|
12
12
|
:visibility,
|
13
|
+
:minimum_visibility,
|
13
14
|
:present_weather,
|
14
15
|
:sky_summary,
|
15
16
|
:temperature
|
@@ -58,6 +59,10 @@ module Metar
|
|
58
59
|
@parser.visibility.to_s
|
59
60
|
end
|
60
61
|
|
62
|
+
def minimum_visibility
|
63
|
+
@parser.minimum_visibility.to_s
|
64
|
+
end
|
65
|
+
|
61
66
|
def runway_visible_range
|
62
67
|
@parser.runway_visible_range.collect { |rvr| rvr.to_s }.join(', ')
|
63
68
|
end
|
data/lib/metar/version.rb
CHANGED
data/locales/en.yml
CHANGED
data/locales/it.yml
CHANGED
data/spec/unit/parser_spec.rb
CHANGED
@@ -64,6 +64,12 @@ describe Metar::Parser do
|
|
64
64
|
|
65
65
|
parser.observer. should == :corrected
|
66
66
|
end
|
67
|
+
|
68
|
+
it 'corrected (Canadian)' do
|
69
|
+
parser = setup_parser('CYZU 310100Z CCA 26004KT 15SM FEW009 BKN040TCU BKN100 OVC210 15/12 A2996 RETS RMK SF1TCU4AC2CI1 SLP149')
|
70
|
+
|
71
|
+
parser.observer. should == :corrected
|
72
|
+
end
|
67
73
|
|
68
74
|
end
|
69
75
|
|
@@ -108,6 +114,13 @@ describe Metar::Parser do
|
|
108
114
|
should be_within( 0.01 ).of( 1.75 )
|
109
115
|
end
|
110
116
|
|
117
|
+
it 'in meters' do
|
118
|
+
parser = setup_parser('VABB 282210Z 22005KT 4000 HZ SCT018 FEW025TCU BKN100 28/25 Q1003 NOSIG')
|
119
|
+
|
120
|
+
parser.visibility.distance.value.
|
121
|
+
should be_within(0.01).of(4000)
|
122
|
+
end
|
123
|
+
|
111
124
|
it '//// with automatic observer' do
|
112
125
|
parser = setup_parser("CYXS 151034Z AUTO 09003KT //// FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
|
113
126
|
|
@@ -211,12 +224,6 @@ describe Metar::Parser do
|
|
211
224
|
should == 30.48
|
212
225
|
end
|
213
226
|
|
214
|
-
it 'temperature_obligatory' do
|
215
|
-
expect do
|
216
|
-
setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 A2910 RMK AO2 P0000")
|
217
|
-
end. to raise_error( Metar::ParseError )
|
218
|
-
end
|
219
|
-
|
220
227
|
it 'temperature' do
|
221
228
|
parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
222
229
|
parser.temperature.value. should == -17
|
@@ -233,6 +240,15 @@ describe Metar::Parser do
|
|
233
240
|
should == 29.10
|
234
241
|
end
|
235
242
|
|
243
|
+
it 'recent weather' do
|
244
|
+
parser = setup_parser("CYQH 310110Z 00000KT 20SM SCT035CB BKN050 RETS RMK CB4SC1")
|
245
|
+
|
246
|
+
parser.recent_weather. should be_a Array
|
247
|
+
parser.recent_weather.size. should == 1
|
248
|
+
parser.recent_weather[0].phenomenon.
|
249
|
+
should == 'thunderstorm'
|
250
|
+
end
|
251
|
+
|
236
252
|
it 'remarks' do
|
237
253
|
parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
238
254
|
|
data/spec/unit/report_spec.rb
CHANGED
@@ -79,6 +79,7 @@ describe Metar::Report do
|
|
79
79
|
:wind,
|
80
80
|
:variable_wind,
|
81
81
|
:visibility,
|
82
|
+
:minimum_visibility,
|
82
83
|
:vertical_visibility,
|
83
84
|
:temperature,
|
84
85
|
:dew_point,
|
@@ -161,10 +162,11 @@ describe Metar::Report do
|
|
161
162
|
end
|
162
163
|
|
163
164
|
it '#to_s' do
|
164
|
-
|
165
|
-
|
165
|
+
sky1 = stub( 'sky1', :to_summary => 'sky1' )
|
166
|
+
sky2 = stub( 'sky2', :to_summary => 'sky2' )
|
166
167
|
@parser.stub!( :wind => 'wind',
|
167
168
|
:visibility => 'visibility',
|
169
|
+
:minimum_visibility => 'min visibility',
|
168
170
|
:present_weather => ['pw'],
|
169
171
|
:sky_conditions => [ sky1, sky2 ],
|
170
172
|
:temperature => 'temp' )
|
@@ -174,6 +176,7 @@ country: Wwwwww
|
|
174
176
|
time: #{@metar_time}
|
175
177
|
wind: wind
|
176
178
|
visibility: visibility
|
179
|
+
minimum visibility: min visibility
|
177
180
|
weather: pw
|
178
181
|
sky: sky2
|
179
182
|
temperature: temp
|
@@ -39,7 +39,8 @@ describe Metar::RunwayVisibleRange do
|
|
39
39
|
[ 'understands comparators: PM', 'R12/P3400', [ '12', [3400.00, nil, :more_than], nil, nil ] ],
|
40
40
|
[ 'understands tendencies: NUD', 'R12/3400U', [ '12', [3400.00, nil, nil], nil, :improving ] ],
|
41
41
|
[ 'understands feet', 'R12/3400FT', [ '12', [1036.32, nil, nil], nil, nil ] ],
|
42
|
-
[ 'understands second
|
42
|
+
[ 'understands second visibilities (m)', 'R26/0750V1200U', [ '12', [ 750.0, nil, nil], [1200.0, nil, nil], :improving ] ],
|
43
|
+
[ 'understands second visibilities (ft)', 'R12/3400V1800FT', [ '12', [1036.32, nil, nil], [548.64, nil, nil], nil ] ],
|
43
44
|
[ 'returns nil for nil', nil, [ nil, nil, nil, nil ] ],
|
44
45
|
].each do | docstring, raw, expected |
|
45
46
|
example docstring do
|
@@ -24,11 +24,13 @@ describe Metar::SkyCondition do
|
|
24
24
|
context '.parse' do
|
25
25
|
|
26
26
|
[
|
27
|
-
[ 'understands clear skies codes', 'NSC', [ nil,
|
28
|
-
[ 'quantity + height', 'BKN12', [ 'broken', 365.76,
|
27
|
+
[ 'understands clear skies codes', 'NSC', [ nil, nil, nil ] ],
|
28
|
+
[ 'quantity + height', 'BKN12', [ 'broken', 365.76, nil ] ],
|
29
29
|
[ 'quantity + height + type', 'BKN12CB', [ 'broken', 365.76, 'cumulonimbus' ] ],
|
30
|
-
[ 'quantity +
|
31
|
-
[ '
|
30
|
+
[ 'quantity + ///', 'BKN///', [ 'broken', nil, nil ] ],
|
31
|
+
[ 'quantity + height + ///', 'FEW038///',[ 'few', 1158.24, nil ] ],
|
32
|
+
[ 'cumulonimbus only', 'CB', [ nil, nil, 'cumulonimbus' ] ], # seems non-standard, but occurs
|
33
|
+
[ 'returns nil for unmatched', 'FUBAR', [ :expect_nil, nil, nil ] ],
|
32
34
|
].each do | docstring, raw, expected |
|
33
35
|
example docstring do
|
34
36
|
Metar::SkyCondition.parse( raw ).should be_sky_condition( *expected )
|
@@ -33,13 +33,14 @@ describe Metar::Visibility do
|
|
33
33
|
[ 'understands 9999', '9999', [ 10000.00, nil, :more_than ] ],
|
34
34
|
[ 'understands nnnn + NDV', '0123NDV', [ 123.00, nil, nil ] ],
|
35
35
|
[ 'understands n/nSM', '3/4SM', [ 1207.01, nil, nil ] ],
|
36
|
+
[ 'understands 3/16SM', '3/16SM', [ 301.752, nil, nil ] ],
|
36
37
|
[ 'understands n n/nSM', '1 1/4SM', [ 2011.68, nil, nil ] ],
|
37
38
|
[ 'understands nSM', '5SM', [ 8046.72, nil, nil ] ],
|
38
39
|
[ 'understands M1/4SM', 'M1/4SM', [ 402.34, nil, :less_than ] ],
|
39
40
|
[ 'understands n + KM', '5KM', [ 5000.00, nil, nil ] ],
|
40
|
-
[ 'understands n', '
|
41
|
-
[ 'understands n + compass', '
|
42
|
-
[ 'returns nil for unmatched', 'FUBAR', [
|
41
|
+
[ 'understands n', '500', [ 500.00, nil, nil ] ],
|
42
|
+
[ 'understands n + compass', '500NW', [ 500.00, 315.0, nil ] ],
|
43
|
+
[ 'returns nil for unmatched', 'FUBAR', [ nil, nil, nil ] ],
|
43
44
|
].each do | docstring, raw, expected |
|
44
45
|
example docstring do
|
45
46
|
Metar::Visibility.parse( raw ).should be_visibility( *expected )
|
@@ -26,7 +26,10 @@ describe Metar::WeatherPhenomenon do
|
|
26
26
|
[
|
27
27
|
[ 'simple phenomenon', 'BR', [ nil, nil, 'mist' ] ],
|
28
28
|
[ 'descriptor + phenomenon', 'BCFG', [ nil, 'patches of', 'fog' ] ],
|
29
|
-
[ '
|
29
|
+
[ 'intensity + phenomenon', '+RA', [ 'heavy', nil, 'rain' ] ],
|
30
|
+
[ 'intensity + proximity + phenomenon', '-VCTSRA', [ 'nearby light', 'thunderstorm and', 'rain' ] ],
|
31
|
+
[ '2 phenomena: SN RA', 'SNRA', [ nil, nil, 'snow and rain' ] ],
|
32
|
+
[ '2 phenomena: RA DZ', 'RADZ', [ nil, nil, 'rain and drizzle' ] ],
|
30
33
|
[ 'modifier + descriptor + phenomenon', 'VCDRFG', [ 'nearby', 'low drifting', 'fog' ] ],
|
31
34
|
[ 'returns nil for unmatched', 'FUBAR', [ nil, nil, nil ] ],
|
32
35
|
].each do | docstring, raw, expected |
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metar-parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -60,45 +60,61 @@ dependencies:
|
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.3.5
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
|
-
name:
|
63
|
+
name: m9t
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
65
65
|
none: false
|
66
66
|
requirements:
|
67
|
-
- -
|
67
|
+
- - ~>
|
68
68
|
- !ruby/object:Gem::Version
|
69
|
-
version:
|
69
|
+
version: 0.3.1
|
70
70
|
type: :runtime
|
71
71
|
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 0.3.1
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: rspec
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 2.3.0
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
72
88
|
version_requirements: !ruby/object:Gem::Requirement
|
73
89
|
none: false
|
74
90
|
requirements:
|
75
91
|
- - ! '>='
|
76
92
|
- !ruby/object:Gem::Version
|
77
|
-
version: 2.
|
93
|
+
version: 2.3.0
|
78
94
|
- !ruby/object:Gem::Dependency
|
79
|
-
name:
|
95
|
+
name: simplecov
|
80
96
|
requirement: !ruby/object:Gem::Requirement
|
81
97
|
none: false
|
82
98
|
requirements:
|
83
|
-
- -
|
99
|
+
- - ! '>='
|
84
100
|
- !ruby/object:Gem::Version
|
85
|
-
version: 0
|
86
|
-
type: :
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
87
103
|
prerelease: false
|
88
104
|
version_requirements: !ruby/object:Gem::Requirement
|
89
105
|
none: false
|
90
106
|
requirements:
|
91
|
-
- -
|
107
|
+
- - ! '>='
|
92
108
|
- !ruby/object:Gem::Version
|
93
|
-
version: 0
|
109
|
+
version: '0'
|
94
110
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
111
|
+
name: pry
|
96
112
|
requirement: !ruby/object:Gem::Requirement
|
97
113
|
none: false
|
98
114
|
requirements:
|
99
115
|
- - ! '>='
|
100
116
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
117
|
+
version: '0'
|
102
118
|
type: :development
|
103
119
|
prerelease: false
|
104
120
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -106,9 +122,9 @@ dependencies:
|
|
106
122
|
requirements:
|
107
123
|
- - ! '>='
|
108
124
|
- !ruby/object:Gem::Version
|
109
|
-
version:
|
125
|
+
version: '0'
|
110
126
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
127
|
+
name: pry-doc
|
112
128
|
requirement: !ruby/object:Gem::Requirement
|
113
129
|
none: false
|
114
130
|
requirements:
|
@@ -176,7 +192,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
176
192
|
version: '0'
|
177
193
|
segments:
|
178
194
|
- 0
|
179
|
-
hash:
|
195
|
+
hash: -116852050728515412
|
180
196
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
197
|
none: false
|
182
198
|
requirements:
|
@@ -185,7 +201,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
185
201
|
version: '0'
|
186
202
|
segments:
|
187
203
|
- 0
|
188
|
-
hash:
|
204
|
+
hash: -116852050728515412
|
189
205
|
requirements: []
|
190
206
|
rubyforge_project: nowarning
|
191
207
|
rubygems_version: 1.8.23
|
@@ -208,3 +224,4 @@ test_files:
|
|
208
224
|
- spec/unit/raw_spec.rb
|
209
225
|
- spec/unit/speed_spec.rb
|
210
226
|
- spec/unit/distance_spec.rb
|
227
|
+
has_rdoc:
|