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 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|)([13])\/([248])SM$/) # US
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+)$/ # Units?
212
- new( Distance.kilometers( $1 ) )
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.kilometers( $1 ), M9t::Direction.compass( $2 ) )
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
- '+' => 'heavy',
320
- '-' => 'light',
321
- 'VC' => 'nearby'
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
- codes = Phenomena.keys.join('|')
366
+ phenomena = Phenomena.keys.join('|')
371
367
  descriptors = Descriptors.keys.join('|')
372
- modifiers = Modifiers.keys.join('|')
368
+ modifiers = Modifiers.keys.join('|')
373
369
  modifiers.gsub!(/([\+\-])/) { "\\#$1" }
374
- rxp = Regexp.new("^(#{ modifiers })?(#{ descriptors })?(#{ codes })$")
375
- if rxp.match(s)
376
- modifier_code = $1
377
- descriptor_code = $2
378
- phenomenon_code = $3
379
- Metar::WeatherPhenomenon.new(Phenomena[phenomenon_code], Modifiers[modifier_code], Descriptors[descriptor_code])
380
- else
381
- nil
382
- end
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+)(CB|TCU|\/{3}|)?$/
413
+ when sky_condition =~ /^(BKN|FEW|OVC|SCT)(\d+|\/{3})(CB|TCU|\/{3}|)?$/
417
414
  quantity = QUANTITY[ $1 ]
418
- height = Distance.new( $2.to_i * 30.48 )
419
- type = CONDITION[ $3 ]
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, :runway_visible_range,
93
- :present_weather, :sky_conditions, :vertical_visibility, :temperature, :dew_point, :sea_level_pressure, :remarks
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
- aasm_enter_initial_state
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 seek_visibility
121
+ def seek_cavok
179
122
  if @chunks[0] == 'CAVOK'
180
123
  @chunks.shift
181
- @visibility = Visibility.new(M9t::Distance.kilometers(10), nil, :more_than)
124
+ @visibility = Visibility.new(M9t::Distance.kilometers(10), nil, :more_than)
182
125
  @present_weather << Metar::WeatherPhenomenon.new('No significant weather')
183
- @sky_conditions << SkyCondition.new # = 'clear skies'
184
- cavok!
185
- return
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
- def collect_runway_visible_range
214
- runway_visible_range = RunwayVisibleRange.parse(@chunks[0])
215
- if runway_visible_range
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
- @runway_visible_range << runway_visible_range
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
- collect_runway_visible_range
224
- runway_visible_range!
225
- end
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
- @present_weather << wtp
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
- collect_present_weather
247
- present_weather!
248
- end
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
- @sky_conditions << sky_condition
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
- collect_sky_conditions
269
- sky_conditions!
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
- sea_level_pressure!
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
@@ -43,6 +43,12 @@ module Metar
43
43
  @@connection.passive = true
44
44
  end
45
45
 
46
+ def disconnect
47
+ return if @connection.nil
48
+ @connection.close
49
+ @cconnection = nil
50
+ end
51
+
46
52
  def fetch(cccc)
47
53
  attempts = 0
48
54
  while attempts < 2
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
@@ -2,7 +2,7 @@ module Metar
2
2
 
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 1
5
- MINOR = 0
5
+ MINOR = 1
6
6
  TINY = 0
7
7
 
8
8
  STRING = [ MAJOR, MINOR, TINY ].join( '.' )
data/locales/en.yml CHANGED
@@ -43,6 +43,8 @@ en:
43
43
  title: wind variation
44
44
  visibility:
45
45
  title: visibility
46
+ minimum_visibility:
47
+ title: minimum visibility
46
48
  sky_summary:
47
49
  title: sky
48
50
  sky_conditions:
data/locales/it.yml CHANGED
@@ -43,6 +43,8 @@ it:
43
43
  title: variazione del vento
44
44
  visibility:
45
45
  title: visibilità
46
+ minimum_visibility:
47
+ title: visibilità minima
46
48
  sky_summary:
47
49
  title: cielo
48
50
  sky_conditions:
@@ -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
 
@@ -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
- sky1 = stub( 'sky1', :to_summary => 'sky1' )
165
- sky2 = stub( 'sky2', :to_summary => 'sky2' )
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 visibilties', 'R12/3400V1800FT', [ '12', [1036.32, nil, nil], [548.64, nil, nil], nil ] ],
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, nil, nil ] ],
28
- [ 'quantity + height', 'BKN12', [ 'broken', 365.76, nil ] ],
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 + height + ///', 'BKN12///', [ 'broken', 365.76, nil ] ],
31
- [ 'returns nil for unmatched', 'FUBAR', [ :expect_nil, nil, nil ] ],
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', '5', [ 5000.00, nil, nil ] ],
41
- [ 'understands n + compass', '5NW', [ 5000.00, 315.0, nil ] ],
42
- [ 'returns nil for unmatched', 'FUBAR', [ nil, nil, nil ] ],
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
- [ 'modifier + phenomenon', '+RA', [ 'heavy', nil, 'rain' ] ],
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.0.0
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-07-29 00:00:00.000000000 Z
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: aasm
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: 2.1.5
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.1.5
93
+ version: 2.3.0
78
94
  - !ruby/object:Gem::Dependency
79
- name: m9t
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.3.1
86
- type: :runtime
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.3.1
109
+ version: '0'
94
110
  - !ruby/object:Gem::Dependency
95
- name: rspec
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: 2.3.0
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: 2.3.0
125
+ version: '0'
110
126
  - !ruby/object:Gem::Dependency
111
- name: simplecov
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: 2800563498014087456
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: 2800563498014087456
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: