metar-parser 0.9.15 → 1.0.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.
data/README.md CHANGED
@@ -62,8 +62,8 @@ puts parser.temperature.value
62
62
  Use Your Own Raw Data
63
63
  ---------------------
64
64
  ```ruby
65
- metar_string = "2012/07/28 08:54\nKHWD 280554Z AUTO 29007KT 10SM OVC008 14/12 A3002 RMK AO2 SLP176 T01390117 10211\n"
66
- raw = Metar::Raw.new( 'KHWD', metar_string )
65
+ metar_string = "KHWD 280554Z AUTO 29007KT 10SM OVC008 14/12 A3002 RMK AO2 SLP176 T01390117 10211\n"
66
+ raw = Metar::Raw.new( metar_string )
67
67
  parser = Metar::Parser.new( raw )
68
68
  ```
69
69
 
@@ -72,6 +72,18 @@ Implementation
72
72
 
73
73
  * Parses METAR strings using a state machine.
74
74
 
75
+ Changelog
76
+ =========
77
+
78
+ 1.0.0
79
+ -----
80
+ This version introduces a major change to the Metar::Raw class.
81
+
82
+ Previously, this class downloaded METAR data from the NOAA FTP site.
83
+ The old functionality has been moved to Metar::Raw::Noaa. The new class,
84
+ Metar::Raw::Data accepts a METAR string as a parameter - allowing the user to
85
+ parse METAR strings without necessarily contacting the NOAA.
86
+
75
87
  Alternative Software
76
88
  ====================
77
89
 
data/lib/metar/data.rb CHANGED
@@ -415,7 +415,7 @@ module Metar
415
415
  new
416
416
  when sky_condition =~ /^(BKN|FEW|OVC|SCT)(\d+)(CB|TCU|\/{3}|)?$/
417
417
  quantity = QUANTITY[ $1 ]
418
- height = Distance.new( $2.to_i * 30.0 )
418
+ height = Distance.new( $2.to_i * 30.48 )
419
419
  type = CONDITION[ $3 ]
420
420
  new(quantity, height, type)
421
421
  else
@@ -452,7 +452,7 @@ module Metar
452
452
  def VerticalVisibility.parse( vertical_visibility )
453
453
  case
454
454
  when vertical_visibility =~ /^VV(\d{3})$/
455
- Distance.new( $1.to_f * 30.0 )
455
+ Distance.new( $1.to_f * 30.48 )
456
456
  when vertical_visibility == '///'
457
457
  Distance.new
458
458
  else
data/lib/metar/parser.rb CHANGED
@@ -84,24 +84,22 @@ module Metar
84
84
  end
85
85
 
86
86
  def self.for_cccc(cccc)
87
- station = Metar::Station.new(cccc)
88
- raw = Metar::Raw.new(station)
87
+ raw = Metar::Raw::Noaa.new(cccc)
89
88
  new(raw)
90
89
  end
91
90
 
92
- attr_reader :raw, :metar, :time
91
+ attr_reader :raw, :metar
93
92
  attr_reader :station_code, :observer, :wind, :variable_wind, :visibility, :runway_visible_range,
94
93
  :present_weather, :sky_conditions, :vertical_visibility, :temperature, :dew_point, :sea_level_pressure, :remarks
95
94
 
96
95
  def initialize(raw)
97
96
  @raw = raw
98
97
  @metar = raw.metar.clone
99
- @time = raw.time.clone
100
98
  analyze
101
99
  end
102
100
 
103
- def date
104
- Date.new(@time.year, @time.month, @time.day)
101
+ def time
102
+ Time.gm(@raw.time.year, @raw.time.month, @day, @hour, @minute)
105
103
  end
106
104
 
107
105
  private
@@ -137,8 +135,9 @@ module Metar
137
135
 
138
136
  def seek_datetime
139
137
  case
140
- when @chunks[0] =~ /^\d{6}Z$/
141
- @datetime = @chunks.shift
138
+ when @chunks[0] =~ /^(\d{2})(\d{2})(\d{2})Z$/
139
+ @chunks.shift
140
+ @day, @hour, @minute = $1.to_i, $2.to_i, $3.to_i
142
141
  else
143
142
  raise ParseError.new("Expecting datetime, found '#{ @chunks[0] }'")
144
143
  end
data/lib/metar/raw.rb CHANGED
@@ -1,88 +1,104 @@
1
1
  require 'net/ftp'
2
+ require 'time'
2
3
 
3
4
  module Metar
4
5
 
5
- class Raw
6
+ module Raw
6
7
 
7
- @@connection = nil
8
+ class Base
9
+ attr_reader :cccc
10
+ attr_reader :metar
11
+ attr_reader :time
12
+ alias :to_s :metar
8
13
 
9
- class << self
10
-
11
- def connection
12
- return @@connection if @@connection
13
- connect
14
- @@connection
14
+ def parse
15
+ @cccc = @metar[/\w+/]
15
16
  end
17
+ end
16
18
 
17
- def connect
18
- @@connection = Net::FTP.new('tgftp.nws.noaa.gov')
19
- @@connection.login
20
- @@connection.chdir('data/observations/metar/stations')
21
- @@connection.passive = true
19
+ class Data < Base
20
+ def initialize(metar, time = Time.now)
21
+ @metar, @time = metar, time
22
+
23
+ parse
22
24
  end
25
+ end
23
26
 
24
- def fetch( cccc )
25
- attempts = 0
26
- while attempts < 2
27
- begin
28
- s = ''
29
- connection.retrbinary( "RETR #{ cccc }.TXT", 1024 ) do | chunk |
30
- s << chunk
27
+ # Collects METAR data from the NOAA site via FTP
28
+ class Noaa < Base
29
+ @@connection = nil
30
+
31
+ class << self
32
+
33
+ def connection
34
+ return @@connection if @@connection
35
+ connect
36
+ @@connection
37
+ end
38
+
39
+ def connect
40
+ @@connection = Net::FTP.new('tgftp.nws.noaa.gov')
41
+ @@connection.login
42
+ @@connection.chdir('data/observations/metar/stations')
43
+ @@connection.passive = true
44
+ end
45
+
46
+ def fetch(cccc)
47
+ attempts = 0
48
+ while attempts < 2
49
+ begin
50
+ s = ''
51
+ connection.retrbinary( "RETR #{ cccc }.TXT", 1024 ) do |chunk|
52
+ s << chunk
53
+ end
54
+ return s
55
+ rescue Net::FTPPermError, Net::FTPTempError, EOFError => e
56
+ connect
57
+ attempts += 1
31
58
  end
32
- return s
33
- rescue Net::FTPPermError, Net::FTPTempError, EOFError => e
34
- connect
35
- attempts += 1
36
59
  end
60
+ raise "Net::FTP.retrbinary failed #{attempts} times"
37
61
  end
38
- raise "Net::FTP.retrbinary failed #{attempts} times"
39
- end
40
-
41
- end
42
62
 
43
- attr_reader :cccc
63
+ end
44
64
 
45
- # Station is a string containing the CCCC code, or
46
- # an object with a 'cccc' method which returns the code
47
- def initialize( station, data = nil )
48
- @cccc = station.respond_to?(:cccc) ? station.cccc : station
49
- parse data if data
50
- end
65
+ # Station is a string containing the CCCC code, or
66
+ # an object with a 'cccc' method which returns the code
67
+ def initialize(station)
68
+ @cccc = station.respond_to?(:cccc) ? station.cccc : station
69
+ end
51
70
 
52
- def data
53
- fetch
54
- @data
55
- end
56
- # #raw is deprecated, use #data
57
- alias :raw :data
71
+ def data
72
+ fetch
73
+ @data
74
+ end
75
+ # #raw is deprecated, use #data
76
+ alias :raw :data
58
77
 
59
- def time
60
- fetch
61
- @time
62
- end
78
+ def time
79
+ fetch
80
+ @time
81
+ end
63
82
 
64
- def raw_time
65
- fetch
66
- @raw_time
67
- end
83
+ def metar
84
+ fetch
85
+ @metar
86
+ end
68
87
 
69
- def metar
70
- fetch
71
- @metar
72
- end
73
- alias :to_s :metar
88
+ private
74
89
 
75
- private
90
+ def fetch
91
+ return if @data
92
+ @data = Noaa.fetch(@cccc)
93
+ parse
94
+ end
76
95
 
77
- def fetch
78
- return if @data
79
- parse Raw.fetch( @cccc )
80
- end
96
+ def parse
97
+ raw_time, @metar = @data.split("\n")
98
+ @time = Time.parse(raw_time)
99
+ super
100
+ end
81
101
 
82
- def parse( data )
83
- @data = data
84
- @raw_time, @metar = @data.split( "\n" )
85
- @time = Time.parse( @raw_time )
86
102
  end
87
103
 
88
104
  end
data/lib/metar/station.rb CHANGED
@@ -78,7 +78,7 @@ module Metar
78
78
  end
79
79
 
80
80
  def parser
81
- raw = Metar::Raw.new( @cccc )
81
+ raw = Metar::Raw::Noaa.new( @cccc )
82
82
  Metar::Parser.new( raw )
83
83
  end
84
84
 
data/lib/metar/version.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  module Metar
2
2
 
3
3
  module VERSION #:nodoc:
4
- MAJOR = 0
5
- MINOR = 9
6
- TINY = 15
4
+ MAJOR = 1
5
+ MINOR = 0
6
+ TINY = 0
7
7
 
8
8
  STRING = [ MAJOR, MINOR, TINY ].join( '.' )
9
9
  end
@@ -10,7 +10,7 @@ describe Metar::Parser do
10
10
  raw = stub( 'raw', :metar => "XXXX 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000",
11
11
  :time => '2010/02/06 16:10' )
12
12
  Metar::Station.stub!( :new => station )
13
- Metar::Raw.stub!( :new => raw )
13
+ Metar::Raw::Noaa.stub!( :new => raw )
14
14
 
15
15
  parser = Metar::Parser.for_cccc( 'XXXX' )
16
16
 
@@ -22,58 +22,70 @@ describe Metar::Parser do
22
22
 
23
23
  context 'attributes' do
24
24
 
25
+ before :each do
26
+ @call_time = Time.parse('2011-05-06 16:35')
27
+ Time.stub!(:now).and_return(@call_time)
28
+ end
29
+
25
30
  it '.location missing' do
26
31
  expect do
27
- setup_parser('PAIL', "2010/02/06 16:10\nFUBAR 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
28
- end. to raise_error( Metar::ParseError, /Expecting location/ )
32
+ setup_parser("FUBAR 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
33
+ end. to raise_error( Metar::ParseError, /Expecting location/ )
29
34
  end
30
35
 
31
36
  it '.time missing' do
32
37
  expect do
33
- setup_parser('PAIL', "2010/02/06 16:10\nPAIL 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
34
- end. to raise_error( Metar::ParseError, /Expecting datetime/ )
38
+ setup_parser("PAIL 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
39
+ end. to raise_error( Metar::ParseError, /Expecting datetime/ )
35
40
  end
36
41
 
37
- it 'date' do
38
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
39
- parser.date. should == Date.new(2010, 2, 6)
42
+ it 'time' do
43
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
44
+
45
+ parser.time. should == Time.gm(2011, 05, 06, 16, 10)
40
46
  end
41
47
 
42
48
  context '.observer' do
43
49
 
44
50
  it 'real' do
45
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
51
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
52
+
46
53
  parser.observer. should == :real
47
54
  end
48
55
 
49
56
  it 'auto' do
50
- parser = setup_parser('CYXS', "2010/02/15 10:34\nCYXS 151034Z AUTO 09003KT 1/8SM FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
57
+ parser = setup_parser("CYXS 151034Z AUTO 09003KT 1/8SM FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
51
58
 
52
59
  parser.observer. should == :auto
53
60
  end
54
61
 
55
62
  it 'corrected' do
56
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z COR 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
63
+ parser = setup_parser("PAIL 061610Z COR 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
64
+
57
65
  parser.observer. should == :corrected
58
66
  end
59
67
 
60
68
  end
61
69
 
62
70
  it 'wind' do
63
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
64
- parser.wind.direction.value. should be_within( 0.0001 ).of( 240 )
65
- parser.wind.speed.to_knots. should be_within( 0.0001 ).of( 6 )
71
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
72
+
73
+ parser.wind.direction.value.should be_within( 0.0001 ).of( 240 )
74
+ parser.wind.speed.to_knots. should be_within( 0.0001 ).of( 6 )
66
75
  end
67
76
 
68
77
  it 'variable_wind' do
69
- parser = setup_parser('LIRQ', "2010/02/06 15:20\nLIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
70
- parser.variable_wind.direction1.value.should be_within( 0.0001 ).of( 350 )
71
- parser.variable_wind.direction2.value.should be_within( 0.0001 ).of( 50 )
78
+ parser = setup_parser("LIRQ 061520Z 01007KT 350V050 9999 SCT035 BKN080 08/02 Q1005")
79
+
80
+ parser.variable_wind.direction1.value.
81
+ should be_within( 0.0001 ).of( 350 )
82
+ parser.variable_wind.direction2.value.
83
+ should be_within( 0.0001 ).of( 50 )
72
84
  end
73
85
 
74
86
  context '.visibility' do
75
87
  it 'CAVOK' do
76
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT CAVOK M17/M20 A2910 RMK AO2 P0000")
88
+ parser = setup_parser("PAIL 061610Z 24006KT CAVOK M17/M20 A2910 RMK AO2 P0000")
77
89
 
78
90
  parser.visibility.distance.value.
79
91
  should be_within( 0.01 ).of( 10000.00 )
@@ -90,43 +102,51 @@ describe Metar::Parser do
90
102
  end
91
103
 
92
104
  it 'visibility_miles_and_fractions' do
93
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
105
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
94
106
 
95
107
  parser.visibility.distance.to_miles.
96
108
  should be_within( 0.01 ).of( 1.75 )
97
109
  end
98
110
 
99
111
  it '//// with automatic observer' do
100
- parser = setup_parser('CYXS', "2010/02/15 10:34\nCYXS 151034Z AUTO 09003KT //// FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
112
+ parser = setup_parser("CYXS 151034Z AUTO 09003KT //// FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
101
113
 
102
114
  parser.visibility. should be_nil
103
115
  end
104
116
  end
105
117
 
106
118
  it 'runway_visible_range' do
107
- parser = setup_parser('ESSB', "2010/02/15 10:20\nESSB 151020Z 26003KT 2000 R12/1000N R30/1500N VV002 M07/M07 Q1013 1271//55")
108
- parser.runway_visible_range.length. should == 2
109
- parser.runway_visible_range[0].designator. should == '12'
110
- parser.runway_visible_range[0].visibility1.distance.value. should == 1000
111
- parser.runway_visible_range[0].tendency. should == :no_change
119
+ parser = setup_parser("ESSB 151020Z 26003KT 2000 R12/1000N R30/1500N VV002 M07/M07 Q1013 1271//55")
120
+ parser.runway_visible_range.length.
121
+ should == 2
122
+ parser.runway_visible_range[0].designator.
123
+ should == '12'
124
+ parser.runway_visible_range[0].visibility1.distance.value.
125
+ should == 1000
126
+ parser.runway_visible_range[0].tendency.
127
+ should == :no_change
112
128
  end
113
129
 
114
130
  it 'runway_visible_range_defaults_to_empty_array' do
115
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
116
- parser.runway_visible_range.length. should == 0
131
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
132
+
133
+ parser.runway_visible_range.length.
134
+ should == 0
117
135
  end
118
136
 
119
137
  it 'runway_visible_range_variable' do
120
- parser = setup_parser('KPDX', "2010/02/15 11:08\nKPDX 151108Z 11006KT 1/4SM R10R/1600VP6000FT FG OVC002 05/05 A3022 RMK AO2")
138
+ parser = setup_parser("KPDX 151108Z 11006KT 1/4SM R10R/1600VP6000FT FG OVC002 05/05 A3022 RMK AO2")
121
139
 
122
- parser.runway_visible_range[0].visibility1.distance.to_feet. should == 1600.0
123
- parser.runway_visible_range[0].visibility2.distance.to_feet. should == 6000.0
140
+ parser.runway_visible_range[0].visibility1.distance.to_feet.
141
+ should == 1600.0
142
+ parser.runway_visible_range[0].visibility2.distance.to_feet.
143
+ should == 6000.0
124
144
  end
125
145
 
126
146
  context '.present_weather' do
127
147
 
128
148
  it 'normal' do
129
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
149
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
130
150
 
131
151
  parser.present_weather.size.
132
152
  should == 1
@@ -137,7 +157,7 @@ describe Metar::Parser do
137
157
  end
138
158
 
139
159
  it 'auto + //' do
140
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z AUTO 24006KT 1 3/4SM // BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
160
+ parser = setup_parser("PAIL 061610Z AUTO 24006KT 1 3/4SM // BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
141
161
 
142
162
  parser.present_weather.size.
143
163
  should == 1
@@ -148,29 +168,30 @@ describe Metar::Parser do
148
168
  end
149
169
 
150
170
  it 'present_weather_defaults_to_empty_array' do
151
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
152
- parser.present_weather.length. should == 0
171
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
172
+ parser.present_weather.length.
173
+ should == 0
153
174
  end
154
175
 
155
176
  context '.sky_conditions' do
156
177
 
157
178
  it 'normal' do
158
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
179
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
159
180
 
160
181
  parser.sky_conditions.size.
161
182
  should == 2
162
183
  parser.sky_conditions[0].quantity.
163
184
  should == 'broken'
164
185
  parser.sky_conditions[0].height.value.
165
- should == 480
186
+ should == 487.68
166
187
  parser.sky_conditions[1].quantity.
167
188
  should == 'overcast'
168
189
  parser.sky_conditions[1].height.value.
169
- should == 900
190
+ should == 914.40
170
191
  end
171
192
 
172
193
  it 'auto + ///' do
173
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z AUTO 24006KT 1 3/4SM /// M17/M20 A2910 RMK AO2 P0000")
194
+ parser = setup_parser("PAIL 061610Z AUTO 24006KT 1 3/4SM /// M17/M20 A2910 RMK AO2 P0000")
174
195
 
175
196
  parser.sky_conditions.size.
176
197
  should == 0
@@ -179,53 +200,58 @@ describe Metar::Parser do
179
200
  end
180
201
 
181
202
  it 'sky_conditions_defaults_to_empty_array' do
182
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN M17/M20 A2910 RMK AO2 P0000")
183
- parser.sky_conditions.length. should == 0
203
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN M17/M20 A2910 RMK AO2 P0000")
204
+ parser.sky_conditions.length.
205
+ should == 0
184
206
  end
185
207
 
186
208
  it 'vertical_visibility' do
187
- parser = setup_parser('CYXS', "2010/02/15 10:34\nCYXS 151034Z AUTO 09003KT 1/8SM FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
188
- parser.vertical_visibility.value. should == 30
209
+ parser = setup_parser("CYXS 151034Z AUTO 09003KT 1/8SM FZFG VV001 M03/M03 A3019 RMK SLP263 ICG")
210
+ parser.vertical_visibility.value.
211
+ should == 30.48
189
212
  end
190
213
 
191
214
  it 'temperature_obligatory' do
192
215
  expect do
193
- setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 A2910 RMK AO2 P0000")
194
- end. to raise_error( Metar::ParseError )
216
+ setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 A2910 RMK AO2 P0000")
217
+ end. to raise_error( Metar::ParseError )
195
218
  end
196
219
 
197
220
  it 'temperature' do
198
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
199
- parser.temperature.value. should == -17
221
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
222
+ parser.temperature.value. should == -17
200
223
  end
201
224
 
202
225
  it 'dew_point' do
203
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
204
- parser.dew_point.value. should == -20
226
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
227
+ parser.dew_point.value. should == -20
205
228
  end
206
229
 
207
230
  it 'sea_level_pressure' do
208
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
209
- parser.sea_level_pressure.to_inches_of_mercury. should == 29.10
231
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
232
+ parser.sea_level_pressure.to_inches_of_mercury.
233
+ should == 29.10
210
234
  end
211
235
 
212
236
  it 'remarks' do
213
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
214
- parser.remarks. should be_a Array
215
- parser.remarks.length. should == 2
216
- parser.remarks[0]. should == 'AO2'
217
- parser.remarks[1]. should == 'P0000'
237
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000")
238
+
239
+ parser.remarks. should be_a Array
240
+ parser.remarks.length. should == 2
241
+ parser.remarks[0]. should == 'AO2'
242
+ parser.remarks[1]. should == 'P0000'
218
243
  end
219
244
 
220
245
  it 'remarks_defaults_to_empty_array' do
221
- parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910")
222
- parser.remarks. should be_a Array
223
- parser.remarks.length. should == 0
246
+ parser = setup_parser("PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910")
247
+
248
+ parser.remarks. should be_a Array
249
+ parser.remarks.length. should == 0
224
250
  end
225
251
 
226
- def setup_parser( cccc, metar )
227
- raw = Metar::Raw.new( cccc, metar )
228
- Metar::Parser.new( raw )
252
+ def setup_parser(metar)
253
+ raw = Metar::Raw::Data.new(metar)
254
+ Metar::Parser.new(raw)
229
255
  end
230
256
 
231
257
  end
@@ -1,12 +1,49 @@
1
- load File.expand_path( '../spec_helper.rb', File.dirname(__FILE__) )
2
1
  # encoding: utf-8
2
+ load File.expand_path( '../spec_helper.rb', File.dirname(__FILE__) )
3
3
 
4
4
  require 'net/ftp'
5
+ require 'time'
6
+
7
+ module MetarRawTestHelper
8
+
9
+ def noaa_metar
10
+ raw_time = "2010/02/15 10:20"
11
+ "#{ raw_time }\n#{ raw_metar }"
12
+ end
13
+
14
+ def raw_metar
15
+ "ESSB 151020Z 26003KT 2000 R12/1000N R30/1500N VV002 M07/M07 Q1013 1271//55"
16
+ end
5
17
 
6
- describe Metar::Raw do
18
+ end
19
+
20
+ describe Metar::Raw::Data do
21
+
22
+ include MetarRawTestHelper
23
+
24
+ context 'initialization' do
25
+
26
+ it 'should parse data, if supplied' do
27
+ @call_time = Time.parse('2012-07-29 16:35')
28
+ Time.stub!(:now).and_return(@call_time)
29
+
30
+ raw = Metar::Raw::Data.new(raw_metar)
31
+
32
+ raw.metar. should == raw_metar
33
+ raw.cccc. should == 'ESSB'
34
+ raw.time. should == @call_time
35
+ end
36
+
37
+ end
38
+
39
+ end
40
+
41
+ describe Metar::Raw::Noaa do
42
+
43
+ include MetarRawTestHelper
7
44
 
8
45
  after :each do
9
- Metar::Raw.send( :class_variable_set, '@@connection', nil )
46
+ Metar::Raw::Noaa.send( :class_variable_set, '@@connection', nil )
10
47
  end
11
48
 
12
49
  context '.connection' do
@@ -19,7 +56,7 @@ describe Metar::Raw do
19
56
  Net::FTP. should_receive( :new ).
20
57
  and_return( ftp )
21
58
 
22
- Metar::Raw.connect
59
+ Metar::Raw::Noaa.connect
23
60
  end
24
61
 
25
62
  end
@@ -28,17 +65,17 @@ describe Metar::Raw do
28
65
 
29
66
  before :each do
30
67
  @ftp = stub( 'ftp' )
31
- Metar::Raw.send( :class_variable_set, '@@connection', @ftp )
68
+ Metar::Raw::Noaa.send( :class_variable_set, '@@connection', @ftp )
32
69
  end
33
70
 
34
71
  it 'does not connect to FTP' do
35
72
  Net::FTP. should_not_receive( :new )
36
73
 
37
- Metar::Raw.connection
74
+ Metar::Raw::Noaa.connection
38
75
  end
39
76
 
40
77
  it 'returns the cached connection' do
41
- connection = Metar::Raw.connection
78
+ connection = Metar::Raw::Noaa.connection
42
79
 
43
80
  connection. should == @ftp
44
81
  end
@@ -59,7 +96,7 @@ describe Metar::Raw do
59
96
  ftp. should_receive( :passive= ).
60
97
  with( true )
61
98
 
62
- Metar::Raw.connect
99
+ Metar::Raw::Noaa.connect
63
100
  end
64
101
 
65
102
  end
@@ -72,7 +109,7 @@ describe Metar::Raw do
72
109
  Net::FTP. should_receive( :new ).
73
110
  and_return( ftp )
74
111
 
75
- Metar::Raw.fetch( 'the_cccc' )
112
+ Metar::Raw::Noaa.fetch( 'the_cccc' )
76
113
  end
77
114
 
78
115
  it 'downloads the raw report' do
@@ -84,7 +121,7 @@ describe Metar::Raw do
84
121
  args[ 1 ]. should be_a Fixnum
85
122
  end
86
123
 
87
- Metar::Raw.fetch( 'the_cccc' )
124
+ Metar::Raw::Noaa.fetch( 'the_cccc' )
88
125
  end
89
126
 
90
127
  it 'returns the data' do
@@ -95,7 +132,7 @@ describe Metar::Raw do
95
132
  end
96
133
  Net::FTP.stub!( :new ).and_return( ftp )
97
134
 
98
- raw = Metar::Raw.fetch( 'the_cccc' )
135
+ raw = Metar::Raw::Noaa.fetch( 'the_cccc' )
99
136
 
100
137
  raw. should == "chunk 1\nchunk 2\n"
101
138
  end
@@ -117,7 +154,7 @@ describe Metar::Raw do
117
154
  end
118
155
  Net::FTP.stub!( :new ).and_return( ftp )
119
156
 
120
- raw = Metar::Raw.fetch( 'the_cccc' )
157
+ raw = Metar::Raw::Noaa.fetch( 'the_cccc' )
121
158
 
122
159
  raw. should == "chunk 1\nchunk 2\n"
123
160
  end
@@ -138,7 +175,7 @@ describe Metar::Raw do
138
175
  Net::FTP.stub!( :new ).and_return( ftp )
139
176
 
140
177
  expect do
141
- Metar::Raw.fetch( 'the_cccc' )
178
+ Metar::Raw::Noaa.fetch( 'the_cccc' )
142
179
  end. to raise_error( RuntimeError, /failed 2 times/)
143
180
  end
144
181
 
@@ -147,50 +184,35 @@ describe Metar::Raw do
147
184
  context 'initialization' do
148
185
 
149
186
  it 'should accept CCCC codes' do
150
- raw = Metar::Raw.new( 'XXXX' )
187
+ raw = Metar::Raw::Noaa.new( 'XXXX' )
151
188
 
152
189
  raw.cccc. should == 'XXXX'
153
190
  end
154
191
 
155
192
  it 'should accept Stations' do
156
193
  station = stub( 'Metar::Station', :cccc => 'YYYY' )
157
- raw = Metar::Raw.new( station )
194
+ raw = Metar::Raw::Noaa.new( station )
158
195
 
159
196
  raw.cccc. should == 'YYYY'
160
197
  end
161
-
162
- it 'should parse data, if supplied' do
163
- raw = Metar::Raw.new( 'XXXX', raw_metar )
164
-
165
- raw.data. should == raw_metar
166
- raw.raw_time. should == @raw_time
167
- raw.metar. should == @metar
168
- raw.time. should == Time.parse( @raw_time )
169
- end
170
198
 
171
199
  end
172
200
 
173
201
  context 'lazy loading' do
174
202
 
175
203
  it 'should fetch data on demand' do
176
- raw = Metar::Raw.new( 'ESSB' )
204
+ raw = Metar::Raw::Noaa.new( 'ESSB' )
177
205
 
178
- Metar::Raw. should_receive( :fetch ).
206
+ Metar::Raw::Noaa. should_receive(:fetch).
179
207
  with( 'ESSB' ).
180
- and_return( raw_metar )
208
+ and_return(noaa_metar)
181
209
 
182
210
  raw.metar
183
211
 
184
- raw.data. should == raw_metar
212
+ raw.data. should == noaa_metar
185
213
  end
186
214
 
187
215
  end
188
216
 
189
- def raw_metar
190
- @raw_time = "2010/02/15 10:20"
191
- @metar = "ESSB 151020Z 26003KT 2000 R12/1000N R30/1500N VV002 M07/M07 Q1013 1271//55"
192
- "#{ @raw_time }\n#{ @metar }"
193
- end
194
-
195
217
  end
196
218
 
@@ -24,11 +24,11 @@ describe Metar::SkyCondition do
24
24
  context '.parse' do
25
25
 
26
26
  [
27
- [ 'understands clear skies codes', 'NSC', [ nil, nil, nil ] ],
28
- [ 'quantity + height', 'BKN12', [ 'broken', 360, nil ] ],
29
- [ 'quantity + height + type', 'BKN12CB', [ 'broken', 360, 'cumulonimbus' ] ],
30
- [ 'quantity + height + ///', 'BKN12///', [ 'broken', 360, nil ] ],
31
- [ 'returns nil for unmatched', 'FUBAR', [ :expect_nil, nil, nil ] ],
27
+ [ 'understands clear skies codes', 'NSC', [ nil, nil, nil ] ],
28
+ [ 'quantity + height', 'BKN12', [ 'broken', 365.76, nil ] ],
29
+ [ 'quantity + height + type', 'BKN12CB', [ 'broken', 365.76, 'cumulonimbus' ] ],
30
+ [ 'quantity + height + ///', 'BKN12///', [ 'broken', 365.76, nil ] ],
31
+ [ 'returns nil for unmatched', 'FUBAR', [ :expect_nil, nil, nil ] ],
32
32
  ].each do | docstring, raw, expected |
33
33
  example docstring do
34
34
  Metar::SkyCondition.parse( raw ).should be_sky_condition( *expected )
@@ -232,7 +232,7 @@ EOT
232
232
  before :each do
233
233
  @raw = stub('raw', :metar => 'PAIL 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000', :time => '2010/02/06 16:10' )
234
234
  # TODO: hack - once parser returns station this can be removed
235
- Metar::Raw. should_receive( :new ).
235
+ Metar::Raw::Noaa. should_receive( :new ).
236
236
  and_return( @raw )
237
237
  end
238
238
 
@@ -22,7 +22,7 @@ describe Metar::VerticalVisibility do
22
22
  context '.parse' do
23
23
 
24
24
  [
25
- [ 'VV + nnn', 'VV300', 9000 ],
25
+ [ 'VV + nnn', 'VV300', 9144 ],
26
26
  [ '///', '///', nil ],
27
27
  [ 'returns nil for unmatched', 'FUBAR', :expect_nil ],
28
28
  ].each do | docstring, raw, expected |
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: metar-parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.15
4
+ version: 1.0.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-28 00:00:00.000000000 Z
12
+ date: 2012-07-29 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -176,7 +176,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
176
176
  version: '0'
177
177
  segments:
178
178
  - 0
179
- hash: -2658375331668671320
179
+ hash: 2800563498014087456
180
180
  required_rubygems_version: !ruby/object:Gem::Requirement
181
181
  none: false
182
182
  requirements:
@@ -185,7 +185,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
185
185
  version: '0'
186
186
  segments:
187
187
  - 0
188
- hash: -2658375331668671320
188
+ hash: 2800563498014087456
189
189
  requirements: []
190
190
  rubyforge_project: nowarning
191
191
  rubygems_version: 1.8.23