metar-parser 1.5.0 → 1.7.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.
- checksums.yaml +4 -4
- data/README.md +6 -48
- data/Rakefile +2 -1
- data/lib/metar/data/base.rb +16 -10
- data/lib/metar/data/density_altitude.rb +16 -10
- data/lib/metar/data/direction.rb +10 -4
- data/lib/metar/data/distance.rb +27 -20
- data/lib/metar/data/lightning.rb +69 -60
- data/lib/metar/data/observer.rb +26 -20
- data/lib/metar/data/pressure.rb +28 -22
- data/lib/metar/data/remark.rb +146 -130
- data/lib/metar/data/runway_visible_range.rb +98 -78
- data/lib/metar/data/sky_condition.rb +68 -57
- data/lib/metar/data/speed.rb +21 -14
- data/lib/metar/data/station_code.rb +8 -4
- data/lib/metar/data/temperature.rb +21 -14
- data/lib/metar/data/temperature_and_dew_point.rb +22 -16
- data/lib/metar/data/time.rb +57 -47
- data/lib/metar/data/variable_wind.rb +30 -19
- data/lib/metar/data/vertical_visibility.rb +27 -21
- data/lib/metar/data/visibility.rb +91 -79
- data/lib/metar/data/visibility_remark.rb +16 -5
- data/lib/metar/data/weather_phenomenon.rb +92 -74
- data/lib/metar/data/wind.rb +105 -93
- data/lib/metar/data.rb +25 -23
- data/lib/metar/i18n.rb +5 -2
- data/lib/metar/parser.rb +46 -21
- data/lib/metar/raw.rb +32 -44
- data/lib/metar/report.rb +31 -20
- data/lib/metar/station.rb +29 -20
- data/lib/metar/version.rb +3 -1
- data/lib/metar.rb +2 -1
- data/locales/de.yml +1 -0
- data/locales/en.yml +1 -0
- data/locales/it.yml +1 -0
- data/locales/pt-BR.yml +1 -0
- data/spec/data/density_altitude_spec.rb +2 -1
- data/spec/data/distance_spec.rb +2 -1
- data/spec/data/lightning_spec.rb +26 -9
- data/spec/data/pressure_spec.rb +2 -0
- data/spec/data/remark_spec.rb +26 -9
- data/spec/data/runway_visible_range_spec.rb +71 -35
- data/spec/data/sky_condition_spec.rb +63 -19
- data/spec/data/speed_spec.rb +2 -0
- data/spec/data/temperature_spec.rb +2 -1
- data/spec/data/variable_wind_spec.rb +2 -0
- data/spec/data/vertical_visibility_spec.rb +4 -4
- data/spec/data/visibility_remark_spec.rb +2 -1
- data/spec/data/visibility_spec.rb +46 -25
- data/spec/data/weather_phenomenon_spec.rb +79 -24
- data/spec/data/wind_spec.rb +156 -38
- data/spec/i18n_spec.rb +2 -0
- data/spec/parser_spec.rb +192 -64
- data/spec/raw_spec.rb +40 -68
- data/spec/report_spec.rb +27 -25
- data/spec/spec_helper.rb +5 -6
- data/spec/station_spec.rb +92 -52
- metadata +53 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e7f1558724e63f52aee14e0f1775c7f4dc90eb187c9d3060426d7ab14de16fe4
|
4
|
+
data.tar.gz: 189365393cc681c9398dc78fe9d941fb56166276dea4645f1f56a93fef19394f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 376de6502034e38fa3581b4c0b7c6cc0df72d4067ae20337c12f3f5f294ca926587628a0a1769848a682545ad04a59b2547fd2697db5aafe73d67e4497c9adb5
|
7
|
+
data.tar.gz: 55bc69ff0cf47c5b7c6a207fe6d56327bc3e0c4c9b9f6b262807c32e13ff554ee611a21158d62acb92426a0223533590a2a221c7dcfab2cced49e8748eb4cdff
|
data/README.md
CHANGED
@@ -1,17 +1,18 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
[][CI Status]
|
2
|
+
|
3
|
+
# metar-parser
|
3
4
|
|
4
5
|
*Get latest weather reports from weather stations worldwide*
|
5
6
|
|
6
7
|
* [Source Code]
|
7
8
|
* [API documentation]
|
8
9
|
* [Rubygem]
|
9
|
-
* [
|
10
|
+
* [CI Status]
|
10
11
|
|
11
12
|
[Source Code]: https://github.com/joeyates/metar-parser "Source code at GitHub"
|
12
13
|
[API documentation]: http://rubydoc.info/gems/metar-parser/frames "RDoc API Documentation at Rubydoc.info"
|
13
14
|
[Rubygem]: http://rubygems.org/gems/metar-parser "Ruby gem at rubygems.org"
|
14
|
-
[
|
15
|
+
[CI Status]: https://github.com/joeyates/metar-parser/actions/workflows/main.yml
|
15
16
|
|
16
17
|
The information comes from the National Oceanic and Atmospheric Association's raw data source.
|
17
18
|
|
@@ -115,53 +116,10 @@ If you only want to accept standards-compliant METAR strings, do this:
|
|
115
116
|
Metar::Parse.compliance = :strict
|
116
117
|
```
|
117
118
|
|
118
|
-
Changelog
|
119
|
-
=========
|
120
|
-
|
121
|
-
1.0.0
|
122
|
-
-----
|
123
|
-
This version introduces a major change to the Metar::Raw class.
|
124
|
-
|
125
|
-
Previously, this class downloaded METAR data from the NOAA FTP site.
|
126
|
-
The old functionality has been moved to Metar::Raw::Noaa. The new class,
|
127
|
-
Metar::Raw::Data accepts a METAR string as a parameter - allowing the user to
|
128
|
-
parse METAR strings without necessarily contacting the NOAA.
|
129
|
-
|
130
119
|
Contributors
|
131
120
|
============
|
132
121
|
|
133
122
|
* [Joe Yates](https://github.com/joeyates)
|
134
123
|
* [Derek Johnson](https://github.com/EpicDraws)
|
135
124
|
* [Florian Egermann and Mathias Wollin](https://github.com/math)
|
136
|
-
|
137
|
-
Alternative Software
|
138
|
-
====================
|
139
|
-
|
140
|
-
Ruby
|
141
|
-
----
|
142
|
-
|
143
|
-
Other Ruby libraries offering METAR parsing:
|
144
|
-
|
145
|
-
* [ruby-metar]
|
146
|
-
* [ruby-wx]
|
147
|
-
|
148
|
-
There are many reports (WMO) that these libraries do not parse.
|
149
|
-
|
150
|
-
[ruby-metar]: http://github.com/brandonh/ruby-metar
|
151
|
-
[ruby-wx]: http://hans.fugal.net/src/ruby-wx/doc/
|
152
|
-
|
153
|
-
There are two gems which read the National Oceanic and Atmospheric Association's XML weather data feeds:
|
154
|
-
|
155
|
-
* [noaa]
|
156
|
-
* [noaa-weather]
|
157
|
-
|
158
|
-
[noaa]: http://github.com/outoftime/noaa
|
159
|
-
[noaa-weather]: http://rubygems.org/gems/noaa-weather "Ruby interface to NOAA SOAP interface"
|
160
|
-
|
161
|
-
Other
|
162
|
-
-----
|
163
|
-
|
164
|
-
* [Interactive map]
|
165
|
-
|
166
|
-
[Interactive map]: http://www.spatiality.at/metarr/frontend/
|
167
|
-
|
125
|
+
* [Douglas Robertson](https://github.com/douglasr)
|
data/Rakefile
CHANGED
data/lib/metar/data/base.rb
CHANGED
@@ -1,15 +1,21 @@
|
|
1
|
-
|
2
|
-
def self.parse(raw)
|
3
|
-
new(raw)
|
4
|
-
end
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
3
|
+
module Metar
|
4
|
+
module Data
|
5
|
+
class Base
|
6
|
+
def self.parse(raw)
|
7
|
+
new(raw)
|
8
|
+
end
|
7
9
|
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
attr_reader :raw
|
11
|
+
|
12
|
+
def initialize(raw)
|
13
|
+
@raw = raw
|
14
|
+
end
|
11
15
|
|
12
|
-
|
13
|
-
|
16
|
+
def value
|
17
|
+
raw
|
18
|
+
end
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
@@ -1,15 +1,21 @@
|
|
1
|
-
|
2
|
-
def self.parse(raw)
|
3
|
-
feet = raw[/^(\d+)(FT)/, 1]
|
4
|
-
height = Metar::Data::Distance.feet(feet)
|
1
|
+
# frozen_string_literal: true
|
5
2
|
|
6
|
-
|
7
|
-
|
3
|
+
module Metar
|
4
|
+
module Data
|
5
|
+
class DensityAltitude < Metar::Data::Base
|
6
|
+
def self.parse(raw)
|
7
|
+
feet = raw[/^(\d+)(FT)/, 1]
|
8
|
+
height = Metar::Data::Distance.feet(feet)
|
9
|
+
|
10
|
+
new(raw, height: height)
|
11
|
+
end
|
8
12
|
|
9
|
-
|
13
|
+
attr_accessor :height
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
def initialize(raw, height:)
|
16
|
+
@raw = raw
|
17
|
+
@height = height
|
18
|
+
end
|
19
|
+
end
|
14
20
|
end
|
15
21
|
end
|
data/lib/metar/data/direction.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "i18n"
|
2
4
|
require "m9t"
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
module Metar
|
7
|
+
module Data
|
8
|
+
class Direction < M9t::Direction
|
9
|
+
def initialize(direction)
|
10
|
+
direction = M9t::Direction.normalize(direction.to_f)
|
11
|
+
super(direction)
|
12
|
+
end
|
13
|
+
end
|
8
14
|
end
|
9
15
|
end
|
data/lib/metar/data/distance.rb
CHANGED
@@ -1,27 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "i18n"
|
2
4
|
require "m9t"
|
3
5
|
|
4
|
-
|
5
|
-
|
6
|
+
module Metar
|
7
|
+
module Data
|
8
|
+
class Distance < M9t::Distance
|
9
|
+
attr_accessor :serialization_units
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
# nil is taken to mean 'data unavailable'
|
12
|
+
def initialize(meters = nil)
|
13
|
+
@serialization_units = :meters
|
14
|
+
if meters
|
15
|
+
super
|
16
|
+
else
|
17
|
+
@value = nil
|
18
|
+
end
|
19
|
+
end
|
16
20
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
# Handles nil case differently to M9t::Distance
|
22
|
+
def to_s(options = {})
|
23
|
+
options = {
|
24
|
+
units: serialization_units,
|
25
|
+
precision: 0,
|
26
|
+
abbreviated: true
|
27
|
+
}.merge(options)
|
28
|
+
return I18n.t("metar.distance.unknown") if @value.nil?
|
29
|
+
|
30
|
+
super(options)
|
31
|
+
end
|
32
|
+
end
|
26
33
|
end
|
27
34
|
end
|
data/lib/metar/data/lightning.rb
CHANGED
@@ -1,74 +1,83 @@
|
|
1
|
-
|
2
|
-
TYPE = {'' => :default}
|
3
|
-
|
4
|
-
def self.parse_chunks(chunks)
|
5
|
-
raw = chunks.shift
|
6
|
-
m = raw.match(/^LTG(|CG|IC|CC|CA)$/)
|
7
|
-
raise 'first chunk is not lightning' if m.nil?
|
8
|
-
type = TYPE[m[1]]
|
9
|
-
|
10
|
-
frequency = nil
|
11
|
-
distance = nil
|
12
|
-
directions = []
|
13
|
-
|
14
|
-
if chunks[0] == 'DSNT'
|
15
|
-
distance = Metar::Data::Distance.miles(10) # Should be >10SM, not 10SM
|
16
|
-
raw += " " + chunks.shift
|
17
|
-
end
|
1
|
+
# frozen_string_literal: true
|
18
2
|
|
19
|
-
|
20
|
-
|
3
|
+
module Metar
|
4
|
+
module Data
|
5
|
+
class Lightning < Metar::Data::Base
|
6
|
+
TYPE = {'' => :default}.freeze
|
21
7
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
next
|
27
|
-
end
|
8
|
+
def self.parse_chunks(chunks)
|
9
|
+
raw = chunks.shift
|
10
|
+
m = raw.match(/^LTG(|CG|IC|CC|CA)$/)
|
11
|
+
raise 'first chunk is not lightning' if m.nil?
|
28
12
|
|
29
|
-
|
30
|
-
directions += ['N', 'E', 'S', 'W']
|
31
|
-
raw += " " + chunks.shift
|
32
|
-
next
|
33
|
-
end
|
13
|
+
type = TYPE[m[1]]
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
15
|
+
frequency = nil
|
16
|
+
distance = nil
|
17
|
+
directions = []
|
18
|
+
|
19
|
+
if chunks[0] == 'DSNT'
|
20
|
+
distance = Metar::Data::Distance.miles(10) # Should be >10SM, not 10SM
|
39
21
|
raw += " " + chunks.shift
|
40
|
-
else
|
41
|
-
break
|
42
22
|
end
|
43
|
-
next
|
44
|
-
end
|
45
23
|
|
46
|
-
|
47
|
-
|
48
|
-
next
|
49
|
-
end
|
24
|
+
loop do
|
25
|
+
break if chunks[0].nil?
|
50
26
|
|
51
|
-
|
52
|
-
|
27
|
+
if compass?(chunks[0])
|
28
|
+
direction = chunks.shift
|
29
|
+
raw += " " + direction
|
30
|
+
directions << direction
|
31
|
+
next
|
32
|
+
end
|
53
33
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
end
|
34
|
+
if chunks[0] == 'ALQDS'
|
35
|
+
directions += %w(N E S W)
|
36
|
+
raw += " " + chunks.shift
|
37
|
+
next
|
38
|
+
end
|
60
39
|
|
61
|
-
|
62
|
-
|
63
|
-
|
40
|
+
m = chunks[0].match(/^([NESW]{1,2})-([NESW]{1,2})$/)
|
41
|
+
if m
|
42
|
+
break if !compass?(m[1])
|
43
|
+
break if !compass?(m[2])
|
44
|
+
|
45
|
+
directions += [m[1], m[2]]
|
46
|
+
raw += " " + chunks.shift
|
47
|
+
next
|
48
|
+
end
|
64
49
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
50
|
+
if chunks[0] == 'AND'
|
51
|
+
raw += " " + chunks.shift
|
52
|
+
next
|
53
|
+
end
|
69
54
|
|
70
|
-
|
71
|
-
|
72
|
-
|
55
|
+
break
|
56
|
+
end
|
57
|
+
|
58
|
+
new(
|
59
|
+
raw,
|
60
|
+
frequency: frequency, type: type,
|
61
|
+
distance: distance, directions: directions
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.compass?(direction)
|
66
|
+
direction =~ /^([NESW]|NE|SE|SW|NW)$/
|
67
|
+
end
|
68
|
+
|
69
|
+
attr_accessor :frequency
|
70
|
+
attr_accessor :type
|
71
|
+
attr_accessor :distance
|
72
|
+
attr_accessor :directions
|
73
|
+
|
74
|
+
def initialize(raw, frequency:, type:, distance:, directions:)
|
75
|
+
@raw = raw
|
76
|
+
@frequency = frequency
|
77
|
+
@type = type
|
78
|
+
@distance = distance
|
79
|
+
@directions = directions
|
80
|
+
end
|
81
|
+
end
|
73
82
|
end
|
74
83
|
end
|
data/lib/metar/data/observer.rb
CHANGED
@@ -1,24 +1,30 @@
|
|
1
|
-
|
2
|
-
def self.parse(raw)
|
3
|
-
case
|
4
|
-
when raw == 'AUTO' # WMO 15.4
|
5
|
-
new(raw, value: :auto)
|
6
|
-
when raw == 'COR' # WMO specified code word for correction
|
7
|
-
new(raw, value: :corrected)
|
8
|
-
when raw =~ /CC[A-Z]/ # Canadian correction
|
9
|
-
# Canada uses CCA for first correction, CCB for second, etc...
|
10
|
-
new(raw, value: :corrected)
|
11
|
-
when raw == 'RTD' # Delayed observation, no comments on observer
|
12
|
-
new(raw, value: :rtd)
|
13
|
-
else
|
14
|
-
new(nil, value: :real)
|
15
|
-
end
|
16
|
-
end
|
1
|
+
# frozen_string_literal: true
|
17
2
|
|
18
|
-
|
3
|
+
module Metar
|
4
|
+
module Data
|
5
|
+
class Observer < Metar::Data::Base
|
6
|
+
def self.parse(raw)
|
7
|
+
case
|
8
|
+
when raw == 'AUTO' # WMO 15.4
|
9
|
+
new(raw, value: :auto)
|
10
|
+
when raw == 'COR' # WMO specified code word for correction
|
11
|
+
new(raw, value: :corrected)
|
12
|
+
when raw =~ /CC[A-Z]/ # Canadian correction
|
13
|
+
# Canada uses CCA for first correction, CCB for second, etc...
|
14
|
+
new(raw, value: :corrected)
|
15
|
+
when raw == 'RTD' # Delayed observation, no comments on observer
|
16
|
+
new(raw, value: :rtd)
|
17
|
+
else
|
18
|
+
new(nil, value: :real)
|
19
|
+
end
|
20
|
+
end
|
19
21
|
|
20
|
-
|
21
|
-
|
22
|
-
|
22
|
+
attr_reader :value
|
23
|
+
|
24
|
+
def initialize(raw, value:)
|
25
|
+
@raw = raw
|
26
|
+
@value = value
|
27
|
+
end
|
28
|
+
end
|
23
29
|
end
|
24
30
|
end
|
data/lib/metar/data/pressure.rb
CHANGED
@@ -1,30 +1,36 @@
|
|
1
|
-
|
2
|
-
def self.parse(raw)
|
3
|
-
return nil if raw.nil?
|
1
|
+
# frozen_string_literal: true
|
4
2
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
3
|
+
module Metar
|
4
|
+
module Data
|
5
|
+
class Pressure < Metar::Data::Base
|
6
|
+
def self.parse(raw)
|
7
|
+
return nil if raw.nil?
|
10
8
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
9
|
+
m1 = raw.match(/^Q(\d{4})$/)
|
10
|
+
if m1
|
11
|
+
pressure = M9t::Pressure.hectopascals(m1[1].to_f)
|
12
|
+
return new(raw, pressure: pressure)
|
13
|
+
end
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
m2 = raw.match(/^A(\d{4})$/)
|
16
|
+
if m2
|
17
|
+
pressure = M9t::Pressure.inches_of_mercury(m2[1].to_f / 100.0)
|
18
|
+
return new(raw, pressure: pressure)
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
+
nil
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
24
|
+
attr_reader :pressure
|
25
|
+
|
26
|
+
def initialize(raw, pressure:)
|
27
|
+
@raw = raw
|
28
|
+
@pressure = pressure
|
29
|
+
end
|
26
30
|
|
27
|
-
|
28
|
-
|
31
|
+
def value
|
32
|
+
pressure.value
|
33
|
+
end
|
34
|
+
end
|
29
35
|
end
|
30
36
|
end
|