metar-parser 0.1.3 → 0.1.4
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/lib/metar/data.rb +15 -8
- data/lib/metar/parser.rb +11 -43
- data/lib/metar/report.rb +77 -32
- data/lib/metar/station.rb +5 -5
- data/lib/metar.rb +2 -2
- data/locales/en.yml +32 -1
- data/locales/it.yml +32 -1
- data/test/metar_test_helper.rb +19 -0
- data/test/unit/data_test.rb +31 -16
- data/test/unit/parser_test.rb +46 -0
- data/test/unit/raw_test.rb +10 -1
- data/test/unit/report_test.rb +18 -4
- data/test/unit/station_test.rb +33 -13
- metadata +2 -2
data/lib/metar/data.rb
CHANGED
@@ -41,9 +41,9 @@ module Metar
|
|
41
41
|
case
|
42
42
|
when s =~ /^(\d+)(KT|MPS|KMH)$/
|
43
43
|
# Call the appropriate factory method for the supplied units
|
44
|
-
send(METAR_UNITS[$2], $1.to_i, { :units =>
|
44
|
+
send(METAR_UNITS[$2], $1.to_i, { :units => :kilometers_per_hour, :precision => 0, :abbreviated => true })
|
45
45
|
when s =~ /^(\d+)$/
|
46
|
-
kilometers_per_hour($1.to_i, { :units => :kilometers_per_hour, :precision => 0 })
|
46
|
+
kilometers_per_hour($1.to_i, { :units => :kilometers_per_hour, :precision => 0, :abbreviated => true })
|
47
47
|
else
|
48
48
|
nil
|
49
49
|
end
|
@@ -88,9 +88,9 @@ module Metar
|
|
88
88
|
def Wind.parse(s)
|
89
89
|
case
|
90
90
|
when s =~ /^(\d{3})(\d{2}(|MPS|KMH|KT))$/
|
91
|
-
new(M9t::Direction.new($1, { :abbreviated => true }), Speed.parse($2))
|
91
|
+
new(M9t::Direction.new($1, { :units => :compass, :abbreviated => true }), Speed.parse($2))
|
92
92
|
when s =~ /^(\d{3})(\d{2})G(\d{2,3}(|MPS|KMH|KT))$/
|
93
|
-
new(M9t::Direction.new($1, { :abbreviated => true }), Speed.parse($2))
|
93
|
+
new(M9t::Direction.new($1, { :units => :compass, :abbreviated => true }), Speed.parse($2))
|
94
94
|
when s =~ /^VRB(\d{2}(|MPS|KMH|KT))$/
|
95
95
|
new(:variable_direction, Speed.parse($1))
|
96
96
|
when s =~ /^\/{3}(\d{2}(|MPS|KMH|KT))$/
|
@@ -125,7 +125,7 @@ module Metar
|
|
125
125
|
else
|
126
126
|
@speed.to_s
|
127
127
|
end
|
128
|
-
"#{
|
128
|
+
"#{ speed } #{ direction }"
|
129
129
|
end
|
130
130
|
|
131
131
|
end
|
@@ -325,7 +325,7 @@ module Metar
|
|
325
325
|
def to_s
|
326
326
|
modifier = @modifier ? @modifier + ' ' : ''
|
327
327
|
descriptor = @descriptor ? @descriptor + ' ' : ''
|
328
|
-
I18n.t("metar.
|
328
|
+
I18n.t("metar.present_weather.%s%s%s" % [modifier, descriptor, @phenomenon])
|
329
329
|
end
|
330
330
|
|
331
331
|
end
|
@@ -333,6 +333,7 @@ module Metar
|
|
333
333
|
class SkyCondition
|
334
334
|
|
335
335
|
QUANTITY = {'BKN' => 'broken', 'FEW' => 'few', 'OVC' => 'overcast', 'SCT' => 'scattered'}
|
336
|
+
|
336
337
|
def SkyCondition.parse(sky_condition)
|
337
338
|
case
|
338
339
|
when (sky_condition == 'NSC' or sky_condition == 'NCD') # WMO
|
@@ -355,7 +356,7 @@ module Metar
|
|
355
356
|
when '///'
|
356
357
|
nil
|
357
358
|
else
|
358
|
-
raise
|
359
|
+
raise ParseError.new("Unexpected sky condition type: #$3")
|
359
360
|
end
|
360
361
|
new(quantity, height, type)
|
361
362
|
else
|
@@ -369,11 +370,17 @@ module Metar
|
|
369
370
|
end
|
370
371
|
|
371
372
|
def to_s
|
373
|
+
conditions = to_summary
|
374
|
+
conditions += ' ' + I18n.t('metar.altitude.at') + ' ' + height.to_s if not @height.nil?
|
375
|
+
conditions
|
376
|
+
end
|
377
|
+
|
378
|
+
def to_summary
|
372
379
|
if @quantity == nil and @height == nil and @type == nil
|
373
380
|
I18n.t('metar.sky_conditions.clear skies')
|
374
381
|
else
|
375
382
|
type = @type ? ' ' + @type : ''
|
376
|
-
I18n.t("metar.sky_conditions.#{ @quantity }#{ type }")
|
383
|
+
I18n.t("metar.sky_conditions.#{ @quantity }#{ type }")
|
377
384
|
end
|
378
385
|
end
|
379
386
|
|
data/lib/metar/parser.rb
CHANGED
@@ -4,9 +4,6 @@ require File.join(File.dirname(__FILE__), 'data')
|
|
4
4
|
|
5
5
|
module Metar
|
6
6
|
|
7
|
-
class ParseError < StandardError
|
8
|
-
end
|
9
|
-
|
10
7
|
class Parser
|
11
8
|
include AASM
|
12
9
|
|
@@ -95,7 +92,7 @@ module Metar
|
|
95
92
|
parser
|
96
93
|
end
|
97
94
|
|
98
|
-
attr_reader :station_code, :
|
95
|
+
attr_reader :station_code, :observer, :time, :wind, :variable_wind, :visibility, :runway_visible_range,
|
99
96
|
:present_weather, :sky_conditions, :vertical_visibility, :temperature, :dew_point, :sea_level_pressure, :remarks
|
100
97
|
|
101
98
|
def initialize(raw)
|
@@ -104,26 +101,6 @@ module Metar
|
|
104
101
|
analyze
|
105
102
|
end
|
106
103
|
|
107
|
-
def attributes
|
108
|
-
h = {
|
109
|
-
:station_code => @location.clone,
|
110
|
-
:time => @time.to_s,
|
111
|
-
:observer => Report.symbol_to_s(@observer)
|
112
|
-
}
|
113
|
-
h[:wind] = @wind if @wind
|
114
|
-
h[:variable_wind] = @variable_wind.clone if @variable_wind
|
115
|
-
h[:visibility] = @visibility if @visibility
|
116
|
-
h[:runway_visible_range] = @runway_visible_range if @runway_visible_range
|
117
|
-
h[:present_weather] = @present_weather if @present_weather
|
118
|
-
h[:sky_conditions] = @sky_conditions if @sky_conditions
|
119
|
-
h[:vertical_visibility] = @vertical_visibility if @vertical_visibility
|
120
|
-
h[:temperature] = @temperature
|
121
|
-
h[:dew_point] = @dew_point
|
122
|
-
h[:sea_level_pressure] = @sea_level_pressure
|
123
|
-
h[:remarks] = @remarks.clone if @remarks
|
124
|
-
h
|
125
|
-
end
|
126
|
-
|
127
104
|
def date
|
128
105
|
Date.new(@time.year, @time.month, @time.day)
|
129
106
|
end
|
@@ -133,26 +110,26 @@ module Metar
|
|
133
110
|
def analyze
|
134
111
|
@chunks = @metar.split(' ')
|
135
112
|
|
136
|
-
@
|
113
|
+
@station_code = nil
|
137
114
|
@observer = :real
|
138
115
|
@wind = nil
|
139
116
|
@variable_wind = nil
|
140
117
|
@visibility = nil
|
141
|
-
@runway_visible_range =
|
142
|
-
@present_weather =
|
143
|
-
@sky_conditions =
|
118
|
+
@runway_visible_range = []
|
119
|
+
@present_weather = []
|
120
|
+
@sky_conditions = []
|
144
121
|
@vertical_visibility = nil
|
145
122
|
@temperature = nil
|
146
123
|
@dew_point = nil
|
147
124
|
@sea_level_pressure = nil
|
148
|
-
@remarks =
|
125
|
+
@remarks = []
|
149
126
|
|
150
127
|
aasm_enter_initial_state
|
151
128
|
end
|
152
129
|
|
153
130
|
def seek_location
|
154
131
|
if @chunks[0] =~ /^[A-Z][A-Z0-9]{3}$/
|
155
|
-
@
|
132
|
+
@station_code = @chunks.shift
|
156
133
|
else
|
157
134
|
raise ParseError.new("Expecting location, found '#{ @chunks[0] }'")
|
158
135
|
end
|
@@ -204,18 +181,15 @@ module Metar
|
|
204
181
|
if @chunks[0] == 'CAVOK'
|
205
182
|
@chunks.shift
|
206
183
|
@visibility = Visibility.new(M9t::Distance.kilometers(10), nil, :more_than)
|
207
|
-
@present_weather ||= []
|
208
184
|
@present_weather << Metar::WeatherPhenomenon.new('No significant weather')
|
209
|
-
@sky_conditions
|
210
|
-
@sky_conditions << 'No significant cloud' # TODO: What does NSC stand for?
|
185
|
+
@sky_conditions << SkyCondition.new # = 'clear skies'
|
211
186
|
cavok!
|
212
187
|
return
|
213
188
|
end
|
214
189
|
|
215
190
|
if @observer == :auto # WMO 15.4
|
216
191
|
if @chunks[0] == '////'
|
217
|
-
@chunks.shift
|
218
|
-
@visibility = Visibility.new('Not observed')
|
192
|
+
@chunks.shift # Simply dispose of it
|
219
193
|
visibility!
|
220
194
|
return
|
221
195
|
end
|
@@ -242,7 +216,6 @@ module Metar
|
|
242
216
|
runway_visible_range = RunwayVisibleRange.parse(@chunks[0])
|
243
217
|
if runway_visible_range
|
244
218
|
@chunks.shift
|
245
|
-
@runway_visible_range ||= []
|
246
219
|
@runway_visible_range << runway_visible_range
|
247
220
|
collect_runway_visible_range
|
248
221
|
end
|
@@ -257,7 +230,6 @@ module Metar
|
|
257
230
|
wtp = WeatherPhenomenon.parse(@chunks[0])
|
258
231
|
if wtp
|
259
232
|
@chunks.shift
|
260
|
-
@present_weather ||= []
|
261
233
|
@present_weather << wtp
|
262
234
|
collect_present_weather
|
263
235
|
end
|
@@ -266,7 +238,7 @@ module Metar
|
|
266
238
|
def seek_present_weather
|
267
239
|
if @observer == :auto
|
268
240
|
if @chunks[0] == '//' # WMO 15.4
|
269
|
-
@
|
241
|
+
@chunks.shift # Simply dispose of it
|
270
242
|
@present_weather << Metar::WeatherPhenomenon.new('not observed')
|
271
243
|
present_weather!
|
272
244
|
return
|
@@ -281,7 +253,6 @@ module Metar
|
|
281
253
|
sky_condition = SkyCondition.parse(@chunks[0])
|
282
254
|
if sky_condition
|
283
255
|
@chunks.shift
|
284
|
-
@sky_conditions ||= []
|
285
256
|
@sky_conditions << sky_condition
|
286
257
|
collect_sky_conditions
|
287
258
|
end
|
@@ -290,9 +261,7 @@ module Metar
|
|
290
261
|
def seek_sky_conditions
|
291
262
|
if @observer == :auto # WMO 15.4
|
292
263
|
if @chunks[0] == '///' or @chunks[0] == '//////'
|
293
|
-
@chunks.shift
|
294
|
-
@sky_conditions ||= []
|
295
|
-
@sky_conditions << 'Not observed'
|
264
|
+
@chunks.shift # Simply dispose of it
|
296
265
|
sky_conditions!
|
297
266
|
return
|
298
267
|
end
|
@@ -336,7 +305,6 @@ module Metar
|
|
336
305
|
if @chunks[0] == 'RMK'
|
337
306
|
@chunks.shift
|
338
307
|
end
|
339
|
-
@remarks ||= []
|
340
308
|
@remarks += @chunks.clone
|
341
309
|
@chunks = []
|
342
310
|
remarks!
|
data/lib/metar/report.rb
CHANGED
@@ -1,10 +1,63 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
module Metar
|
4
|
+
|
4
5
|
class Report
|
5
6
|
|
7
|
+
KNOWN_ATTRIBUTES =
|
8
|
+
[
|
9
|
+
:station_code, :station_name, :station_country,
|
10
|
+
:date, :time, :observer,
|
11
|
+
:wind, :variable_wind,
|
12
|
+
:visibility, :runway_visible_range,
|
13
|
+
:present_weather,
|
14
|
+
:sky_summary, :sky_conditions,
|
15
|
+
:temperature, :dew_point, :remarks
|
16
|
+
]
|
17
|
+
|
18
|
+
DEFAULT_ATTRIBUTES =
|
19
|
+
[
|
20
|
+
:station_name, :station_country,
|
21
|
+
:time,
|
22
|
+
:wind,
|
23
|
+
:visibility,
|
24
|
+
:present_weather,
|
25
|
+
:sky_summary,
|
26
|
+
:temperature
|
27
|
+
]
|
28
|
+
|
29
|
+
instance_eval do
|
30
|
+
|
31
|
+
def reset_options!
|
32
|
+
@attributes = DEFAULT_ATTRIBUTES.clone
|
33
|
+
end
|
34
|
+
|
35
|
+
def attributes
|
36
|
+
@attributes
|
37
|
+
end
|
38
|
+
|
39
|
+
def attributes=(attributes)
|
40
|
+
@attributes = attributes.clone
|
41
|
+
end
|
42
|
+
|
43
|
+
reset_options!
|
44
|
+
end
|
45
|
+
|
6
46
|
def initialize(parser)
|
7
47
|
@parser = parser
|
48
|
+
@station = Station.find_by_cccc(@parser.station_code)
|
49
|
+
end
|
50
|
+
|
51
|
+
def station_name
|
52
|
+
@station.name
|
53
|
+
end
|
54
|
+
|
55
|
+
def station_country
|
56
|
+
@station.country
|
57
|
+
end
|
58
|
+
|
59
|
+
def station_code
|
60
|
+
@parser.station_code
|
8
61
|
end
|
9
62
|
|
10
63
|
def date
|
@@ -15,6 +68,10 @@ module Metar
|
|
15
68
|
"%u:%u" % [@parser.time.hour, @parser.time.min]
|
16
69
|
end
|
17
70
|
|
71
|
+
def observer
|
72
|
+
I18n.t('metar.observer.' + @parser.observer.to_s)
|
73
|
+
end
|
74
|
+
|
18
75
|
def wind
|
19
76
|
@parser.wind.to_s
|
20
77
|
end
|
@@ -35,6 +92,11 @@ module Metar
|
|
35
92
|
@parser.present_weather.to_s
|
36
93
|
end
|
37
94
|
|
95
|
+
def sky_summary
|
96
|
+
return I18n.t('metar.sky_conditions.clear skies') if @parser.sky_conditions.length == 0
|
97
|
+
@parser.sky_conditions[-1].to_summary
|
98
|
+
end
|
99
|
+
|
38
100
|
def sky_conditions
|
39
101
|
@parser.sky_conditions.collect { |sky| sky.to_s }.join(', ')
|
40
102
|
end
|
@@ -55,41 +117,24 @@ module Metar
|
|
55
117
|
@parser.sea_level_pressure.to_s
|
56
118
|
end
|
57
119
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
texts[:variable_wind] = attrib[:variable_wind] if attrib[:variable_wind]
|
69
|
-
texts[:visibility] = "%u meters" % attrib[:visibility].value if attrib[:visibility]
|
70
|
-
texts[:runway_visible_range] = attrib[:runway_visible_range].join(', ') if attrib[:runway_visible_range]
|
71
|
-
texts[:present_weather] = attrib[:present_weather].join(', ') if attrib[:present_weather]
|
72
|
-
texts[:sky_conditions] = attrib[:sky_conditions].join(', ') if attrib[:sky_conditions]
|
73
|
-
texts[:temperature] = "%u celcius" % attrib[:temperature] if attrib[:temperature]
|
74
|
-
texts[:dew_point] = "%u celcius" % attrib[:dew_point] if attrib[:dew_point]
|
75
|
-
texts[:remarks] = attrib[:remarks].join(', ') if attrib[:remarks]
|
76
|
-
|
77
|
-
texts
|
120
|
+
def remarks
|
121
|
+
@parser.remarks.join(', ')
|
122
|
+
end
|
123
|
+
|
124
|
+
def attributes
|
125
|
+
Metar::Report.attributes.reduce([]) do |memo, key|
|
126
|
+
value = self.send(key).to_s
|
127
|
+
memo << {:attribute => key, :value => value} if not value.empty?
|
128
|
+
memo
|
129
|
+
end
|
78
130
|
end
|
79
131
|
|
80
132
|
def to_s
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
[:station_code, :time, :observer, :wind, :variable_wind, :visibility, :runway_visible_range,
|
85
|
-
:present_weather, :sky_conditions, :temperature, :dew_point, :remarks].collect do |key|
|
86
|
-
attr[key] ? self.symbol_to_s(key) + ": " + attr[key] : nil
|
87
|
-
end.compact.join("\n")
|
133
|
+
attributes.collect do |attribute|
|
134
|
+
I18n.t('metar.' + attribute[:attribute].to_s + '.title') + ': ' + attribute[:value]
|
135
|
+
end.join("\n")
|
88
136
|
end
|
89
137
|
|
90
|
-
|
138
|
+
end
|
91
139
|
|
92
|
-
|
93
|
-
def self.symbol_to_s(sym)
|
94
|
-
sym.to_s.gsub(/^([a-z])/) {$1.upcase}.gsub(/_([a-z])/) {" #$1"}
|
95
|
-
end
|
140
|
+
end
|
data/lib/metar/station.rb
CHANGED
@@ -23,7 +23,7 @@ module Metar
|
|
23
23
|
end
|
24
24
|
|
25
25
|
# Load local copy of the station list
|
26
|
-
# and download it first if
|
26
|
+
# and download it first if missing
|
27
27
|
def load_local
|
28
28
|
download_local if not File.exist?(Metar::Station.local_nsd_path)
|
29
29
|
@nsd_cccc = File.open(Metar::Station.local_nsd_path) do |fil|
|
@@ -39,15 +39,15 @@ module Metar
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
def find_by_cccc(cccc)
|
43
|
-
all.find { |station| station.cccc == cccc }
|
44
|
-
end
|
45
|
-
|
46
42
|
# Does the given CCCC code exist?
|
47
43
|
def exist?(cccc)
|
48
44
|
not find_data_by_cccc(cccc).nil?
|
49
45
|
end
|
50
46
|
|
47
|
+
def find_by_cccc(cccc)
|
48
|
+
all.find { |station| station.cccc == cccc }
|
49
|
+
end
|
50
|
+
|
51
51
|
def to_longitude(s)
|
52
52
|
s =~ /^(\d+)-(\d+)([EW])/ or return nil
|
53
53
|
($3 == 'E' ? 1.0 : -1.0) * ($1.to_f + $2.to_f / 60.0)
|
data/lib/metar.rb
CHANGED
@@ -8,7 +8,7 @@ module Metar
|
|
8
8
|
module VERSION #:nodoc:
|
9
9
|
MAJOR = 0
|
10
10
|
MINOR = 1
|
11
|
-
TINY =
|
11
|
+
TINY = 4
|
12
12
|
|
13
13
|
STRING = [MAJOR, MINOR, TINY].join('.')
|
14
14
|
end
|
@@ -18,7 +18,7 @@ module Metar
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# Raised when an unrecognized value is found
|
21
|
-
class
|
21
|
+
class ParseError < MetarError
|
22
22
|
end
|
23
23
|
|
24
24
|
end
|
data/locales/en.yml
CHANGED
@@ -11,15 +11,37 @@ en:
|
|
11
11
|
bar:
|
12
12
|
full: bar
|
13
13
|
metar:
|
14
|
+
station_code:
|
15
|
+
title: station code
|
16
|
+
station_name:
|
17
|
+
title: name
|
18
|
+
station_country:
|
19
|
+
title: country
|
20
|
+
time:
|
21
|
+
title: time
|
22
|
+
observer:
|
23
|
+
title: observer
|
24
|
+
real: real
|
25
|
+
auto: automatic
|
26
|
+
corrected: corrected
|
14
27
|
altitude:
|
15
28
|
at: at
|
16
29
|
distance:
|
30
|
+
title: distance
|
17
31
|
unknown: unknown
|
18
32
|
wind:
|
33
|
+
title: wind
|
19
34
|
variable_direction: variable direction
|
20
35
|
unknown_direction: unknown direction
|
21
36
|
unknown_speed: unknown speed
|
37
|
+
variable_wind:
|
38
|
+
title: wind variation
|
39
|
+
visibility:
|
40
|
+
title: visibility
|
41
|
+
sky_summary:
|
42
|
+
title: sky
|
22
43
|
sky_conditions:
|
44
|
+
title: sky conditions
|
23
45
|
clear skies: clear skies
|
24
46
|
broken: broken cloud
|
25
47
|
broken cumulonimbus: broken cumulonimbus
|
@@ -32,10 +54,13 @@ en:
|
|
32
54
|
scattered towering cumulus: scattered towering cumulus clouds
|
33
55
|
overcast: overcast
|
34
56
|
runway_visible_range:
|
57
|
+
title: runway visible range
|
35
58
|
runway: runway
|
36
59
|
from: from
|
37
60
|
to: to
|
38
|
-
|
61
|
+
present_weather:
|
62
|
+
title: weather
|
63
|
+
not observed: not observed
|
39
64
|
mist: mist
|
40
65
|
dust: dust
|
41
66
|
blowing dust: blowing dust
|
@@ -119,3 +144,9 @@ en:
|
|
119
144
|
light thunderstorm and unknown phenomenon: light thunderstorm and unknown phenomenon
|
120
145
|
heavy unknown phenomenon: heavy unknown phenomenon
|
121
146
|
light unknown phenomenon: light unknown phenomenon
|
147
|
+
temperature:
|
148
|
+
title: temperature
|
149
|
+
dew_point:
|
150
|
+
title: punto di rugiada
|
151
|
+
remarks:
|
152
|
+
title: annotazioni
|
data/locales/it.yml
CHANGED
@@ -11,15 +11,37 @@ it:
|
|
11
11
|
bar:
|
12
12
|
full: bar
|
13
13
|
metar:
|
14
|
+
station_code:
|
15
|
+
title: codice stazione
|
16
|
+
station_name:
|
17
|
+
title: nome
|
18
|
+
station_country:
|
19
|
+
title: nazione
|
20
|
+
time:
|
21
|
+
title: ora
|
22
|
+
observer:
|
23
|
+
title: osservatore
|
24
|
+
real: reale
|
25
|
+
auto: automazzato
|
26
|
+
corrected: corretto
|
14
27
|
altitude:
|
15
28
|
at: a
|
16
29
|
distance:
|
30
|
+
title: distanza
|
17
31
|
unknown: sconosciuto
|
18
32
|
wind:
|
33
|
+
title: vento
|
19
34
|
variable_direction: direzione variabile
|
20
35
|
unknown_direction: direzione sconosciuta
|
21
36
|
unknown_speed: velocità sconosciuta
|
37
|
+
variable_wind:
|
38
|
+
title: variazione del vento
|
39
|
+
visibility:
|
40
|
+
title: visibilità
|
41
|
+
sky_summary:
|
42
|
+
title: cielo
|
22
43
|
sky_conditions:
|
44
|
+
title: condizioni del cielo
|
23
45
|
clear skies: cielo sereno
|
24
46
|
broken: nuvolosità parziale
|
25
47
|
broken cumulonimbus: copertura parziale di cumulonembi
|
@@ -32,10 +54,13 @@ it:
|
|
32
54
|
scattered towering cumulus: cumulonembi sparsi
|
33
55
|
overcast: chiuso
|
34
56
|
runway_visible_range:
|
57
|
+
title: visibilità sulle piste
|
35
58
|
runway: pista
|
36
59
|
from: da
|
37
60
|
to: a
|
38
|
-
|
61
|
+
present_weather:
|
62
|
+
title: tempo
|
63
|
+
not observed: non osservato
|
39
64
|
mist: foschia
|
40
65
|
dust: polvere
|
41
66
|
blowing dust: polviscolo
|
@@ -119,3 +144,9 @@ it:
|
|
119
144
|
light thunderstorm and unknown phenomenon: temporale con fenomeno sconosciuto leggero
|
120
145
|
heavy unknown phenomenon: fenomeno sconosciuto intenso
|
121
146
|
light unknown phenomenon: fenomeno sconosciuto leggero
|
147
|
+
temperature:
|
148
|
+
title: temperatura
|
149
|
+
dew_point:
|
150
|
+
title: punto di rugiada
|
151
|
+
remarks:
|
152
|
+
title: annotazioni
|
data/test/metar_test_helper.rb
CHANGED
@@ -11,4 +11,23 @@ Metar::Raw.instance_eval do
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
# Don't load station data from files
|
15
|
+
module Metar
|
16
|
+
class Station
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
def all_structures
|
21
|
+
[
|
22
|
+
{ :cccc => 'LIRQ', :country => 'Italy', :latitude => '43-48N', :longitude => '011-12E', :name => 'Firenze / Peretola', :state => '' },
|
23
|
+
{ :cccc => 'DAAS', :country => 'Algeria', :latitude => '36-11N', :longitude => '005-25E', :name => 'Setif', :state => '' },
|
24
|
+
{ :cccc => 'ESSB', :country => 'Sweden', :latitude => '59-21N', :longitude => '017-57E',:name => 'Stockholm / Bromma', :state => '' },
|
25
|
+
{ :cccc => 'KPDX', :country => 'United States', :latitude => '45-35N', :longitude => '122-36W', :name => 'PORTLAND INTERNATIONAL AIRPORT', :state => '' },
|
26
|
+
{ :cccc => 'CYXS', :country => 'Canada', :latitude => '53-53N', :longitude => '122-41W', :name => 'Prince George, B. C.', :state => '' },
|
27
|
+
]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
14
33
|
require 'test/unit'
|
data/test/unit/data_test.rb
CHANGED
@@ -43,26 +43,31 @@ class TestMetarData < Test::Unit::TestCase
|
|
43
43
|
assert_not_nil(Metar::Speed.options)
|
44
44
|
end
|
45
45
|
|
46
|
-
def
|
46
|
+
def test_speed_parse_without_units
|
47
47
|
speed = Metar::Speed.parse('12')
|
48
48
|
assert_equal(12, speed.to_kilometers_per_hour)
|
49
|
-
assert_equal(:kilometers_per_hour, speed.options[:units])
|
50
49
|
end
|
51
50
|
|
52
51
|
def test_speed_parse_kilometers_per_hour
|
53
52
|
speed = Metar::Speed.parse('12KMH')
|
54
53
|
assert_equal(12, speed.to_kilometers_per_hour)
|
55
|
-
assert_equal(:kilometers_per_hour, speed.options[:units])
|
56
54
|
end
|
57
55
|
|
58
56
|
def test_speed_parse_knots
|
59
57
|
speed = Metar::Speed.parse('12KT')
|
60
|
-
assert_equal(
|
58
|
+
assert_equal(12.0, speed.to_knots)
|
59
|
+
assert_equal(:kilometers_per_hour, speed.options[:units])
|
61
60
|
end
|
62
61
|
|
63
|
-
def
|
62
|
+
def test_speed_parse_kilometers_per_hour_is_default
|
63
|
+
speed = Metar::Speed.parse('12')
|
64
|
+
assert_equal(:kilometers_per_hour, speed.options[:units])
|
64
65
|
speed = Metar::Speed.parse('12MPS')
|
65
|
-
assert_equal(:
|
66
|
+
assert_equal(:kilometers_per_hour, speed.options[:units])
|
67
|
+
speed = Metar::Speed.parse('12KMH')
|
68
|
+
assert_equal(:kilometers_per_hour, speed.options[:units])
|
69
|
+
speed = Metar::Speed.parse('12KT')
|
70
|
+
assert_equal(:kilometers_per_hour, speed.options[:units])
|
66
71
|
end
|
67
72
|
|
68
73
|
# Temperature
|
@@ -104,55 +109,65 @@ class TestMetarData < Test::Unit::TestCase
|
|
104
109
|
end
|
105
110
|
|
106
111
|
# Wind
|
107
|
-
def
|
112
|
+
def test_wind_parse_without_units
|
108
113
|
wind = Metar::Wind.parse('18012')
|
109
114
|
assert_equal(180, wind.direction.value)
|
110
115
|
assert_equal(12.0, wind.speed.to_kilometers_per_hour)
|
111
|
-
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
112
116
|
end
|
113
117
|
|
114
118
|
def test_wind_parse_mps
|
115
119
|
wind = Metar::Wind.parse('18012MPS')
|
116
120
|
assert_equal(180, wind.direction.value)
|
117
121
|
assert_equal(12.0, wind.speed.value)
|
118
|
-
assert_equal(:meters_per_second, wind.speed.options[:units])
|
119
122
|
end
|
120
123
|
|
121
124
|
def test_wind_parse_kmh
|
122
125
|
wind = Metar::Wind.parse('27012KMH')
|
123
126
|
assert_equal(270, wind.direction.value)
|
124
127
|
assert_equal(12.0, wind.speed.to_kilometers_per_hour)
|
125
|
-
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
126
128
|
end
|
127
129
|
|
128
130
|
def test_wind_parse_knots
|
129
131
|
wind = Metar::Wind.parse('24006KT')
|
130
132
|
assert_equal(240, wind.direction.value)
|
131
133
|
assert_equal(6, wind.speed.to_knots)
|
132
|
-
assert_equal(:
|
134
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
133
135
|
end
|
134
136
|
|
135
137
|
def test_wind_parse_variable_direction
|
136
138
|
wind = Metar::Wind.parse('VRB20KT')
|
137
139
|
assert_equal(:variable_direction, wind.direction)
|
138
140
|
assert_equal(20, wind.speed.to_knots)
|
139
|
-
assert_equal(
|
140
|
-
assert_equal('variable direction, 20 knots', wind.to_s)
|
141
|
+
assert_equal('37km/h variable direction', wind.to_s)
|
141
142
|
end
|
142
143
|
|
143
144
|
def test_wind_parse_unknown_direction
|
144
145
|
wind = Metar::Wind.parse('///20KT')
|
145
146
|
assert_equal(:unknown_direction, wind.direction)
|
146
147
|
assert_equal(20, wind.speed.to_knots)
|
147
|
-
assert_equal(
|
148
|
-
assert_equal('unknown direction, 20 knots', wind.to_s)
|
148
|
+
assert_equal('37km/h unknown direction', wind.to_s)
|
149
149
|
end
|
150
150
|
|
151
151
|
def test_wind_parse_unknown_direction_and_speed
|
152
152
|
wind = Metar::Wind.parse('/////')
|
153
153
|
assert_equal(:unknown_direction, wind.direction)
|
154
154
|
assert_equal(:unknown, wind.speed)
|
155
|
-
assert_equal('unknown
|
155
|
+
assert_equal('unknown speed unknown direction', wind.to_s)
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_wind_parse_default_output_units_kilometers_per_hour
|
159
|
+
wind = Metar::Wind.parse('18012')
|
160
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
161
|
+
wind = Metar::Wind.parse('18012MPS')
|
162
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
163
|
+
wind = Metar::Wind.parse('27012KMH')
|
164
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
165
|
+
wind = Metar::Wind.parse('24006KT')
|
166
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
167
|
+
wind = Metar::Wind.parse('VRB20KT')
|
168
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
169
|
+
wind = Metar::Wind.parse('///20KT')
|
170
|
+
assert_equal(:kilometers_per_hour, wind.speed.options[:units])
|
156
171
|
end
|
157
172
|
|
158
173
|
# VariableWind
|
data/test/unit/parser_test.rb
CHANGED
@@ -15,11 +15,22 @@ class TestMetarParser < Test::Unit::TestCase
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
def test_time_obligatory
|
19
|
+
assert_raise(Metar::ParseError) {
|
20
|
+
setup_parser('PAIL', "2010/02/06 16:10\nPAIL 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
18
24
|
def test_date
|
19
25
|
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
20
26
|
assert_equal(Date.new(2010, 2, 6), parser.date)
|
21
27
|
end
|
22
28
|
|
29
|
+
def test_observer_real
|
30
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
31
|
+
assert_equal(:real, parser.observer)
|
32
|
+
end
|
33
|
+
|
23
34
|
def test_wind
|
24
35
|
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
25
36
|
assert_in_delta(240, parser.wind.direction.value, 0.0001)
|
@@ -46,6 +57,11 @@ class TestMetarParser < Test::Unit::TestCase
|
|
46
57
|
assert_equal(:no_change, parser.runway_visible_range[0].tendency)
|
47
58
|
end
|
48
59
|
|
60
|
+
def test_runway_visible_range_defaults_to_empty_array
|
61
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
62
|
+
assert_equal(0, parser.runway_visible_range.length)
|
63
|
+
end
|
64
|
+
|
49
65
|
def test_runway_visible_range_variable
|
50
66
|
parser = setup_parser('KPDX', "2010/02/15 11:08\nKPDX 151108Z 11006KT 1/4SM R10R/1600VP6000FT FG OVC002 05/05 A3022 RMK AO2")
|
51
67
|
assert_equal(1600.0, parser.runway_visible_range[0].visibility1.distance.to_feet)
|
@@ -61,6 +77,11 @@ class TestMetarParser < Test::Unit::TestCase
|
|
61
77
|
assert_equal('snow', parser.present_weather[0].phenomenon)
|
62
78
|
end
|
63
79
|
|
80
|
+
def test_present_weather_defaults_to_empty_array
|
81
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
82
|
+
assert_equal(0, parser.present_weather.length)
|
83
|
+
end
|
84
|
+
|
64
85
|
def test_sky_conditions
|
65
86
|
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
66
87
|
assert_equal(2, parser.sky_conditions.length)
|
@@ -70,11 +91,22 @@ class TestMetarParser < Test::Unit::TestCase
|
|
70
91
|
assert_equal(900, parser.sky_conditions[1].height.value)
|
71
92
|
end
|
72
93
|
|
94
|
+
def test_sky_conditions_defaults_to_empty_array
|
95
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN M17/M20 A2910 RMK AO2 P0000")
|
96
|
+
assert_equal(0, parser.sky_conditions.length)
|
97
|
+
end
|
98
|
+
|
73
99
|
def test_vertical_visibility
|
74
100
|
parser = setup_parser('CYXS', "2010/02/15 10:34\nCYXS 151034Z AUTO 09003KT 1/8SM FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
|
75
101
|
assert_equal(30, parser.vertical_visibility.value)
|
76
102
|
end
|
77
103
|
|
104
|
+
def test_temperature_obligatory
|
105
|
+
assert_raise(Metar::ParseError) {
|
106
|
+
setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 A2910 RMK AO2 P0000")
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
78
110
|
def test_temperature
|
79
111
|
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
80
112
|
assert_equal(-17, parser.temperature.value)
|
@@ -91,6 +123,20 @@ class TestMetarParser < Test::Unit::TestCase
|
|
91
123
|
assert_equal(:bar, parser.sea_level_pressure.options[:units])
|
92
124
|
end
|
93
125
|
|
126
|
+
def test_remarks
|
127
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
|
128
|
+
assert_instance_of(Array, parser.remarks)
|
129
|
+
assert_equal(2, parser.remarks.length)
|
130
|
+
assert_equal('AO2', parser.remarks[0])
|
131
|
+
assert_equal('P0000', parser.remarks[1])
|
132
|
+
end
|
133
|
+
|
134
|
+
def test_remarks_defaults_to_empty_array
|
135
|
+
parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910")
|
136
|
+
assert_instance_of(Array, parser.remarks)
|
137
|
+
assert_equal(0, parser.remarks.length)
|
138
|
+
end
|
139
|
+
|
94
140
|
private
|
95
141
|
|
96
142
|
def setup_parser(cccc, metar)
|
data/test/unit/raw_test.rb
CHANGED
@@ -18,10 +18,19 @@ class TestMetarRaw < Test::Unit::TestCase
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
21
|
+
def test_cccc
|
22
22
|
raw = Metar::Raw.new('LIRQ')
|
23
23
|
assert_equal('LIRQ', raw.cccc)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_time
|
27
|
+
raw = Metar::Raw.new('LIRQ')
|
24
28
|
assert_instance_of(Time, raw.time)
|
29
|
+
assert_equal(2010, raw.time.year)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_metar
|
33
|
+
raw = Metar::Raw.new('LIRQ')
|
25
34
|
assert_instance_of(String, raw.metar)
|
26
35
|
end
|
27
36
|
|
data/test/unit/report_test.rb
CHANGED
@@ -5,7 +5,11 @@ require File.dirname(__FILE__) + '/../metar_test_helper'
|
|
5
5
|
|
6
6
|
class TestMetarReport < Test::Unit::TestCase
|
7
7
|
def setup
|
8
|
-
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_name
|
11
|
+
report = setup_report('LIRQ', "2010/02/06 15:20\nLIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
|
12
|
+
assert_equal('Firenze / Peretola', report.station_name)
|
9
13
|
end
|
10
14
|
|
11
15
|
def test_date
|
@@ -20,13 +24,12 @@ class TestMetarReport < Test::Unit::TestCase
|
|
20
24
|
|
21
25
|
def test_wind_knots
|
22
26
|
report = setup_report('LIRQ', "2010/02/06 15:20\nLIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
|
23
|
-
assert_equal('
|
24
|
-
I18n.locale = :it
|
25
|
-
assert_equal('10°, 7 nodi', report.wind)
|
27
|
+
assert_equal('13km/h N', report.wind)
|
26
28
|
end
|
27
29
|
|
28
30
|
def test_variable_wind
|
29
31
|
report = setup_report('LIRQ', "2010/02/06 15:20\nLIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
|
32
|
+
I18n.locale = :en
|
30
33
|
assert_equal('350 degrees - 50 degrees', report.variable_wind)
|
31
34
|
end
|
32
35
|
|
@@ -37,11 +40,15 @@ class TestMetarReport < Test::Unit::TestCase
|
|
37
40
|
|
38
41
|
def test_runway_visible_range
|
39
42
|
report = setup_report('ESSB', "2010/02/15 10:20\nESSB 151020Z 26003KT 2000 R12/1000N R30/1500N VV002 M07/M07 Q1013 1271//55")
|
43
|
+
I18n.locale = :en
|
40
44
|
assert_equal('runway 12: 1000m, runway 30: 1500m', report.runway_visible_range)
|
45
|
+
I18n.locale = :it
|
46
|
+
assert_equal('pista 12: 1000m, pista 30: 1500m', report.runway_visible_range)
|
41
47
|
end
|
42
48
|
|
43
49
|
def test_runway_visible_range_variable
|
44
50
|
report = setup_report('KPDX', "2010/02/15 11:08\nKPDX 151108Z 11006KT 1/4SM R10R/1600VP6000FT FG OVC002 05/05 A3022 RMK AO2")
|
51
|
+
I18n.locale = :en
|
45
52
|
assert_equal('runway 10R: from 1600ft to more than 6000ft', report.runway_visible_range)
|
46
53
|
end
|
47
54
|
|
@@ -80,6 +87,13 @@ class TestMetarReport < Test::Unit::TestCase
|
|
80
87
|
assert_equal('1.00500 bar', report.sea_level_pressure)
|
81
88
|
end
|
82
89
|
|
90
|
+
def test_to_s
|
91
|
+
report = setup_report('LIRQ', "2010/02/06 15:20\nLIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
|
92
|
+
Metar::Report.attributes -= [:station_code, :variable_wind, :observer, :remarks]
|
93
|
+
I18n.locale = :en
|
94
|
+
assert_equal("name: Firenze / Peretola\ncountry: Italy\ntime: 15:20\nwind: 13km/h N\nvisibility: more than 10km\nsky: broken cloud\ntemperature: 8°C", report.to_s)
|
95
|
+
end
|
96
|
+
|
83
97
|
private
|
84
98
|
|
85
99
|
def setup_report(cccc, metar)
|
data/test/unit/station_test.rb
CHANGED
@@ -24,6 +24,26 @@ class TestStation < Test::Unit::TestCase
|
|
24
24
|
assert_not_nil Metar::Station.find_by_cccc('LIRQ')
|
25
25
|
end
|
26
26
|
|
27
|
+
def test_to_latitude_incorrect_gives_nil
|
28
|
+
assert_nil Metar::Station.to_latitude('23-15')
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_to_latitude_n
|
32
|
+
assert_equal 43.8, Metar::Station.to_latitude('43-48N')
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_to_latitude_s
|
36
|
+
assert_equal -23.25, Metar::Station.to_latitude('23-15S')
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_to_longitude_e
|
40
|
+
assert_equal 11.2, Metar::Station.to_longitude('11-12E')
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_to_longitude_w
|
44
|
+
assert_equal -11.2, Metar::Station.to_longitude('11-12W')
|
45
|
+
end
|
46
|
+
|
27
47
|
def test_instantiation_sets_cccc
|
28
48
|
station = Metar::Station.new('LIRQ')
|
29
49
|
assert_equal 'LIRQ', station.cccc
|
@@ -40,29 +60,29 @@ class TestStation < Test::Unit::TestCase
|
|
40
60
|
assert station.loaded?
|
41
61
|
end
|
42
62
|
|
43
|
-
def
|
63
|
+
def test_name
|
44
64
|
station = Metar::Station.new('LIRQ')
|
45
|
-
|
65
|
+
assert_equal 'Firenze / Peretola', station.name
|
46
66
|
end
|
47
67
|
|
48
|
-
def
|
68
|
+
def test_state
|
49
69
|
station = Metar::Station.new('LIRQ')
|
50
|
-
|
70
|
+
assert_equal '', station.state
|
51
71
|
end
|
52
72
|
|
53
|
-
def
|
54
|
-
|
73
|
+
def test_country
|
74
|
+
station = Metar::Station.new('LIRQ')
|
75
|
+
assert_equal 'Italy', station.country
|
55
76
|
end
|
56
77
|
|
57
|
-
def
|
58
|
-
|
78
|
+
def test_latitude_is_a_decimal_number
|
79
|
+
station = Metar::Station.new('LIRQ')
|
80
|
+
assert_equal station.latitude.to_s, station.latitude.to_f.to_s
|
59
81
|
end
|
60
82
|
|
61
|
-
def
|
62
|
-
|
83
|
+
def test_longitude_is_a_decimal_number
|
84
|
+
station = Metar::Station.new('LIRQ')
|
85
|
+
assert_equal station.longitude.to_s, station.longitude.to_f.to_s
|
63
86
|
end
|
64
87
|
|
65
|
-
def test_to_longitude_west
|
66
|
-
assert(Metar::Station.to_longitude('011-12W') == -11.2)
|
67
|
-
end
|
68
88
|
end
|