metar-parser 0.9.11 → 0.9.12

Sign up to get free protection for your applications and to get access to all the features.
data/lib/metar/station.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'rubygems' if RUBY_VERSION < '1.9'
2
1
  require 'open-uri'
3
2
  require 'set'
4
3
 
@@ -14,7 +13,6 @@ module Metar
14
13
  class << self
15
14
 
16
15
  @nsd_cccc = nil # Contains the text of the station list
17
- attr_accessor :nsd_cccc # Allow tests to run from local file
18
16
 
19
17
  def download_local
20
18
  nsd_cccc = Metar::Station.download_stations
@@ -33,7 +31,7 @@ module Metar
33
31
  end
34
32
 
35
33
  def countries
36
- all_structures.reduce( Set.new ) { |a, s| a.add( s[ :country ] ); a }
34
+ all_structures.reduce( Set.new ) { |a, s| a.add( s[ :country ] ) }.to_a.sort
37
35
  end
38
36
 
39
37
  def all
@@ -44,6 +42,10 @@ module Metar
44
42
  end
45
43
  end
46
44
 
45
+ def find_by_cccc(cccc)
46
+ all.find { |station| station.cccc == cccc }
47
+ end
48
+
47
49
  # Does the given CCCC code exist?
48
50
  def exist?(cccc)
49
51
  not find_data_by_cccc(cccc).nil?
@@ -53,10 +55,6 @@ module Metar
53
55
  all.select { | s | s.country == country }
54
56
  end
55
57
 
56
- def find_by_cccc(cccc)
57
- all.find { |station| station.cccc == cccc }
58
- end
59
-
60
58
  def to_longitude(s)
61
59
  s =~ /^(\d+)-(\d+)([EW])/ or return nil
62
60
  ($3 == 'E' ? 1.0 : -1.0) * ($1.to_f + $2.to_f / 60.0)
@@ -68,64 +66,23 @@ module Metar
68
66
  end
69
67
  end
70
68
 
71
- attr_reader :cccc, :loaded
69
+ attr_reader :cccc, :name, :state, :country, :longitude, :latitude, :raw
72
70
  alias :code :cccc
73
- # loaded? indicates whether the data has been collected from the Web
74
- alias :loaded? :loaded
75
71
 
76
72
  # No check is made on the existence of the station
77
- def initialize(cccc, options = {})
78
- raise "Station identifier must not be nil" if cccc.nil?
79
- raise "Station identifier must be a text" if not cccc.respond_to?('to_s')
80
- @cccc = cccc
81
- @name = options[:name]
82
- @state = options[:state]
83
- @country = options[:country]
84
- @longitude = options[:longitude]
85
- @latitude = options[:latitude]
86
- @raw = options[:raw]
87
- @loaded = false
73
+ def initialize( cccc, noaa_data )
74
+ raise "Station identifier must not be nil" if cccc.nil?
75
+ raise "Station identifier must not be empty" if cccc.to_s == ''
76
+ @cccc = cccc
77
+ load! noaa_data
88
78
  end
89
79
 
90
- # Lazy loaded attributes
91
- ## TODO: DRY this up by generating these methods
92
- def name
93
- load! if not @loaded
94
- @name
95
- end
96
-
97
- def state
98
- load! if not @loaded
99
- @state
100
- end
101
-
102
- def country
103
- load! if not @loaded
104
- @country
105
- end
106
-
107
- def latitude
108
- load! if not @loaded
109
- @latitude
110
- end
111
-
112
- def longitude
113
- load! if not @loaded
114
- @longitude
115
- end
116
-
117
- def raw
118
- load! if not @loaded
119
- @raw
120
- end
121
-
122
- def exist?
123
- Station.exist?(@cccc)
80
+ def parser
81
+ raw = Metar::Raw.new( @cccc )
82
+ Metar::Parser.new( raw )
124
83
  end
125
84
 
126
85
  def report
127
- raw = Metar::Raw.new( @cccc )
128
- parser = Metar::Parser.new( raw )
129
86
  Metar::Report.new( parser )
130
87
  end
131
88
 
@@ -172,20 +129,16 @@ module Metar
172
129
 
173
130
  end
174
131
 
175
- # Get data from the NOAA data file (very slow on first call!)
176
- def load!
177
- noaa_data = Station.find_data_by_cccc(@cccc)
178
- raise "Station identifier '#{ @cccc }' not found" if noaa_data.nil?
132
+ def load!( noaa_data )
179
133
  @name = noaa_data[:name]
180
134
  @state = noaa_data[:state]
181
135
  @country = noaa_data[:country]
182
136
  @longitude = Station.to_longitude(noaa_data[:longitude])
183
137
  @latitude = Station.to_latitude(noaa_data[:latitude])
184
138
  @raw = noaa_data[:raw]
185
- @loaded = true
186
- self
187
139
  end
188
140
 
189
141
  end
190
142
 
191
143
  end
144
+
data/lib/metar/version.rb CHANGED
@@ -3,7 +3,7 @@ module Metar
3
3
  module VERSION #:nodoc:
4
4
  MAJOR = 0
5
5
  MINOR = 9
6
- TINY = 11
6
+ TINY = 12
7
7
 
8
8
  STRING = [ MAJOR, MINOR, TINY ].join( '.' )
9
9
  end
data/locales/en.yml CHANGED
@@ -6,6 +6,10 @@ en:
6
6
  comparison:
7
7
  more_than: more than
8
8
  less_than: less than
9
+ tendency:
10
+ no_change: no change
11
+ improving: improving
12
+ worsening: worsening
9
13
  units:
10
14
  pressure:
11
15
  bar:
@@ -34,6 +38,7 @@ en:
34
38
  variable_direction: variable direction
35
39
  unknown_direction: unknown direction
36
40
  unknown_speed: unknown speed
41
+ gusts: gusts
37
42
  variable_wind:
38
43
  title: wind variation
39
44
  visibility:
@@ -147,6 +152,7 @@ en:
147
152
  temperature:
148
153
  title: temperature
149
154
  dew_point:
150
- title: punto di rugiada
155
+ title: dew point
151
156
  remarks:
152
- title: annotazioni
157
+ title: remarks
158
+
data/locales/it.yml CHANGED
@@ -6,6 +6,10 @@ it:
6
6
  comparison:
7
7
  more_than: piú di
8
8
  less_than: meno di
9
+ tendency:
10
+ no_change: invariato
11
+ improving: in miglioramento
12
+ worsening: tendente a peggiorare
9
13
  units:
10
14
  pressure:
11
15
  bar:
@@ -34,6 +38,7 @@ it:
34
38
  variable_direction: direzione variabile
35
39
  unknown_direction: direzione sconosciuta
36
40
  unknown_speed: velocità sconosciuta
41
+ gusts: folate di
37
42
  variable_wind:
38
43
  title: variazione del vento
39
44
  visibility:
@@ -150,3 +155,4 @@ it:
150
155
  title: punto di rugiada
151
156
  remarks:
152
157
  title: annotazioni
158
+
@@ -0,0 +1,5 @@
1
+ require 'rspec'
2
+ require 'rspec/autorun'
3
+
4
+ require File.expand_path( File.dirname(__FILE__) + '/../lib/metar' )
5
+
@@ -0,0 +1,85 @@
1
+ load File.expand_path( '../spec_helper.rb', File.dirname(__FILE__) )
2
+
3
+ describe Metar::Distance do
4
+
5
+ context '#value' do
6
+
7
+ it 'should treat the parameter as meters' do
8
+ @distance = Metar::Distance.new( 12345.67 )
9
+
10
+ @distance.units. should == :meters
11
+ @distance.value. should == 12345.67
12
+ end
13
+
14
+ end
15
+
16
+ context '#to_s' do
17
+
18
+ it 'should default to meters' do
19
+ @distance = Metar::Distance.new( rand * 1000.0 )
20
+
21
+ @distance.to_s. should =~ %r(^\d+m)
22
+ end
23
+
24
+ it 'should round down to the nearest meter' do
25
+ @distance = Metar::Distance.new( 12.345 )
26
+
27
+ @distance.to_s. should == '12m'
28
+ end
29
+
30
+ it 'should round up to meters' do
31
+ @distance = Metar::Distance.new( 8.750 )
32
+
33
+ @distance.to_s. should == '9m'
34
+ end
35
+
36
+ it 'should allow units overrides' do
37
+ @distance = Metar::Distance.new( 12345.67 )
38
+
39
+ @distance.to_s( :units => :kilometers ).
40
+ should == '12km'
41
+ end
42
+
43
+ it 'should allow precision overrides' do
44
+ @distance = Metar::Distance.new( 12.34567 )
45
+
46
+ @distance.to_s( :precision => 1 ).
47
+ should == '12.3m'
48
+ end
49
+
50
+ it 'should handle nil' do
51
+ @distance = Metar::Distance.new( nil )
52
+
53
+ @distance.to_s. should == 'unknown'
54
+ end
55
+
56
+ context 'translated' do
57
+
58
+ before :each do
59
+ @locale = I18n.locale
60
+ I18n.locale = :it
61
+ end
62
+
63
+ after :each do
64
+ I18n.locale = @locale
65
+ end
66
+
67
+ it 'should allow precision overrides' do
68
+ @distance = Metar::Distance.new( 12.34567 )
69
+
70
+ @distance.to_s( :precision => 1 ).
71
+ should == '12,3m'
72
+ end
73
+
74
+ it 'should handle nil' do
75
+ @distance = Metar::Distance.new( nil )
76
+
77
+ @distance.to_s. should == 'sconosciuto'
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+
84
+ end
85
+
@@ -0,0 +1,234 @@
1
+ load File.expand_path( '../spec_helper.rb', File.dirname(__FILE__) )
2
+ # encoding: utf-8
3
+
4
+ describe Metar::Parser do
5
+
6
+ context '.for_cccc' do
7
+
8
+ it 'returns a loaded parser' do
9
+ station = stub( 'station' )
10
+ raw = stub( 'raw', :metar => "XXXX 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000",
11
+ :time => '2010/02/06 16:10' )
12
+ Metar::Station.stub!( :new => station )
13
+ Metar::Raw.stub!( :new => raw )
14
+
15
+ parser = Metar::Parser.for_cccc( 'XXXX' )
16
+
17
+ parser. should be_a( Metar::Parser )
18
+ parser.station_code. should == 'XXXX'
19
+ end
20
+
21
+ end
22
+
23
+ context 'attributes' do
24
+
25
+ it '.location missing' do
26
+ 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/ )
29
+ end
30
+
31
+ it '.time missing' do
32
+ 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/ )
35
+ end
36
+
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)
40
+ end
41
+
42
+ context '.observer' do
43
+
44
+ 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")
46
+ parser.observer. should == :real
47
+ end
48
+
49
+ 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")
51
+
52
+ parser.observer. should == :auto
53
+ end
54
+
55
+ 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")
57
+ parser.observer. should == :corrected
58
+ end
59
+
60
+ end
61
+
62
+ 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 )
66
+ end
67
+
68
+ 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 )
72
+ end
73
+
74
+ context '.visibility' do
75
+ it 'CAVOK' do
76
+ parser = setup_parser('PAIL', "2010/02/06 16:10\nPAIL 061610Z 24006KT CAVOK M17/M20 A2910 RMK AO2 P0000")
77
+
78
+ parser.visibility.distance.value.
79
+ should be_within( 0.01 ).of( 10000.00 )
80
+ parser.visibility.comparator.
81
+ should == :more_than
82
+ parser.present_weather.size.
83
+ should == 1
84
+ parser.present_weather[ 0 ].phenomenon.
85
+ should == 'No significant weather'
86
+ parser.sky_conditions.size.
87
+ should == 1
88
+ parser.sky_conditions[ 0 ].type.
89
+ should == nil
90
+ end
91
+
92
+ 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")
94
+
95
+ parser.visibility.distance.to_miles.
96
+ should be_within( 0.01 ).of( 1.75 )
97
+ end
98
+
99
+ 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")
101
+
102
+ parser.visibility. should be_nil
103
+ end
104
+ end
105
+
106
+ 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
112
+ end
113
+
114
+ 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
117
+ end
118
+
119
+ 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")
121
+
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
124
+ end
125
+
126
+ context '.present_weather' do
127
+
128
+ 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")
130
+
131
+ parser.present_weather.size.
132
+ should == 1
133
+ parser.present_weather[0].modifier.
134
+ should == 'light'
135
+ parser.present_weather[0].phenomenon.
136
+ should == 'snow'
137
+ end
138
+
139
+ 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")
141
+
142
+ parser.present_weather.size.
143
+ should == 1
144
+ parser.present_weather[0].phenomenon.
145
+ should == 'not observed'
146
+ end
147
+
148
+ end
149
+
150
+ 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
153
+ end
154
+
155
+ context '.sky_conditions' do
156
+
157
+ 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")
159
+
160
+ parser.sky_conditions.size.
161
+ should == 2
162
+ parser.sky_conditions[0].quantity.
163
+ should == 'broken'
164
+ parser.sky_conditions[0].height.value.
165
+ should == 480
166
+ parser.sky_conditions[1].quantity.
167
+ should == 'overcast'
168
+ parser.sky_conditions[1].height.value.
169
+ should == 900
170
+ end
171
+
172
+ 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")
174
+
175
+ parser.sky_conditions.size.
176
+ should == 0
177
+ end
178
+
179
+ end
180
+
181
+ 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
184
+ end
185
+
186
+ 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
189
+ end
190
+
191
+ it 'temperature_obligatory' do
192
+ 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 )
195
+ end
196
+
197
+ 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
200
+ end
201
+
202
+ 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
205
+ end
206
+
207
+ 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
210
+ end
211
+
212
+ 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'
218
+ end
219
+
220
+ 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
224
+ end
225
+
226
+ def setup_parser( cccc, metar )
227
+ raw = Metar::Raw.new( cccc, metar )
228
+ Metar::Parser.new( raw )
229
+ end
230
+
231
+ end
232
+
233
+ end
234
+