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