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
@@ -1,86 +1,104 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "metar/i18n"
2
4
 
3
- class Metar::Data::WeatherPhenomenon < Metar::Data::Base
4
- Modifiers = {
5
- '+' => 'heavy',
6
- '-' => 'light',
7
- 'VC' => 'nearby',
8
- '-VC' => 'nearby light',
9
- '+VC' => 'nearby heavy',
10
- }
5
+ module Metar
6
+ module Data
7
+ class WeatherPhenomenon < Metar::Data::Base
8
+ MODIFIERS = {
9
+ '+' => 'heavy',
10
+ '-' => 'light',
11
+ 'VC' => 'nearby',
12
+ '-VC' => 'nearby light',
13
+ '+VC' => 'nearby heavy'
14
+ }.freeze
11
15
 
12
- Descriptors = {
13
- 'BC' => 'patches of',
14
- 'BL' => 'blowing',
15
- 'DR' => 'low drifting',
16
- 'FZ' => 'freezing',
17
- 'MI' => 'shallow',
18
- 'PR' => 'partial',
19
- 'SH' => 'shower of',
20
- 'TS' => 'thunderstorm and',
21
- }
16
+ DESCRIPTORS = {
17
+ 'BC' => 'patches of',
18
+ 'BL' => 'blowing',
19
+ 'DR' => 'low drifting',
20
+ 'FZ' => 'freezing',
21
+ 'MI' => 'shallow',
22
+ 'PR' => 'partial',
23
+ 'SH' => 'shower of',
24
+ 'TS' => 'thunderstorm and'
25
+ }.freeze
22
26
 
23
- Phenomena = {
24
- 'BR' => 'mist',
25
- 'DU' => 'dust',
26
- 'DZ' => 'drizzle',
27
- 'FG' => 'fog',
28
- 'FU' => 'smoke',
29
- 'GR' => 'hail',
30
- 'GS' => 'small hail',
31
- 'HZ' => 'haze',
32
- 'IC' => 'ice crystals',
33
- 'PL' => 'ice pellets',
34
- 'PO' => 'dust whirls',
35
- 'PY' => 'spray', # US only
36
- 'RA' => 'rain',
37
- 'SA' => 'sand',
38
- 'SH' => 'shower',
39
- 'SN' => 'snow',
40
- 'SG' => 'snow grains',
41
- 'SQ' => 'squall',
42
- 'UP' => 'unknown phenomenon', # => AUTO
43
- 'VA' => 'volcanic ash',
44
- 'FC' => 'funnel cloud',
45
- 'SS' => 'sand storm',
46
- 'DS' => 'dust storm',
47
- 'TS' => 'thunderstorm',
48
- }
27
+ PHENOMENA = {
28
+ 'BR' => 'mist',
29
+ 'DU' => 'dust',
30
+ 'DZ' => 'drizzle',
31
+ 'FG' => 'fog',
32
+ 'FU' => 'smoke',
33
+ 'GR' => 'hail',
34
+ 'GS' => 'small hail',
35
+ 'HZ' => 'haze',
36
+ 'IC' => 'ice crystals',
37
+ 'PL' => 'ice pellets',
38
+ 'PO' => 'dust whirls',
39
+ 'PY' => 'spray', # US only
40
+ 'RA' => 'rain',
41
+ 'SA' => 'sand',
42
+ 'SH' => 'shower',
43
+ 'SN' => 'snow',
44
+ 'SG' => 'snow grains',
45
+ 'SQ' => 'squall',
46
+ 'UP' => 'unknown phenomenon', # => AUTO
47
+ 'VA' => 'volcanic ash',
48
+ 'FC' => 'funnel cloud',
49
+ 'SS' => 'sand storm',
50
+ 'DS' => 'dust storm',
51
+ 'TS' => 'thunderstorm'
52
+ }.freeze
49
53
 
50
- # Accepts all standard (and some non-standard) present weather codes
51
- def self.parse(raw)
52
- phenomena = Phenomena.keys.join('|')
53
- descriptors = Descriptors.keys.join('|')
54
- modifiers = Modifiers.keys.join('|')
55
- modifiers.gsub!(/([\+\-])/) { |m| "\\#{m}" }
56
- rxp = Regexp.new("^(RE)?(#{modifiers})?(#{descriptors})?((?:#{phenomena}){1,2})$")
57
- m = rxp.match(raw)
58
- return nil if m.nil?
54
+ # Accepts all standard (and some non-standard) present weather codes
55
+ def self.parse(raw)
56
+ modifiers = MODIFIERS.keys.join('|')
57
+ modifiers.gsub!(/([\+\-])/) { |m| "\\#{m}" }
59
58
 
60
- recent = m[1] == "RE"
61
- modifier_code = m[2]
62
- descriptor_code = m[3]
63
- phenomena_codes = m[4].scan(/../)
64
- phenomena_phrase = phenomena_codes.map { |c| Phenomena[c] }.join(' and ')
59
+ descriptors = DESCRIPTORS.keys.join('|')
65
60
 
66
- new(
67
- raw,
68
- phenomenon: phenomena_phrase,
69
- modifier: Modifiers[modifier_code],
70
- descriptor: Descriptors[descriptor_code]
71
- )
72
- end
61
+ phenomena = PHENOMENA.keys.join('|')
73
62
 
74
- attr_reader :phenomenon, :modifier, :descriptor, :recent
63
+ rxp = Regexp.new(
64
+ "^(RE)?(#{modifiers})?(#{descriptors})?((?:#{phenomena}){1,2})$"
65
+ )
75
66
 
76
- def initialize(raw, phenomenon:, modifier: nil, descriptor: nil, recent: false)
77
- @raw = raw
78
- @phenomenon, @modifier, @descriptor = phenomenon, modifier, descriptor
79
- @recent = recent
80
- end
67
+ m = rxp.match(raw)
68
+ return nil if m.nil?
69
+
70
+ recent = m[1] == "RE"
71
+ modifier_code = m[2]
72
+ descriptor_code = m[3]
73
+ phenomena_codes = m[4].scan(/../)
74
+ phenomena = phenomena_codes.map { |c| PHENOMENA[c] }
75
+ phenomena_phrase = phenomena.join(' and ')
76
+
77
+ new(
78
+ raw,
79
+ phenomenon: phenomena_phrase,
80
+ modifier: MODIFIERS[modifier_code],
81
+ descriptor: DESCRIPTORS[descriptor_code],
82
+ recent: recent
83
+ )
84
+ end
85
+
86
+ attr_reader :phenomenon, :modifier, :descriptor, :recent
87
+
88
+ def initialize(
89
+ raw, phenomenon:, modifier: nil, descriptor: nil, recent: false
90
+ )
91
+ @raw = raw
92
+ @phenomenon = phenomenon
93
+ @modifier = modifier
94
+ @descriptor = descriptor
95
+ @recent = recent
96
+ end
81
97
 
82
- def to_s
83
- key = [modifier, descriptor, phenomenon].compact.join(' ')
84
- I18n.t("metar.present_weather.%s" % key)
98
+ def to_s
99
+ key = [modifier, descriptor, phenomenon].compact.join(' ')
100
+ I18n.t("metar.present_weather.#{key}")
101
+ end
102
+ end
85
103
  end
86
104
  end
@@ -1,108 +1,120 @@
1
- class Metar::Data::Wind < Metar::Data::Base
2
- def self.parse(raw, strict: false)
3
- return nil if raw.nil?
4
-
5
- plain_match =
6
- if strict
7
- /^(\d{3})(\d{2}(|MPS|KMH|KT))$/
8
- else
9
- /^(\d{3})(\d{2,3}(|MPS|KMH|KT))$/
10
- end
1
+ # frozen_string_literal: true
11
2
 
12
- m1 = raw.match(plain_match)
13
- if m1
14
- return nil if m1[1].to_i > 360
15
- return new(
16
- raw,
17
- direction: Metar::Data::Direction.new(m1[1]),
18
- speed: Metar::Data::Speed.parse(m1[2])
19
- )
20
- end
3
+ module Metar
4
+ module Data
5
+ class Wind < Metar::Data::Base
6
+ def self.parse(raw, strict: false)
7
+ return nil if raw.nil?
21
8
 
22
- m2 = raw.match(/^(\d{3})(\d{2})G(\d{2,3}(|MPS|KMH|KT))$/)
23
- if m2
24
- return nil if m2[1].to_i > 360
25
- return new(
26
- raw,
27
- direction: Metar::Data::Direction.new(m2[1]),
28
- speed: Metar::Data::Speed.parse(m2[2] + m2[4]),
29
- gusts: Metar::Data::Speed.parse(m2[3])
30
- )
31
- end
9
+ plain_match =
10
+ if strict
11
+ /^(\d{3})(\d{2}(|MPS|KMH|KT))$/
12
+ else
13
+ /^(\d{3})(\d{2,3}(|MPS|KMH|KT))$/
14
+ end
32
15
 
33
- m3 = raw.match(/^VRB(\d{2})G(\d{2,3})(|MPS|KMH|KT)$/)
34
- if m3
35
- speed = m3[1] + m3[3]
36
- gusts = m3[2] + m3[3]
37
- return new(
38
- raw,
39
- direction: :variable_direction,
40
- speed: Metar::Data::Speed.parse(speed),
41
- gusts: Metar::Data::Speed.parse(gusts)
42
- )
43
- end
16
+ m1 = raw.match(plain_match)
17
+ if m1
18
+ return nil if m1[1].to_i > 360
44
19
 
45
- m4 = raw.match(/^VRB(\d{2}(|MPS|KMH|KT))$/)
46
- if m4
47
- speed = Metar::Data::Speed.parse(m4[1])
48
- return new(raw, direction: :variable_direction, speed: speed)
49
- end
20
+ return new(
21
+ raw,
22
+ direction: Metar::Data::Direction.new(m1[1]),
23
+ speed: Metar::Data::Speed.parse(m1[2])
24
+ )
25
+ end
50
26
 
51
- m5 = raw.match(/^\/{3}(\d{2}(|MPS|KMH|KT))$/)
52
- if m5
53
- speed = Metar::Data::Speed.parse(m5[1])
54
- return new(raw, direction: :unknown_direction, speed: speed)
55
- end
27
+ m2 = raw.match(/^(\d{3})(\d{2})G(\d{2,3}(|MPS|KMH|KT))$/)
28
+ if m2
29
+ return nil if m2[1].to_i > 360
56
30
 
57
- m6 = raw.match(%r(^/////(|MPS|KMH|KT)$))
58
- if m6
59
- return new(raw, direction: :unknown_direction, speed: :unknown_speed)
60
- end
31
+ return new(
32
+ raw,
33
+ direction: Metar::Data::Direction.new(m2[1]),
34
+ speed: Metar::Data::Speed.parse(m2[2] + m2[4]),
35
+ gusts: Metar::Data::Speed.parse(m2[3])
36
+ )
37
+ end
61
38
 
62
- nil
63
- end
39
+ m3 = raw.match(/^VRB(\d{2})G(\d{2,3})(|MPS|KMH|KT)$/)
40
+ if m3
41
+ speed = m3[1] + m3[3]
42
+ gusts = m3[2] + m3[3]
43
+ return new(
44
+ raw,
45
+ direction: :variable_direction,
46
+ speed: Metar::Data::Speed.parse(speed),
47
+ gusts: Metar::Data::Speed.parse(gusts)
48
+ )
49
+ end
64
50
 
65
- attr_reader :direction, :speed, :gusts
51
+ m4 = raw.match(/^VRB(\d{2}(|MPS|KMH|KT))$/)
52
+ if m4
53
+ speed = Metar::Data::Speed.parse(m4[1])
54
+ return new(raw, direction: :variable_direction, speed: speed)
55
+ end
66
56
 
67
- def initialize(raw, direction:, speed:, gusts: nil)
68
- @raw = raw
69
- @direction, @speed, @gusts = direction, speed, gusts
70
- end
57
+ m5 = raw.match(%r{^/{3}(\d{2}(|MPS|KMH|KT))$})
58
+ if m5
59
+ speed = Metar::Data::Speed.parse(m5[1])
60
+ return new(raw, direction: :unknown_direction, speed: speed)
61
+ end
62
+
63
+ m6 = raw.match(%r{^/////(|MPS|KMH|KT)$})
64
+ if m6
65
+ return new(raw, direction: :unknown_direction, speed: :unknown_speed)
66
+ end
67
+
68
+ nil
69
+ end
71
70
 
72
- def to_s(options = {})
73
- options = {
74
- direction_units: :compass,
75
- speed_units: :kilometers_per_hour,
76
- }.merge(options)
77
- speed =
78
- case @speed
79
- when :unknown_speed
80
- I18n.t('metar.wind.unknown_speed')
81
- else
82
- @speed.to_s(
83
- abbreviated: true,
84
- precision: 0,
85
- units: options[:speed_units]
86
- )
71
+ attr_reader :direction, :speed, :gusts
72
+
73
+ def initialize(raw, direction:, speed:, gusts: nil)
74
+ @raw = raw
75
+ @direction = direction
76
+ @speed = speed
77
+ @gusts = gusts
87
78
  end
88
- direction =
89
- case @direction
90
- when :variable_direction
91
- I18n.t('metar.wind.variable_direction')
92
- when :unknown_direction
93
- I18n.t('metar.wind.unknown_direction')
94
- else
95
- @direction.to_s(units: options[:direction_units])
79
+
80
+ def to_s(options = {})
81
+ options = {
82
+ direction_units: :compass,
83
+ speed_units: :kilometers_per_hour
84
+ }.merge(options)
85
+ speed =
86
+ case @speed
87
+ when :unknown_speed
88
+ I18n.t('metar.wind.unknown_speed')
89
+ else
90
+ @speed.to_s(
91
+ abbreviated: true,
92
+ precision: 0,
93
+ units: options[:speed_units]
94
+ )
95
+ end
96
+ direction =
97
+ case @direction
98
+ when :variable_direction
99
+ I18n.t('metar.wind.variable_direction')
100
+ when :unknown_direction
101
+ I18n.t('metar.wind.unknown_direction')
102
+ else
103
+ @direction.to_s(units: options[:direction_units])
104
+ end
105
+ s = "#{speed} #{direction}"
106
+
107
+ if !@gusts.nil?
108
+ g = @gusts.to_s(
109
+ abbreviated: true,
110
+ precision: 0,
111
+ units: options[:speed_units]
112
+ )
113
+ s += " #{I18n.t('metar.wind.gusts')} #{g}"
114
+ end
115
+
116
+ s
96
117
  end
97
- s = "#{speed} #{direction}"
98
- if not @gusts.nil?
99
- g = @gusts.to_s(
100
- abbreviated: true,
101
- precision: 0,
102
- units: options[:speed_units]
103
- )
104
- s += " #{I18n.t('metar.wind.gusts')} #{g}"
105
118
  end
106
- s
107
119
  end
108
120
  end
data/lib/metar/data.rb CHANGED
@@ -1,25 +1,27 @@
1
- # encoding: utf-8
1
+ # frozen_string_literal: true
2
2
 
3
- module Metar::Data
4
- autoload :Base, "metar/data/base"
5
- autoload :DensityAltitude, "metar/data/density_altitude"
6
- autoload :Direction, "metar/data/direction"
7
- autoload :Distance, "metar/data/distance"
8
- autoload :Lightning, "metar/data/lightning"
9
- autoload :Observer, "metar/data/observer"
10
- autoload :Pressure, "metar/data/pressure"
11
- autoload :Remark, "metar/data/remark"
12
- autoload :RunwayVisibleRange, "metar/data/runway_visible_range"
13
- autoload :SkyCondition, "metar/data/sky_condition"
14
- autoload :Speed, "metar/data/speed"
15
- autoload :StationCode, "metar/data/station_code"
16
- autoload :Temperature, "metar/data/temperature"
17
- autoload :TemperatureAndDewPoint, "metar/data/temperature_and_dew_point"
18
- autoload :Time, "metar/data/time"
19
- autoload :VariableWind, "metar/data/variable_wind"
20
- autoload :VerticalVisibility, "metar/data/vertical_visibility"
21
- autoload :Visibility, "metar/data/visibility"
22
- autoload :VisibilityRemark, "metar/data/visibility_remark"
23
- autoload :WeatherPhenomenon, "metar/data/weather_phenomenon"
24
- autoload :Wind, "metar/data/wind"
3
+ module Metar
4
+ module Data
5
+ autoload :Base, "metar/data/base"
6
+ autoload :DensityAltitude, "metar/data/density_altitude"
7
+ autoload :Direction, "metar/data/direction"
8
+ autoload :Distance, "metar/data/distance"
9
+ autoload :Lightning, "metar/data/lightning"
10
+ autoload :Observer, "metar/data/observer"
11
+ autoload :Pressure, "metar/data/pressure"
12
+ autoload :Remark, "metar/data/remark"
13
+ autoload :RunwayVisibleRange, "metar/data/runway_visible_range"
14
+ autoload :SkyCondition, "metar/data/sky_condition"
15
+ autoload :Speed, "metar/data/speed"
16
+ autoload :StationCode, "metar/data/station_code"
17
+ autoload :Temperature, "metar/data/temperature"
18
+ autoload :TemperatureAndDewPoint, "metar/data/temperature_and_dew_point"
19
+ autoload :Time, "metar/data/time"
20
+ autoload :VariableWind, "metar/data/variable_wind"
21
+ autoload :VerticalVisibility, "metar/data/vertical_visibility"
22
+ autoload :Visibility, "metar/data/visibility"
23
+ autoload :VisibilityRemark, "metar/data/visibility_remark"
24
+ autoload :WeatherPhenomenon, "metar/data/weather_phenomenon"
25
+ autoload :Wind, "metar/data/wind"
26
+ end
25
27
  end
data/lib/metar/i18n.rb CHANGED
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "i18n"
2
4
 
3
- locales_path = File.expand_path(File.join(File.dirname(__FILE__), "..", "..", "locales"))
5
+ locales_path = File.expand_path(
6
+ File.join(File.dirname(__FILE__), "..", "..", "locales")
7
+ )
4
8
  I18n.load_path += Dir.glob("#{locales_path}/*.yml")
5
9
  I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
6
-
data/lib/metar/parser.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "m9t"
2
4
 
3
5
  require "metar/data"
@@ -13,7 +15,7 @@ module Metar
13
15
  new(raw)
14
16
  end
15
17
 
16
- COMPLIANCE = [:strict, :loose]
18
+ COMPLIANCE = %i(strict loose).freeze
17
19
 
18
20
  def self.thread_attributes
19
21
  Thread.current[:metar_parser] ||= {}
@@ -25,6 +27,7 @@ module Metar
25
27
 
26
28
  def self.compliance=(compliance)
27
29
  raise 'Unknown compliance' unless COMPLIANCE.find(compliance)
30
+
28
31
  thread_attributes[:compliance] = compliance
29
32
  end
30
33
 
@@ -65,11 +68,13 @@ module Metar
65
68
 
66
69
  def temperature
67
70
  return nil if @temperature_and_dew_point.nil?
71
+
68
72
  @temperature_and_dew_point.temperature
69
73
  end
70
74
 
71
75
  def dew_point
72
76
  return nil if @temperature_and_dew_point.nil?
77
+
73
78
  @temperature_and_dew_point.dew_point
74
79
  end
75
80
 
@@ -77,7 +82,7 @@ module Metar
77
82
  attr = {
78
83
  metar: metar,
79
84
  datetime: @time.raw,
80
- station_code: station_code,
85
+ station_code: station_code
81
86
  }
82
87
  %i(
83
88
  minimum_visibility
@@ -106,6 +111,7 @@ module Metar
106
111
  value = send(attribute)
107
112
  return hash if value.nil?
108
113
  return hash if value.raw.nil?
114
+
109
115
  hash[attribute] = value.raw
110
116
  hash
111
117
  end
@@ -113,7 +119,8 @@ module Metar
113
119
  def add_raw_if_not_empty(hash, attribute)
114
120
  values = send(attribute)
115
121
  raws = values.map(&:raw).compact
116
- return hash if raws.size == 0
122
+ return hash if raws.empty?
123
+
117
124
  hash[attribute] = raws.join(" ")
118
125
  hash
119
126
  end
@@ -121,8 +128,8 @@ module Metar
121
128
  def analyze
122
129
  @chunks = @metar.split(' ')
123
130
  # Strip final '='
124
- if !strict? && @chunks.length > 0
125
- @chunks[-1].gsub!(/\s?=$/, '')
131
+ if !strict?
132
+ @chunks[-1].gsub!(/\s?=$/, '') if !@chunks.empty?
126
133
  end
127
134
 
128
135
  @station_code = nil
@@ -167,7 +174,8 @@ module Metar
167
174
  def seek_station_code
168
175
  @station_code = Metar::Data::StationCode.parse(@chunks[0])
169
176
  if @station_code.nil?
170
- raise ParseError.new("Expecting location, found '#{ @chunks[0] }' in #{@metar}")
177
+ message = "Expecting location, found '#{@chunks[0]}' in #{@metar}"
178
+ raise ParseError, message
171
179
  end
172
180
  @chunks.shift
173
181
  @station_code
@@ -178,9 +186,11 @@ module Metar
178
186
  @time = Metar::Data::Time.parse(
179
187
  datetime, year: raw.time.year, month: raw.time.month, strict: strict?
180
188
  )
189
+
181
190
  if !@time
182
- raise ParseError.new("Expecting datetime, found '#{datetime}' in #{@metar}")
191
+ raise ParseError, "Expecting datetime, found '#{datetime}' in #{@metar}"
183
192
  end
193
+
184
194
  @time
185
195
  end
186
196
 
@@ -228,17 +238,17 @@ module Metar
228
238
  end
229
239
  end
230
240
 
231
- if @chunks[0] == '1' or @chunks[0] == '2'
232
- @visibility = Metar::Data::Visibility.parse(@chunks[0] + ' ' + @chunks[1])
241
+ if @chunks[0] == '1' || @chunks[0] == '2'
242
+ @visibility = Metar::Data::Visibility.parse(
243
+ @chunks[0] + ' ' + @chunks[1]
244
+ )
233
245
  if @visibility
234
246
  @chunks.shift
235
247
  @chunks.shift
236
248
  end
237
249
  else
238
250
  @visibility = Metar::Data::Visibility.parse(@chunks[0])
239
- if @visibility
240
- @chunks.shift
241
- end
251
+ @chunks.shift if @visibility
242
252
  end
243
253
  @visibility
244
254
  end
@@ -254,6 +264,7 @@ module Metar
254
264
  loop do
255
265
  rvr = Metar::Data::RunwayVisibleRange.parse(@chunks[0])
256
266
  break if rvr.nil?
267
+
257
268
  @chunks.shift
258
269
  @runway_visible_range << rvr
259
270
  end
@@ -271,11 +282,21 @@ module Metar
271
282
  end
272
283
  end
273
284
 
285
+ if @chunks[0] == 'NSW'
286
+ @present_weather << Metar::Data::WeatherPhenomenon.new(
287
+ nil, phenomenon: "no significant weather"
288
+ )
289
+ @chunks.shift
290
+ return
291
+ end
292
+
274
293
  loop do
275
- break if @chunks.size == 0
294
+ break if @chunks.empty?
276
295
  break if @chunks[0].start_with?("RE")
296
+
277
297
  wtp = Metar::Data::WeatherPhenomenon.parse(@chunks[0])
278
298
  break if wtp.nil?
299
+
279
300
  @chunks.shift
280
301
  @present_weather << wtp
281
302
  end
@@ -284,7 +305,7 @@ module Metar
284
305
  # Repeatable: 15.9.1.3
285
306
  def seek_sky_conditions
286
307
  if observer.value == :auto # WMO 15.4
287
- if @chunks[0] == '///' or @chunks[0] == '//////'
308
+ if @chunks[0] == '///' || @chunks[0] == '//////'
288
309
  @chunks.shift # Simply dispose of it
289
310
  return
290
311
  end
@@ -293,6 +314,7 @@ module Metar
293
314
  loop do
294
315
  sky_condition = Metar::Data::SkyCondition.parse(@chunks[0])
295
316
  break if sky_condition.nil?
317
+
296
318
  @chunks.shift
297
319
  @sky_conditions << sky_condition
298
320
  end
@@ -321,10 +343,12 @@ module Metar
321
343
 
322
344
  def seek_recent_weather
323
345
  loop do
324
- return if @chunks.size == 0
346
+ return if @chunks.empty?
325
347
  break if !@chunks[0].start_with?("RE")
348
+
326
349
  recent_weather = Metar::Data::WeatherPhenomenon.parse(@chunks[0])
327
350
  break if recent_weather.nil?
351
+
328
352
  @chunks.shift
329
353
  @recent_weather << recent_weather
330
354
  end
@@ -333,11 +357,11 @@ module Metar
333
357
 
334
358
  def seek_to_remarks
335
359
  if strict?
336
- if @chunks.size > 0 and @chunks[0] != 'RMK'
337
- raise ParseError.new("Unparsable text found: '#{@chunks.join(' ')}'")
360
+ if !@chunks.empty? && @chunks[0] != 'RMK'
361
+ raise ParseError, "Unparsable text found: '#{@chunks.join(' ')}'"
338
362
  end
339
363
  else
340
- while @chunks.size > 0 and @chunks[0] != 'RMK' do
364
+ while !@chunks.empty? && @chunks[0] != 'RMK' do
341
365
  @unparsed << @chunks.shift
342
366
  end
343
367
  end
@@ -345,13 +369,14 @@ module Metar
345
369
 
346
370
  # WMO: 15.15
347
371
  def seek_remarks
348
- return if @chunks.size == 0
372
+ return if @chunks.empty?
349
373
  raise 'seek_remarks called without remark' if @chunks[0] != 'RMK'
350
374
 
351
375
  @chunks.shift # Drop 'RMK'
352
376
  @remarks = []
353
377
  loop do
354
- break if @chunks.size == 0
378
+ break if @chunks.empty?
379
+
355
380
  r = Metar::Data::Remark.parse(@chunks[0])
356
381
  if r
357
382
  if r.is_a?(Array)
@@ -362,7 +387,7 @@ module Metar
362
387
  @chunks.shift
363
388
  next
364
389
  end
365
- if @chunks[0] == 'VIS' and @chunks.size >= 3 and @chunks[1] == 'MIN'
390
+ if @chunks[0] == 'VIS' && @chunks.size >= 3 && @chunks[1] == 'MIN'
366
391
  @chunks.shift(2)
367
392
  r = Metar::Data::VisibilityRemark.parse(@chunks[0])
368
393
  @remarks << r