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 +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
|