metar-parser 1.0.0 → 1.1.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.
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: