metar-parser 1.5.0 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
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