metar-parser 0.9.15 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +14 -2
- data/lib/metar/data.rb +2 -2
- data/lib/metar/parser.rb +7 -8
- data/lib/metar/raw.rb +79 -63
- data/lib/metar/station.rb +1 -1
- data/lib/metar/version.rb +3 -3
- data/spec/unit/parser_spec.rb +87 -61
- data/spec/unit/raw_spec.rb +56 -34
- data/spec/unit/sky_condition_spec.rb +5 -5
- data/spec/unit/station_spec.rb +1 -1
- data/spec/unit/vertical_visibility_spec.rb +1 -1
- metadata +4 -4
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 = "
|
66
|
-
raw = Metar::Raw.new(
|
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.
|
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.
|
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
|
-
|
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
|
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
|
104
|
-
|
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] =~
|
141
|
-
@
|
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
|
-
|
6
|
+
module Raw
|
6
7
|
|
7
|
-
|
8
|
+
class Base
|
9
|
+
attr_reader :cccc
|
10
|
+
attr_reader :metar
|
11
|
+
attr_reader :time
|
12
|
+
alias :to_s :metar
|
8
13
|
|
9
|
-
|
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
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
63
|
+
end
|
44
64
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
71
|
+
def data
|
72
|
+
fetch
|
73
|
+
@data
|
74
|
+
end
|
75
|
+
# #raw is deprecated, use #data
|
76
|
+
alias :raw :data
|
58
77
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
78
|
+
def time
|
79
|
+
fetch
|
80
|
+
@time
|
81
|
+
end
|
63
82
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
83
|
+
def metar
|
84
|
+
fetch
|
85
|
+
@metar
|
86
|
+
end
|
68
87
|
|
69
|
-
|
70
|
-
fetch
|
71
|
-
@metar
|
72
|
-
end
|
73
|
-
alias :to_s :metar
|
88
|
+
private
|
74
89
|
|
75
|
-
|
90
|
+
def fetch
|
91
|
+
return if @data
|
92
|
+
@data = Noaa.fetch(@cccc)
|
93
|
+
parse
|
94
|
+
end
|
76
95
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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
data/lib/metar/version.rb
CHANGED
data/spec/unit/parser_spec.rb
CHANGED
@@ -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(
|
28
|
-
end.
|
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(
|
34
|
-
end.
|
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 '
|
38
|
-
parser = setup_parser(
|
39
|
-
|
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(
|
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(
|
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(
|
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(
|
64
|
-
|
65
|
-
parser.wind.
|
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(
|
70
|
-
|
71
|
-
parser.variable_wind.
|
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(
|
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(
|
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(
|
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(
|
108
|
-
parser.runway_visible_range.length.
|
109
|
-
|
110
|
-
parser.runway_visible_range[0].
|
111
|
-
|
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(
|
116
|
-
|
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(
|
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.
|
123
|
-
|
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(
|
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(
|
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(
|
152
|
-
parser.present_weather.length.
|
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(
|
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 ==
|
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 ==
|
190
|
+
should == 914.40
|
170
191
|
end
|
171
192
|
|
172
193
|
it 'auto + ///' do
|
173
|
-
parser = setup_parser(
|
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(
|
183
|
-
parser.sky_conditions.length.
|
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(
|
188
|
-
parser.vertical_visibility.value.
|
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(
|
194
|
-
end.
|
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(
|
199
|
-
parser.temperature.value.
|
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(
|
204
|
-
parser.dew_point.value.
|
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(
|
209
|
-
parser.sea_level_pressure.to_inches_of_mercury.
|
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(
|
214
|
-
|
215
|
-
parser.remarks.
|
216
|
-
parser.remarks
|
217
|
-
parser.remarks[
|
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(
|
222
|
-
|
223
|
-
parser.remarks.
|
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(
|
227
|
-
raw = Metar::Raw.new(
|
228
|
-
Metar::Parser.new(
|
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
|
data/spec/unit/raw_spec.rb
CHANGED
@@ -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
|
-
|
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.
|
206
|
+
Metar::Raw::Noaa. should_receive(:fetch).
|
179
207
|
with( 'ESSB' ).
|
180
|
-
and_return(
|
208
|
+
and_return(noaa_metar)
|
181
209
|
|
182
210
|
raw.metar
|
183
211
|
|
184
|
-
raw.data. should ==
|
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',
|
29
|
-
[ 'quantity + height + type', 'BKN12CB', [ 'broken',
|
30
|
-
[ 'quantity + height + ///', 'BKN12///', [ 'broken',
|
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 )
|
data/spec/unit/station_spec.rb
CHANGED
@@ -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.
|
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',
|
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.
|
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-
|
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:
|
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:
|
188
|
+
hash: 2800563498014087456
|
189
189
|
requirements: []
|
190
190
|
rubyforge_project: nowarning
|
191
191
|
rubygems_version: 1.8.23
|