metar-parser 1.5.0 → 1.6.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.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -48
  3. data/Rakefile +2 -1
  4. data/lib/metar/data/base.rb +16 -10
  5. data/lib/metar/data/density_altitude.rb +16 -10
  6. data/lib/metar/data/direction.rb +10 -4
  7. data/lib/metar/data/distance.rb +27 -20
  8. data/lib/metar/data/lightning.rb +69 -60
  9. data/lib/metar/data/observer.rb +26 -20
  10. data/lib/metar/data/pressure.rb +28 -22
  11. data/lib/metar/data/remark.rb +146 -130
  12. data/lib/metar/data/runway_visible_range.rb +98 -78
  13. data/lib/metar/data/sky_condition.rb +68 -57
  14. data/lib/metar/data/speed.rb +21 -14
  15. data/lib/metar/data/station_code.rb +8 -4
  16. data/lib/metar/data/temperature.rb +21 -14
  17. data/lib/metar/data/temperature_and_dew_point.rb +22 -16
  18. data/lib/metar/data/time.rb +57 -47
  19. data/lib/metar/data/variable_wind.rb +30 -19
  20. data/lib/metar/data/vertical_visibility.rb +27 -21
  21. data/lib/metar/data/visibility.rb +91 -79
  22. data/lib/metar/data/visibility_remark.rb +16 -5
  23. data/lib/metar/data/weather_phenomenon.rb +92 -74
  24. data/lib/metar/data/wind.rb +105 -93
  25. data/lib/metar/data.rb +25 -23
  26. data/lib/metar/i18n.rb +5 -2
  27. data/lib/metar/parser.rb +46 -21
  28. data/lib/metar/raw.rb +32 -44
  29. data/lib/metar/report.rb +31 -20
  30. data/lib/metar/station.rb +28 -19
  31. data/lib/metar/version.rb +3 -1
  32. data/lib/metar.rb +2 -1
  33. data/locales/de.yml +1 -0
  34. data/locales/en.yml +1 -0
  35. data/locales/it.yml +1 -0
  36. data/locales/pt-BR.yml +1 -0
  37. data/spec/data/density_altitude_spec.rb +2 -1
  38. data/spec/data/distance_spec.rb +2 -1
  39. data/spec/data/lightning_spec.rb +26 -9
  40. data/spec/data/pressure_spec.rb +2 -0
  41. data/spec/data/remark_spec.rb +26 -9
  42. data/spec/data/runway_visible_range_spec.rb +71 -35
  43. data/spec/data/sky_condition_spec.rb +63 -19
  44. data/spec/data/speed_spec.rb +2 -0
  45. data/spec/data/temperature_spec.rb +2 -1
  46. data/spec/data/variable_wind_spec.rb +2 -0
  47. data/spec/data/vertical_visibility_spec.rb +4 -4
  48. data/spec/data/visibility_remark_spec.rb +2 -1
  49. data/spec/data/visibility_spec.rb +46 -25
  50. data/spec/data/weather_phenomenon_spec.rb +79 -24
  51. data/spec/data/wind_spec.rb +156 -38
  52. data/spec/i18n_spec.rb +2 -0
  53. data/spec/parser_spec.rb +192 -64
  54. data/spec/raw_spec.rb +40 -68
  55. data/spec/report_spec.rb +27 -25
  56. data/spec/spec_helper.rb +5 -6
  57. data/spec/station_spec.rb +43 -44
  58. metadata +56 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d2ff4b24fb06f90f8d661f3d28767733f13de8fe4ca7b4a98d5dd99489e1a4a
4
- data.tar.gz: 1d5be21117623704381b395020a0646a5692ef26b5cd99f385be80bb84df4dbd
3
+ metadata.gz: b9cd36dbde3df4b92e6a196ef774fe54ac20877b942bc04f49a9cc12e9ce9d1f
4
+ data.tar.gz: a6e77ae8a9ead64ab0877f204d858731e45f29aa7fd2fc8e2fff7a87672eab17
5
5
  SHA512:
6
- metadata.gz: a03d25be50664efca1ea07011e09f26a57fe9719415b08dbc3bf2c9705b6093deb3e2a4c23cc6edcd699a916d23aec8e398bc160085d2deb28075fe7e3c6e8a7
7
- data.tar.gz: 7e74f5fd5953541dfc897284bd9610d8cae24abe544fc27e3a97aaec38a8b9c66ac117659d48742ba5ce9554f3f80999188297b36650e1a264d3582599b10a7b
6
+ metadata.gz: 357e2d2187207db5ca6db35a084698eed370a537d8bbbd1ff4293da5748b71c7e9886d3ad45647069a44dcc5454c18878f3799a814a344a760f1c9846e7c6d9f
7
+ data.tar.gz: fe2acd2ccb94821e6a6c06e283bc131bdb6bc7a99fb646018f8bd7bb85a3a026bce30d6d72af7870cc049d26623adefebcffea0f702a2f39ae5181d3596c1fad
data/README.md CHANGED
@@ -1,17 +1,18 @@
1
- metar-parser [![Build Status](https://secure.travis-ci.org/joeyates/metar-parser.png)][Continuous Integration]
2
- ============
1
+ [![Build Status](https://github.com/joeyates/metar-parser/actions/workflows/main.yml/badge.svg)][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
- * [Continuous Integration]
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
- [Continuous Integration]: http://travis-ci.org/joeyates/metar-parser "Build status by Travis-CI"
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
@@ -1,4 +1,5 @@
1
- #!/usr/bin/env rake
1
+ # frozen_string_literal: true
2
+
2
3
  require "bundler/gem_tasks"
3
4
  require 'rcov/rcovtask' if RUBY_VERSION < '1.9'
4
5
  require 'rspec/core/rake_task'
@@ -1,15 +1,21 @@
1
- class Metar::Data::Base
2
- def self.parse(raw)
3
- new(raw)
4
- end
1
+ # frozen_string_literal: true
5
2
 
6
- attr_reader :raw
3
+ module Metar
4
+ module Data
5
+ class Base
6
+ def self.parse(raw)
7
+ new(raw)
8
+ end
7
9
 
8
- def initialize(raw)
9
- @raw = raw
10
- end
10
+ attr_reader :raw
11
+
12
+ def initialize(raw)
13
+ @raw = raw
14
+ end
11
15
 
12
- def value
13
- raw
16
+ def value
17
+ raw
18
+ end
19
+ end
14
20
  end
15
21
  end
@@ -1,15 +1,21 @@
1
- class Metar::Data::DensityAltitude < Metar::Data::Base
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
- new(raw, height: height)
7
- end
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
- attr_accessor :height
13
+ attr_accessor :height
10
14
 
11
- def initialize(raw, height:)
12
- @raw = raw
13
- @height = height
15
+ def initialize(raw, height:)
16
+ @raw = raw
17
+ @height = height
18
+ end
19
+ end
14
20
  end
15
21
  end
@@ -1,9 +1,15 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "i18n"
2
4
  require "m9t"
3
5
 
4
- class Metar::Data::Direction < M9t::Direction
5
- def initialize(direction)
6
- direction = M9t::Direction::normalize(direction.to_f)
7
- super(direction)
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
@@ -1,27 +1,34 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "i18n"
2
4
  require "m9t"
3
5
 
4
- class Metar::Data::Distance < M9t::Distance
5
- attr_accessor :serialization_units
6
+ module Metar
7
+ module Data
8
+ class Distance < M9t::Distance
9
+ attr_accessor :serialization_units
6
10
 
7
- # nil is taken to mean 'data unavailable'
8
- def initialize(meters = nil)
9
- @serialization_units = :meters
10
- if meters
11
- super
12
- else
13
- @value = nil
14
- end
15
- end
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
- # Handles nil case differently to M9t::Distance
18
- def to_s(options = {})
19
- options = {
20
- units: serialization_units,
21
- precision: 0,
22
- abbreviated: true,
23
- }.merge(options)
24
- return I18n.t("metar.distance.unknown") if @value.nil?
25
- super(options)
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
@@ -1,74 +1,83 @@
1
- class Metar::Data::Lightning < Metar::Data::Base
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
- loop do
20
- break if chunks[0].nil?
3
+ module Metar
4
+ module Data
5
+ class Lightning < Metar::Data::Base
6
+ TYPE = {'' => :default}.freeze
21
7
 
22
- if is_compass?(chunks[0])
23
- direction = chunks.shift
24
- raw += " " + direction
25
- directions << direction
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
- if chunks[0] == 'ALQDS'
30
- directions += ['N', 'E', 'S', 'W']
31
- raw += " " + chunks.shift
32
- next
33
- end
13
+ type = TYPE[m[1]]
34
14
 
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]]
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
- if chunks[0] == 'AND'
47
- raw += " " + chunks.shift
48
- next
49
- end
24
+ loop do
25
+ break if chunks[0].nil?
50
26
 
51
- break
52
- end
27
+ if compass?(chunks[0])
28
+ direction = chunks.shift
29
+ raw += " " + direction
30
+ directions << direction
31
+ next
32
+ end
53
33
 
54
- new(
55
- raw,
56
- frequency: frequency, type: type,
57
- distance: distance, directions: directions
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
- def self.is_compass?(s)
62
- s =~ /^([NESW]|NE|SE|SW|NW)$/
63
- end
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
- attr_accessor :frequency
66
- attr_accessor :type
67
- attr_accessor :distance
68
- attr_accessor :directions
50
+ if chunks[0] == 'AND'
51
+ raw += " " + chunks.shift
52
+ next
53
+ end
69
54
 
70
- def initialize(raw, frequency:, type:, distance:, directions:)
71
- @raw = raw
72
- @frequency, @type, @distance, @directions = frequency, type, distance, directions
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
@@ -1,24 +1,30 @@
1
- class Metar::Data::Observer < Metar::Data::Base
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
- attr_reader :value
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
- def initialize(raw, value:)
21
- @raw = raw
22
- @value = value
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
@@ -1,30 +1,36 @@
1
- class Metar::Data::Pressure < Metar::Data::Base
2
- def self.parse(raw)
3
- return nil if raw.nil?
1
+ # frozen_string_literal: true
4
2
 
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
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
- 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)
15
- end
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
- nil
18
- end
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
- attr_reader :pressure
21
+ nil
22
+ end
21
23
 
22
- def initialize(raw, pressure:)
23
- @raw = raw
24
- @pressure = pressure
25
- end
24
+ attr_reader :pressure
25
+
26
+ def initialize(raw, pressure:)
27
+ @raw = raw
28
+ @pressure = pressure
29
+ end
26
30
 
27
- def value
28
- pressure.value
31
+ def value
32
+ pressure.value
33
+ end
34
+ end
29
35
  end
30
36
  end