metar-parser 1.3.1 → 1.3.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/metar/data/lightning.rb +20 -7
- data/lib/metar/data/pressure.rb +14 -7
- data/lib/metar/data/remark.rb +75 -37
- data/lib/metar/data/runway_visible_range.rb +24 -19
- data/lib/metar/data/sky_condition.rb +23 -14
- data/lib/metar/data/speed.rb +5 -7
- data/lib/metar/data/temperature.rb +6 -8
- data/lib/metar/data/temperature_and_dew_point.rb +8 -5
- data/lib/metar/data/time.rb +8 -9
- data/lib/metar/data/variable_wind.rb +10 -9
- data/lib/metar/data/vertical_visibility.rb +12 -7
- data/lib/metar/data/visibility.rb +46 -23
- data/lib/metar/data/weather_phenomenon.rb +1 -1
- data/lib/metar/data/wind.rb +43 -24
- data/lib/metar/station.rb +7 -5
- data/lib/metar/version.rb +1 -1
- data/spec/parser_spec.rb +0 -1
- metadata +7 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 456cd34e625a1ba09f41ae95253611d7fcacdf20
|
4
|
+
data.tar.gz: 45063d94795f39b8bd092258e1ad72eeb207a3c3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a052fccc41b27c6cc87380892c2ac563aaa53b763669c3347d1fdf4daa9c4b3719937880ec5ee820e829cb138262c3a8aa1a37479e0b100159723fcee52c22e
|
7
|
+
data.tar.gz: 30afb02c2e7a5b8ecd30fa4e37b03300dffb3600f1224b4d50aa2d5f8f4c63c453ee2530342ca48bf2e04582b65692ab68819607caaeb2d6e2010bae86a6a00b
|
data/lib/metar/data/lightning.rb
CHANGED
@@ -17,25 +17,38 @@ class Metar::Data::Lightning < Metar::Data::Base
|
|
17
17
|
end
|
18
18
|
|
19
19
|
loop do
|
20
|
+
break if chunks[0].nil?
|
21
|
+
|
20
22
|
if is_compass?(chunks[0])
|
21
23
|
direction = chunks.shift
|
22
24
|
raw += " " + direction
|
23
25
|
directions << direction
|
24
|
-
|
26
|
+
next
|
27
|
+
end
|
28
|
+
|
29
|
+
if chunks[0] == 'ALQDS'
|
25
30
|
directions += ['N', 'E', 'S', 'W']
|
26
31
|
raw += " " + chunks.shift
|
27
|
-
|
28
|
-
|
29
|
-
|
32
|
+
next
|
33
|
+
end
|
34
|
+
|
35
|
+
m = chunks[0].match(/^([NESW]{1,2})-([NESW]{1,2})$/)
|
36
|
+
if m
|
37
|
+
if is_compass?(m[1]) && is_compass?(m[1])
|
38
|
+
directions += [m[1], m[2]]
|
30
39
|
raw += " " + chunks.shift
|
31
40
|
else
|
32
41
|
break
|
33
42
|
end
|
34
|
-
|
43
|
+
next
|
44
|
+
end
|
45
|
+
|
46
|
+
if chunks[0] == 'AND'
|
35
47
|
raw += " " + chunks.shift
|
36
|
-
|
37
|
-
break
|
48
|
+
next
|
38
49
|
end
|
50
|
+
|
51
|
+
break
|
39
52
|
end
|
40
53
|
|
41
54
|
new(
|
data/lib/metar/data/pressure.rb
CHANGED
@@ -1,13 +1,20 @@
|
|
1
1
|
class Metar::Data::Pressure < Metar::Data::Base
|
2
2
|
def self.parse(raw)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
return nil if raw.nil?
|
4
|
+
|
5
|
+
m1 = raw.match(/^Q(\d{4})$/)
|
6
|
+
if m1
|
7
|
+
pressure = M9t::Pressure.hectopascals(m1[1].to_f)
|
8
|
+
return new(raw, pressure: pressure)
|
9
|
+
end
|
10
|
+
|
11
|
+
m2 = raw.match(/^A(\d{4})$/)
|
12
|
+
if m2
|
13
|
+
pressure = M9t::Pressure.inches_of_mercury(m2[1].to_f / 100.0)
|
14
|
+
return new(raw, pressure: pressure)
|
10
15
|
end
|
16
|
+
|
17
|
+
nil
|
11
18
|
end
|
12
19
|
|
13
20
|
attr_reader :pressure
|
data/lib/metar/data/remark.rb
CHANGED
@@ -23,46 +23,84 @@ class Metar::Data::Remark
|
|
23
23
|
COLOR_CODE = ['RED', 'AMB', 'YLO', 'GRN', 'WHT', 'BLU']
|
24
24
|
|
25
25
|
def self.parse(raw)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
[
|
33
|
-
|
34
|
-
|
26
|
+
if !raw
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
m1 = raw.match(/^([12])([01])(\d{3})$/)
|
31
|
+
if m1
|
32
|
+
extreme = {'1' => :maximum, '2' => :minimum}[m1[1]]
|
33
|
+
value = sign(m1[2]) * tenths(m1[3])
|
34
|
+
return Metar::Data::TemperatureExtreme.new(raw, extreme, value)
|
35
|
+
end
|
36
|
+
|
37
|
+
m2 = raw.match(/^4([01])(\d{3})([01])(\d{3})$/)
|
38
|
+
if m2
|
39
|
+
return [
|
40
|
+
Metar::Data::TemperatureExtreme.new(raw, :maximum, sign(m2[1]) * tenths(m2[2])),
|
41
|
+
Metar::Data::TemperatureExtreme.new(raw, :minimum, sign(m2[3]) * tenths(m2[4])),
|
35
42
|
]
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
Metar::Data::
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
43
|
+
end
|
44
|
+
|
45
|
+
m3 = raw.match(/^5([0-8])(\d{3})$/)
|
46
|
+
if m3
|
47
|
+
character = PRESSURE_CHANGE_CHARACTER[m3[1].to_i]
|
48
|
+
return Metar::Data::PressureTendency.new(raw, character, tenths(m3[2]))
|
49
|
+
end
|
50
|
+
|
51
|
+
m4 = raw.match(/^6(\d{4})$/)
|
52
|
+
if m4
|
53
|
+
return Metar::Data::Precipitation.new(raw, 3, Metar::Data::Distance.new(inches_to_meters(m4[1]))) # actually 3 or 6 depending on reporting time
|
54
|
+
end
|
55
|
+
|
56
|
+
m5 = raw.match(/^7(\d{4})$/)
|
57
|
+
if m5
|
58
|
+
return Metar::Data::Precipitation.new(raw, 24, Metar::Data::Distance.new(inches_to_meters(m5[1])))
|
59
|
+
end
|
60
|
+
|
61
|
+
m6 = raw.match(/^A[0O]([12])$/)
|
62
|
+
if m6
|
63
|
+
type = [:with_precipitation_discriminator, :without_precipitation_discriminator][m6[1].to_i - 1]
|
64
|
+
return Metar::Data::AutomatedStationType.new(raw, type)
|
65
|
+
end
|
66
|
+
|
67
|
+
m7 = raw.match(/^P(\d{4})$/)
|
68
|
+
if m7
|
69
|
+
return Metar::Data::Precipitation.new(raw, 1, Metar::Data::Distance.new(inches_to_meters(m7[1])))
|
70
|
+
end
|
71
|
+
|
72
|
+
m8 = raw.match(/^T([01])(\d{3})([01])(\d{3})$/)
|
73
|
+
if m8
|
74
|
+
temperature = Metar::Data::Temperature.new(sign(m8[1]) * tenths(m8[2]))
|
75
|
+
dew_point = Metar::Data::Temperature.new(sign(m8[3]) * tenths(m8[4]))
|
76
|
+
return Metar::Data::HourlyTemperatureAndDewPoint.new(raw, temperature, dew_point)
|
77
|
+
end
|
78
|
+
|
79
|
+
m9 = raw.match(/^SLP(\d{3})$/)
|
80
|
+
if m9
|
81
|
+
return Metar::Data::SeaLevelPressure.new(raw, M9t::Pressure.hectopascals(tenths(m9[1])))
|
82
|
+
end
|
83
|
+
|
84
|
+
m10 = raw.match(/^(#{INDICATOR_TYPE.keys.join('|')})NO$/)
|
85
|
+
if m10
|
86
|
+
type = INDICATOR_TYPE[m10[1]]
|
87
|
+
return Metar::Data::SensorStatusIndicator.new(raw, type, :not_available)
|
88
|
+
end
|
89
|
+
|
90
|
+
m11 = raw.match(/^(#{COLOR_CODE.join('|')})$/)
|
91
|
+
if m11
|
92
|
+
return Metar::Data::ColorCode.new(raw, m11[1])
|
93
|
+
end
|
94
|
+
|
95
|
+
if raw == 'SKC'
|
96
|
+
return Metar::Data::SkyCondition.new(raw)
|
97
|
+
end
|
98
|
+
|
99
|
+
if raw == '$'
|
62
100
|
Metar::Data::MaintenanceNeeded.new(raw)
|
63
|
-
else
|
64
|
-
nil
|
65
101
|
end
|
102
|
+
|
103
|
+
nil
|
66
104
|
end
|
67
105
|
|
68
106
|
def self.sign(digit)
|
@@ -4,29 +4,34 @@ class Metar::Data::RunwayVisibleRange < Metar::Data::Base
|
|
4
4
|
UNITS = {'' => :meters, 'FT' => :feet}
|
5
5
|
|
6
6
|
def self.parse(raw)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
7
|
+
return nil if raw.nil?
|
8
|
+
|
9
|
+
m1 = raw.match(/^R(\d+[RLC]?)\/(P|M|)(\d{4})(FT|)\/?(N|U|D|)$/)
|
10
|
+
if m1
|
11
|
+
designator = m1[1]
|
12
|
+
comparator = COMPARATOR[m1[2]]
|
13
|
+
count = m1[3].to_f
|
14
|
+
units = UNITS[m1[4]]
|
15
|
+
tendency = TENDENCY[m1[5]]
|
14
16
|
distance = Metar::Data::Distance.send(units, count)
|
15
17
|
visibility = Metar::Data::Visibility.new(
|
16
18
|
nil, distance: distance, comparator: comparator
|
17
19
|
)
|
18
|
-
new(
|
20
|
+
return new(
|
19
21
|
raw,
|
20
22
|
designator: designator, visibility1: visibility, tendency: tendency
|
21
23
|
)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
24
|
+
end
|
25
|
+
|
26
|
+
m2 = raw.match(/^R(\d+[RLC]?)\/(P|M|)(\d{4})V(P|M|)(\d{4})(FT|)\/?(N|U|D)?$/)
|
27
|
+
if m2
|
28
|
+
designator = m2[1]
|
29
|
+
comparator1 = COMPARATOR[m2[2]]
|
30
|
+
count1 = m2[3].to_f
|
31
|
+
comparator2 = COMPARATOR[m2[4]]
|
32
|
+
count2 = m2[5].to_f
|
33
|
+
units = UNITS[m2[6]]
|
34
|
+
tendency = TENDENCY[m2[7]]
|
30
35
|
distance1 = Metar::Data::Distance.send(units, count1)
|
31
36
|
distance2 = Metar::Data::Distance.send(units, count2)
|
32
37
|
visibility1 = Metar::Data::Visibility.new(
|
@@ -35,15 +40,15 @@ class Metar::Data::RunwayVisibleRange < Metar::Data::Base
|
|
35
40
|
visibility2 = Metar::Data::Visibility.new(
|
36
41
|
nil, distance: distance2, comparator: comparator2
|
37
42
|
)
|
38
|
-
new(
|
43
|
+
return new(
|
39
44
|
raw,
|
40
45
|
designator: designator,
|
41
46
|
visibility1: visibility1, visibility2: visibility2,
|
42
47
|
tendency: tendency, units: units
|
43
48
|
)
|
44
|
-
else
|
45
|
-
nil
|
46
49
|
end
|
50
|
+
|
51
|
+
nil
|
47
52
|
end
|
48
53
|
|
49
54
|
attr_reader :designator, :visibility1, :visibility2, :tendency
|
@@ -14,25 +14,34 @@ class Metar::Data::SkyCondition < Metar::Data::Base
|
|
14
14
|
]
|
15
15
|
|
16
16
|
def self.parse(raw)
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
17
|
+
if !raw
|
18
|
+
return nil
|
19
|
+
end
|
20
|
+
|
21
|
+
if CLEAR_SKIES.include?(raw)
|
22
|
+
return new(raw)
|
23
|
+
end
|
24
|
+
|
25
|
+
m1 = raw.match(/^(BKN|FEW|OVC|SCT)(\d+|\/{3})(CB|TCU|\/{3}|)?$/)
|
26
|
+
if m1
|
27
|
+
quantity = QUANTITY[m1[1]]
|
22
28
|
height =
|
23
|
-
if
|
29
|
+
if m1[2] == '///'
|
24
30
|
nil
|
25
31
|
else
|
26
|
-
Metar::Data::Distance.new(
|
32
|
+
Metar::Data::Distance.new(m1[2].to_i * 30.48)
|
27
33
|
end
|
28
|
-
type = CONDITION[
|
29
|
-
new(raw, quantity: quantity, height: height, type: type)
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
34
|
+
type = CONDITION[m1[3]]
|
35
|
+
return new(raw, quantity: quantity, height: height, type: type)
|
36
|
+
end
|
37
|
+
|
38
|
+
m2 = raw.match(/^(CB|TCU)$/)
|
39
|
+
if m2
|
40
|
+
type = CONDITION[m2[1]]
|
41
|
+
return new(raw, type: type)
|
35
42
|
end
|
43
|
+
|
44
|
+
nil
|
36
45
|
end
|
37
46
|
|
38
47
|
attr_reader :quantity, :height, :type
|
data/lib/metar/data/speed.rb
CHANGED
@@ -11,12 +11,10 @@ class Metar::Data::Speed < M9t::Speed
|
|
11
11
|
}
|
12
12
|
|
13
13
|
def self.parse(raw)
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
nil
|
20
|
-
end
|
14
|
+
return nil if raw.nil?
|
15
|
+
m = raw.match(/^(\d+)(|KT|MPS|KMH)$/)
|
16
|
+
return nil if m.nil?
|
17
|
+
# Call the appropriate factory method for the supplied units
|
18
|
+
return send(METAR_UNITS[m[2]], m[1].to_i)
|
21
19
|
end
|
22
20
|
end
|
@@ -4,14 +4,12 @@ require "m9t"
|
|
4
4
|
# Adds a parse method to the M9t base class
|
5
5
|
class Metar::Data::Temperature < M9t::Temperature
|
6
6
|
def self.parse(raw)
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
nil
|
14
|
-
end
|
7
|
+
m = raw.match(/^(M?)(\d+)$/)
|
8
|
+
return nil if !m
|
9
|
+
sign = m[1]
|
10
|
+
value = m[2].to_i
|
11
|
+
value *= -1 if sign == 'M'
|
12
|
+
new(value)
|
15
13
|
end
|
16
14
|
|
17
15
|
def to_s(options = {})
|
@@ -1,10 +1,13 @@
|
|
1
1
|
class Metar::Data::TemperatureAndDewPoint < Metar::Data::Base
|
2
2
|
def self.parse(raw)
|
3
|
-
if raw
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
return nil if !raw
|
4
|
+
|
5
|
+
m = raw.match(/^(M?\d+|XX|\/\/)\/(M?\d+|XX|\/\/)?$/)
|
6
|
+
return nil if !m
|
7
|
+
|
8
|
+
temperature = Metar::Data::Temperature.parse(m[1])
|
9
|
+
dew_point = Metar::Data::Temperature.parse(m[2])
|
10
|
+
new(raw, temperature: temperature, dew_point: dew_point)
|
8
11
|
end
|
9
12
|
|
10
13
|
attr_reader :temperature
|
data/lib/metar/data/time.rb
CHANGED
@@ -10,18 +10,17 @@ class Metar::Data::Time < Metar::Data::Base
|
|
10
10
|
/^(\d{1,2})(\d{2})(\d{2})Z$/
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
m1 = raw.match(date_matcher)
|
14
|
+
if m1
|
15
|
+
day, hour, minute = m1[1].to_i, m1[2].to_i, m1[3].to_i
|
15
16
|
else
|
16
17
|
return nil if strict
|
17
18
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
return nil
|
24
|
-
end
|
19
|
+
m2 = raw.match(/^(\d{1,2})(\d{2})Z$/)
|
20
|
+
return nil if !m2
|
21
|
+
# The day is missing, use today's date
|
22
|
+
day = Time.now.day
|
23
|
+
hour, minute = m2[1].to_i, m2[2].to_i
|
25
24
|
end
|
26
25
|
|
27
26
|
new(
|
@@ -1,14 +1,15 @@
|
|
1
1
|
class Metar::Data::VariableWind < Metar::Data::Base
|
2
2
|
def self.parse(raw)
|
3
|
-
if raw
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
3
|
+
return nil if raw.nil?
|
4
|
+
|
5
|
+
m = raw.match(/^(\d+)V(\d+)$/)
|
6
|
+
return nil if m.nil?
|
7
|
+
|
8
|
+
return new(
|
9
|
+
raw,
|
10
|
+
direction1: Metar::Data::Direction.new(m[1]),
|
11
|
+
direction2: Metar::Data::Direction.new(m[2])
|
12
|
+
)
|
12
13
|
end
|
13
14
|
|
14
15
|
attr_reader :direction1
|
@@ -3,14 +3,19 @@ require "m9t"
|
|
3
3
|
|
4
4
|
class Metar::Data::VerticalVisibility < Metar::Data::Base
|
5
5
|
def self.parse(raw)
|
6
|
-
|
7
|
-
|
8
|
-
new(raw, distance: Metar::Data::Distance.new($1.to_f * 30.48))
|
9
|
-
when raw == '///'
|
10
|
-
new(raw, distance: Metar::Data::Distance.new)
|
11
|
-
else
|
12
|
-
nil
|
6
|
+
if !raw
|
7
|
+
return nil
|
13
8
|
end
|
9
|
+
m1 = raw.match(/^VV(\d{3})$/)
|
10
|
+
if m1
|
11
|
+
return new(raw, distance: Metar::Data::Distance.new(m1[1].to_f * 30.48))
|
12
|
+
end
|
13
|
+
|
14
|
+
if raw == '///'
|
15
|
+
return new(raw, distance: Metar::Data::Distance.new)
|
16
|
+
end
|
17
|
+
|
18
|
+
nil
|
14
19
|
end
|
15
20
|
|
16
21
|
attr_reader :distance
|
@@ -1,36 +1,59 @@
|
|
1
1
|
class Metar::Data::Visibility < Metar::Data::Base
|
2
2
|
def self.parse(raw)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
if !raw
|
4
|
+
return nil
|
5
|
+
end
|
6
|
+
|
7
|
+
if raw == '9999'
|
8
|
+
return new(raw, distance: Metar::Data::Distance.new(10000), comparator: :more_than)
|
9
|
+
end
|
10
|
+
|
11
|
+
m1 = raw.match(/(\d{4})NDV/) # WMO
|
12
|
+
if m1
|
13
|
+
return new(raw, distance: Metar::Data::Distance.new(m1[1].to_f)) # Assuming meters
|
14
|
+
end
|
15
|
+
|
16
|
+
m2 = raw.match(/^((1|2)\s|)([1357])\/([248]|16)SM$/) # US
|
17
|
+
if m2
|
18
|
+
miles = m2[1].to_f + m2[3].to_f / m2[4].to_f
|
10
19
|
distance = Metar::Data::Distance.miles(miles)
|
11
20
|
distance.units = :miles
|
12
|
-
|
13
|
-
|
14
|
-
|
21
|
+
return new(raw, distance: distance)
|
22
|
+
end
|
23
|
+
|
24
|
+
m3 = raw.match(/^(\d+)SM$/) # US
|
25
|
+
if m3
|
26
|
+
distance = Metar::Data::Distance.miles(m3[1].to_f)
|
15
27
|
distance.units = :miles
|
16
|
-
|
17
|
-
|
28
|
+
return new(raw, distance: distance)
|
29
|
+
end
|
30
|
+
|
31
|
+
if raw == 'M1/4SM' # US
|
18
32
|
distance = Metar::Data::Distance.miles(0.25)
|
19
33
|
distance.units = :miles
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
34
|
+
return new(raw, distance: distance, comparator: :less_than)
|
35
|
+
end
|
36
|
+
|
37
|
+
m4 = raw.match(/^(\d+)KM$/)
|
38
|
+
if m4
|
39
|
+
return new(raw, distance: Metar::Data::Distance.kilometers(m4[1]))
|
40
|
+
end
|
41
|
+
|
42
|
+
m5 = raw.match(/^(\d+)$/) # We assume meters
|
43
|
+
if m5
|
44
|
+
return new(raw, distance: Metar::Data::Distance.new(m5[1]))
|
45
|
+
end
|
46
|
+
|
47
|
+
m6 = raw.match(/^(\d+)(N|NE|E|SE|S|SW|W|NW)$/)
|
48
|
+
if m6
|
49
|
+
return new(
|
27
50
|
raw,
|
28
|
-
distance: Metar::Data::Distance.meters(
|
29
|
-
direction: M9t::Direction.compass(
|
51
|
+
distance: Metar::Data::Distance.meters(m6[1]),
|
52
|
+
direction: M9t::Direction.compass(m6[2])
|
30
53
|
)
|
31
|
-
else
|
32
|
-
nil
|
33
54
|
end
|
55
|
+
|
56
|
+
nil
|
34
57
|
end
|
35
58
|
|
36
59
|
attr_reader :distance, :direction, :comparator
|
@@ -52,7 +52,7 @@ class Metar::Data::WeatherPhenomenon < Metar::Data::Base
|
|
52
52
|
phenomena = Phenomena.keys.join('|')
|
53
53
|
descriptors = Descriptors.keys.join('|')
|
54
54
|
modifiers = Modifiers.keys.join('|')
|
55
|
-
modifiers.gsub!(/([\+\-])/) { "
|
55
|
+
modifiers.gsub!(/([\+\-])/) { |m| "\\#{m}" }
|
56
56
|
rxp = Regexp.new("^(RE)?(#{modifiers})?(#{descriptors})?((?:#{phenomena}){1,2})$")
|
57
57
|
m = rxp.match(raw)
|
58
58
|
return nil if m.nil?
|
data/lib/metar/data/wind.rb
CHANGED
@@ -1,39 +1,58 @@
|
|
1
1
|
class Metar::Data::Wind < Metar::Data::Base
|
2
2
|
def self.parse(raw)
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
3
|
+
return nil if raw.nil?
|
4
|
+
|
5
|
+
m1 = raw.match(/^(\d{3})(\d{2}(|MPS|KMH|KT))$/)
|
6
|
+
if m1
|
7
|
+
return nil if m1[1].to_i > 360
|
8
|
+
return new(
|
7
9
|
raw,
|
8
|
-
direction: Metar::Data::Direction.new(
|
9
|
-
speed: Metar::Data::Speed.parse(
|
10
|
+
direction: Metar::Data::Direction.new(m1[1]),
|
11
|
+
speed: Metar::Data::Speed.parse(m1[2])
|
10
12
|
)
|
11
|
-
|
12
|
-
|
13
|
-
|
13
|
+
end
|
14
|
+
|
15
|
+
m2 = raw.match(/^(\d{3})(\d{2})G(\d{2,3}(|MPS|KMH|KT))$/)
|
16
|
+
if m2
|
17
|
+
return nil if m2[1].to_i > 360
|
18
|
+
return new(
|
14
19
|
raw,
|
15
|
-
direction: Metar::Data::Direction.new(
|
16
|
-
speed: Metar::Data::Speed.parse(
|
17
|
-
gusts: Metar::Data::Speed.parse(
|
20
|
+
direction: Metar::Data::Direction.new(m2[1]),
|
21
|
+
speed: Metar::Data::Speed.parse(m2[2] + m2[4]),
|
22
|
+
gusts: Metar::Data::Speed.parse(m2[3])
|
18
23
|
)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
24
|
+
end
|
25
|
+
|
26
|
+
m3 = raw.match(/^VRB(\d{2})G(\d{2,3})(|MPS|KMH|KT)$/)
|
27
|
+
if m3
|
28
|
+
speed = m3[1] + m3[3]
|
29
|
+
gusts = m3[2] + m3[3]
|
30
|
+
return new(
|
23
31
|
raw,
|
24
32
|
direction: :variable_direction,
|
25
33
|
speed: Metar::Data::Speed.parse(speed),
|
26
34
|
gusts: Metar::Data::Speed.parse(gusts)
|
27
35
|
)
|
28
|
-
when raw =~ /^VRB(\d{2}(|MPS|KMH|KT))$/
|
29
|
-
new(raw, direction: :variable_direction, speed: Metar::Data::Speed.parse($1))
|
30
|
-
when raw =~ /^\/{3}(\d{2}(|MPS|KMH|KT))$/
|
31
|
-
new(raw, direction: :unknown_direction, speed: Metar::Data::Speed.parse($1))
|
32
|
-
when raw =~ %r(^/////(|MPS|KMH|KT)$)
|
33
|
-
new(raw, direction: :unknown_direction, speed: :unknown_speed)
|
34
|
-
else
|
35
|
-
nil
|
36
36
|
end
|
37
|
+
|
38
|
+
m4 = raw.match(/^VRB(\d{2}(|MPS|KMH|KT))$/)
|
39
|
+
if m4
|
40
|
+
speed = Metar::Data::Speed.parse(m4[1])
|
41
|
+
return new(raw, direction: :variable_direction, speed: speed)
|
42
|
+
end
|
43
|
+
|
44
|
+
m5 = raw.match(/^\/{3}(\d{2}(|MPS|KMH|KT))$/)
|
45
|
+
if m5
|
46
|
+
speed = Metar::Data::Speed.parse(m5[1])
|
47
|
+
return new(raw, direction: :unknown_direction, speed: speed)
|
48
|
+
end
|
49
|
+
|
50
|
+
m6 = raw.match(%r(^/////(|MPS|KMH|KT)$))
|
51
|
+
if m6
|
52
|
+
return new(raw, direction: :unknown_direction, speed: :unknown_speed)
|
53
|
+
end
|
54
|
+
|
55
|
+
nil
|
37
56
|
end
|
38
57
|
|
39
58
|
attr_reader :direction, :speed, :gusts
|
data/lib/metar/station.rb
CHANGED
@@ -7,7 +7,7 @@ require 'set'
|
|
7
7
|
|
8
8
|
module Metar
|
9
9
|
class Station
|
10
|
-
NOAA_STATION_LIST_URL = 'http://
|
10
|
+
NOAA_STATION_LIST_URL = 'http://tgftp.nws.noaa.gov/data/nsd_cccc.txt'
|
11
11
|
|
12
12
|
class << self
|
13
13
|
@nsd_cccc = nil # Contains the text of the station list
|
@@ -38,13 +38,15 @@ module Metar
|
|
38
38
|
end
|
39
39
|
|
40
40
|
def to_longitude(s)
|
41
|
-
|
42
|
-
|
41
|
+
m = s.match(/^(\d+)-(\d+)([EW])/)
|
42
|
+
return nil if !m
|
43
|
+
(m[3] == 'E' ? 1.0 : -1.0) * (m[1].to_f + m[2].to_f / 60.0)
|
43
44
|
end
|
44
45
|
|
45
46
|
def to_latitude(s)
|
46
|
-
|
47
|
-
|
47
|
+
m = s.match(/^(\d+)-(\d+)([SN])/)
|
48
|
+
return nil if !m
|
49
|
+
(m[3] == 'E' ? 1.0 : -1.0) * (m[1].to_f + m[2].to_f / 60.0)
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
data/lib/metar/version.rb
CHANGED
data/spec/parser_spec.rb
CHANGED
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: metar-parser
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
4
|
+
version: 1.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Joe Yates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "<"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '11.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "<"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '11.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rdoc
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -237,7 +237,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
237
237
|
version: '0'
|
238
238
|
requirements: []
|
239
239
|
rubyforge_project: nowarning
|
240
|
-
rubygems_version: 2.5.
|
240
|
+
rubygems_version: 2.5.2
|
241
241
|
signing_key:
|
242
242
|
specification_version: 4
|
243
243
|
summary: A Ruby gem for worldwide weather reports
|