metar-parser 1.1.8 → 1.2.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.
- checksums.yaml +7 -0
- data/README.md +39 -24
- data/Rakefile +0 -11
- data/bin/parse_raw.rb +0 -1
- data/lib/metar/raw.rb +57 -18
- data/lib/metar/version.rb +2 -2
- data/spec/spec_helper.rb +0 -1
- data/spec/unit/distance_spec.rb +36 -46
- data/spec/unit/parser_spec.rb +32 -11
- data/spec/unit/pressure_spec.rb +6 -17
- data/spec/unit/raw_spec.rb +117 -38
- data/spec/unit/remark_spec.rb +34 -39
- data/spec/unit/report_spec.rb +92 -102
- data/spec/unit/runway_visible_range_spec.rb +3 -4
- data/spec/unit/sky_condition_spec.rb +2 -2
- data/spec/unit/speed_spec.rb +11 -17
- data/spec/unit/station_spec.rb +92 -101
- data/spec/unit/temperature_spec.rb +8 -19
- data/spec/unit/variable_wind_spec.rb +9 -17
- data/spec/unit/vertical_visibility_spec.rb +8 -14
- data/spec/unit/visibility_spec.rb +16 -19
- data/spec/unit/weather_phenomenon_spec.rb +3 -4
- data/spec/unit/wind_spec.rb +13 -14
- metadata +147 -163
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5f2c3aa5a4cae4d28cfa2ac65827416eae8ea706
|
4
|
+
data.tar.gz: 2edc10a772b9142531f3e3a942b5c913d043c98b
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: aa27381ba8e8bca2a90df135f4d1d3d9558d8c063f119e575a51e76577b4bb97164412204d0cffd49d4557e6ea99654ddd44b48c3781dfd4826bb3a4e18c93dd
|
7
|
+
data.tar.gz: 18eb8ba4319e3864b129dce58fffc9231623e63da8f8c737445c53693e5eaef669c9d4da3c87377d2b3dffcdaac00787a848c51fcd679cecd31d47396a2e08e5
|
data/README.md
CHANGED
@@ -15,19 +15,15 @@ metar-parser [
|
|
36
32
|
puts station.report.to_s
|
37
33
|
```
|
38
34
|
|
39
|
-
|
40
|
-
---------
|
35
|
+
## Using Your Own Raw Data
|
41
36
|
|
42
|
-
|
37
|
+
The parser needs to know the full date when the reading was taken. Unfortunately,
|
38
|
+
the METAR string itself only contains the day of the month.
|
39
|
+
|
40
|
+
### When you know the date of the reading
|
41
|
+
|
42
|
+
Use `Metar::Raw::Data` and supply the date as the second parameter:
|
43
43
|
|
44
44
|
```ruby
|
45
|
-
|
45
|
+
metar_string = "KHWD 280554Z AUTO 29007KT 10SM OVC008 14/12 A3002 RMK AO2 SLP176 T01390117 10211\n"
|
46
|
+
raw = Metar::Raw::Data.new(metar_string, reading_date)
|
47
|
+
parser = Metar::Parser.new(raw)
|
46
48
|
```
|
47
49
|
|
48
|
-
|
50
|
+
### When you do not know the date
|
51
|
+
|
52
|
+
Use `Metar::Raw::Metar` - the library will choose the date as the most recent
|
53
|
+
day with the day of the month indicated in the METAR string:
|
54
|
+
|
55
|
+
I.e. on 11th April 2016:
|
49
56
|
|
50
57
|
```ruby
|
51
|
-
|
58
|
+
metar_string = "KHWD 280554Z AUTO 29007KT 10SM OVC008 14/12 A3002 RMK AO2 SLP176 T01390117 10211\n"
|
59
|
+
raw = Metar::Raw::Metar.new(metar_string)
|
60
|
+
raw.time.to_s # => "2016-03-28"
|
61
|
+
parser = Metar::Parser.new(raw)
|
52
62
|
```
|
53
63
|
|
54
|
-
|
55
|
-
|
64
|
+
## Access Specific Data
|
65
|
+
|
56
66
|
```ruby
|
57
67
|
station = Metar::Station.find_by_cccc('KPDX')
|
58
68
|
parser = station.parser
|
59
69
|
puts parser.temperature.value
|
60
70
|
```
|
61
71
|
|
62
|
-
|
63
|
-
|
72
|
+
# Countries
|
73
|
+
|
74
|
+
List countries:
|
75
|
+
|
64
76
|
```ruby
|
65
|
-
|
66
|
-
raw = Metar::Raw::Data.new(metar_string)
|
67
|
-
parser = Metar::Parser.new(raw)
|
77
|
+
puts Metar::Station.countries
|
68
78
|
```
|
69
79
|
|
70
|
-
|
71
|
-
|
80
|
+
Find a country's weather stations:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
spanish = Metar::Station.find_all_by_country('Spain')
|
84
|
+
```
|
85
|
+
|
86
|
+
# Translations
|
87
|
+
|
72
88
|
Translations are available for the following languages (and region):
|
73
89
|
* :de
|
74
90
|
* :en
|
@@ -84,8 +100,7 @@ I18n.locale = :'en-US'
|
|
84
100
|
I18n.t('metar.station_code.title') # station code
|
85
101
|
```
|
86
102
|
|
87
|
-
Compliance
|
88
|
-
==========
|
103
|
+
# Compliance
|
89
104
|
|
90
105
|
By default, the parser runs in 'loose' compliance mode. That means that it tries to
|
91
106
|
accept non-standard input.
|
data/Rakefile
CHANGED
@@ -8,14 +8,3 @@ task :default => :spec
|
|
8
8
|
RSpec::Core::RakeTask.new do | t |
|
9
9
|
t.pattern = 'spec/**/*_spec.rb'
|
10
10
|
end
|
11
|
-
|
12
|
-
if RUBY_VERSION < '1.9'
|
13
|
-
|
14
|
-
RSpec::Core::RakeTask.new( 'spec:rcov' ) do |t|
|
15
|
-
t.pattern = 'spec/**/*_spec.rb'
|
16
|
-
t.rcov = true
|
17
|
-
t.rcov_opts = [ '--exclude', 'spec/,/gems/' ]
|
18
|
-
end
|
19
|
-
|
20
|
-
end
|
21
|
-
|
data/bin/parse_raw.rb
CHANGED
data/lib/metar/raw.rb
CHANGED
@@ -1,26 +1,70 @@
|
|
1
|
+
require 'date'
|
1
2
|
require 'net/ftp'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
module Metar
|
5
|
-
|
6
6
|
module Raw
|
7
|
-
|
8
7
|
class Base
|
9
|
-
attr_reader :cccc
|
10
8
|
attr_reader :metar
|
11
9
|
attr_reader :time
|
12
10
|
alias :to_s :metar
|
13
|
-
|
14
|
-
def parse
|
15
|
-
@cccc = @metar[/\w+/]
|
16
|
-
end
|
17
11
|
end
|
18
12
|
|
13
|
+
##
|
14
|
+
# Use this class when you have a METAR string and the date of reading
|
19
15
|
class Data < Base
|
20
|
-
def initialize(metar, time =
|
16
|
+
def initialize(metar, time = nil)
|
17
|
+
if time == nil
|
18
|
+
warn <<-EOT
|
19
|
+
Using Metar::Raw::Data without a time parameter is deprecated.
|
20
|
+
Please supply the reading time as the second parameter.
|
21
|
+
EOT
|
22
|
+
time = Time.now
|
23
|
+
end
|
21
24
|
@metar, @time = metar, time
|
25
|
+
end
|
26
|
+
end
|
22
27
|
|
23
|
-
|
28
|
+
##
|
29
|
+
# Use this class when you only have a METAR string.
|
30
|
+
# The date of the reading is decided as follows:
|
31
|
+
# * the day of the month is extracted from the METAR,
|
32
|
+
# * the most recent day with that day of the month is taken as the
|
33
|
+
# date of the reading.
|
34
|
+
class Metar < Base
|
35
|
+
def initialize(metar)
|
36
|
+
@metar = metar
|
37
|
+
@time = nil
|
38
|
+
end
|
39
|
+
|
40
|
+
def time
|
41
|
+
return @time if @time
|
42
|
+
dom = day_of_month
|
43
|
+
date = Date.today
|
44
|
+
loop do
|
45
|
+
if date.day >= dom
|
46
|
+
@time = Date.new(date.year, date.month, dom)
|
47
|
+
break
|
48
|
+
end
|
49
|
+
# skip to the last day of the previous month
|
50
|
+
date = Date.new(date.year, date.month, 1).prev_day
|
51
|
+
end
|
52
|
+
@time
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def datetime
|
58
|
+
datetime = metar[/^\w{4} (\d{6})Z/, 1]
|
59
|
+
raise "The METAR string must have a 6 digit datetime" if datetime.nil?
|
60
|
+
datetime
|
61
|
+
end
|
62
|
+
|
63
|
+
def day_of_month
|
64
|
+
dom = datetime[0..1].to_i
|
65
|
+
raise "Day of month must be at most 31" if dom > 31
|
66
|
+
raise "Day of month must be greater than 0" if dom == 0
|
67
|
+
dom
|
24
68
|
end
|
25
69
|
end
|
26
70
|
|
@@ -44,9 +88,9 @@ module Metar
|
|
44
88
|
end
|
45
89
|
|
46
90
|
def disconnect
|
47
|
-
return if
|
48
|
-
|
49
|
-
|
91
|
+
return if @@connection.nil
|
92
|
+
@@connection.close
|
93
|
+
@@connection = nil
|
50
94
|
end
|
51
95
|
|
52
96
|
def fetch(cccc)
|
@@ -101,13 +145,8 @@ module Metar
|
|
101
145
|
|
102
146
|
def parse
|
103
147
|
raw_time, @metar = @data.split("\n")
|
104
|
-
@time = Time.parse(raw_time)
|
105
|
-
super
|
148
|
+
@time = Time.parse(raw_time + " UTC")
|
106
149
|
end
|
107
|
-
|
108
150
|
end
|
109
|
-
|
110
151
|
end
|
111
|
-
|
112
152
|
end
|
113
|
-
|
data/lib/metar/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
data/spec/unit/distance_spec.rb
CHANGED
@@ -1,86 +1,76 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
|
2
|
+
require "spec_helper"
|
3
3
|
|
4
4
|
describe Metar::Distance do
|
5
|
+
let(:value) { 12345.6789 }
|
5
6
|
|
6
|
-
|
7
|
-
|
8
|
-
it 'should treat the parameter as meters' do
|
9
|
-
@distance = Metar::Distance.new( 12345.67 )
|
7
|
+
subject { described_class.new(value) }
|
10
8
|
|
11
|
-
|
12
|
-
|
9
|
+
context '#value' do
|
10
|
+
it 'treats the parameter as meters' do
|
11
|
+
expect(subject.units).to eq(:meters)
|
12
|
+
expect(subject.value).to eq(12345.6789)
|
13
13
|
end
|
14
|
-
|
15
14
|
end
|
16
15
|
|
17
16
|
context '#to_s' do
|
18
|
-
|
19
17
|
it 'should default to meters' do
|
20
|
-
|
21
|
-
|
22
|
-
@distance.to_s. should =~ %r(^\d+m)
|
18
|
+
expect(subject.to_s).to match(%r(^\d+m))
|
23
19
|
end
|
24
20
|
|
25
|
-
|
26
|
-
|
21
|
+
context 'when <= 0.5' do
|
22
|
+
let(:value) { 12.345678 }
|
27
23
|
|
28
|
-
|
24
|
+
it 'should round down to the nearest meter' do
|
25
|
+
expect(subject.to_s).to eq('12m')
|
26
|
+
end
|
29
27
|
end
|
30
28
|
|
31
|
-
|
32
|
-
|
29
|
+
context 'when > 0.5' do
|
30
|
+
let(:value) { 8.750 }
|
33
31
|
|
34
|
-
|
32
|
+
it 'should round up to meters' do
|
33
|
+
expect(subject.to_s).to eq('9m')
|
34
|
+
end
|
35
35
|
end
|
36
36
|
|
37
|
-
it '
|
38
|
-
|
39
|
-
|
40
|
-
@distance.to_s( :units => :kilometers ).
|
41
|
-
should == '12km'
|
37
|
+
it 'allows units overrides' do
|
38
|
+
expect(subject.to_s(units: :kilometers)).to eq('12km')
|
42
39
|
end
|
43
40
|
|
44
|
-
it '
|
45
|
-
|
46
|
-
|
47
|
-
@distance.to_s( :precision => 1 ).
|
48
|
-
should == '12.3m'
|
41
|
+
it 'allows precision overrides' do
|
42
|
+
expect(subject.to_s(precision: 1)).to eq('12345.7m')
|
49
43
|
end
|
50
44
|
|
51
|
-
|
52
|
-
|
45
|
+
context 'when value is nil' do
|
46
|
+
let(:value) { nil }
|
53
47
|
|
54
|
-
|
48
|
+
it 'is unknown' do
|
49
|
+
expect(subject.to_s).to eq('unknown')
|
50
|
+
end
|
55
51
|
end
|
56
52
|
|
57
53
|
context 'translated' do
|
58
|
-
|
59
|
-
before :each do
|
54
|
+
before do
|
60
55
|
@locale = I18n.locale
|
61
56
|
I18n.locale = :it
|
62
57
|
end
|
63
58
|
|
64
|
-
after
|
59
|
+
after do
|
65
60
|
I18n.locale = @locale
|
66
61
|
end
|
67
62
|
|
68
|
-
it '
|
69
|
-
|
70
|
-
|
71
|
-
@distance.to_s( :precision => 1 ).
|
72
|
-
should == '12,3m'
|
63
|
+
it 'localizes the decimal separator' do
|
64
|
+
expect(subject.to_s(precision: 1)).to eq('12345,7m')
|
73
65
|
end
|
74
66
|
|
75
|
-
|
76
|
-
|
67
|
+
context 'when value is nil' do
|
68
|
+
let(:value) { nil }
|
77
69
|
|
78
|
-
|
70
|
+
it 'translates' do
|
71
|
+
expect(subject.to_s).to eq('sconosciuto')
|
72
|
+
end
|
79
73
|
end
|
80
|
-
|
81
74
|
end
|
82
|
-
|
83
75
|
end
|
84
|
-
|
85
76
|
end
|
86
|
-
|
data/spec/unit/parser_spec.rb
CHANGED
@@ -1,19 +1,25 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
require 'spec_helper'
|
3
3
|
|
4
|
+
require 'timecop'
|
5
|
+
|
4
6
|
describe Metar::Parser do
|
5
7
|
after do
|
6
8
|
Metar::Parser.compliance = :loose
|
7
9
|
end
|
8
10
|
|
9
11
|
context '.for_cccc' do
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
Metar::Station.stub!(:new => station)
|
15
|
-
Metar::Raw::Noaa.stub!(:new => raw)
|
12
|
+
let(:station) { double(Metar::Station) }
|
13
|
+
let(:raw) { double(Metar::Raw::Noaa, metar: metar, time: time) }
|
14
|
+
let(:metar) { "XXXX 061610Z 24006KT 1 3/4SM -SN BKN016 OVC030 M17/M20 A2910 RMK AO2 P0000" }
|
15
|
+
let(:time) { '2010/02/06 16:10' }
|
16
16
|
|
17
|
+
before do
|
18
|
+
allow(Metar::Station).to receive(:new) { station }
|
19
|
+
allow(Metar::Raw::Noaa).to receive(:new) { raw }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns a loaded parser' do
|
17
23
|
parser = Metar::Parser.for_cccc('XXXX')
|
18
24
|
|
19
25
|
expect(parser).to be_a(Metar::Parser)
|
@@ -22,10 +28,10 @@ describe Metar::Parser do
|
|
22
28
|
end
|
23
29
|
|
24
30
|
context 'attributes' do
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
31
|
+
let(:call_time) { Time.parse('2011-05-06 16:35') }
|
32
|
+
|
33
|
+
before { Timecop.freeze(call_time) }
|
34
|
+
after { Timecop.return }
|
29
35
|
|
30
36
|
it '.location missing' do
|
31
37
|
expect do
|
@@ -46,6 +52,21 @@ describe Metar::Parser do
|
|
46
52
|
end.to raise_error(Metar::ParseError, /Expecting datetime/)
|
47
53
|
end
|
48
54
|
|
55
|
+
context 'across a month rollover' do
|
56
|
+
let(:time) { Time.gm(2016, 3, 31, 23, 59) }
|
57
|
+
let(:metar) { "OPPS 312359Z 23006KT 4000 HZ SCT040 SCT100 17/12 Q1011" }
|
58
|
+
let(:raw) { double(Metar::Raw, metar: metar, time: time) }
|
59
|
+
let(:call_time) { Time.parse("2016/04/01 00:02:11 PDT") }
|
60
|
+
|
61
|
+
subject { described_class.new(raw) }
|
62
|
+
|
63
|
+
it 'has the correct date' do
|
64
|
+
expect(subject.time.year).to eq(2016)
|
65
|
+
expect(subject.time.month).to eq(3)
|
66
|
+
expect(subject.time.day).to eq(31)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
49
70
|
context 'in strict mode' do
|
50
71
|
before do
|
51
72
|
Metar::Parser.compliance = :strict
|
@@ -295,7 +316,7 @@ describe Metar::Parser do
|
|
295
316
|
end
|
296
317
|
|
297
318
|
def setup_parser(metar)
|
298
|
-
raw = Metar::Raw::Data.new(metar)
|
319
|
+
raw = Metar::Raw::Data.new(metar, Time.now)
|
299
320
|
Metar::Parser.new(raw)
|
300
321
|
end
|
301
322
|
end
|